mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-11-26 15:35:52 +00:00
Use noble-ed25519 over tweetnacl for signature verification
Much faster than tweetnacl, and no constant-timeness required. We are not using v2 for now, despite being smaller, because it relies on bigint literals, and it requires polyfilling the WebCrypto lib manually in Node < 19.
This commit is contained in:
parent
4026e24585
commit
3d9b2899d0
19
package-lock.json
generated
19
package-lock.json
generated
@ -10,6 +10,7 @@
|
||||
"license": "LGPL-3.0+",
|
||||
"devDependencies": {
|
||||
"@noble/curves": "^1.4.0",
|
||||
"@noble/ed25519": "^1.7.3",
|
||||
"@noble/hashes": "^1.4.0",
|
||||
"@openpgp/asmcrypto.js": "^3.1.0",
|
||||
"@openpgp/jsdoc": "^3.6.11",
|
||||
@ -813,6 +814,18 @@
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/ed25519": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz",
|
||||
"integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz",
|
||||
@ -9050,6 +9063,12 @@
|
||||
"@noble/hashes": "1.4.0"
|
||||
}
|
||||
},
|
||||
"@noble/ed25519": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz",
|
||||
"integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@noble/hashes": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz",
|
||||
|
||||
@ -63,6 +63,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@noble/curves": "^1.4.0",
|
||||
"@noble/ed25519": "^1.7.3",
|
||||
"@noble/hashes": "^1.4.0",
|
||||
"@openpgp/asmcrypto.js": "^3.1.0",
|
||||
"@openpgp/jsdoc": "^3.6.11",
|
||||
|
||||
@ -70,6 +70,13 @@ export default Object.assign([
|
||||
commonjs({
|
||||
ignore: nodeBuiltinModules.concat(nodeDependencies)
|
||||
}),
|
||||
replace({
|
||||
include: 'node_modules/@noble/ed25519/**',
|
||||
// Rollup ignores the `browser: { crypto: false }` directive in package.json, since `exports` are present,
|
||||
// hence we need to manually drop it.
|
||||
"import * as nodeCrypto from 'crypto'": 'const nodeCrypto = null',
|
||||
delimiters: ['', '']
|
||||
}),
|
||||
replace({
|
||||
'OpenPGP.js VERSION': `OpenPGP.js ${pkg.version}`,
|
||||
"import { createRequire } from 'module';": 'const createRequire = () => () => {}',
|
||||
@ -119,6 +126,13 @@ export default Object.assign([
|
||||
commonjs({
|
||||
ignore: nodeBuiltinModules.concat(nodeDependencies)
|
||||
}),
|
||||
replace({
|
||||
include: 'node_modules/@noble/ed25519/**',
|
||||
// Rollup ignores the `browser: { crypto: false }` directive in package.json, since `exports` are present,
|
||||
// hence we need to manually drop it.
|
||||
"import * as nodeCrypto from 'crypto'": 'const nodeCrypto = null',
|
||||
delimiters: ['', '']
|
||||
}),
|
||||
replace({
|
||||
'OpenPGP.js VERSION': `OpenPGP.js ${pkg.version}`,
|
||||
"import { createRequire } from 'module';": 'const createRequire = () => () => {}',
|
||||
@ -149,6 +163,13 @@ export default Object.assign([
|
||||
ignore: nodeBuiltinModules.concat(nodeDependencies),
|
||||
requireReturnsDefault: 'preferred'
|
||||
}),
|
||||
replace({
|
||||
include: 'node_modules/@noble/ed25519/**',
|
||||
// Rollup ignores the `browser: { crypto: false }` directive in package.json, since `exports` are present,
|
||||
// hence we need to manually drop it.
|
||||
"import * as nodeCrypto from 'crypto'": 'const nodeCrypto = null',
|
||||
delimiters: ['', '']
|
||||
}),
|
||||
replace({
|
||||
"import { createRequire } from 'module';": 'const createRequire = () => () => {}',
|
||||
delimiters: ['', '']
|
||||
|
||||
@ -20,7 +20,9 @@
|
||||
* @module crypto/public_key/elliptic/eddsa
|
||||
*/
|
||||
|
||||
import ed25519 from '@openpgp/tweetnacl';
|
||||
import naclEd25519 from '@openpgp/tweetnacl'; // better constant-timeness as it uses Uint8Arrays over BigInts
|
||||
import { verify as nobleEd25519Verify } from '@noble/ed25519';
|
||||
|
||||
import util from '../../../util';
|
||||
import enums from '../../../enums';
|
||||
import hash from '../../hash';
|
||||
@ -36,7 +38,7 @@ export async function generate(algo) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.ed25519: {
|
||||
const seed = getRandomBytes(getPayloadSize(algo));
|
||||
const { publicKey: A } = ed25519.sign.keyPair.fromSeed(seed);
|
||||
const { publicKey: A } = naclEd25519.sign.keyPair.fromSeed(seed);
|
||||
return { A, seed };
|
||||
}
|
||||
case enums.publicKey.ed448: {
|
||||
@ -70,7 +72,7 @@ export async function sign(algo, hashAlgo, message, publicKey, privateKey, hashe
|
||||
switch (algo) {
|
||||
case enums.publicKey.ed25519: {
|
||||
const secretKey = util.concatUint8Array([privateKey, publicKey]);
|
||||
const signature = ed25519.sign.detached(hashed, secretKey);
|
||||
const signature = naclEd25519.sign.detached(hashed, secretKey);
|
||||
return { RS: signature };
|
||||
}
|
||||
case enums.publicKey.ed448: {
|
||||
@ -101,7 +103,7 @@ export async function verify(algo, hashAlgo, { RS }, m, publicKey, hashed) {
|
||||
}
|
||||
switch (algo) {
|
||||
case enums.publicKey.ed25519:
|
||||
return ed25519.sign.detached.verify(hashed, RS, publicKey);
|
||||
return nobleEd25519Verify(RS, hashed, publicKey);
|
||||
case enums.publicKey.ed448: {
|
||||
const ed448 = await util.getNobleCurve(enums.publicKey.ed448);
|
||||
return ed448.verify(RS, hashed, publicKey);
|
||||
@ -126,7 +128,7 @@ export async function validateParams(algo, A, seed) {
|
||||
* Derive public point A' from private key
|
||||
* and expect A == A'
|
||||
*/
|
||||
const { publicKey } = ed25519.sign.keyPair.fromSeed(seed);
|
||||
const { publicKey } = naclEd25519.sign.keyPair.fromSeed(seed);
|
||||
return util.equalsUint8Array(A, publicKey);
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,8 @@
|
||||
* @module crypto/public_key/elliptic/eddsa_legacy
|
||||
*/
|
||||
|
||||
import nacl from '@openpgp/tweetnacl';
|
||||
import naclEd25519 from '@openpgp/tweetnacl'; // better constant-timeness as it uses Uint8Arrays over BigInts
|
||||
import { verify as nobleEd25519Verify } from '@noble/ed25519';
|
||||
import util from '../../../util';
|
||||
import enums from '../../../enums';
|
||||
import hash from '../../hash';
|
||||
@ -49,7 +50,7 @@ export async function sign(oid, hashAlgo, message, publicKey, privateKey, hashed
|
||||
throw new Error('Hash algorithm too weak for EdDSA.');
|
||||
}
|
||||
const secretKey = util.concatUint8Array([privateKey, publicKey.subarray(1)]);
|
||||
const signature = nacl.sign.detached(hashed, secretKey);
|
||||
const signature = naclEd25519.sign.detached(hashed, secretKey);
|
||||
// EdDSA signature params are returned in little-endian format
|
||||
return {
|
||||
r: signature.subarray(0, 32),
|
||||
@ -76,7 +77,7 @@ export async function verify(oid, hashAlgo, { r, s }, m, publicKey, hashed) {
|
||||
throw new Error('Hash algorithm too weak for EdDSA.');
|
||||
}
|
||||
const signature = util.concatUint8Array([r, s]);
|
||||
return nacl.sign.detached.verify(hashed, signature, publicKey.subarray(1));
|
||||
return nobleEd25519Verify(signature, hashed, publicKey.subarray(1));
|
||||
}
|
||||
/**
|
||||
* Validate legacy EdDSA parameters
|
||||
@ -96,7 +97,7 @@ export async function validateParams(oid, Q, k) {
|
||||
* Derive public point Q' = dG from private key
|
||||
* and expect Q == Q'
|
||||
*/
|
||||
const { publicKey } = nacl.sign.keyPair.fromSeed(k);
|
||||
const { publicKey } = naclEd25519.sign.keyPair.fromSeed(k);
|
||||
const dG = new Uint8Array([0x40, ...publicKey]); // Add public key prefix
|
||||
return util.equalsUint8Array(Q, dG);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user