diff --git a/src/crypto/hash/index.js b/src/crypto/hash/index.js index 0e2a6c6c..1d829611 100644 --- a/src/crypto/hash/index.js +++ b/src/crypto/hash/index.js @@ -20,11 +20,12 @@ import stream from 'web-stream-tools'; import md5 from './md5'; import util from '../../util'; +const webCrypto = util.getWebCrypto(); const nodeCrypto = util.getNodeCrypto(); const Buffer = util.getNodeBuffer(); function node_hash(type) { - return function (data) { + return async function (data) { const shasum = nodeCrypto.createHash(type); return stream.transform(data, value => { shasum.update(new Buffer(value)); @@ -32,8 +33,11 @@ function node_hash(type) { }; } -function hashjs_hash(hash) { - return function(data) { +function hashjs_hash(hash, webCryptoHash) { + return async function(data) { + if (!util.isStream(data) && webCrypto && webCryptoHash) { + return new Uint8Array(await webCrypto.digest(webCryptoHash, data)); + } const hashInstance = hash(); return stream.transform(data, value => { hashInstance.update(value); @@ -41,13 +45,15 @@ function hashjs_hash(hash) { }; } -function asmcrypto_hash(hash) { - return function(data) { +function asmcrypto_hash(hash, webCryptoHash) { + return async function(data) { if (util.isStream(data)) { const hashInstance = new hash(); return stream.transform(data, value => { hashInstance.process(value); }, () => hashInstance.finish().result); + } else if (webCrypto && webCryptoHash) { + return new Uint8Array(await webCrypto.digest(webCryptoHash, data)); } else { return hash.bytes(data); } @@ -68,11 +74,11 @@ if (nodeCrypto) { // Use Node native crypto for all hash functions } else { // Use JS fallbacks hash_fns = { md5: md5, - sha1: asmcrypto_hash(Sha1), + sha1: asmcrypto_hash(Sha1, navigator.userAgent.indexOf('Edge') === -1 && 'SHA-1'), sha224: hashjs_hash(sha224), - sha256: asmcrypto_hash(Sha256), - sha384: hashjs_hash(sha384), - sha512: hashjs_hash(sha512), // asmcrypto sha512 is huge. + sha256: asmcrypto_hash(Sha256, 'SHA-256'), + sha384: hashjs_hash(sha384, 'SHA-384'), + sha512: hashjs_hash(sha512, 'SHA-512'), // asmcrypto sha512 is huge. ripemd: hashjs_hash(ripemd160) }; } diff --git a/src/crypto/hash/md5.js b/src/crypto/hash/md5.js index 5b0e71f4..fb277030 100644 --- a/src/crypto/hash/md5.js +++ b/src/crypto/hash/md5.js @@ -19,7 +19,7 @@ import util from '../../util'; // MD5 Digest -function md5(entree) { +async function md5(entree) { const digest = md51(util.Uint8Array_to_str(entree)); return util.hex_to_Uint8Array(hex(digest)); } diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js index db8195bb..c5421189 100644 --- a/src/crypto/public_key/elliptic/ecdh.js +++ b/src/crypto/public_key/elliptic/ecdh.js @@ -49,12 +49,13 @@ function buildEcdhParam(public_algo, oid, cipher_algo, hash_algo, fingerprint) { } // Key Derivation Function (RFC 6637) -function kdf(hash_algo, X, length, param) { - return hash.digest(hash_algo, util.concatUint8Array([ +async function kdf(hash_algo, X, length, param) { + const digest = await hash.digest(hash_algo, util.concatUint8Array([ new Uint8Array([0, 0, 0, 1]), new Uint8Array(X), param - ])).subarray(0, length); + ])); + return digest.subarray(0, length); } @@ -77,7 +78,7 @@ async function encrypt(oid, cipher_algo, hash_algo, m, Q, fingerprint) { const v = await curve.genKeyPair(); Q = curve.keyFromPublic(Q); const S = v.derive(Q); - const Z = kdf(hash_algo, S, cipher[cipher_algo].keySize, param); + const Z = await kdf(hash_algo, S, cipher[cipher_algo].keySize, param); const C = aes_kw.wrap(Z, m.toString()); return { V: new BN(v.getPublic()), @@ -105,7 +106,7 @@ async function decrypt(oid, cipher_algo, hash_algo, V, C, d, fingerprint) { V = curve.keyFromPublic(V); d = curve.keyFromPrivate(d); const S = d.derive(V); - const Z = kdf(hash_algo, S, cipher[cipher_algo].keySize, param); + const Z = await kdf(hash_algo, S, cipher[cipher_algo].keySize, param); return new BN(aes_kw.unwrap(Z, C)); } diff --git a/src/message.js b/src/message.js index 9405dd42..87e1f8d0 100644 --- a/src/message.js +++ b/src/message.js @@ -553,14 +553,14 @@ Message.prototype.verify = async function(keys, date=new Date(), streaming) { const onePassSigList = msg.packets.filterByTag(enums.packet.onePassSignature).reverse(); const signatureList = msg.packets.filterByTag(enums.packet.signature); if (onePassSigList.length && !signatureList.length && msg.packets.stream) { - onePassSigList.forEach(onePassSig => { + await Promise.all(onePassSigList.map(async onePassSig => { onePassSig.correspondingSig = new Promise((resolve, reject) => { onePassSig.correspondingSigResolve = resolve; onePassSig.correspondingSigReject = reject; }); onePassSig.signatureData = stream.fromAsync(async () => (await onePassSig.correspondingSig).signatureData); - onePassSig.hashed = onePassSig.hash(literalDataList[0], undefined, streaming); - }); + onePassSig.hashed = await onePassSig.hash(literalDataList[0], undefined, streaming); + })); msg.packets.stream = stream.transformPair(msg.packets.stream, async (readable, writable) => { const reader = stream.getReader(readable); const writer = stream.getWriter(writable); diff --git a/src/packet/public_key.js b/src/packet/public_key.js index 87d9c219..023e26db 100644 --- a/src/packet/public_key.js +++ b/src/packet/public_key.js @@ -24,6 +24,8 @@ * @requires util */ +import { Sha1 } from 'asmcrypto.js/dist_es5/hash/sha1/sha1'; +import { Sha256 } from 'asmcrypto.js/dist_es5/hash/sha256/sha256'; import type_keyid from '../type/keyid'; import type_mpi from '../type/mpi'; import config from '../config'; @@ -215,10 +217,10 @@ PublicKey.prototype.getFingerprintBytes = function () { if (this.version === 5) { const bytes = this.writePublicKey(); toHash = util.concatUint8Array([new Uint8Array([0x9A]), util.writeNumber(bytes.length, 4), bytes]); - this.fingerprint = crypto.hash.sha256(toHash); + this.fingerprint = Sha256.bytes(toHash); } else if (this.version === 4) { toHash = this.writeOld(); - this.fingerprint = crypto.hash.sha1(toHash); + this.fingerprint = Sha1.bytes(toHash); } return this.fingerprint; }; diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js index ccfec0b7..497dce3c 100644 --- a/src/packet/secret_key.js +++ b/src/packet/secret_key.js @@ -59,38 +59,13 @@ function SecretKey(date=new Date()) { SecretKey.prototype = new publicKey(); SecretKey.prototype.constructor = SecretKey; -function get_hash_len(hash) { - if (hash === 'sha1') { - return 20; - } - return 2; -} - -function get_hash_fn(hash) { - if (hash === 'sha1') { - return crypto.hash.sha1; - } - return function(c) { - return util.writeNumber(util.calc_checksum(c), 2); - }; +function write_checksum(c) { + return util.writeNumber(util.calc_checksum(c), 2); } // Helper function -function parse_cleartext_params(hash_algorithm, cleartext, algorithm) { - if (hash_algorithm) { - const hashlen = get_hash_len(hash_algorithm); - const hashfn = get_hash_fn(hash_algorithm); - - const hashtext = util.Uint8Array_to_str(cleartext.subarray(cleartext.length - hashlen, cleartext.length)); - cleartext = cleartext.subarray(0, cleartext.length - hashlen); - const hash = util.Uint8Array_to_str(hashfn(cleartext)); - - if (hash !== hashtext) { - throw new Error("Incorrect key passphrase"); - } - } - +function parse_cleartext_params(cleartext, algorithm) { const algo = enums.write(enums.publicKey, algorithm); const types = crypto.getPrivKeyParamTypes(algo); const params = crypto.constructParams(types); @@ -106,7 +81,7 @@ function parse_cleartext_params(hash_algorithm, cleartext, algorithm) { return params; } -function write_cleartext_params(hash_algorithm, algorithm, params) { +function write_cleartext_params(params, algorithm) { const arr = []; const algo = enums.write(enums.publicKey, algorithm); const numPublicParams = crypto.getPubKeyParamTypes(algo).length; @@ -115,15 +90,7 @@ function write_cleartext_params(hash_algorithm, algorithm, params) { arr.push(params[i].write()); } - const bytes = util.concatUint8Array(arr); - - if (hash_algorithm) { - const hash = get_hash_fn(hash_algorithm)(bytes); - - return util.concatUint8Array([bytes, hash]); - } - - return bytes; + return util.concatUint8Array(arr); } @@ -154,7 +121,11 @@ SecretKey.prototype.read = function (bytes) { // - Plain or encrypted multiprecision integers comprising the secret // key data. These algorithm-specific fields are as described // below. - const privParams = parse_cleartext_params('mod', bytes.subarray(1, bytes.length), this.algorithm); + const cleartext = bytes.subarray(1, -2); + if (!util.equalsUint8Array(write_checksum(cleartext), bytes.subarray(-2))) { + throw new Error('Key checksum mismatch'); + } + const privParams = parse_cleartext_params(cleartext, this.algorithm); this.params = this.params.concat(privParams); this.isEncrypted = false; } @@ -169,7 +140,9 @@ SecretKey.prototype.write = function () { if (!this.encrypted) { arr.push(new Uint8Array([0])); - arr.push(write_cleartext_params('mod', this.algorithm, this.params)); + const cleartextParams = write_cleartext_params(this.params, this.algorithm); + arr.push(cleartextParams); + arr.push(write_checksum(cleartextParams)); } else { arr.push(this.encrypted); } @@ -205,9 +178,8 @@ SecretKey.prototype.encrypt = async function (passphrase) { const s2k = new type_s2k(); s2k.salt = await crypto.random.getRandomBytes(8); const symmetric = 'aes256'; - const hash = this.version === 5 ? null : 'sha1'; - const cleartext = write_cleartext_params(hash, this.algorithm, this.params); - const key = produceEncryptionKey(s2k, passphrase, symmetric); + const cleartext = write_cleartext_params(this.params, this.algorithm); + const key = await produceEncryptionKey(s2k, passphrase, symmetric); const blockLen = crypto.cipher[symmetric].blockSize; const iv = await crypto.random.getRandomBytes(blockLen); @@ -227,14 +199,17 @@ SecretKey.prototype.encrypt = async function (passphrase) { arr = [new Uint8Array([254, enums.write(enums.symmetric, symmetric)])]; arr.push(s2k.write()); arr.push(iv); - arr.push(crypto.cfb.normalEncrypt(symmetric, key, cleartext, iv)); + arr.push(crypto.cfb.normalEncrypt(symmetric, key, util.concatUint8Array([ + cleartext, + await crypto.hash.sha1(cleartext) + ]), iv)); } this.encrypted = util.concatUint8Array(arr); return true; }; -function produceEncryptionKey(s2k, passphrase, algorithm) { +async function produceEncryptionKey(s2k, passphrase, algorithm) { return s2k.produce_key( passphrase, crypto.cipher[algorithm].keySize @@ -286,11 +261,11 @@ SecretKey.prototype.decrypt = async function (passphrase) { const s2k = new type_s2k(); i += s2k.read(this.encrypted.subarray(i, this.encrypted.length)); - key = produceEncryptionKey(s2k, passphrase, symmetric); + key = await produceEncryptionKey(s2k, passphrase, symmetric); } else { symmetric = s2k_usage; symmetric = enums.read(enums.symmetric, symmetric); - key = crypto.hash.md5(passphrase); + key = await crypto.hash.md5(passphrase); } // - [Optional] If secret data is encrypted (string-to-key usage octet @@ -322,14 +297,26 @@ SecretKey.prototype.decrypt = async function (passphrase) { } } } else { - cleartext = crypto.cfb.normalDecrypt(symmetric, key, ciphertext, iv); - } - const hash = - s2k_usage === 253 ? null : - s2k_usage === 254 ? 'sha1' : - 'mod'; + const cleartextWithHash = crypto.cfb.normalDecrypt(symmetric, key, ciphertext, iv); - const privParams = parse_cleartext_params(hash, cleartext, this.algorithm); + let hash; + let hashlen; + if (s2k_usage === 255) { + hashlen = 2; + cleartext = cleartextWithHash.subarray(0, -hashlen); + hash = write_checksum(cleartext); + } else { + hashlen = 20; + cleartext = cleartextWithHash.subarray(0, -hashlen); + hash = await crypto.hash.sha1(cleartext); + } + + if (!util.equalsUint8Array(hash, cleartextWithHash.subarray(-hashlen))) { + throw new Error('Incorrect key passphrase'); + } + } + + const privParams = parse_cleartext_params(cleartext, this.algorithm); this.params = this.params.concat(privParams); this.isEncrypted = false; this.encrypted = null; diff --git a/src/packet/signature.js b/src/packet/signature.js index 25464690..a3ab97f0 100644 --- a/src/packet/signature.js +++ b/src/packet/signature.js @@ -193,7 +193,7 @@ Signature.prototype.sign = async function (key, data) { this.signatureData = util.concat(arr); const toHash = this.toHash(data); - const hash = this.hash(data, toHash); + const hash = await this.hash(data, toHash); this.signedHashValue = stream.slice(stream.clone(hash), 0, 2); @@ -606,7 +606,7 @@ Signature.prototype.toHash = function(data) { return util.concat([bytes, this.signatureData, this.calculateTrailer()]); }; -Signature.prototype.hash = function(data, toHash, streaming=true) { +Signature.prototype.hash = async function(data, toHash, streaming=true) { const hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm); if (!toHash) toHash = this.toHash(data); if (!streaming && util.isStream(toHash)) { @@ -634,7 +634,7 @@ Signature.prototype.verify = async function (key, data) { hash = this.hashed; } else { toHash = this.toHash(data); - hash = this.hash(data, toHash); + hash = await this.hash(data, toHash); } hash = await stream.readToEnd(hash); diff --git a/src/packet/sym_encrypted_integrity_protected.js b/src/packet/sym_encrypted_integrity_protected.js index 88468576..4362ee5d 100644 --- a/src/packet/sym_encrypted_integrity_protected.js +++ b/src/packet/sym_encrypted_integrity_protected.js @@ -100,7 +100,7 @@ SymEncryptedIntegrityProtected.prototype.encrypt = async function (sessionKeyAlg const mdc = new Uint8Array([0xD3, 0x14]); // modification detection code packet let tohash = util.concat([bytes, mdc]); - const hash = crypto.hash.sha1(util.concat([prefix, stream.passiveClone(tohash)])); + const hash = await crypto.hash.sha1(util.concat([prefix, stream.passiveClone(tohash)])); tohash = util.concat([tohash, hash]); if (sessionKeyAlgorithm.substr(0, 3) === 'aes') { // AES optimizations. Native code for node, asmCrypto for browser. @@ -140,7 +140,7 @@ SymEncryptedIntegrityProtected.prototype.decrypt = async function (sessionKeyAlg const bytes = stream.slice(decrypted, 0, -20); const tohash = util.concat([prefix, stream.passiveClone(bytes)]); const verifyHash = Promise.all([ - stream.readToEnd(crypto.hash.sha1(tohash)), + stream.readToEnd(await crypto.hash.sha1(tohash)), stream.readToEnd(realHash) ]).then(([hash, mdc]) => { if (!util.equalsUint8Array(hash, mdc)) { diff --git a/src/packet/sym_encrypted_session_key.js b/src/packet/sym_encrypted_session_key.js index c0a26049..b371f0e9 100644 --- a/src/packet/sym_encrypted_session_key.js +++ b/src/packet/sym_encrypted_session_key.js @@ -137,7 +137,7 @@ SymEncryptedSessionKey.prototype.decrypt = async function(passphrase) { this.sessionKeyAlgorithm; const length = crypto.cipher[algo].keySize; - const key = this.s2k.produce_key(passphrase, length); + const key = await this.s2k.produce_key(passphrase, length); if (this.version === 5) { const mode = crypto[this.aeadAlgorithm]; @@ -173,7 +173,7 @@ SymEncryptedSessionKey.prototype.encrypt = async function(passphrase) { this.s2k.salt = await crypto.random.getRandomBytes(8); const length = crypto.cipher[algo].keySize; - const key = this.s2k.produce_key(passphrase, length); + const key = await this.s2k.produce_key(passphrase, length); if (this.sessionKey === null) { this.sessionKey = await crypto.generateSessionKey(this.sessionKeyAlgorithm); diff --git a/src/type/s2k.js b/src/type/s2k.js index ce644941..0e5745f6 100644 --- a/src/type/s2k.js +++ b/src/type/s2k.js @@ -142,10 +142,10 @@ S2K.prototype.write = function () { * @returns {Uint8Array} Produced key with a length corresponding to * hashAlgorithm hash length */ -S2K.prototype.produce_key = function (passphrase, numBytes) { +S2K.prototype.produce_key = async function (passphrase, numBytes) { passphrase = util.encode_utf8(passphrase); - function round(prefix, s2k) { + async function round(prefix, s2k) { const algorithm = enums.write(enums.hash, s2k.algorithm); switch (s2k.type) { @@ -189,7 +189,7 @@ S2K.prototype.produce_key = function (passphrase, numBytes) { let i = 0; while (rlength < numBytes) { - const result = round(prefix.subarray(0, i), this); + const result = await round(prefix.subarray(0, i), this); arr.push(result); rlength += result.length; i++; diff --git a/src/wkd.js b/src/wkd.js index 4c3dfa69..84db8031 100644 --- a/src/wkd.js +++ b/src/wkd.js @@ -43,7 +43,7 @@ function WKD() { * err: (Array|null)}>} The public key. * @async */ -WKD.prototype.lookup = function(options) { +WKD.prototype.lookup = async function(options) { const fetch = this._fetch; if (!options.email) { @@ -55,7 +55,7 @@ WKD.prototype.lookup = function(options) { } const [, localPart, domain] = /(.*)@(.*)/.exec(options.email); - const localEncoded = util.encodeZBase32(crypto.hash.sha1(util.str_to_Uint8Array(localPart.toLowerCase()))); + const localEncoded = util.encodeZBase32(await crypto.hash.sha1(util.str_to_Uint8Array(localPart.toLowerCase()))); const url = `https://${domain}/.well-known/openpgpkey/hu/${localEncoded}`; diff --git a/test/crypto/crypto.js b/test/crypto/crypto.js index 081ac5c3..00d03e70 100644 --- a/test/crypto/crypto.js +++ b/test/crypto/crypto.js @@ -234,28 +234,28 @@ describe('API functional testing', function() { const data = util.str_to_Uint8Array("foobar"); describe('Sign and verify', function () { - it('RSA', function () { + it('RSA', async function () { // FIXME //Originally we passed public and secret MPI separately, now they are joined. Is this what we want to do long term? // RSA return crypto.signature.sign( - 1, 2, RSApubMPIs.concat(RSAsecMPIs), data, crypto.hash.digest(2, data) - ).then(RSAsignedData => { + 1, 2, RSApubMPIs.concat(RSAsecMPIs), data, await crypto.hash.digest(2, data) + ).then(async RSAsignedData => { const RSAsignedDataMPI = new openpgp.MPI(); RSAsignedDataMPI.read(RSAsignedData); return crypto.signature.verify( - 1, 2, [RSAsignedDataMPI], RSApubMPIs, data, crypto.hash.digest(2, data) + 1, 2, [RSAsignedDataMPI], RSApubMPIs, data, await crypto.hash.digest(2, data) ).then(success => { return expect(success).to.be.true; }); }); }); - it('DSA', function () { + it('DSA', async function () { // DSA return crypto.signature.sign( - 17, 2, DSApubMPIs.concat(DSAsecMPIs), data, crypto.hash.digest(2, data) - ).then(DSAsignedData => { + 17, 2, DSApubMPIs.concat(DSAsecMPIs), data, await crypto.hash.digest(2, data) + ).then(async DSAsignedData => { DSAsignedData = util.Uint8Array_to_str(DSAsignedData); const DSAmsgMPIs = []; DSAmsgMPIs[0] = new openpgp.MPI(); @@ -263,7 +263,7 @@ describe('API functional testing', function() { DSAmsgMPIs[0].read(DSAsignedData.substring(0,34)); DSAmsgMPIs[1].read(DSAsignedData.substring(34,68)); return crypto.signature.verify( - 17, 2, DSAmsgMPIs, DSApubMPIs, data, crypto.hash.digest(2, data) + 17, 2, DSAmsgMPIs, DSApubMPIs, data, await crypto.hash.digest(2, data) ).then(success => { return expect(success).to.be.true; }); diff --git a/test/crypto/elliptic.js b/test/crypto/elliptic.js index 22da58f2..9e1b72c8 100644 --- a/test/crypto/elliptic.js +++ b/test/crypto/elliptic.js @@ -6,7 +6,7 @@ chai.use(require('chai-as-promised')); const expect = chai.expect; -describe('Elliptic Curve Cryptography', function () { +describe('Elliptic Curve Cryptography', async function () { const elliptic_curves = openpgp.crypto.publicKey.elliptic; const key_data = { p256: { @@ -138,7 +138,7 @@ describe('Elliptic Curve Cryptography', function () { ]) } }; - signature_data.hashed = openpgp.crypto.hash.digest(8, signature_data.message); + signature_data.hashed = await openpgp.crypto.hash.digest(8, signature_data.message); describe('Basic Operations', function () { it('Creating curve from name or oid', function (done) { for (let name_or_oid in openpgp.enums.curves) { @@ -206,7 +206,7 @@ describe('Elliptic Curve Cryptography', function () { }); }); describe('ECDSA signature', function () { - const verify_signature = function (oid, hash, r, s, message, pub) { + const verify_signature = async function (oid, hash, r, s, message, pub) { if (openpgp.util.isString(message)) { message = openpgp.util.str_to_Uint8Array(message); } else if (!openpgp.util.isUint8Array(message)) { @@ -214,7 +214,7 @@ describe('Elliptic Curve Cryptography', function () { } const ecdsa = elliptic_curves.ecdsa; return ecdsa.verify( - oid, hash, { r: new Uint8Array(r), s: new Uint8Array(s) }, message, new Uint8Array(pub), openpgp.crypto.hash.digest(hash, message) + oid, hash, { r: new Uint8Array(r), s: new Uint8Array(s) }, message, new Uint8Array(pub), await openpgp.crypto.hash.digest(hash, message) ); }; const secp256k1_dummy_value = new Uint8Array([ @@ -291,13 +291,13 @@ describe('Elliptic Curve Cryptography', function () { }); it('Sign and verify message', function () { const curve = new elliptic_curves.Curve('p521'); - return curve.genKeyPair().then(keyPair => { + return curve.genKeyPair().then(async keyPair => { const keyPublic = new Uint8Array(keyPair.getPublic()); const keyPrivate = new Uint8Array(keyPair.getPrivate()); const oid = curve.oid; const message = p384_message; - return elliptic_curves.ecdsa.sign(oid, 10, message, keyPrivate, openpgp.crypto.hash.digest(10, message)).then(async signature => { - await expect(elliptic_curves.ecdsa.verify(oid, 10, signature, message, keyPublic, openpgp.crypto.hash.digest(10, message))) + return elliptic_curves.ecdsa.sign(oid, 10, message, keyPrivate, await openpgp.crypto.hash.digest(10, message)).then(async signature => { + await expect(elliptic_curves.ecdsa.verify(oid, 10, signature, message, keyPublic, await openpgp.crypto.hash.digest(10, message))) .to.eventually.be.true; }); }); diff --git a/test/crypto/hash/md5.js b/test/crypto/hash/md5.js index f7aa028a..9c07af60 100644 --- a/test/crypto/hash/md5.js +++ b/test/crypto/hash/md5.js @@ -6,12 +6,11 @@ const { util } = openpgp; const MD5 = openpgp.crypto.hash.md5; const { expect } = chai; -it('MD5 with test vectors from RFC 1321', function(done) { - expect(util.str_to_hex(util.Uint8Array_to_str(MD5(util.str_to_Uint8Array(''))), 'MD5("") = d41d8cd98f00b204e9800998ecf8427e')).to.equal('d41d8cd98f00b204e9800998ecf8427e'); - expect(util.str_to_hex(util.Uint8Array_to_str(MD5(util.str_to_Uint8Array('abc'))), 'MD5("a") = 0cc175b9c0f1b6a831c399e269772661')).to.equal('900150983cd24fb0d6963f7d28e17f72'); - expect(util.str_to_hex(util.Uint8Array_to_str(MD5(util.str_to_Uint8Array('message digest'))), 'MD5("message digest") = f96b697d7cb7938d525a2f31aaf161d0')).to.equal('f96b697d7cb7938d525a2f31aaf161d0'); - expect(util.str_to_hex(util.Uint8Array_to_str(MD5(util.str_to_Uint8Array('abcdefghijklmnopqrstuvwxyz'))), 'MD5("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b')).to.equal('c3fcd3d76192e4007dfb496cca67e13b'); - expect(util.str_to_hex(util.Uint8Array_to_str(MD5(util.str_to_Uint8Array('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'))), 'MD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = d174ab98d277d9f5a5611c2c9f419d9f')).to.equal('d174ab98d277d9f5a5611c2c9f419d9f'); - expect(util.str_to_hex(util.Uint8Array_to_str(MD5(util.str_to_Uint8Array('12345678901234567890123456789012345678901234567890123456789012345678901234567890'))), 'MD5("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = 57edf4a22be3c955ac49da2e2107b67a')).to.equal('57edf4a22be3c955ac49da2e2107b67a'); - done(); +it('MD5 with test vectors from RFC 1321', async function() { + expect(util.str_to_hex(util.Uint8Array_to_str(await MD5(util.str_to_Uint8Array(''))), 'MD5("") = d41d8cd98f00b204e9800998ecf8427e')).to.equal('d41d8cd98f00b204e9800998ecf8427e'); + expect(util.str_to_hex(util.Uint8Array_to_str(await MD5(util.str_to_Uint8Array('abc'))), 'MD5("a") = 0cc175b9c0f1b6a831c399e269772661')).to.equal('900150983cd24fb0d6963f7d28e17f72'); + expect(util.str_to_hex(util.Uint8Array_to_str(await MD5(util.str_to_Uint8Array('message digest'))), 'MD5("message digest") = f96b697d7cb7938d525a2f31aaf161d0')).to.equal('f96b697d7cb7938d525a2f31aaf161d0'); + expect(util.str_to_hex(util.Uint8Array_to_str(await MD5(util.str_to_Uint8Array('abcdefghijklmnopqrstuvwxyz'))), 'MD5("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b')).to.equal('c3fcd3d76192e4007dfb496cca67e13b'); + expect(util.str_to_hex(util.Uint8Array_to_str(await MD5(util.str_to_Uint8Array('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'))), 'MD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = d174ab98d277d9f5a5611c2c9f419d9f')).to.equal('d174ab98d277d9f5a5611c2c9f419d9f'); + expect(util.str_to_hex(util.Uint8Array_to_str(await MD5(util.str_to_Uint8Array('12345678901234567890123456789012345678901234567890123456789012345678901234567890'))), 'MD5("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = 57edf4a22be3c955ac49da2e2107b67a')).to.equal('57edf4a22be3c955ac49da2e2107b67a'); }); diff --git a/test/crypto/hash/ripemd.js b/test/crypto/hash/ripemd.js index 7ed9c559..549a4256 100644 --- a/test/crypto/hash/ripemd.js +++ b/test/crypto/hash/ripemd.js @@ -6,10 +6,9 @@ const { util } = openpgp; const RMDstring = openpgp.crypto.hash.ripemd; const { expect } = chai; -it("RIPE-MD 160 bits with test vectors from https://homes.esat.kuleuven.be/~bosselae/ripemd160.html", function(done) { - expect(util.str_to_hex(util.Uint8Array_to_str(RMDstring(util.str_to_Uint8Array(''))), 'RMDstring("") = 9c1185a5c5e9fc54612808977ee8f548b2258d31')).to.equal('9c1185a5c5e9fc54612808977ee8f548b2258d31'); - expect(util.str_to_hex(util.Uint8Array_to_str(RMDstring(util.str_to_Uint8Array('a'))), 'RMDstring("a") = 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe')).to.equal('0bdc9d2d256b3ee9daae347be6f4dc835a467ffe'); - expect(util.str_to_hex(util.Uint8Array_to_str(RMDstring(util.str_to_Uint8Array('abc'))), 'RMDstring("abc") = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc')).to.equal('8eb208f7e05d987a9b044a8e98c6b087f15a0bfc'); - expect(util.str_to_hex(util.Uint8Array_to_str(RMDstring(util.str_to_Uint8Array('message digest'))), 'RMDstring("message digest") = 5d0689ef49d2fae572b881b123a85ffa21595f36')).to.equal('5d0689ef49d2fae572b881b123a85ffa21595f36'); - done(); +it("RIPE-MD 160 bits with test vectors from https://homes.esat.kuleuven.be/~bosselae/ripemd160.html", async function() { + expect(util.str_to_hex(util.Uint8Array_to_str(await RMDstring(util.str_to_Uint8Array(''))), 'RMDstring("") = 9c1185a5c5e9fc54612808977ee8f548b2258d31')).to.equal('9c1185a5c5e9fc54612808977ee8f548b2258d31'); + expect(util.str_to_hex(util.Uint8Array_to_str(await RMDstring(util.str_to_Uint8Array('a'))), 'RMDstring("a") = 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe')).to.equal('0bdc9d2d256b3ee9daae347be6f4dc835a467ffe'); + expect(util.str_to_hex(util.Uint8Array_to_str(await RMDstring(util.str_to_Uint8Array('abc'))), 'RMDstring("abc") = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc')).to.equal('8eb208f7e05d987a9b044a8e98c6b087f15a0bfc'); + expect(util.str_to_hex(util.Uint8Array_to_str(await RMDstring(util.str_to_Uint8Array('message digest'))), 'RMDstring("message digest") = 5d0689ef49d2fae572b881b123a85ffa21595f36')).to.equal('5d0689ef49d2fae572b881b123a85ffa21595f36'); }); diff --git a/test/crypto/hash/sha.js b/test/crypto/hash/sha.js index 5e1fb2c2..ebbdf7bb 100644 --- a/test/crypto/hash/sha.js +++ b/test/crypto/hash/sha.js @@ -6,16 +6,15 @@ const { util } = openpgp; const { hash } = openpgp.crypto; const { expect } = chai; -it('SHA* with test vectors from NIST FIPS 180-2', function(done) { - expect(util.str_to_hex(util.Uint8Array_to_str(hash.sha1(util.str_to_Uint8Array('abc'))), 'hash.sha1("abc") = a9993e364706816aba3e25717850c26c9cd0d89d')).to.equal('a9993e364706816aba3e25717850c26c9cd0d89d'); - expect(util.str_to_hex(util.Uint8Array_to_str(hash.sha1(util.str_to_Uint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'))), 'hash.sha1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 84983e441c3bd26ebaae4aa1f95129e5e54670f1')).to.equal('84983e441c3bd26ebaae4aa1f95129e5e54670f1'); - expect(util.str_to_hex(util.Uint8Array_to_str(hash.sha224(util.str_to_Uint8Array('abc'))), 'hash.sha224("abc") = 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7')).to.equal('23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7'); - expect(util.str_to_hex(util.Uint8Array_to_str(hash.sha224(util.str_to_Uint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'))), 'hash.sha224("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525')).to.equal('75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525'); - expect(util.str_to_hex(util.Uint8Array_to_str(hash.sha256(util.str_to_Uint8Array('abc'))), 'hash.sha256("abc") = ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad')).to.equal('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'); - expect(util.str_to_hex(util.Uint8Array_to_str(hash.sha256(util.str_to_Uint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'))), 'hash.sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1')).to.equal('248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1'); - expect(util.str_to_hex(util.Uint8Array_to_str(hash.sha384(util.str_to_Uint8Array('abc'))), 'hash.sha384("abc") = cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7')).to.equal('cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7'); - expect(util.str_to_hex(util.Uint8Array_to_str(hash.sha384(util.str_to_Uint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'))), 'hash.sha384("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b')).to.equal('3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b'); - expect(util.str_to_hex(util.Uint8Array_to_str(hash.sha512(util.str_to_Uint8Array('abc'))), 'hash.sha512("abc") = ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f')).to.equal('ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f'); - expect(util.str_to_hex(util.Uint8Array_to_str(hash.sha512(util.str_to_Uint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'))), 'hash.sha512("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445')).to.equal('204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445'); - done(); +it('SHA* with test vectors from NIST FIPS 180-2', async function() { + expect(util.str_to_hex(util.Uint8Array_to_str(await hash.sha1(util.str_to_Uint8Array('abc'))), 'hash.sha1("abc") = a9993e364706816aba3e25717850c26c9cd0d89d')).to.equal('a9993e364706816aba3e25717850c26c9cd0d89d'); + expect(util.str_to_hex(util.Uint8Array_to_str(await hash.sha1(util.str_to_Uint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'))), 'hash.sha1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 84983e441c3bd26ebaae4aa1f95129e5e54670f1')).to.equal('84983e441c3bd26ebaae4aa1f95129e5e54670f1'); + expect(util.str_to_hex(util.Uint8Array_to_str(await hash.sha224(util.str_to_Uint8Array('abc'))), 'hash.sha224("abc") = 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7')).to.equal('23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7'); + expect(util.str_to_hex(util.Uint8Array_to_str(await hash.sha224(util.str_to_Uint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'))), 'hash.sha224("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525')).to.equal('75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525'); + expect(util.str_to_hex(util.Uint8Array_to_str(await hash.sha256(util.str_to_Uint8Array('abc'))), 'hash.sha256("abc") = ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad')).to.equal('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'); + expect(util.str_to_hex(util.Uint8Array_to_str(await hash.sha256(util.str_to_Uint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'))), 'hash.sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1')).to.equal('248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1'); + expect(util.str_to_hex(util.Uint8Array_to_str(await hash.sha384(util.str_to_Uint8Array('abc'))), 'hash.sha384("abc") = cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7')).to.equal('cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7'); + expect(util.str_to_hex(util.Uint8Array_to_str(await hash.sha384(util.str_to_Uint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'))), 'hash.sha384("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b')).to.equal('3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b'); + expect(util.str_to_hex(util.Uint8Array_to_str(await hash.sha512(util.str_to_Uint8Array('abc'))), 'hash.sha512("abc") = ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f')).to.equal('ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f'); + expect(util.str_to_hex(util.Uint8Array_to_str(await hash.sha512(util.str_to_Uint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'))), 'hash.sha512("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445')).to.equal('204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445'); });