diff --git a/openpgp.d.ts b/openpgp.d.ts index 5b4e567ce..3baca2221 100644 --- a/openpgp.d.ts +++ b/openpgp.d.ts @@ -345,7 +345,7 @@ interface Config { rejectPublicKeyAlgorithms: Set; rejectCurves: Set; } -export var config: Config; +export var config: Config & { checkEdDSAFaultySignatures: boolean }; // option only supported if set at the global openpgp.config level // PartialConfig has the same properties as Config, but declared as optional. // This interface is relevant for top-level functions, which accept a subset of configuration options diff --git a/src/config/config.js b/src/config/config.js index a5b60896f..dcf68d728 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -286,5 +286,12 @@ export default { * @memberof module:config * @property {Set} rejectCurves {@link module:enums.curve} */ - rejectCurves: new Set([enums.curve.secp256k1]) + rejectCurves: new Set([enums.curve.secp256k1]), + /** + * Whether to validate generated EdDSA signatures before returning them, to ensure they are not faulty signatures. + * This check will make signing 2-3 times slower. + * Faulty signatures may be generated (in principle) if random bitflips occur at specific points in the signature + * computation, and could be used to recover the signer's secret key given a second signature over the same data. + */ + checkEdDSAFaultySignatures: true }; diff --git a/src/crypto/public_key/elliptic/eddsa.js b/src/crypto/public_key/elliptic/eddsa.js index 33649c4e4..c7acf0d6b 100644 --- a/src/crypto/public_key/elliptic/eddsa.js +++ b/src/crypto/public_key/elliptic/eddsa.js @@ -27,6 +27,7 @@ import util from '../../../util'; import enums from '../../../enums'; import hash from '../../hash'; import { getRandomBytes } from '../../random'; +import defaultConfig from '../../../config'; nacl.hash = bytes => new Uint8Array(sha512().update(bytes).digest()); @@ -68,7 +69,7 @@ export async function sign(algo, hashAlgo, message, publicKey, privateKey, hashe case enums.publicKey.ed25519: { const secretKey = util.concatUint8Array([privateKey, publicKey]); const signature = nacl.sign.detached(hashed, secretKey); - if (!nacl.sign.detached.verify(hashed, signature, publicKey)) { + if (defaultConfig.checkEdDSAFaultySignatures && !nacl.sign.detached.verify(hashed, signature, publicKey)) { /** * Detect faulty signatures caused by random bitflips during `crypto_sign` which could lead to private key extraction * if two signatures over the same message are obtained. diff --git a/src/crypto/public_key/elliptic/eddsa_legacy.js b/src/crypto/public_key/elliptic/eddsa_legacy.js index c21e321dc..65b5f7fce 100644 --- a/src/crypto/public_key/elliptic/eddsa_legacy.js +++ b/src/crypto/public_key/elliptic/eddsa_legacy.js @@ -27,6 +27,7 @@ import nacl from '@openpgp/tweetnacl/nacl-fast-light'; import util from '../../../util'; import enums from '../../../enums'; import hash from '../../hash'; +import defaultConfig from '../../../config'; nacl.hash = bytes => new Uint8Array(sha512().update(bytes).digest()); @@ -51,7 +52,7 @@ export async function sign(oid, hashAlgo, message, publicKey, privateKey, hashed } const secretKey = util.concatUint8Array([privateKey, publicKey.subarray(1)]); const signature = nacl.sign.detached(hashed, secretKey); - if (!nacl.sign.detached.verify(hashed, signature, publicKey.subarray(1))) { + if (defaultConfig.checkEdDSAFaultySignatures && !nacl.sign.detached.verify(hashed, signature, publicKey.subarray(1))) { /** * Detect faulty signatures caused by random bitflips during `crypto_sign` which could lead to private key extraction * if two signatures over the same message are obtained.