mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-07-03 03:22:30 +00:00
Merge pull request #1812
Improve internal tree-shaking and lazy load md5
This commit is contained in:
commit
b2bd8a0fdd
@ -11,7 +11,8 @@ export async function getLegacyCipher(algo) {
|
|||||||
case enums.symmetric.twofish:
|
case enums.symmetric.twofish:
|
||||||
case enums.symmetric.tripledes: {
|
case enums.symmetric.tripledes: {
|
||||||
const { legacyCiphers } = await import('./legacy_ciphers');
|
const { legacyCiphers } = await import('./legacy_ciphers');
|
||||||
const cipher = legacyCiphers.get(algo);
|
const algoName = enums.read(enums.symmetric, algo);
|
||||||
|
const cipher = legacyCiphers.get(algoName);
|
||||||
if (!cipher) {
|
if (!cipher) {
|
||||||
throw new Error('Unsupported cipher algorithm');
|
throw new Error('Unsupported cipher algorithm');
|
||||||
}
|
}
|
||||||
|
@ -3,15 +3,16 @@
|
|||||||
* Separate dynamic imports are not convenient as they result in multiple chunks.
|
* Separate dynamic imports are not convenient as they result in multiple chunks.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { TripleDES } from './des';
|
import { TripleDES as tripledes } from './des';
|
||||||
import CAST5 from './cast5';
|
import cast5 from './cast5';
|
||||||
import TwoFish from './twofish';
|
import twofish from './twofish';
|
||||||
import BlowFish from './blowfish';
|
import blowfish from './blowfish';
|
||||||
import enums from '../../enums';
|
|
||||||
|
|
||||||
export const legacyCiphers = new Map([
|
// We avoid importing 'enums' as this module is lazy loaded, and doing so could mess up
|
||||||
[enums.symmetric.tripledes, TripleDES],
|
// chunking for the lightweight build
|
||||||
[enums.symmetric.cast5, CAST5],
|
export const legacyCiphers = new Map(Object.entries({
|
||||||
[enums.symmetric.blowfish, BlowFish],
|
tripledes,
|
||||||
[enums.symmetric.twofish, TwoFish]
|
cast5,
|
||||||
]);
|
twofish,
|
||||||
|
blowfish
|
||||||
|
}));
|
||||||
|
@ -23,10 +23,11 @@
|
|||||||
|
|
||||||
import { cfb as nobleAesCfb, unsafe as nobleAesHelpers } from '@noble/ciphers/aes';
|
import { cfb as nobleAesCfb, unsafe as nobleAesHelpers } from '@noble/ciphers/aes';
|
||||||
|
|
||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { transform as streamTransform } from '@openpgp/web-stream-tools';
|
||||||
import util from '../../util';
|
import util from '../../util';
|
||||||
import enums from '../../enums';
|
import enums from '../../enums';
|
||||||
import { getLegacyCipher, getCipherParams } from '../cipher';
|
import { getLegacyCipher, getCipherParams } from '../cipher';
|
||||||
|
import { getRandomBytes } from '../random';
|
||||||
|
|
||||||
const webCrypto = util.getWebCrypto();
|
const webCrypto = util.getWebCrypto();
|
||||||
const nodeCrypto = util.getNodeCrypto();
|
const nodeCrypto = util.getNodeCrypto();
|
||||||
@ -43,6 +44,20 @@ const nodeAlgos = {
|
|||||||
/* twofish is not implemented in OpenSSL */
|
/* twofish is not implemented in OpenSSL */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a random byte prefix for the specified algorithm
|
||||||
|
* See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms.
|
||||||
|
* @param {module:enums.symmetric} algo - Symmetric encryption algorithm
|
||||||
|
* @returns {Promise<Uint8Array>} Random bytes with length equal to the block size of the cipher, plus the last two bytes repeated.
|
||||||
|
* @async
|
||||||
|
*/
|
||||||
|
export async function getPrefixRandom(algo) {
|
||||||
|
const { blockSize } = getCipherParams(algo);
|
||||||
|
const prefixrandom = await getRandomBytes(blockSize);
|
||||||
|
const repeat = new Uint8Array([prefixrandom[prefixrandom.length - 2], prefixrandom[prefixrandom.length - 1]]);
|
||||||
|
return util.concat([prefixrandom, repeat]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CFB encryption
|
* CFB encryption
|
||||||
* @param {enums.symmetric} algo - block cipher algorithm
|
* @param {enums.symmetric} algo - block cipher algorithm
|
||||||
@ -84,7 +99,7 @@ export async function encrypt(algo, key, plaintext, iv, config) {
|
|||||||
}
|
}
|
||||||
return ciphertext.subarray(0, j);
|
return ciphertext.subarray(0, j);
|
||||||
};
|
};
|
||||||
return stream.transform(plaintext, process, process);
|
return streamTransform(plaintext, process, process);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -127,7 +142,7 @@ export async function decrypt(algo, key, ciphertext, iv) {
|
|||||||
}
|
}
|
||||||
return plaintext.subarray(0, j);
|
return plaintext.subarray(0, j);
|
||||||
};
|
};
|
||||||
return stream.transform(ciphertext, process, process);
|
return streamTransform(ciphertext, process, process);
|
||||||
}
|
}
|
||||||
|
|
||||||
class WebCryptoEncryptor {
|
class WebCryptoEncryptor {
|
||||||
@ -331,10 +346,10 @@ class NobleStreamProcessor {
|
|||||||
async function aesEncrypt(algo, key, pt, iv) {
|
async function aesEncrypt(algo, key, pt, iv) {
|
||||||
if (webCrypto && await WebCryptoEncryptor.isSupported(algo)) { // Chromium does not implement AES with 192-bit keys
|
if (webCrypto && await WebCryptoEncryptor.isSupported(algo)) { // Chromium does not implement AES with 192-bit keys
|
||||||
const cfb = new WebCryptoEncryptor(algo, key, iv);
|
const cfb = new WebCryptoEncryptor(algo, key, iv);
|
||||||
return util.isStream(pt) ? stream.transform(pt, value => cfb.encryptChunk(value), () => cfb.finish()) : cfb.encrypt(pt);
|
return util.isStream(pt) ? streamTransform(pt, value => cfb.encryptChunk(value), () => cfb.finish()) : cfb.encrypt(pt);
|
||||||
} else if (util.isStream(pt)) { // async callbacks are not accepted by stream.transform unless the input is a stream
|
} else if (util.isStream(pt)) { // async callbacks are not accepted by streamTransform unless the input is a stream
|
||||||
const cfb = new NobleStreamProcessor(true, algo, key, iv);
|
const cfb = new NobleStreamProcessor(true, algo, key, iv);
|
||||||
return stream.transform(pt, value => cfb.processChunk(value), () => cfb.finish());
|
return streamTransform(pt, value => cfb.processChunk(value), () => cfb.finish());
|
||||||
}
|
}
|
||||||
return nobleAesCfb(key, iv).encrypt(pt);
|
return nobleAesCfb(key, iv).encrypt(pt);
|
||||||
}
|
}
|
||||||
@ -342,7 +357,7 @@ async function aesEncrypt(algo, key, pt, iv) {
|
|||||||
async function aesDecrypt(algo, key, ct, iv) {
|
async function aesDecrypt(algo, key, ct, iv) {
|
||||||
if (util.isStream(ct)) {
|
if (util.isStream(ct)) {
|
||||||
const cfb = new NobleStreamProcessor(false, algo, key, iv);
|
const cfb = new NobleStreamProcessor(false, algo, key, iv);
|
||||||
return stream.transform(ct, value => cfb.processChunk(value), () => cfb.finish());
|
return streamTransform(ct, value => cfb.processChunk(value), () => cfb.finish());
|
||||||
}
|
}
|
||||||
return nobleAesCfb(key, iv).decrypt(ct);
|
return nobleAesCfb(key, iv).decrypt(ct);
|
||||||
}
|
}
|
||||||
@ -359,11 +374,11 @@ const getUint32Array = arr => new Uint32Array(arr.buffer, arr.byteOffset, Math.f
|
|||||||
function nodeEncrypt(algo, key, pt, iv) {
|
function nodeEncrypt(algo, key, pt, iv) {
|
||||||
const algoName = enums.read(enums.symmetric, algo);
|
const algoName = enums.read(enums.symmetric, algo);
|
||||||
const cipherObj = new nodeCrypto.createCipheriv(nodeAlgos[algoName], key, iv);
|
const cipherObj = new nodeCrypto.createCipheriv(nodeAlgos[algoName], key, iv);
|
||||||
return stream.transform(pt, value => new Uint8Array(cipherObj.update(value)));
|
return streamTransform(pt, value => new Uint8Array(cipherObj.update(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function nodeDecrypt(algo, key, ct, iv) {
|
function nodeDecrypt(algo, key, ct, iv) {
|
||||||
const algoName = enums.read(enums.symmetric, algo);
|
const algoName = enums.read(enums.symmetric, algo);
|
||||||
const decipherObj = new nodeCrypto.createDecipheriv(nodeAlgos[algoName], key, iv);
|
const decipherObj = new nodeCrypto.createDecipheriv(nodeAlgos[algoName], key, iv);
|
||||||
return stream.transform(ct, value => new Uint8Array(decipherObj.update(value)));
|
return streamTransform(ct, value => new Uint8Array(decipherObj.update(value)));
|
||||||
}
|
}
|
35
src/crypto/cipherMode/index.js
Normal file
35
src/crypto/cipherMode/index.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Cipher modes
|
||||||
|
* @module crypto/cipherMode
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * as cfb from './cfb';
|
||||||
|
import eax from './eax';
|
||||||
|
import ocb from './ocb';
|
||||||
|
import gcm from './gcm';
|
||||||
|
import enums from '../../enums';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get implementation of the given AEAD mode
|
||||||
|
* @param {enums.aead} algo
|
||||||
|
* @param {Boolean} [acceptExperimentalGCM] - whether to allow the non-standard, legacy `experimentalGCM` algo
|
||||||
|
* @returns {Object}
|
||||||
|
* @throws {Error} on invalid algo
|
||||||
|
*/
|
||||||
|
export function getAEADMode(algo, acceptExperimentalGCM = false) {
|
||||||
|
switch (algo) {
|
||||||
|
case enums.aead.eax:
|
||||||
|
return eax;
|
||||||
|
case enums.aead.ocb:
|
||||||
|
return ocb;
|
||||||
|
case enums.aead.gcm:
|
||||||
|
return gcm;
|
||||||
|
case enums.aead.experimentalGCM:
|
||||||
|
if (!acceptExperimentalGCM) {
|
||||||
|
throw new Error('Unexpected non-standard `experimentalGCM` AEAD algorithm provided in `config.preferredAEADAlgorithm`: use `gcm` instead');
|
||||||
|
}
|
||||||
|
return gcm;
|
||||||
|
default:
|
||||||
|
throw new Error('Unsupported AEAD mode');
|
||||||
|
}
|
||||||
|
}
|
@ -23,8 +23,7 @@
|
|||||||
* @module crypto/crypto
|
* @module crypto/crypto
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import publicKey from './public_key';
|
import { rsa, elliptic, elgamal, dsa } from './public_key';
|
||||||
import mode from './mode';
|
|
||||||
import { getRandomBytes } from './random';
|
import { getRandomBytes } from './random';
|
||||||
import { getCipherParams } from './cipher';
|
import { getCipherParams } from './cipher';
|
||||||
import ECDHSymkey from '../type/ecdh_symkey';
|
import ECDHSymkey from '../type/ecdh_symkey';
|
||||||
@ -51,16 +50,16 @@ export async function publicKeyEncrypt(keyAlgo, symmetricAlgo, publicParams, dat
|
|||||||
case enums.publicKey.rsaEncrypt:
|
case enums.publicKey.rsaEncrypt:
|
||||||
case enums.publicKey.rsaEncryptSign: {
|
case enums.publicKey.rsaEncryptSign: {
|
||||||
const { n, e } = publicParams;
|
const { n, e } = publicParams;
|
||||||
const c = await publicKey.rsa.encrypt(data, n, e);
|
const c = await rsa.encrypt(data, n, e);
|
||||||
return { c };
|
return { c };
|
||||||
}
|
}
|
||||||
case enums.publicKey.elgamal: {
|
case enums.publicKey.elgamal: {
|
||||||
const { p, g, y } = publicParams;
|
const { p, g, y } = publicParams;
|
||||||
return publicKey.elgamal.encrypt(data, p, g, y);
|
return elgamal.encrypt(data, p, g, y);
|
||||||
}
|
}
|
||||||
case enums.publicKey.ecdh: {
|
case enums.publicKey.ecdh: {
|
||||||
const { oid, Q, kdfParams } = publicParams;
|
const { oid, Q, kdfParams } = publicParams;
|
||||||
const { publicKey: V, wrappedKey: C } = await publicKey.elliptic.ecdh.encrypt(
|
const { publicKey: V, wrappedKey: C } = await elliptic.ecdh.encrypt(
|
||||||
oid, kdfParams, data, Q, fingerprint);
|
oid, kdfParams, data, Q, fingerprint);
|
||||||
return { V, C: new ECDHSymkey(C) };
|
return { V, C: new ECDHSymkey(C) };
|
||||||
}
|
}
|
||||||
@ -71,7 +70,7 @@ export async function publicKeyEncrypt(keyAlgo, symmetricAlgo, publicParams, dat
|
|||||||
throw new Error('X25519 and X448 keys can only encrypt AES session keys');
|
throw new Error('X25519 and X448 keys can only encrypt AES session keys');
|
||||||
}
|
}
|
||||||
const { A } = publicParams;
|
const { A } = publicParams;
|
||||||
const { ephemeralPublicKey, wrappedKey } = await publicKey.elliptic.ecdhX.encrypt(
|
const { ephemeralPublicKey, wrappedKey } = await elliptic.ecdhX.encrypt(
|
||||||
keyAlgo, data, A);
|
keyAlgo, data, A);
|
||||||
const C = ECDHXSymmetricKey.fromObject({ algorithm: symmetricAlgo, wrappedKey });
|
const C = ECDHXSymmetricKey.fromObject({ algorithm: symmetricAlgo, wrappedKey });
|
||||||
return { ephemeralPublicKey, C };
|
return { ephemeralPublicKey, C };
|
||||||
@ -102,19 +101,19 @@ export async function publicKeyDecrypt(algo, publicKeyParams, privateKeyParams,
|
|||||||
const { c } = sessionKeyParams;
|
const { c } = sessionKeyParams;
|
||||||
const { n, e } = publicKeyParams;
|
const { n, e } = publicKeyParams;
|
||||||
const { d, p, q, u } = privateKeyParams;
|
const { d, p, q, u } = privateKeyParams;
|
||||||
return publicKey.rsa.decrypt(c, n, e, d, p, q, u, randomPayload);
|
return rsa.decrypt(c, n, e, d, p, q, u, randomPayload);
|
||||||
}
|
}
|
||||||
case enums.publicKey.elgamal: {
|
case enums.publicKey.elgamal: {
|
||||||
const { c1, c2 } = sessionKeyParams;
|
const { c1, c2 } = sessionKeyParams;
|
||||||
const p = publicKeyParams.p;
|
const p = publicKeyParams.p;
|
||||||
const x = privateKeyParams.x;
|
const x = privateKeyParams.x;
|
||||||
return publicKey.elgamal.decrypt(c1, c2, p, x, randomPayload);
|
return elgamal.decrypt(c1, c2, p, x, randomPayload);
|
||||||
}
|
}
|
||||||
case enums.publicKey.ecdh: {
|
case enums.publicKey.ecdh: {
|
||||||
const { oid, Q, kdfParams } = publicKeyParams;
|
const { oid, Q, kdfParams } = publicKeyParams;
|
||||||
const { d } = privateKeyParams;
|
const { d } = privateKeyParams;
|
||||||
const { V, C } = sessionKeyParams;
|
const { V, C } = sessionKeyParams;
|
||||||
return publicKey.elliptic.ecdh.decrypt(
|
return elliptic.ecdh.decrypt(
|
||||||
oid, kdfParams, V, C.data, Q, d, fingerprint);
|
oid, kdfParams, V, C.data, Q, d, fingerprint);
|
||||||
}
|
}
|
||||||
case enums.publicKey.x25519:
|
case enums.publicKey.x25519:
|
||||||
@ -125,7 +124,7 @@ export async function publicKeyDecrypt(algo, publicKeyParams, privateKeyParams,
|
|||||||
if (C.algorithm !== null && !util.isAES(C.algorithm)) {
|
if (C.algorithm !== null && !util.isAES(C.algorithm)) {
|
||||||
throw new Error('AES session key expected');
|
throw new Error('AES session key expected');
|
||||||
}
|
}
|
||||||
return publicKey.elliptic.ecdhX.decrypt(
|
return elliptic.ecdhX.decrypt(
|
||||||
algo, ephemeralPublicKey, C.wrappedKey, A, k);
|
algo, ephemeralPublicKey, C.wrappedKey, A, k);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -338,22 +337,22 @@ export function generateParams(algo, bits, oid) {
|
|||||||
case enums.publicKey.rsaEncrypt:
|
case enums.publicKey.rsaEncrypt:
|
||||||
case enums.publicKey.rsaEncryptSign:
|
case enums.publicKey.rsaEncryptSign:
|
||||||
case enums.publicKey.rsaSign:
|
case enums.publicKey.rsaSign:
|
||||||
return publicKey.rsa.generate(bits, 65537).then(({ n, e, d, p, q, u }) => ({
|
return rsa.generate(bits, 65537).then(({ n, e, d, p, q, u }) => ({
|
||||||
privateParams: { d, p, q, u },
|
privateParams: { d, p, q, u },
|
||||||
publicParams: { n, e }
|
publicParams: { n, e }
|
||||||
}));
|
}));
|
||||||
case enums.publicKey.ecdsa:
|
case enums.publicKey.ecdsa:
|
||||||
return publicKey.elliptic.generate(oid).then(({ oid, Q, secret }) => ({
|
return elliptic.generate(oid).then(({ oid, Q, secret }) => ({
|
||||||
privateParams: { d: secret },
|
privateParams: { d: secret },
|
||||||
publicParams: { oid: new OID(oid), Q }
|
publicParams: { oid: new OID(oid), Q }
|
||||||
}));
|
}));
|
||||||
case enums.publicKey.eddsaLegacy:
|
case enums.publicKey.eddsaLegacy:
|
||||||
return publicKey.elliptic.generate(oid).then(({ oid, Q, secret }) => ({
|
return elliptic.generate(oid).then(({ oid, Q, secret }) => ({
|
||||||
privateParams: { seed: secret },
|
privateParams: { seed: secret },
|
||||||
publicParams: { oid: new OID(oid), Q }
|
publicParams: { oid: new OID(oid), Q }
|
||||||
}));
|
}));
|
||||||
case enums.publicKey.ecdh:
|
case enums.publicKey.ecdh:
|
||||||
return publicKey.elliptic.generate(oid).then(({ oid, Q, secret, hash, cipher }) => ({
|
return elliptic.generate(oid).then(({ oid, Q, secret, hash, cipher }) => ({
|
||||||
privateParams: { d: secret },
|
privateParams: { d: secret },
|
||||||
publicParams: {
|
publicParams: {
|
||||||
oid: new OID(oid),
|
oid: new OID(oid),
|
||||||
@ -363,13 +362,13 @@ export function generateParams(algo, bits, oid) {
|
|||||||
}));
|
}));
|
||||||
case enums.publicKey.ed25519:
|
case enums.publicKey.ed25519:
|
||||||
case enums.publicKey.ed448:
|
case enums.publicKey.ed448:
|
||||||
return publicKey.elliptic.eddsa.generate(algo).then(({ A, seed }) => ({
|
return elliptic.eddsa.generate(algo).then(({ A, seed }) => ({
|
||||||
privateParams: { seed },
|
privateParams: { seed },
|
||||||
publicParams: { A }
|
publicParams: { A }
|
||||||
}));
|
}));
|
||||||
case enums.publicKey.x25519:
|
case enums.publicKey.x25519:
|
||||||
case enums.publicKey.x448:
|
case enums.publicKey.x448:
|
||||||
return publicKey.elliptic.ecdhX.generate(algo).then(({ A, k }) => ({
|
return elliptic.ecdhX.generate(algo).then(({ A, k }) => ({
|
||||||
privateParams: { k },
|
privateParams: { k },
|
||||||
publicParams: { A }
|
publicParams: { A }
|
||||||
}));
|
}));
|
||||||
@ -399,21 +398,21 @@ export async function validateParams(algo, publicParams, privateParams) {
|
|||||||
case enums.publicKey.rsaSign: {
|
case enums.publicKey.rsaSign: {
|
||||||
const { n, e } = publicParams;
|
const { n, e } = publicParams;
|
||||||
const { d, p, q, u } = privateParams;
|
const { d, p, q, u } = privateParams;
|
||||||
return publicKey.rsa.validateParams(n, e, d, p, q, u);
|
return rsa.validateParams(n, e, d, p, q, u);
|
||||||
}
|
}
|
||||||
case enums.publicKey.dsa: {
|
case enums.publicKey.dsa: {
|
||||||
const { p, q, g, y } = publicParams;
|
const { p, q, g, y } = publicParams;
|
||||||
const { x } = privateParams;
|
const { x } = privateParams;
|
||||||
return publicKey.dsa.validateParams(p, q, g, y, x);
|
return dsa.validateParams(p, q, g, y, x);
|
||||||
}
|
}
|
||||||
case enums.publicKey.elgamal: {
|
case enums.publicKey.elgamal: {
|
||||||
const { p, g, y } = publicParams;
|
const { p, g, y } = publicParams;
|
||||||
const { x } = privateParams;
|
const { x } = privateParams;
|
||||||
return publicKey.elgamal.validateParams(p, g, y, x);
|
return elgamal.validateParams(p, g, y, x);
|
||||||
}
|
}
|
||||||
case enums.publicKey.ecdsa:
|
case enums.publicKey.ecdsa:
|
||||||
case enums.publicKey.ecdh: {
|
case enums.publicKey.ecdh: {
|
||||||
const algoModule = publicKey.elliptic[enums.read(enums.publicKey, algo)];
|
const algoModule = elliptic[enums.read(enums.publicKey, algo)];
|
||||||
const { oid, Q } = publicParams;
|
const { oid, Q } = publicParams;
|
||||||
const { d } = privateParams;
|
const { d } = privateParams;
|
||||||
return algoModule.validateParams(oid, Q, d);
|
return algoModule.validateParams(oid, Q, d);
|
||||||
@ -421,39 +420,25 @@ export async function validateParams(algo, publicParams, privateParams) {
|
|||||||
case enums.publicKey.eddsaLegacy: {
|
case enums.publicKey.eddsaLegacy: {
|
||||||
const { Q, oid } = publicParams;
|
const { Q, oid } = publicParams;
|
||||||
const { seed } = privateParams;
|
const { seed } = privateParams;
|
||||||
return publicKey.elliptic.eddsaLegacy.validateParams(oid, Q, seed);
|
return elliptic.eddsaLegacy.validateParams(oid, Q, seed);
|
||||||
}
|
}
|
||||||
case enums.publicKey.ed25519:
|
case enums.publicKey.ed25519:
|
||||||
case enums.publicKey.ed448: {
|
case enums.publicKey.ed448: {
|
||||||
const { A } = publicParams;
|
const { A } = publicParams;
|
||||||
const { seed } = privateParams;
|
const { seed } = privateParams;
|
||||||
return publicKey.elliptic.eddsa.validateParams(algo, A, seed);
|
return elliptic.eddsa.validateParams(algo, A, seed);
|
||||||
}
|
}
|
||||||
case enums.publicKey.x25519:
|
case enums.publicKey.x25519:
|
||||||
case enums.publicKey.x448: {
|
case enums.publicKey.x448: {
|
||||||
const { A } = publicParams;
|
const { A } = publicParams;
|
||||||
const { k } = privateParams;
|
const { k } = privateParams;
|
||||||
return publicKey.elliptic.ecdhX.validateParams(algo, A, k);
|
return elliptic.ecdhX.validateParams(algo, A, k);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new Error('Unknown public key algorithm.');
|
throw new Error('Unknown public key algorithm.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a random byte prefix for the specified algorithm
|
|
||||||
* See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms.
|
|
||||||
* @param {module:enums.symmetric} algo - Symmetric encryption algorithm
|
|
||||||
* @returns {Promise<Uint8Array>} Random bytes with length equal to the block size of the cipher, plus the last two bytes repeated.
|
|
||||||
* @async
|
|
||||||
*/
|
|
||||||
export async function getPrefixRandom(algo) {
|
|
||||||
const { blockSize } = getCipherParams(algo);
|
|
||||||
const prefixrandom = await getRandomBytes(blockSize);
|
|
||||||
const repeat = new Uint8Array([prefixrandom[prefixrandom.length - 2], prefixrandom[prefixrandom.length - 1]]);
|
|
||||||
return util.concat([prefixrandom, repeat]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generating a session key for the specified symmetric algorithm
|
* Generating a session key for the specified symmetric algorithm
|
||||||
* See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms.
|
* See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms.
|
||||||
@ -465,31 +450,6 @@ export function generateSessionKey(algo) {
|
|||||||
return getRandomBytes(keySize);
|
return getRandomBytes(keySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get implementation of the given AEAD mode
|
|
||||||
* @param {enums.aead} algo
|
|
||||||
* @param {Boolean} [acceptExperimentalGCM] - whether to allow the non-standard, legacy `experimentalGCM` algo
|
|
||||||
* @returns {Object}
|
|
||||||
* @throws {Error} on invalid algo
|
|
||||||
*/
|
|
||||||
export function getAEADMode(algo, acceptExperimentalGCM = false) {
|
|
||||||
switch (algo) {
|
|
||||||
case enums.aead.eax:
|
|
||||||
return mode.eax;
|
|
||||||
case enums.aead.ocb:
|
|
||||||
return mode.ocb;
|
|
||||||
case enums.aead.gcm:
|
|
||||||
return mode.gcm;
|
|
||||||
case enums.aead.experimentalGCM:
|
|
||||||
if (!acceptExperimentalGCM) {
|
|
||||||
throw new Error('Unexpected non-standard `experimentalGCM` AEAD algorithm provided in `config.preferredAEADAlgorithm`: use `gcm` instead');
|
|
||||||
}
|
|
||||||
return mode.gcm;
|
|
||||||
default:
|
|
||||||
throw new Error('Unsupported AEAD mode');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the given curve OID is supported
|
* Check whether the given curve OID is supported
|
||||||
* @param {module:type/oid} oid - EC object identifier
|
* @param {module:type/oid} oid - EC object identifier
|
||||||
@ -513,13 +473,13 @@ export function getCurvePayloadSize(algo, oid) {
|
|||||||
case enums.publicKey.ecdsa:
|
case enums.publicKey.ecdsa:
|
||||||
case enums.publicKey.ecdh:
|
case enums.publicKey.ecdh:
|
||||||
case enums.publicKey.eddsaLegacy:
|
case enums.publicKey.eddsaLegacy:
|
||||||
return new publicKey.elliptic.CurveWithOID(oid).payloadSize;
|
return new elliptic.CurveWithOID(oid).payloadSize;
|
||||||
case enums.publicKey.ed25519:
|
case enums.publicKey.ed25519:
|
||||||
case enums.publicKey.ed448:
|
case enums.publicKey.ed448:
|
||||||
return publicKey.elliptic.eddsa.getPayloadSize(algo);
|
return elliptic.eddsa.getPayloadSize(algo);
|
||||||
case enums.publicKey.x25519:
|
case enums.publicKey.x25519:
|
||||||
case enums.publicKey.x448:
|
case enums.publicKey.x448:
|
||||||
return publicKey.elliptic.ecdhX.getPayloadSize(algo);
|
return elliptic.ecdhX.getPayloadSize(algo);
|
||||||
default:
|
default:
|
||||||
throw new Error('Unknown elliptic algo');
|
throw new Error('Unknown elliptic algo');
|
||||||
}
|
}
|
||||||
@ -534,14 +494,12 @@ export function getPreferredCurveHashAlgo(algo, oid) {
|
|||||||
switch (algo) {
|
switch (algo) {
|
||||||
case enums.publicKey.ecdsa:
|
case enums.publicKey.ecdsa:
|
||||||
case enums.publicKey.eddsaLegacy:
|
case enums.publicKey.eddsaLegacy:
|
||||||
return publicKey.elliptic.getPreferredHashAlgo(oid);
|
return elliptic.getPreferredHashAlgo(oid);
|
||||||
case enums.publicKey.ed25519:
|
case enums.publicKey.ed25519:
|
||||||
case enums.publicKey.ed448:
|
case enums.publicKey.ed448:
|
||||||
return publicKey.elliptic.eddsa.getPreferredHashAlgo(algo);
|
return elliptic.eddsa.getPreferredHashAlgo(algo);
|
||||||
default:
|
default:
|
||||||
throw new Error('Unknown elliptic signing algo');
|
throw new Error('Unknown elliptic signing algo');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export { getCipherParams };
|
|
||||||
|
@ -5,8 +5,7 @@
|
|||||||
* @module crypto/hash
|
* @module crypto/hash
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { transform as streamTransform, isArrayStream, readToEnd as streamReadToEnd } from '@openpgp/web-stream-tools';
|
||||||
import md5 from './md5';
|
|
||||||
import util from '../../util';
|
import util from '../../util';
|
||||||
import enums from '../../enums';
|
import enums from '../../enums';
|
||||||
|
|
||||||
@ -20,7 +19,7 @@ function nodeHash(type) {
|
|||||||
}
|
}
|
||||||
return async function (data) {
|
return async function (data) {
|
||||||
const shasum = nodeCrypto.createHash(type);
|
const shasum = nodeCrypto.createHash(type);
|
||||||
return stream.transform(data, value => {
|
return streamTransform(data, value => {
|
||||||
shasum.update(value);
|
shasum.update(value);
|
||||||
}, () => new Uint8Array(shasum.digest()));
|
}, () => new Uint8Array(shasum.digest()));
|
||||||
};
|
};
|
||||||
@ -35,14 +34,14 @@ function nobleHash(nobleHashName, webCryptoHashName) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return async function(data) {
|
return async function(data) {
|
||||||
if (stream.isArrayStream(data)) {
|
if (isArrayStream(data)) {
|
||||||
data = await stream.readToEnd(data);
|
data = await streamReadToEnd(data);
|
||||||
}
|
}
|
||||||
if (util.isStream(data)) {
|
if (util.isStream(data)) {
|
||||||
const hash = await getNobleHash();
|
const hash = await getNobleHash();
|
||||||
|
|
||||||
const hashInstance = hash.create();
|
const hashInstance = hash.create();
|
||||||
return stream.transform(data, value => {
|
return streamTransform(data, value => {
|
||||||
hashInstance.update(value);
|
hashInstance.update(value);
|
||||||
}, () => hashInstance.digest());
|
}, () => hashInstance.digest());
|
||||||
} else if (webCrypto && webCryptoHashName) {
|
} else if (webCrypto && webCryptoHashName) {
|
||||||
@ -55,76 +54,72 @@ function nobleHash(nobleHashName, webCryptoHashName) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
const md5 = nodeHash('md5') || nobleHash('md5');
|
||||||
|
const sha1 = nodeHash('sha1') || nobleHash('sha1', 'SHA-1');
|
||||||
|
const sha224 = nodeHash('sha224') || nobleHash('sha224');
|
||||||
|
const sha256 = nodeHash('sha256') || nobleHash('sha256', 'SHA-256');
|
||||||
|
const sha384 = nodeHash('sha384') || nobleHash('sha384', 'SHA-384');
|
||||||
|
const sha512 = nodeHash('sha512') || nobleHash('sha512', 'SHA-512');
|
||||||
|
const ripemd = nodeHash('ripemd160') || nobleHash('ripemd160');
|
||||||
|
const sha3_256 = nodeHash('sha3-256') || nobleHash('sha3_256');
|
||||||
|
const sha3_512 = nodeHash('sha3-512') || nobleHash('sha3_512');
|
||||||
|
|
||||||
/** @see module:md5 */
|
/**
|
||||||
md5: nodeHash('md5') || md5,
|
* Create a hash on the specified data using the specified algorithm
|
||||||
sha1: nodeHash('sha1') || nobleHash('sha1', 'SHA-1'),
|
* @param {module:enums.hash} algo - Hash algorithm type (see {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4})
|
||||||
sha224: nodeHash('sha224') || nobleHash('sha224'),
|
* @param {Uint8Array} data - Data to be hashed
|
||||||
sha256: nodeHash('sha256') || nobleHash('sha256', 'SHA-256'),
|
* @returns {Promise<Uint8Array>} Hash value.
|
||||||
sha384: nodeHash('sha384') || nobleHash('sha384', 'SHA-384'),
|
*/
|
||||||
sha512: nodeHash('sha512') || nobleHash('sha512', 'SHA-512'),
|
export function computeDigest(algo, data) {
|
||||||
ripemd: nodeHash('ripemd160') || nobleHash('ripemd160'),
|
switch (algo) {
|
||||||
sha3_256: nodeHash('sha3-256') || nobleHash('sha3_256'),
|
case enums.hash.md5:
|
||||||
sha3_512: nodeHash('sha3-512') || nobleHash('sha3_512'),
|
return md5(data);
|
||||||
|
case enums.hash.sha1:
|
||||||
/**
|
return sha1(data);
|
||||||
* Create a hash on the specified data using the specified algorithm
|
case enums.hash.ripemd:
|
||||||
* @param {module:enums.hash} algo - Hash algorithm type (see {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4})
|
return ripemd(data);
|
||||||
* @param {Uint8Array} data - Data to be hashed
|
case enums.hash.sha256:
|
||||||
* @returns {Promise<Uint8Array>} Hash value.
|
return sha256(data);
|
||||||
*/
|
case enums.hash.sha384:
|
||||||
digest: function(algo, data) {
|
return sha384(data);
|
||||||
switch (algo) {
|
case enums.hash.sha512:
|
||||||
case enums.hash.md5:
|
return sha512(data);
|
||||||
return this.md5(data);
|
case enums.hash.sha224:
|
||||||
case enums.hash.sha1:
|
return sha224(data);
|
||||||
return this.sha1(data);
|
case enums.hash.sha3_256:
|
||||||
case enums.hash.ripemd:
|
return sha3_256(data);
|
||||||
return this.ripemd(data);
|
case enums.hash.sha3_512:
|
||||||
case enums.hash.sha256:
|
return sha3_512(data);
|
||||||
return this.sha256(data);
|
default:
|
||||||
case enums.hash.sha384:
|
throw new Error('Unsupported hash function');
|
||||||
return this.sha384(data);
|
|
||||||
case enums.hash.sha512:
|
|
||||||
return this.sha512(data);
|
|
||||||
case enums.hash.sha224:
|
|
||||||
return this.sha224(data);
|
|
||||||
case enums.hash.sha3_256:
|
|
||||||
return this.sha3_256(data);
|
|
||||||
case enums.hash.sha3_512:
|
|
||||||
return this.sha3_512(data);
|
|
||||||
default:
|
|
||||||
throw new Error('Unsupported hash function');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the hash size in bytes of the specified hash algorithm type
|
|
||||||
* @param {module:enums.hash} algo - Hash algorithm type (See {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4})
|
|
||||||
* @returns {Integer} Size in bytes of the resulting hash.
|
|
||||||
*/
|
|
||||||
getHashByteLength: function(algo) {
|
|
||||||
switch (algo) {
|
|
||||||
case enums.hash.md5:
|
|
||||||
return 16;
|
|
||||||
case enums.hash.sha1:
|
|
||||||
case enums.hash.ripemd:
|
|
||||||
return 20;
|
|
||||||
case enums.hash.sha256:
|
|
||||||
return 32;
|
|
||||||
case enums.hash.sha384:
|
|
||||||
return 48;
|
|
||||||
case enums.hash.sha512:
|
|
||||||
return 64;
|
|
||||||
case enums.hash.sha224:
|
|
||||||
return 28;
|
|
||||||
case enums.hash.sha3_256:
|
|
||||||
return 32;
|
|
||||||
case enums.hash.sha3_512:
|
|
||||||
return 64;
|
|
||||||
default:
|
|
||||||
throw new Error('Invalid hash algorithm.');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hash size in bytes of the specified hash algorithm type
|
||||||
|
* @param {module:enums.hash} algo - Hash algorithm type (See {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4})
|
||||||
|
* @returns {Integer} Size in bytes of the resulting hash.
|
||||||
|
*/
|
||||||
|
export function getHashByteLength(algo) {
|
||||||
|
switch (algo) {
|
||||||
|
case enums.hash.md5:
|
||||||
|
return 16;
|
||||||
|
case enums.hash.sha1:
|
||||||
|
case enums.hash.ripemd:
|
||||||
|
return 20;
|
||||||
|
case enums.hash.sha256:
|
||||||
|
return 32;
|
||||||
|
case enums.hash.sha384:
|
||||||
|
return 48;
|
||||||
|
case enums.hash.sha512:
|
||||||
|
return 64;
|
||||||
|
case enums.hash.sha224:
|
||||||
|
return 28;
|
||||||
|
case enums.hash.sha3_256:
|
||||||
|
return 32;
|
||||||
|
case enums.hash.sha3_512:
|
||||||
|
return 64;
|
||||||
|
default:
|
||||||
|
throw new Error('Invalid hash algorithm.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,201 +0,0 @@
|
|||||||
/**
|
|
||||||
* A fast MD5 JavaScript implementation
|
|
||||||
* Copyright (c) 2012 Joseph Myers
|
|
||||||
* http://www.myersdaily.org/joseph/javascript/md5-text.html
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software
|
|
||||||
* and its documentation for any purposes and without
|
|
||||||
* fee is hereby granted provided that this copyright notice
|
|
||||||
* appears in all copies.
|
|
||||||
*
|
|
||||||
* Of course, this soft is provided "as is" without express or implied
|
|
||||||
* warranty of any kind.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import util from '../../util';
|
|
||||||
|
|
||||||
// MD5 Digest
|
|
||||||
async function md5(entree) {
|
|
||||||
const digest = md51(util.uint8ArrayToString(entree));
|
|
||||||
return util.hexToUint8Array(hex(digest));
|
|
||||||
}
|
|
||||||
|
|
||||||
function md5cycle(x, k) {
|
|
||||||
let a = x[0];
|
|
||||||
let b = x[1];
|
|
||||||
let c = x[2];
|
|
||||||
let d = x[3];
|
|
||||||
|
|
||||||
a = ff(a, b, c, d, k[0], 7, -680876936);
|
|
||||||
d = ff(d, a, b, c, k[1], 12, -389564586);
|
|
||||||
c = ff(c, d, a, b, k[2], 17, 606105819);
|
|
||||||
b = ff(b, c, d, a, k[3], 22, -1044525330);
|
|
||||||
a = ff(a, b, c, d, k[4], 7, -176418897);
|
|
||||||
d = ff(d, a, b, c, k[5], 12, 1200080426);
|
|
||||||
c = ff(c, d, a, b, k[6], 17, -1473231341);
|
|
||||||
b = ff(b, c, d, a, k[7], 22, -45705983);
|
|
||||||
a = ff(a, b, c, d, k[8], 7, 1770035416);
|
|
||||||
d = ff(d, a, b, c, k[9], 12, -1958414417);
|
|
||||||
c = ff(c, d, a, b, k[10], 17, -42063);
|
|
||||||
b = ff(b, c, d, a, k[11], 22, -1990404162);
|
|
||||||
a = ff(a, b, c, d, k[12], 7, 1804603682);
|
|
||||||
d = ff(d, a, b, c, k[13], 12, -40341101);
|
|
||||||
c = ff(c, d, a, b, k[14], 17, -1502002290);
|
|
||||||
b = ff(b, c, d, a, k[15], 22, 1236535329);
|
|
||||||
|
|
||||||
a = gg(a, b, c, d, k[1], 5, -165796510);
|
|
||||||
d = gg(d, a, b, c, k[6], 9, -1069501632);
|
|
||||||
c = gg(c, d, a, b, k[11], 14, 643717713);
|
|
||||||
b = gg(b, c, d, a, k[0], 20, -373897302);
|
|
||||||
a = gg(a, b, c, d, k[5], 5, -701558691);
|
|
||||||
d = gg(d, a, b, c, k[10], 9, 38016083);
|
|
||||||
c = gg(c, d, a, b, k[15], 14, -660478335);
|
|
||||||
b = gg(b, c, d, a, k[4], 20, -405537848);
|
|
||||||
a = gg(a, b, c, d, k[9], 5, 568446438);
|
|
||||||
d = gg(d, a, b, c, k[14], 9, -1019803690);
|
|
||||||
c = gg(c, d, a, b, k[3], 14, -187363961);
|
|
||||||
b = gg(b, c, d, a, k[8], 20, 1163531501);
|
|
||||||
a = gg(a, b, c, d, k[13], 5, -1444681467);
|
|
||||||
d = gg(d, a, b, c, k[2], 9, -51403784);
|
|
||||||
c = gg(c, d, a, b, k[7], 14, 1735328473);
|
|
||||||
b = gg(b, c, d, a, k[12], 20, -1926607734);
|
|
||||||
|
|
||||||
a = hh(a, b, c, d, k[5], 4, -378558);
|
|
||||||
d = hh(d, a, b, c, k[8], 11, -2022574463);
|
|
||||||
c = hh(c, d, a, b, k[11], 16, 1839030562);
|
|
||||||
b = hh(b, c, d, a, k[14], 23, -35309556);
|
|
||||||
a = hh(a, b, c, d, k[1], 4, -1530992060);
|
|
||||||
d = hh(d, a, b, c, k[4], 11, 1272893353);
|
|
||||||
c = hh(c, d, a, b, k[7], 16, -155497632);
|
|
||||||
b = hh(b, c, d, a, k[10], 23, -1094730640);
|
|
||||||
a = hh(a, b, c, d, k[13], 4, 681279174);
|
|
||||||
d = hh(d, a, b, c, k[0], 11, -358537222);
|
|
||||||
c = hh(c, d, a, b, k[3], 16, -722521979);
|
|
||||||
b = hh(b, c, d, a, k[6], 23, 76029189);
|
|
||||||
a = hh(a, b, c, d, k[9], 4, -640364487);
|
|
||||||
d = hh(d, a, b, c, k[12], 11, -421815835);
|
|
||||||
c = hh(c, d, a, b, k[15], 16, 530742520);
|
|
||||||
b = hh(b, c, d, a, k[2], 23, -995338651);
|
|
||||||
|
|
||||||
a = ii(a, b, c, d, k[0], 6, -198630844);
|
|
||||||
d = ii(d, a, b, c, k[7], 10, 1126891415);
|
|
||||||
c = ii(c, d, a, b, k[14], 15, -1416354905);
|
|
||||||
b = ii(b, c, d, a, k[5], 21, -57434055);
|
|
||||||
a = ii(a, b, c, d, k[12], 6, 1700485571);
|
|
||||||
d = ii(d, a, b, c, k[3], 10, -1894986606);
|
|
||||||
c = ii(c, d, a, b, k[10], 15, -1051523);
|
|
||||||
b = ii(b, c, d, a, k[1], 21, -2054922799);
|
|
||||||
a = ii(a, b, c, d, k[8], 6, 1873313359);
|
|
||||||
d = ii(d, a, b, c, k[15], 10, -30611744);
|
|
||||||
c = ii(c, d, a, b, k[6], 15, -1560198380);
|
|
||||||
b = ii(b, c, d, a, k[13], 21, 1309151649);
|
|
||||||
a = ii(a, b, c, d, k[4], 6, -145523070);
|
|
||||||
d = ii(d, a, b, c, k[11], 10, -1120210379);
|
|
||||||
c = ii(c, d, a, b, k[2], 15, 718787259);
|
|
||||||
b = ii(b, c, d, a, k[9], 21, -343485551);
|
|
||||||
|
|
||||||
x[0] = add32(a, x[0]);
|
|
||||||
x[1] = add32(b, x[1]);
|
|
||||||
x[2] = add32(c, x[2]);
|
|
||||||
x[3] = add32(d, x[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function cmn(q, a, b, x, s, t) {
|
|
||||||
a = add32(add32(a, q), add32(x, t));
|
|
||||||
return add32((a << s) | (a >>> (32 - s)), b);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ff(a, b, c, d, x, s, t) {
|
|
||||||
return cmn((b & c) | ((~b) & d), a, b, x, s, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
function gg(a, b, c, d, x, s, t) {
|
|
||||||
return cmn((b & d) | (c & (~d)), a, b, x, s, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
function hh(a, b, c, d, x, s, t) {
|
|
||||||
return cmn(b ^ c ^ d, a, b, x, s, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ii(a, b, c, d, x, s, t) {
|
|
||||||
return cmn(c ^ (b | (~d)), a, b, x, s, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
function md51(s) {
|
|
||||||
const n = s.length;
|
|
||||||
const state = [1732584193, -271733879, -1732584194, 271733878];
|
|
||||||
let i;
|
|
||||||
for (i = 64; i <= s.length; i += 64) {
|
|
||||||
md5cycle(state, md5blk(s.substring(i - 64, i)));
|
|
||||||
}
|
|
||||||
s = s.substring(i - 64);
|
|
||||||
const tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
||||||
for (i = 0; i < s.length; i++) {
|
|
||||||
tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
|
|
||||||
}
|
|
||||||
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
|
|
||||||
if (i > 55) {
|
|
||||||
md5cycle(state, tail);
|
|
||||||
for (i = 0; i < 16; i++) {
|
|
||||||
tail[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tail[14] = n * 8;
|
|
||||||
md5cycle(state, tail);
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* there needs to be support for Unicode here,
|
|
||||||
* unless we pretend that we can redefine the MD-5
|
|
||||||
* algorithm for multi-byte characters (perhaps
|
|
||||||
* by adding every four 16-bit characters and
|
|
||||||
* shortening the sum to 32 bits). Otherwise
|
|
||||||
* I suggest performing MD-5 as if every character
|
|
||||||
* was two bytes--e.g., 0040 0025 = @%--but then
|
|
||||||
* how will an ordinary MD-5 sum be matched?
|
|
||||||
* There is no way to standardize text to something
|
|
||||||
* like UTF-8 before transformation; speed cost is
|
|
||||||
* utterly prohibitive. The JavaScript standard
|
|
||||||
* itself needs to look at this: it should start
|
|
||||||
* providing access to strings as preformed UTF-8
|
|
||||||
* 8-bit unsigned value arrays.
|
|
||||||
*/
|
|
||||||
function md5blk(s) { /* I figured global was faster. */
|
|
||||||
const md5blks = [];
|
|
||||||
let i; /* Andy King said do it this way. */
|
|
||||||
for (i = 0; i < 64; i += 4) {
|
|
||||||
md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) <<
|
|
||||||
24);
|
|
||||||
}
|
|
||||||
return md5blks;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hex_chr = '0123456789abcdef'.split('');
|
|
||||||
|
|
||||||
function rhex(n) {
|
|
||||||
let s = '';
|
|
||||||
let j = 0;
|
|
||||||
for (; j < 4; j++) {
|
|
||||||
s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
function hex(x) {
|
|
||||||
for (let i = 0; i < x.length; i++) {
|
|
||||||
x[i] = rhex(x[i]);
|
|
||||||
}
|
|
||||||
return x.join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this function is much faster,
|
|
||||||
so if possible we use it. Some IEs
|
|
||||||
are the only ones I know of that
|
|
||||||
need the idiotic second function,
|
|
||||||
generated by an if clause. */
|
|
||||||
|
|
||||||
function add32(a, b) {
|
|
||||||
return (a + b) & 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default md5;
|
|
80
src/crypto/hash/md5.ts
Normal file
80
src/crypto/hash/md5.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// Copied from https://github.com/paulmillr/noble-hashes/blob/main/test/misc/md5.ts
|
||||||
|
|
||||||
|
import { HashMD } from '@noble/hashes/_md';
|
||||||
|
import { rotl, wrapConstructor } from '@noble/hashes/utils';
|
||||||
|
|
||||||
|
// Per-round constants
|
||||||
|
const K = Array.from({ length: 64 }, (_, i) => Math.floor(2 ** 32 * Math.abs(Math.sin(i + 1))));
|
||||||
|
// Choice: a ? b : c
|
||||||
|
const Chi = (a: number, b: number, c: number) => (a & b) ^ (~a & c);
|
||||||
|
// Initial state (same as sha1, but 4 u32 instead of 5)
|
||||||
|
const IV = /* @__PURE__ */ new Uint32Array([0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476]);
|
||||||
|
// Temporary buffer, not used to store anything between runs
|
||||||
|
// Named this way for SHA1 compat
|
||||||
|
const MD5_W = /* @__PURE__ */ new Uint32Array(16);
|
||||||
|
class MD5 extends HashMD<MD5> {
|
||||||
|
private A = IV[0] | 0;
|
||||||
|
private B = IV[1] | 0;
|
||||||
|
private C = IV[2] | 0;
|
||||||
|
private D = IV[3] | 0;
|
||||||
|
constructor() {
|
||||||
|
super(64, 16, 8, true);
|
||||||
|
}
|
||||||
|
protected get(): [number, number, number, number] {
|
||||||
|
const { A, B, C, D } = this;
|
||||||
|
return [A, B, C, D];
|
||||||
|
}
|
||||||
|
protected set(A: number, B: number, C: number, D: number) {
|
||||||
|
this.A = A | 0;
|
||||||
|
this.B = B | 0;
|
||||||
|
this.C = C | 0;
|
||||||
|
this.D = D | 0;
|
||||||
|
}
|
||||||
|
protected process(view: DataView, offset: number): void {
|
||||||
|
for (let i = 0; i < 16; i++, offset += 4) MD5_W[i] = view.getUint32(offset, true);
|
||||||
|
// Compression function main loop, 64 rounds
|
||||||
|
let { A, B, C, D } = this;
|
||||||
|
for (let i = 0; i < 64; i++) {
|
||||||
|
// eslint-disable-next-line one-var, one-var-declaration-per-line
|
||||||
|
let F, g, s;
|
||||||
|
if (i < 16) {
|
||||||
|
// eslint-disable-next-line new-cap
|
||||||
|
F = Chi(B, C, D);
|
||||||
|
g = i;
|
||||||
|
s = [7, 12, 17, 22];
|
||||||
|
} else if (i < 32) {
|
||||||
|
// eslint-disable-next-line new-cap
|
||||||
|
F = Chi(D, B, C);
|
||||||
|
g = (5 * i + 1) % 16;
|
||||||
|
s = [5, 9, 14, 20];
|
||||||
|
} else if (i < 48) {
|
||||||
|
F = B ^ C ^ D;
|
||||||
|
g = (3 * i + 5) % 16;
|
||||||
|
s = [4, 11, 16, 23];
|
||||||
|
} else {
|
||||||
|
F = C ^ (B | ~D);
|
||||||
|
g = (7 * i) % 16;
|
||||||
|
s = [6, 10, 15, 21];
|
||||||
|
}
|
||||||
|
F = F + A + K[i] + MD5_W[g];
|
||||||
|
A = D;
|
||||||
|
D = C;
|
||||||
|
C = B;
|
||||||
|
B = B + rotl(F, s[i % 4]);
|
||||||
|
}
|
||||||
|
// Add the compressed chunk to the current hash value
|
||||||
|
A = (A + this.A) | 0;
|
||||||
|
B = (B + this.B) | 0;
|
||||||
|
C = (C + this.C) | 0;
|
||||||
|
D = (D + this.D) | 0;
|
||||||
|
this.set(A, B, C, D);
|
||||||
|
}
|
||||||
|
protected roundClean() {
|
||||||
|
MD5_W.fill(0);
|
||||||
|
}
|
||||||
|
destroy() {
|
||||||
|
this.set(0, 0, 0, 0);
|
||||||
|
this.buffer.fill(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export const md5 = /* @__PURE__ */ wrapConstructor(() => new MD5());
|
@ -9,8 +9,10 @@ import { sha224, sha256 } from '@noble/hashes/sha256';
|
|||||||
import { sha384, sha512 } from '@noble/hashes/sha512';
|
import { sha384, sha512 } from '@noble/hashes/sha512';
|
||||||
import { sha3_256, sha3_512 } from '@noble/hashes/sha3';
|
import { sha3_256, sha3_512 } from '@noble/hashes/sha3';
|
||||||
import { ripemd160 } from '@noble/hashes/ripemd160';
|
import { ripemd160 } from '@noble/hashes/ripemd160';
|
||||||
|
import { md5 } from './md5';
|
||||||
|
|
||||||
export const nobleHashes = new Map(Object.entries({
|
export const nobleHashes = new Map(Object.entries({
|
||||||
|
md5,
|
||||||
sha1,
|
sha1,
|
||||||
sha224,
|
sha224,
|
||||||
sha256,
|
sha256,
|
||||||
|
@ -9,39 +9,10 @@
|
|||||||
* @module crypto
|
* @module crypto
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as cipher from './cipher';
|
export * from './crypto';
|
||||||
import hash from './hash';
|
export { getCipherParams } from './cipher';
|
||||||
import mode from './mode';
|
export * from './hash';
|
||||||
import publicKey from './public_key';
|
export * as cipherMode from './cipherMode';
|
||||||
import * as signature from './signature';
|
export * as publicKey from './public_key';
|
||||||
import * as random from './random';
|
export * as signature from './signature';
|
||||||
import * as pkcs1 from './pkcs1';
|
export { getRandomBytes } from './random';
|
||||||
import * as pkcs5 from './pkcs5';
|
|
||||||
import * as crypto from './crypto';
|
|
||||||
import * as aesKW from './aes_kw';
|
|
||||||
|
|
||||||
// TODO move cfb and gcm to cipher
|
|
||||||
const mod = {
|
|
||||||
/** @see module:crypto/cipher */
|
|
||||||
cipher: cipher,
|
|
||||||
/** @see module:crypto/hash */
|
|
||||||
hash: hash,
|
|
||||||
/** @see module:crypto/mode */
|
|
||||||
mode: mode,
|
|
||||||
/** @see module:crypto/public_key */
|
|
||||||
publicKey: publicKey,
|
|
||||||
/** @see module:crypto/signature */
|
|
||||||
signature: signature,
|
|
||||||
/** @see module:crypto/random */
|
|
||||||
random: random,
|
|
||||||
/** @see module:crypto/pkcs1 */
|
|
||||||
pkcs1: pkcs1,
|
|
||||||
/** @see module:crypto/pkcs5 */
|
|
||||||
pkcs5: pkcs5,
|
|
||||||
/** @see module:crypto/aes_kw */
|
|
||||||
aesKW: aesKW
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.assign(mod, crypto);
|
|
||||||
|
|
||||||
export default mod;
|
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
/**
|
|
||||||
* @fileoverview Cipher modes
|
|
||||||
* @module crypto/mode
|
|
||||||
*/
|
|
||||||
|
|
||||||
import * as cfb from './cfb';
|
|
||||||
import eax from './eax';
|
|
||||||
import ocb from './ocb';
|
|
||||||
import gcm from './gcm';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
/** @see module:crypto/mode/cfb */
|
|
||||||
cfb: cfb,
|
|
||||||
/** @see module:crypto/mode/gcm */
|
|
||||||
gcm: gcm,
|
|
||||||
experimentalGCM: gcm,
|
|
||||||
/** @see module:crypto/mode/eax */
|
|
||||||
eax: eax,
|
|
||||||
/** @see module:crypto/mode/ocb */
|
|
||||||
ocb: ocb
|
|
||||||
};
|
|
@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { getRandomBytes } from './random';
|
import { getRandomBytes } from './random';
|
||||||
import hash from './hash';
|
import { getHashByteLength } from './hash';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -134,7 +134,7 @@ export function emeDecode(encoded, randomPayload) {
|
|||||||
*/
|
*/
|
||||||
export function emsaEncode(algo, hashed, emLen) {
|
export function emsaEncode(algo, hashed, emLen) {
|
||||||
let i;
|
let i;
|
||||||
if (hashed.length !== hash.getHashByteLength(algo)) {
|
if (hashed.length !== getHashByteLength(algo)) {
|
||||||
throw new Error('Invalid hash length');
|
throw new Error('Invalid hash length');
|
||||||
}
|
}
|
||||||
// produce an ASN.1 DER value for the hash function used.
|
// produce an ASN.1 DER value for the hash function used.
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
import { CurveWithOID, jwkToRawPublic, rawPublicToJWK, privateToJWK, validateStandardParams, checkPublicPointEnconding } from './oid_curves';
|
import { CurveWithOID, jwkToRawPublic, rawPublicToJWK, privateToJWK, validateStandardParams, checkPublicPointEnconding } from './oid_curves';
|
||||||
import * as aesKW from '../../aes_kw';
|
import * as aesKW from '../../aes_kw';
|
||||||
import hash from '../../hash';
|
import { computeDigest } from '../../hash';
|
||||||
import enums from '../../../enums';
|
import enums from '../../../enums';
|
||||||
import util from '../../../util';
|
import util from '../../../util';
|
||||||
import { b64ToUint8Array } from '../../../encoding/base64';
|
import { b64ToUint8Array } from '../../../encoding/base64';
|
||||||
@ -72,7 +72,7 @@ async function kdf(hashAlgo, X, length, param, stripLeading = false, stripTraili
|
|||||||
for (i = X.length - 1; i >= 0 && X[i] === 0; i--);
|
for (i = X.length - 1; i >= 0 && X[i] === 0; i--);
|
||||||
X = X.subarray(0, i + 1);
|
X = X.subarray(0, i + 1);
|
||||||
}
|
}
|
||||||
const digest = await hash.digest(hashAlgo, util.concatUint8Array([
|
const digest = await computeDigest(hashAlgo, util.concatUint8Array([
|
||||||
new Uint8Array([0, 0, 0, 1]),
|
new Uint8Array([0, 0, 0, 1]),
|
||||||
X,
|
X,
|
||||||
param
|
param
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
import enums from '../../../enums';
|
import enums from '../../../enums';
|
||||||
import util from '../../../util';
|
import util from '../../../util';
|
||||||
import { getRandomBytes } from '../../random';
|
import { getRandomBytes } from '../../random';
|
||||||
import hash from '../../hash';
|
import { computeDigest } from '../../hash';
|
||||||
import { CurveWithOID, webCurves, privateToJWK, rawPublicToJWK, validateStandardParams, nodeCurves, checkPublicPointEnconding } from './oid_curves';
|
import { CurveWithOID, webCurves, privateToJWK, rawPublicToJWK, validateStandardParams, nodeCurves, checkPublicPointEnconding } from './oid_curves';
|
||||||
import { bigIntToUint8Array } from '../../biginteger';
|
import { bigIntToUint8Array } from '../../biginteger';
|
||||||
|
|
||||||
@ -156,7 +156,7 @@ export async function validateParams(oid, Q, d) {
|
|||||||
case 'node': {
|
case 'node': {
|
||||||
const message = getRandomBytes(8);
|
const message = getRandomBytes(8);
|
||||||
const hashAlgo = enums.hash.sha256;
|
const hashAlgo = enums.hash.sha256;
|
||||||
const hashed = await hash.digest(hashAlgo, message);
|
const hashed = await computeDigest(hashAlgo, message);
|
||||||
try {
|
try {
|
||||||
const signature = await sign(oid, hashAlgo, message, Q, d, hashed);
|
const signature = await sign(oid, hashAlgo, message, Q, d, hashed);
|
||||||
// eslint-disable-next-line @typescript-eslint/return-await
|
// eslint-disable-next-line @typescript-eslint/return-await
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
import ed25519 from '@openpgp/tweetnacl';
|
import ed25519 from '@openpgp/tweetnacl';
|
||||||
import util from '../../../util';
|
import util from '../../../util';
|
||||||
import enums from '../../../enums';
|
import enums from '../../../enums';
|
||||||
import hash from '../../hash';
|
import { getHashByteLength } from '../../hash';
|
||||||
import { getRandomBytes } from '../../random';
|
import { getRandomBytes } from '../../random';
|
||||||
import { b64ToUint8Array, uint8ArrayToB64 } from '../../../encoding/base64';
|
import { b64ToUint8Array, uint8ArrayToB64 } from '../../../encoding/base64';
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ export async function generate(algo) {
|
|||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function sign(algo, hashAlgo, message, publicKey, privateKey, hashed) {
|
export async function sign(algo, hashAlgo, message, publicKey, privateKey, hashed) {
|
||||||
if (hash.getHashByteLength(hashAlgo) < hash.getHashByteLength(getPreferredHashAlgo(algo))) {
|
if (getHashByteLength(hashAlgo) < getHashByteLength(getPreferredHashAlgo(algo))) {
|
||||||
// Enforce digest sizes:
|
// Enforce digest sizes:
|
||||||
// - Ed25519: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.4-4
|
// - Ed25519: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.4-4
|
||||||
// - Ed448: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.5-4
|
// - Ed448: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.5-4
|
||||||
@ -131,7 +131,7 @@ export async function sign(algo, hashAlgo, message, publicKey, privateKey, hashe
|
|||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function verify(algo, hashAlgo, { RS }, m, publicKey, hashed) {
|
export async function verify(algo, hashAlgo, { RS }, m, publicKey, hashed) {
|
||||||
if (hash.getHashByteLength(hashAlgo) < hash.getHashByteLength(getPreferredHashAlgo(algo))) {
|
if (getHashByteLength(hashAlgo) < getHashByteLength(getPreferredHashAlgo(algo))) {
|
||||||
// Enforce digest sizes:
|
// Enforce digest sizes:
|
||||||
// - Ed25519: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.4-4
|
// - Ed25519: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.4-4
|
||||||
// - Ed448: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.5-4
|
// - Ed448: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.5-4
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
import nacl from '@openpgp/tweetnacl';
|
import nacl from '@openpgp/tweetnacl';
|
||||||
import util from '../../../util';
|
import util from '../../../util';
|
||||||
import enums from '../../../enums';
|
import enums from '../../../enums';
|
||||||
import hash from '../../hash';
|
import { getHashByteLength } from '../../hash';
|
||||||
import { CurveWithOID, checkPublicPointEnconding } from './oid_curves';
|
import { CurveWithOID, checkPublicPointEnconding } from './oid_curves';
|
||||||
import { sign as eddsaSign, verify as eddsaVerify } from './eddsa';
|
import { sign as eddsaSign, verify as eddsaVerify } from './eddsa';
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ import { sign as eddsaSign, verify as eddsaVerify } from './eddsa';
|
|||||||
export async function sign(oid, hashAlgo, message, publicKey, privateKey, hashed) {
|
export async function sign(oid, hashAlgo, message, publicKey, privateKey, hashed) {
|
||||||
const curve = new CurveWithOID(oid);
|
const curve = new CurveWithOID(oid);
|
||||||
checkPublicPointEnconding(curve, publicKey);
|
checkPublicPointEnconding(curve, publicKey);
|
||||||
if (hash.getHashByteLength(hashAlgo) < hash.getHashByteLength(enums.hash.sha256)) {
|
if (getHashByteLength(hashAlgo) < getHashByteLength(enums.hash.sha256)) {
|
||||||
// Enforce digest sizes, since the constraint was already present in RFC4880bis:
|
// Enforce digest sizes, since the constraint was already present in RFC4880bis:
|
||||||
// see https://tools.ietf.org/id/draft-ietf-openpgp-rfc4880bis-10.html#section-15-7.2
|
// see https://tools.ietf.org/id/draft-ietf-openpgp-rfc4880bis-10.html#section-15-7.2
|
||||||
// and https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.3-3
|
// and https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.3-3
|
||||||
@ -74,7 +74,7 @@ export async function sign(oid, hashAlgo, message, publicKey, privateKey, hashed
|
|||||||
export async function verify(oid, hashAlgo, { r, s }, m, publicKey, hashed) {
|
export async function verify(oid, hashAlgo, { r, s }, m, publicKey, hashed) {
|
||||||
const curve = new CurveWithOID(oid);
|
const curve = new CurveWithOID(oid);
|
||||||
checkPublicPointEnconding(curve, publicKey);
|
checkPublicPointEnconding(curve, publicKey);
|
||||||
if (hash.getHashByteLength(hashAlgo) < hash.getHashByteLength(enums.hash.sha256)) {
|
if (getHashByteLength(hashAlgo) < getHashByteLength(enums.hash.sha256)) {
|
||||||
// Enforce digest sizes, since the constraint was already present in RFC4880bis:
|
// Enforce digest sizes, since the constraint was already present in RFC4880bis:
|
||||||
// see https://tools.ietf.org/id/draft-ietf-openpgp-rfc4880bis-10.html#section-15-7.2
|
// see https://tools.ietf.org/id/draft-ietf-openpgp-rfc4880bis-10.html#section-15-7.2
|
||||||
// and https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.3-3
|
// and https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.3-3
|
||||||
|
@ -3,18 +3,7 @@
|
|||||||
* @module crypto/public_key
|
* @module crypto/public_key
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as rsa from './rsa';
|
export * as rsa from './rsa';
|
||||||
import * as elgamal from './elgamal';
|
export * as elgamal from './elgamal';
|
||||||
import * as elliptic from './elliptic';
|
export * as elliptic from './elliptic';
|
||||||
import * as dsa from './dsa';
|
export * as dsa from './dsa';
|
||||||
|
|
||||||
export default {
|
|
||||||
/** @see module:crypto/public_key/rsa */
|
|
||||||
rsa: rsa,
|
|
||||||
/** @see module:crypto/public_key/elgamal */
|
|
||||||
elgamal: elgamal,
|
|
||||||
/** @see module:crypto/public_key/elliptic */
|
|
||||||
elliptic: elliptic,
|
|
||||||
/** @see module:crypto/public_key/dsa */
|
|
||||||
dsa: dsa
|
|
||||||
};
|
|
||||||
|
@ -26,7 +26,7 @@ import { uint8ArrayToB64, b64ToUint8Array } from '../../encoding/base64';
|
|||||||
import { emsaEncode, emeEncode, emeDecode } from '../pkcs1';
|
import { emsaEncode, emeEncode, emeDecode } from '../pkcs1';
|
||||||
import enums from '../../enums';
|
import enums from '../../enums';
|
||||||
import { bigIntToNumber, bigIntToUint8Array, bitLength, byteLength, mod, modExp, modInv, uint8ArrayToBigInt } from '../biginteger';
|
import { bigIntToNumber, bigIntToUint8Array, bitLength, byteLength, mod, modExp, modInv, uint8ArrayToBigInt } from '../biginteger';
|
||||||
import hash from '../hash';
|
import { getHashByteLength } from '../hash';
|
||||||
|
|
||||||
const webCrypto = util.getWebCrypto();
|
const webCrypto = util.getWebCrypto();
|
||||||
const nodeCrypto = util.getNodeCrypto();
|
const nodeCrypto = util.getNodeCrypto();
|
||||||
@ -46,7 +46,7 @@ const _1n = BigInt(1);
|
|||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function sign(hashAlgo, data, n, e, d, p, q, u, hashed) {
|
export async function sign(hashAlgo, data, n, e, d, p, q, u, hashed) {
|
||||||
if (hash.getHashByteLength(hashAlgo) >= n.length) {
|
if (getHashByteLength(hashAlgo) >= n.length) {
|
||||||
// Throw here instead of `emsaEncode` below, to provide a clearer and consistent error
|
// Throw here instead of `emsaEncode` below, to provide a clearer and consistent error
|
||||||
// e.g. if a 512-bit RSA key is used with a SHA-512 digest.
|
// e.g. if a 512-bit RSA key is used with a SHA-512 digest.
|
||||||
// The size limit is actually slightly different but here we only care about throwing
|
// The size limit is actually slightly different but here we only care about throwing
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* @module crypto/signature
|
* @module crypto/signature
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import publicKey from './public_key';
|
import { elliptic, rsa, dsa } from './public_key';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
import { UnsupportedError } from '../packet/packet';
|
import { UnsupportedError } from '../packet/packet';
|
||||||
@ -61,7 +61,7 @@ export function parseSignatureParams(algo, signature) {
|
|||||||
// - 114 octets of the native signature
|
// - 114 octets of the native signature
|
||||||
case enums.publicKey.ed25519:
|
case enums.publicKey.ed25519:
|
||||||
case enums.publicKey.ed448: {
|
case enums.publicKey.ed448: {
|
||||||
const rsSize = 2 * publicKey.elliptic.eddsa.getPayloadSize(algo);
|
const rsSize = 2 * elliptic.eddsa.getPayloadSize(algo);
|
||||||
const RS = util.readExactSubarray(signature, read, read + rsSize); read += RS.length;
|
const RS = util.readExactSubarray(signature, read, read + rsSize); read += RS.length;
|
||||||
return { read, signatureParams: { RS } };
|
return { read, signatureParams: { RS } };
|
||||||
}
|
}
|
||||||
@ -92,34 +92,34 @@ export async function verify(algo, hashAlgo, signature, publicParams, data, hash
|
|||||||
case enums.publicKey.rsaSign: {
|
case enums.publicKey.rsaSign: {
|
||||||
const { n, e } = publicParams;
|
const { n, e } = publicParams;
|
||||||
const s = util.leftPad(signature.s, n.length); // padding needed for webcrypto and node crypto
|
const s = util.leftPad(signature.s, n.length); // padding needed for webcrypto and node crypto
|
||||||
return publicKey.rsa.verify(hashAlgo, data, s, n, e, hashed);
|
return rsa.verify(hashAlgo, data, s, n, e, hashed);
|
||||||
}
|
}
|
||||||
case enums.publicKey.dsa: {
|
case enums.publicKey.dsa: {
|
||||||
const { g, p, q, y } = publicParams;
|
const { g, p, q, y } = publicParams;
|
||||||
const { r, s } = signature; // no need to pad, since we always handle them as BigIntegers
|
const { r, s } = signature; // no need to pad, since we always handle them as BigIntegers
|
||||||
return publicKey.dsa.verify(hashAlgo, r, s, hashed, g, p, q, y);
|
return dsa.verify(hashAlgo, r, s, hashed, g, p, q, y);
|
||||||
}
|
}
|
||||||
case enums.publicKey.ecdsa: {
|
case enums.publicKey.ecdsa: {
|
||||||
const { oid, Q } = publicParams;
|
const { oid, Q } = publicParams;
|
||||||
const curveSize = new publicKey.elliptic.CurveWithOID(oid).payloadSize;
|
const curveSize = new elliptic.CurveWithOID(oid).payloadSize;
|
||||||
// padding needed for webcrypto
|
// padding needed for webcrypto
|
||||||
const r = util.leftPad(signature.r, curveSize);
|
const r = util.leftPad(signature.r, curveSize);
|
||||||
const s = util.leftPad(signature.s, curveSize);
|
const s = util.leftPad(signature.s, curveSize);
|
||||||
return publicKey.elliptic.ecdsa.verify(oid, hashAlgo, { r, s }, data, Q, hashed);
|
return elliptic.ecdsa.verify(oid, hashAlgo, { r, s }, data, Q, hashed);
|
||||||
}
|
}
|
||||||
case enums.publicKey.eddsaLegacy: {
|
case enums.publicKey.eddsaLegacy: {
|
||||||
const { oid, Q } = publicParams;
|
const { oid, Q } = publicParams;
|
||||||
const curveSize = new publicKey.elliptic.CurveWithOID(oid).payloadSize;
|
const curveSize = new elliptic.CurveWithOID(oid).payloadSize;
|
||||||
// When dealing little-endian MPI data, we always need to left-pad it, as done with big-endian values:
|
// When dealing little-endian MPI data, we always need to left-pad it, as done with big-endian values:
|
||||||
// https://www.ietf.org/archive/id/draft-ietf-openpgp-rfc4880bis-10.html#section-3.2-9
|
// https://www.ietf.org/archive/id/draft-ietf-openpgp-rfc4880bis-10.html#section-3.2-9
|
||||||
const r = util.leftPad(signature.r, curveSize);
|
const r = util.leftPad(signature.r, curveSize);
|
||||||
const s = util.leftPad(signature.s, curveSize);
|
const s = util.leftPad(signature.s, curveSize);
|
||||||
return publicKey.elliptic.eddsaLegacy.verify(oid, hashAlgo, { r, s }, data, Q, hashed);
|
return elliptic.eddsaLegacy.verify(oid, hashAlgo, { r, s }, data, Q, hashed);
|
||||||
}
|
}
|
||||||
case enums.publicKey.ed25519:
|
case enums.publicKey.ed25519:
|
||||||
case enums.publicKey.ed448: {
|
case enums.publicKey.ed448: {
|
||||||
const { A } = publicParams;
|
const { A } = publicParams;
|
||||||
return publicKey.elliptic.eddsa.verify(algo, hashAlgo, signature, data, A, hashed);
|
return elliptic.eddsa.verify(algo, hashAlgo, signature, data, A, hashed);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new Error('Unknown signature algorithm.');
|
throw new Error('Unknown signature algorithm.');
|
||||||
@ -150,31 +150,31 @@ export async function sign(algo, hashAlgo, publicKeyParams, privateKeyParams, da
|
|||||||
case enums.publicKey.rsaSign: {
|
case enums.publicKey.rsaSign: {
|
||||||
const { n, e } = publicKeyParams;
|
const { n, e } = publicKeyParams;
|
||||||
const { d, p, q, u } = privateKeyParams;
|
const { d, p, q, u } = privateKeyParams;
|
||||||
const s = await publicKey.rsa.sign(hashAlgo, data, n, e, d, p, q, u, hashed);
|
const s = await rsa.sign(hashAlgo, data, n, e, d, p, q, u, hashed);
|
||||||
return { s };
|
return { s };
|
||||||
}
|
}
|
||||||
case enums.publicKey.dsa: {
|
case enums.publicKey.dsa: {
|
||||||
const { g, p, q } = publicKeyParams;
|
const { g, p, q } = publicKeyParams;
|
||||||
const { x } = privateKeyParams;
|
const { x } = privateKeyParams;
|
||||||
return publicKey.dsa.sign(hashAlgo, hashed, g, p, q, x);
|
return dsa.sign(hashAlgo, hashed, g, p, q, x);
|
||||||
}
|
}
|
||||||
case enums.publicKey.elgamal:
|
case enums.publicKey.elgamal:
|
||||||
throw new Error('Signing with Elgamal is not defined in the OpenPGP standard.');
|
throw new Error('Signing with Elgamal is not defined in the OpenPGP standard.');
|
||||||
case enums.publicKey.ecdsa: {
|
case enums.publicKey.ecdsa: {
|
||||||
const { oid, Q } = publicKeyParams;
|
const { oid, Q } = publicKeyParams;
|
||||||
const { d } = privateKeyParams;
|
const { d } = privateKeyParams;
|
||||||
return publicKey.elliptic.ecdsa.sign(oid, hashAlgo, data, Q, d, hashed);
|
return elliptic.ecdsa.sign(oid, hashAlgo, data, Q, d, hashed);
|
||||||
}
|
}
|
||||||
case enums.publicKey.eddsaLegacy: {
|
case enums.publicKey.eddsaLegacy: {
|
||||||
const { oid, Q } = publicKeyParams;
|
const { oid, Q } = publicKeyParams;
|
||||||
const { seed } = privateKeyParams;
|
const { seed } = privateKeyParams;
|
||||||
return publicKey.elliptic.eddsaLegacy.sign(oid, hashAlgo, data, Q, seed, hashed);
|
return elliptic.eddsaLegacy.sign(oid, hashAlgo, data, Q, seed, hashed);
|
||||||
}
|
}
|
||||||
case enums.publicKey.ed25519:
|
case enums.publicKey.ed25519:
|
||||||
case enums.publicKey.ed448: {
|
case enums.publicKey.ed448: {
|
||||||
const { A } = publicKeyParams;
|
const { A } = publicKeyParams;
|
||||||
const { seed } = privateKeyParams;
|
const { seed } = privateKeyParams;
|
||||||
return publicKey.elliptic.eddsa.sign(algo, hashAlgo, data, A, seed, hashed);
|
return elliptic.eddsa.sign(algo, hashAlgo, data, A, seed, hashed);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new Error('Unknown signature algorithm.');
|
throw new Error('Unknown signature algorithm.');
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { transform as streamTransform, transformPair as streamTransformPair, getReader as streamGetReader, getWriter as streamGetWriter, isArrayStream, readToEnd as streamReadToEnd, passiveClone as streamPassiveClone } from '@openpgp/web-stream-tools';
|
||||||
import * as base64 from './base64';
|
import { encode as encodeBase64, decode as decodeBase64 } from './base64';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
import defaultConfig from '../config';
|
import defaultConfig from '../config';
|
||||||
@ -115,7 +115,7 @@ function addheader(customComment, config) {
|
|||||||
*/
|
*/
|
||||||
function getCheckSum(data) {
|
function getCheckSum(data) {
|
||||||
const crc = createcrc24(data);
|
const crc = createcrc24(data);
|
||||||
return base64.encode(crc);
|
return encodeBase64(crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://create.stephan-brumme.com/crc32/#slicing-by-8-overview
|
// https://create.stephan-brumme.com/crc32/#slicing-by-8-overview
|
||||||
@ -163,7 +163,7 @@ const isLittleEndian = (function() {
|
|||||||
*/
|
*/
|
||||||
function createcrc24(input) {
|
function createcrc24(input) {
|
||||||
let crc = 0xCE04B7;
|
let crc = 0xCE04B7;
|
||||||
return stream.transform(input, value => {
|
return streamTransform(input, value => {
|
||||||
const len32 = isLittleEndian ? Math.floor(value.length / 4) : 0;
|
const len32 = isLittleEndian ? Math.floor(value.length / 4) : 0;
|
||||||
const arr32 = new Uint32Array(value.buffer, value.byteOffset, len32);
|
const arr32 = new Uint32Array(value.buffer, value.byteOffset, len32);
|
||||||
for (let i = 0; i < len32; i++) {
|
for (let i = 0; i < len32; i++) {
|
||||||
@ -239,8 +239,8 @@ export function unarmor(input) {
|
|||||||
let headersDone;
|
let headersDone;
|
||||||
let text = [];
|
let text = [];
|
||||||
let textDone;
|
let textDone;
|
||||||
const data = base64.decode(stream.transformPair(input, async (readable, writable) => {
|
const data = decodeBase64(streamTransformPair(input, async (readable, writable) => {
|
||||||
const reader = stream.getReader(readable);
|
const reader = streamGetReader(readable);
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
let line = await reader.readLine();
|
let line = await reader.readLine();
|
||||||
@ -284,7 +284,7 @@ export function unarmor(input) {
|
|||||||
reject(e);
|
reject(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const writer = stream.getWriter(writable);
|
const writer = streamGetWriter(writable);
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
await writer.ready;
|
await writer.ready;
|
||||||
@ -319,8 +319,8 @@ export function unarmor(input) {
|
|||||||
reject(e);
|
reject(e);
|
||||||
}
|
}
|
||||||
}).then(async result => {
|
}).then(async result => {
|
||||||
if (stream.isArrayStream(result.data)) {
|
if (isArrayStream(result.data)) {
|
||||||
result.data = await stream.readToEnd(result.data);
|
result.data = await streamReadToEnd(result.data);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
@ -350,21 +350,21 @@ export function armor(messageType, body, partIndex, partTotal, customComment, em
|
|||||||
}
|
}
|
||||||
// unless explicitly forbidden by the spec, we need to include the checksum to work around a GnuPG bug
|
// unless explicitly forbidden by the spec, we need to include the checksum to work around a GnuPG bug
|
||||||
// where data fails to be decoded if the base64 ends with no padding chars (=) (see https://dev.gnupg.org/T7071)
|
// where data fails to be decoded if the base64 ends with no padding chars (=) (see https://dev.gnupg.org/T7071)
|
||||||
const maybeBodyClone = emitChecksum && stream.passiveClone(body);
|
const maybeBodyClone = emitChecksum && streamPassiveClone(body);
|
||||||
|
|
||||||
const result = [];
|
const result = [];
|
||||||
switch (messageType) {
|
switch (messageType) {
|
||||||
case enums.armor.multipartSection:
|
case enums.armor.multipartSection:
|
||||||
result.push('-----BEGIN PGP MESSAGE, PART ' + partIndex + '/' + partTotal + '-----\n');
|
result.push('-----BEGIN PGP MESSAGE, PART ' + partIndex + '/' + partTotal + '-----\n');
|
||||||
result.push(addheader(customComment, config));
|
result.push(addheader(customComment, config));
|
||||||
result.push(base64.encode(body));
|
result.push(encodeBase64(body));
|
||||||
maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
|
maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
|
||||||
result.push('-----END PGP MESSAGE, PART ' + partIndex + '/' + partTotal + '-----\n');
|
result.push('-----END PGP MESSAGE, PART ' + partIndex + '/' + partTotal + '-----\n');
|
||||||
break;
|
break;
|
||||||
case enums.armor.multipartLast:
|
case enums.armor.multipartLast:
|
||||||
result.push('-----BEGIN PGP MESSAGE, PART ' + partIndex + '-----\n');
|
result.push('-----BEGIN PGP MESSAGE, PART ' + partIndex + '-----\n');
|
||||||
result.push(addheader(customComment, config));
|
result.push(addheader(customComment, config));
|
||||||
result.push(base64.encode(body));
|
result.push(encodeBase64(body));
|
||||||
maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
|
maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
|
||||||
result.push('-----END PGP MESSAGE, PART ' + partIndex + '-----\n');
|
result.push('-----END PGP MESSAGE, PART ' + partIndex + '-----\n');
|
||||||
break;
|
break;
|
||||||
@ -374,35 +374,35 @@ export function armor(messageType, body, partIndex, partTotal, customComment, em
|
|||||||
result.push(text.replace(/^-/mg, '- -'));
|
result.push(text.replace(/^-/mg, '- -'));
|
||||||
result.push('\n-----BEGIN PGP SIGNATURE-----\n');
|
result.push('\n-----BEGIN PGP SIGNATURE-----\n');
|
||||||
result.push(addheader(customComment, config));
|
result.push(addheader(customComment, config));
|
||||||
result.push(base64.encode(body));
|
result.push(encodeBase64(body));
|
||||||
maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
|
maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
|
||||||
result.push('-----END PGP SIGNATURE-----\n');
|
result.push('-----END PGP SIGNATURE-----\n');
|
||||||
break;
|
break;
|
||||||
case enums.armor.message:
|
case enums.armor.message:
|
||||||
result.push('-----BEGIN PGP MESSAGE-----\n');
|
result.push('-----BEGIN PGP MESSAGE-----\n');
|
||||||
result.push(addheader(customComment, config));
|
result.push(addheader(customComment, config));
|
||||||
result.push(base64.encode(body));
|
result.push(encodeBase64(body));
|
||||||
maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
|
maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
|
||||||
result.push('-----END PGP MESSAGE-----\n');
|
result.push('-----END PGP MESSAGE-----\n');
|
||||||
break;
|
break;
|
||||||
case enums.armor.publicKey:
|
case enums.armor.publicKey:
|
||||||
result.push('-----BEGIN PGP PUBLIC KEY BLOCK-----\n');
|
result.push('-----BEGIN PGP PUBLIC KEY BLOCK-----\n');
|
||||||
result.push(addheader(customComment, config));
|
result.push(addheader(customComment, config));
|
||||||
result.push(base64.encode(body));
|
result.push(encodeBase64(body));
|
||||||
maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
|
maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
|
||||||
result.push('-----END PGP PUBLIC KEY BLOCK-----\n');
|
result.push('-----END PGP PUBLIC KEY BLOCK-----\n');
|
||||||
break;
|
break;
|
||||||
case enums.armor.privateKey:
|
case enums.armor.privateKey:
|
||||||
result.push('-----BEGIN PGP PRIVATE KEY BLOCK-----\n');
|
result.push('-----BEGIN PGP PRIVATE KEY BLOCK-----\n');
|
||||||
result.push(addheader(customComment, config));
|
result.push(addheader(customComment, config));
|
||||||
result.push(base64.encode(body));
|
result.push(encodeBase64(body));
|
||||||
maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
|
maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
|
||||||
result.push('-----END PGP PRIVATE KEY BLOCK-----\n');
|
result.push('-----END PGP PRIVATE KEY BLOCK-----\n');
|
||||||
break;
|
break;
|
||||||
case enums.armor.signature:
|
case enums.armor.signature:
|
||||||
result.push('-----BEGIN PGP SIGNATURE-----\n');
|
result.push('-----BEGIN PGP SIGNATURE-----\n');
|
||||||
result.push(addheader(customComment, config));
|
result.push(addheader(customComment, config));
|
||||||
result.push(base64.encode(body));
|
result.push(encodeBase64(body));
|
||||||
maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
|
maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
|
||||||
result.push('-----END PGP SIGNATURE-----\n');
|
result.push('-----END PGP SIGNATURE-----\n');
|
||||||
break;
|
break;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* @module encoding/base64
|
* @module encoding/base64
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { transform as streamTransform } from '@openpgp/web-stream-tools';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
|
||||||
const Buffer = util.getNodeBuffer();
|
const Buffer = util.getNodeBuffer();
|
||||||
@ -41,7 +41,7 @@ if (Buffer) {
|
|||||||
*/
|
*/
|
||||||
export function encode(data) {
|
export function encode(data) {
|
||||||
let buf = new Uint8Array();
|
let buf = new Uint8Array();
|
||||||
return stream.transform(data, value => {
|
return streamTransform(data, value => {
|
||||||
buf = util.concatUint8Array([buf, value]);
|
buf = util.concatUint8Array([buf, value]);
|
||||||
const r = [];
|
const r = [];
|
||||||
const bytesPerLine = 45; // 60 chars per line * (3 bytes / 4 chars of base64).
|
const bytesPerLine = 45; // 60 chars per line * (3 bytes / 4 chars of base64).
|
||||||
@ -65,7 +65,7 @@ export function encode(data) {
|
|||||||
*/
|
*/
|
||||||
export function decode(data) {
|
export function decode(data) {
|
||||||
let buf = '';
|
let buf = '';
|
||||||
return stream.transform(data, value => {
|
return streamTransform(data, value => {
|
||||||
buf += value;
|
buf += value;
|
||||||
|
|
||||||
// Count how many whitespace characters there are in buf
|
// Count how many whitespace characters there are in buf
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
SignaturePacket
|
SignaturePacket
|
||||||
} from '../packet';
|
} from '../packet';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import crypto from '../crypto';
|
import { getPreferredCurveHashAlgo, getHashByteLength } from '../crypto';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
import defaultConfig from '../config';
|
import defaultConfig from '../config';
|
||||||
|
|
||||||
@ -149,10 +149,10 @@ export async function getPreferredHashAlgo(targetKeys, signingKeyPacket, date =
|
|||||||
}
|
}
|
||||||
const sortedHashAlgos = Array.from(supportedAlgosMap.keys())
|
const sortedHashAlgos = Array.from(supportedAlgosMap.keys())
|
||||||
.filter(hashAlgo => isSupportedHashAlgo(hashAlgo))
|
.filter(hashAlgo => isSupportedHashAlgo(hashAlgo))
|
||||||
.sort((algoA, algoB) => crypto.hash.getHashByteLength(algoA) - crypto.hash.getHashByteLength(algoB));
|
.sort((algoA, algoB) => getHashByteLength(algoA) - getHashByteLength(algoB));
|
||||||
const strongestHashAlgo = sortedHashAlgos[0];
|
const strongestHashAlgo = sortedHashAlgos[0];
|
||||||
// defaultAlgo is always implicilty supported, and might be stronger than the rest
|
// defaultAlgo is always implicilty supported, and might be stronger than the rest
|
||||||
return crypto.hash.getHashByteLength(strongestHashAlgo) >= crypto.hash.getHashByteLength(defaultAlgo) ? strongestHashAlgo : defaultAlgo;
|
return getHashByteLength(strongestHashAlgo) >= getHashByteLength(defaultAlgo) ? strongestHashAlgo : defaultAlgo;
|
||||||
};
|
};
|
||||||
|
|
||||||
const eccAlgos = new Set([
|
const eccAlgos = new Set([
|
||||||
@ -171,16 +171,16 @@ export async function getPreferredHashAlgo(targetKeys, signingKeyPacket, date =
|
|||||||
// Hence, we return the `preferredHashAlgo` as long as it's supported and strong enough;
|
// Hence, we return the `preferredHashAlgo` as long as it's supported and strong enough;
|
||||||
// Otherwise, we look at the strongest supported algo, and ultimately fallback to the curve
|
// Otherwise, we look at the strongest supported algo, and ultimately fallback to the curve
|
||||||
// preferred algo, even if not supported by all targets.
|
// preferred algo, even if not supported by all targets.
|
||||||
const preferredCurveAlgo = crypto.getPreferredCurveHashAlgo(signingKeyPacket.algorithm, signingKeyPacket.publicParams.oid);
|
const preferredCurveAlgo = getPreferredCurveHashAlgo(signingKeyPacket.algorithm, signingKeyPacket.publicParams.oid);
|
||||||
|
|
||||||
const preferredSenderAlgoIsSupported = isSupportedHashAlgo(preferredSenderAlgo);
|
const preferredSenderAlgoIsSupported = isSupportedHashAlgo(preferredSenderAlgo);
|
||||||
const preferredSenderAlgoStrongerThanCurveAlgo = crypto.hash.getHashByteLength(preferredSenderAlgo) >= crypto.hash.getHashByteLength(preferredCurveAlgo);
|
const preferredSenderAlgoStrongerThanCurveAlgo = getHashByteLength(preferredSenderAlgo) >= getHashByteLength(preferredCurveAlgo);
|
||||||
|
|
||||||
if (preferredSenderAlgoIsSupported && preferredSenderAlgoStrongerThanCurveAlgo) {
|
if (preferredSenderAlgoIsSupported && preferredSenderAlgoStrongerThanCurveAlgo) {
|
||||||
return preferredSenderAlgo;
|
return preferredSenderAlgo;
|
||||||
} else {
|
} else {
|
||||||
const strongestSupportedAlgo = getStrongestSupportedHashAlgo();
|
const strongestSupportedAlgo = getStrongestSupportedHashAlgo();
|
||||||
return crypto.hash.getHashByteLength(strongestSupportedAlgo) >= crypto.hash.getHashByteLength(preferredCurveAlgo) ?
|
return getHashByteLength(strongestSupportedAlgo) >= getHashByteLength(preferredCurveAlgo) ?
|
||||||
strongestSupportedAlgo :
|
strongestSupportedAlgo :
|
||||||
preferredCurveAlgo;
|
preferredCurveAlgo;
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,11 @@
|
|||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { isArrayStream, cancel as streamCancel, readToEnd as streamReadToEnd, fromAsync as streamFromAsync, transformPair as streamTransformPair, getWriter as streamGetWriter, getReader as streamGetReader } from '@openpgp/web-stream-tools';
|
||||||
import { armor, unarmor } from './encoding/armor';
|
import { armor, unarmor } from './encoding/armor';
|
||||||
import { Argon2OutOfMemoryError } from './type/s2k';
|
import { Argon2OutOfMemoryError } from './type/s2k';
|
||||||
import defaultConfig from './config';
|
import defaultConfig from './config';
|
||||||
import crypto from './crypto';
|
import { generateSessionKey } from './crypto';
|
||||||
import enums from './enums';
|
import enums from './enums';
|
||||||
import util from './util';
|
import util from './util';
|
||||||
import { Signature } from './signature';
|
import { Signature } from './signature';
|
||||||
@ -137,7 +137,7 @@ export class Message {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
// We don't await stream.cancel here because it only returns when the other copy is canceled too.
|
// We don't await stream.cancel here because it only returns when the other copy is canceled too.
|
||||||
stream.cancel(symEncryptedPacket.encrypted); // Don't keep copy of encrypted data in memory.
|
streamCancel(symEncryptedPacket.encrypted); // Don't keep copy of encrypted data in memory.
|
||||||
symEncryptedPacket.encrypted = null;
|
symEncryptedPacket.encrypted = null;
|
||||||
await decryptedPromise;
|
await decryptedPromise;
|
||||||
|
|
||||||
@ -255,7 +255,7 @@ export class Message {
|
|||||||
pkeskPacketCopy.read(serialisedPKESK);
|
pkeskPacketCopy.read(serialisedPKESK);
|
||||||
const randomSessionKey = {
|
const randomSessionKey = {
|
||||||
sessionKeyAlgorithm,
|
sessionKeyAlgorithm,
|
||||||
sessionKey: crypto.generateSessionKey(sessionKeyAlgorithm)
|
sessionKey: generateSessionKey(sessionKeyAlgorithm)
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
await pkeskPacketCopy.decrypt(decryptionKeyPacket, randomSessionKey);
|
await pkeskPacketCopy.decrypt(decryptionKeyPacket, randomSessionKey);
|
||||||
@ -282,7 +282,7 @@ export class Message {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}));
|
}));
|
||||||
stream.cancel(pkeskPacket.encrypted); // Don't keep copy of encrypted data in memory.
|
streamCancel(pkeskPacket.encrypted); // Don't keep copy of encrypted data in memory.
|
||||||
pkeskPacket.encrypted = null;
|
pkeskPacket.encrypted = null;
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
@ -368,7 +368,7 @@ export class Message {
|
|||||||
})
|
})
|
||||||
));
|
));
|
||||||
|
|
||||||
const sessionKeyData = crypto.generateSessionKey(symmetricAlgo);
|
const sessionKeyData = generateSessionKey(symmetricAlgo);
|
||||||
return { data: sessionKeyData, algorithm: symmetricAlgoName, aeadAlgorithm: aeadAlgoName };
|
return { data: sessionKeyData, algorithm: symmetricAlgoName, aeadAlgorithm: aeadAlgoName };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,24 +588,24 @@ export class Message {
|
|||||||
if (literalDataList.length !== 1) {
|
if (literalDataList.length !== 1) {
|
||||||
throw new Error('Can only verify message with one literal data packet.');
|
throw new Error('Can only verify message with one literal data packet.');
|
||||||
}
|
}
|
||||||
if (stream.isArrayStream(msg.packets.stream)) {
|
if (isArrayStream(msg.packets.stream)) {
|
||||||
msg.packets.push(...await stream.readToEnd(msg.packets.stream, _ => _ || []));
|
msg.packets.push(...await streamReadToEnd(msg.packets.stream, _ => _ || []));
|
||||||
}
|
}
|
||||||
const onePassSigList = msg.packets.filterByTag(enums.packet.onePassSignature).reverse();
|
const onePassSigList = msg.packets.filterByTag(enums.packet.onePassSignature).reverse();
|
||||||
const signatureList = msg.packets.filterByTag(enums.packet.signature);
|
const signatureList = msg.packets.filterByTag(enums.packet.signature);
|
||||||
if (onePassSigList.length && !signatureList.length && util.isStream(msg.packets.stream) && !stream.isArrayStream(msg.packets.stream)) {
|
if (onePassSigList.length && !signatureList.length && util.isStream(msg.packets.stream) && !isArrayStream(msg.packets.stream)) {
|
||||||
await Promise.all(onePassSigList.map(async onePassSig => {
|
await Promise.all(onePassSigList.map(async onePassSig => {
|
||||||
onePassSig.correspondingSig = new Promise((resolve, reject) => {
|
onePassSig.correspondingSig = new Promise((resolve, reject) => {
|
||||||
onePassSig.correspondingSigResolve = resolve;
|
onePassSig.correspondingSigResolve = resolve;
|
||||||
onePassSig.correspondingSigReject = reject;
|
onePassSig.correspondingSigReject = reject;
|
||||||
});
|
});
|
||||||
onePassSig.signatureData = stream.fromAsync(async () => (await onePassSig.correspondingSig).signatureData);
|
onePassSig.signatureData = streamFromAsync(async () => (await onePassSig.correspondingSig).signatureData);
|
||||||
onePassSig.hashed = stream.readToEnd(await onePassSig.hash(onePassSig.signatureType, literalDataList[0], undefined, false));
|
onePassSig.hashed = streamReadToEnd(await onePassSig.hash(onePassSig.signatureType, literalDataList[0], undefined, false));
|
||||||
onePassSig.hashed.catch(() => {});
|
onePassSig.hashed.catch(() => {});
|
||||||
}));
|
}));
|
||||||
msg.packets.stream = stream.transformPair(msg.packets.stream, async (readable, writable) => {
|
msg.packets.stream = streamTransformPair(msg.packets.stream, async (readable, writable) => {
|
||||||
const reader = stream.getReader(readable);
|
const reader = streamGetReader(readable);
|
||||||
const writer = stream.getWriter(writable);
|
const writer = streamGetWriter(writable);
|
||||||
try {
|
try {
|
||||||
for (let i = 0; i < onePassSigList.length; i++) {
|
for (let i = 0; i < onePassSigList.length; i++) {
|
||||||
const { value: signature } = await reader.read();
|
const { value: signature } = await reader.read();
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { fromAsync as streamFromAsync, concat as streamConcat, transformPair as streamTransformPair, pipe as streamPipe, readToEnd as streamReadToEnd, getWriter as streamGetWriter } from '@openpgp/web-stream-tools';
|
||||||
import { Message } from './message';
|
import { Message } from './message';
|
||||||
import { CleartextMessage } from './cleartext';
|
import { CleartextMessage } from './cleartext';
|
||||||
import { generate, reformat, getPreferredCompressionAlgo } from './key';
|
import { generate, reformat, getPreferredCompressionAlgo } from './key';
|
||||||
@ -365,9 +365,9 @@ export async function decrypt({ message, decryptionKeys, passwords, sessionKeys,
|
|||||||
if (result.signatures.length === 0) {
|
if (result.signatures.length === 0) {
|
||||||
throw new Error('Message is not signed');
|
throw new Error('Message is not signed');
|
||||||
}
|
}
|
||||||
result.data = stream.concat([
|
result.data = streamConcat([
|
||||||
result.data,
|
result.data,
|
||||||
stream.fromAsync(async () => {
|
streamFromAsync(async () => {
|
||||||
await util.anyPromise(result.signatures.map(sig => sig.verified));
|
await util.anyPromise(result.signatures.map(sig => sig.verified));
|
||||||
return format === 'binary' ? new Uint8Array() : '';
|
return format === 'binary' ? new Uint8Array() : '';
|
||||||
})
|
})
|
||||||
@ -434,10 +434,10 @@ export async function sign({ message, signingKeys, recipientKeys = [], format =
|
|||||||
const armor = format === 'armored';
|
const armor = format === 'armored';
|
||||||
signature = armor ? signature.armor(config) : signature.write();
|
signature = armor ? signature.armor(config) : signature.write();
|
||||||
if (detached) {
|
if (detached) {
|
||||||
signature = stream.transformPair(message.packets.write(), async (readable, writable) => {
|
signature = streamTransformPair(message.packets.write(), async (readable, writable) => {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
stream.pipe(signature, writable),
|
streamPipe(signature, writable),
|
||||||
stream.readToEnd(readable).catch(() => {})
|
streamReadToEnd(readable).catch(() => {})
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -497,9 +497,9 @@ export async function verify({ message, verificationKeys, expectSigned = false,
|
|||||||
if (result.signatures.length === 0) {
|
if (result.signatures.length === 0) {
|
||||||
throw new Error('Message is not signed');
|
throw new Error('Message is not signed');
|
||||||
}
|
}
|
||||||
result.data = stream.concat([
|
result.data = streamConcat([
|
||||||
result.data,
|
result.data,
|
||||||
stream.fromAsync(async () => {
|
streamFromAsync(async () => {
|
||||||
await util.anyPromise(result.signatures.map(sig => sig.verified));
|
await util.anyPromise(result.signatures.map(sig => sig.verified));
|
||||||
return format === 'binary' ? new Uint8Array() : '';
|
return format === 'binary' ? new Uint8Array() : '';
|
||||||
})
|
})
|
||||||
@ -683,7 +683,7 @@ function toArray(param) {
|
|||||||
async function convertStream(data) {
|
async function convertStream(data) {
|
||||||
const streamType = util.isStream(data);
|
const streamType = util.isStream(data);
|
||||||
if (streamType === 'array') {
|
if (streamType === 'array') {
|
||||||
return stream.readToEnd(data);
|
return streamReadToEnd(data);
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@ -697,14 +697,14 @@ async function convertStream(data) {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
function linkStreams(result, message) {
|
function linkStreams(result, message) {
|
||||||
result.data = stream.transformPair(message.packets.stream, async (readable, writable) => {
|
result.data = streamTransformPair(message.packets.stream, async (readable, writable) => {
|
||||||
await stream.pipe(result.data, writable, {
|
await streamPipe(result.data, writable, {
|
||||||
preventClose: true
|
preventClose: true
|
||||||
});
|
});
|
||||||
const writer = stream.getWriter(writable);
|
const writer = streamGetWriter(writable);
|
||||||
try {
|
try {
|
||||||
// Forward errors in the message stream to result.data.
|
// Forward errors in the message stream to result.data.
|
||||||
await stream.readToEnd(readable, _ => _);
|
await streamReadToEnd(readable, _ => _);
|
||||||
await writer.close();
|
await writer.close();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await writer.abort(e);
|
await writer.abort(e);
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { clone as streamClone, parse as streamParse } from '@openpgp/web-stream-tools';
|
||||||
import crypto from '../crypto';
|
import { cipherMode, getRandomBytes } from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
import defaultConfig from '../config';
|
import defaultConfig from '../config';
|
||||||
@ -69,7 +69,7 @@ class AEADEncryptedDataPacket {
|
|||||||
* @throws {Error} on parsing failure
|
* @throws {Error} on parsing failure
|
||||||
*/
|
*/
|
||||||
async read(bytes) {
|
async read(bytes) {
|
||||||
await stream.parse(bytes, async reader => {
|
await streamParse(bytes, async reader => {
|
||||||
const version = await reader.readByte();
|
const version = await reader.readByte();
|
||||||
if (version !== VERSION) { // The only currently defined value is 1.
|
if (version !== VERSION) { // The only currently defined value is 1.
|
||||||
throw new UnsupportedError(`Version ${version} of the AEAD-encrypted data packet is not supported.`);
|
throw new UnsupportedError(`Version ${version} of the AEAD-encrypted data packet is not supported.`);
|
||||||
@ -78,7 +78,7 @@ class AEADEncryptedDataPacket {
|
|||||||
this.aeadAlgorithm = await reader.readByte();
|
this.aeadAlgorithm = await reader.readByte();
|
||||||
this.chunkSizeByte = await reader.readByte();
|
this.chunkSizeByte = await reader.readByte();
|
||||||
|
|
||||||
const mode = crypto.getAEADMode(this.aeadAlgorithm, true);
|
const mode = cipherMode.getAEADMode(this.aeadAlgorithm, true);
|
||||||
this.iv = await reader.readBytes(mode.ivLength);
|
this.iv = await reader.readBytes(mode.ivLength);
|
||||||
this.encrypted = reader.remainder();
|
this.encrypted = reader.remainder();
|
||||||
});
|
});
|
||||||
@ -102,7 +102,7 @@ class AEADEncryptedDataPacket {
|
|||||||
*/
|
*/
|
||||||
async decrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
|
async decrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
|
||||||
this.packets = await PacketList.fromBinary(
|
this.packets = await PacketList.fromBinary(
|
||||||
await runAEAD(this, 'decrypt', key, stream.clone(this.encrypted)),
|
await runAEAD(this, 'decrypt', key, streamClone(this.encrypted)),
|
||||||
allowedPackets,
|
allowedPackets,
|
||||||
config
|
config
|
||||||
);
|
);
|
||||||
@ -119,8 +119,8 @@ class AEADEncryptedDataPacket {
|
|||||||
async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
|
async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
|
||||||
this.cipherAlgorithm = sessionKeyAlgorithm;
|
this.cipherAlgorithm = sessionKeyAlgorithm;
|
||||||
|
|
||||||
const { ivLength } = crypto.getAEADMode(this.aeadAlgorithm, true);
|
const { ivLength } = cipherMode.getAEADMode(this.aeadAlgorithm, true);
|
||||||
this.iv = crypto.random.getRandomBytes(ivLength); // generate new random IV
|
this.iv = getRandomBytes(ivLength); // generate new random IV
|
||||||
this.chunkSizeByte = config.aeadChunkSizeByte;
|
this.chunkSizeByte = config.aeadChunkSizeByte;
|
||||||
const data = this.packets.write();
|
const data = this.packets.write();
|
||||||
this.encrypted = await runAEAD(this, 'encrypt', key, data);
|
this.encrypted = await runAEAD(this, 'encrypt', key, data);
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
import { Inflate, Deflate, Zlib, Unzlib } from 'fflate';
|
import { Inflate, Deflate, Zlib, Unzlib } from 'fflate';
|
||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { isArrayStream, fromAsync as streamFromAsync, parse as streamParse, readToEnd as streamReadToEnd } from '@openpgp/web-stream-tools';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
import defaultConfig from '../config';
|
import defaultConfig from '../config';
|
||||||
@ -74,7 +74,7 @@ class CompressedDataPacket {
|
|||||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||||
*/
|
*/
|
||||||
async read(bytes, config = defaultConfig) {
|
async read(bytes, config = defaultConfig) {
|
||||||
await stream.parse(bytes, async reader => {
|
await streamParse(bytes, async reader => {
|
||||||
|
|
||||||
// One octet that gives the algorithm used to compress the packet.
|
// One octet that gives the algorithm used to compress the packet.
|
||||||
this.algorithm = await reader.readByte();
|
this.algorithm = await reader.readByte();
|
||||||
@ -145,8 +145,8 @@ export default CompressedDataPacket;
|
|||||||
*/
|
*/
|
||||||
function zlib(compressionStreamInstantiator, ZlibStreamedConstructor) {
|
function zlib(compressionStreamInstantiator, ZlibStreamedConstructor) {
|
||||||
return data => {
|
return data => {
|
||||||
if (!util.isStream(data) || stream.isArrayStream(data)) {
|
if (!util.isStream(data) || isArrayStream(data)) {
|
||||||
return stream.fromAsync(() => stream.readToEnd(data).then(inputData => {
|
return streamFromAsync(() => streamReadToEnd(data).then(inputData => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const zlibStream = new ZlibStreamedConstructor();
|
const zlibStream = new ZlibStreamedConstructor();
|
||||||
zlibStream.ondata = processedData => {
|
zlibStream.ondata = processedData => {
|
||||||
@ -204,7 +204,7 @@ function zlib(compressionStreamInstantiator, ZlibStreamedConstructor) {
|
|||||||
function bzip2Decompress() {
|
function bzip2Decompress() {
|
||||||
return async function(data) {
|
return async function(data) {
|
||||||
const { decode: bunzipDecode } = await import('@openpgp/seek-bzip');
|
const { decode: bunzipDecode } = await import('@openpgp/seek-bzip');
|
||||||
return stream.fromAsync(async () => bunzipDecode(await stream.readToEnd(data)));
|
return streamFromAsync(async () => bunzipDecode(await streamReadToEnd(data)));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { isArrayStream, passiveClone as streamPassiveClone, parse as streamParse, readToEnd as streamReadToEnd } from '@openpgp/web-stream-tools';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ class LiteralDataPacket {
|
|||||||
this.data = util.canonicalizeEOL(util.encodeUTF8(this.text));
|
this.data = util.canonicalizeEOL(util.encodeUTF8(this.text));
|
||||||
}
|
}
|
||||||
if (clone) {
|
if (clone) {
|
||||||
return stream.passiveClone(this.data);
|
return streamPassiveClone(this.data);
|
||||||
}
|
}
|
||||||
return this.data;
|
return this.data;
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ class LiteralDataPacket {
|
|||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async read(bytes) {
|
async read(bytes) {
|
||||||
await stream.parse(bytes, async reader => {
|
await streamParse(bytes, async reader => {
|
||||||
// - A one-octet field that describes how the data is formatted.
|
// - A one-octet field that describes how the data is formatted.
|
||||||
const format = await reader.readByte(); // enums.literal
|
const format = await reader.readByte(); // enums.literal
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ class LiteralDataPacket {
|
|||||||
this.date = util.readDate(await reader.readBytes(4));
|
this.date = util.readDate(await reader.readBytes(4));
|
||||||
|
|
||||||
let data = reader.remainder();
|
let data = reader.remainder();
|
||||||
if (stream.isArrayStream(data)) data = await stream.readToEnd(data);
|
if (isArrayStream(data)) data = await streamReadToEnd(data);
|
||||||
this.setBytes(data, format);
|
this.setBytes(data, format);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { fromAsync as streamFromAsync } from '@openpgp/web-stream-tools';
|
||||||
import SignaturePacket from './signature';
|
import SignaturePacket from './signature';
|
||||||
import KeyID from '../type/keyid';
|
import KeyID from '../type/keyid';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
@ -169,7 +169,7 @@ class OnePassSignaturePacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
calculateTrailer(...args) {
|
calculateTrailer(...args) {
|
||||||
return stream.fromAsync(async () => SignaturePacket.prototype.calculateTrailer.apply(await this.correspondingSig, args));
|
return streamFromAsync(async () => SignaturePacket.prototype.calculateTrailer.apply(await this.correspondingSig, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
async verify() {
|
async verify() {
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* @module packet/packet
|
* @module packet/packet
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { ArrayStream, getWriter as streamGetWriter, getReader as streamGetReader } from '@openpgp/web-stream-tools';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ export function supportsStreaming(tag) {
|
|||||||
* @returns {Boolean} Returns false if the stream was empty and parsing is done, and true otherwise.
|
* @returns {Boolean} Returns false if the stream was empty and parsing is done, and true otherwise.
|
||||||
*/
|
*/
|
||||||
export async function readPackets(input, callback) {
|
export async function readPackets(input, callback) {
|
||||||
const reader = stream.getReader(input);
|
const reader = streamGetReader(input);
|
||||||
let writer;
|
let writer;
|
||||||
let callbackReturned;
|
let callbackReturned;
|
||||||
try {
|
try {
|
||||||
@ -148,12 +148,12 @@ export async function readPackets(input, callback) {
|
|||||||
let packet = null;
|
let packet = null;
|
||||||
if (packetSupportsStreaming) {
|
if (packetSupportsStreaming) {
|
||||||
if (util.isStream(input) === 'array') {
|
if (util.isStream(input) === 'array') {
|
||||||
const arrayStream = new stream.ArrayStream();
|
const arrayStream = new ArrayStream();
|
||||||
writer = stream.getWriter(arrayStream);
|
writer = streamGetWriter(arrayStream);
|
||||||
packet = arrayStream;
|
packet = arrayStream;
|
||||||
} else {
|
} else {
|
||||||
const transform = new TransformStream();
|
const transform = new TransformStream();
|
||||||
writer = stream.getWriter(transform.writable);
|
writer = streamGetWriter(transform.writable);
|
||||||
packet = transform.readable;
|
packet = transform.readable;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line callback-return
|
// eslint-disable-next-line callback-return
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { transformPair as streamTransformPair, transform as streamTransform, getWriter as streamGetWriter, getReader as streamGetReader, clone as streamClone } from '@openpgp/web-stream-tools';
|
||||||
import {
|
import {
|
||||||
readPackets, supportsStreaming,
|
readPackets, supportsStreaming,
|
||||||
writeTag, writeHeader,
|
writeTag, writeHeader,
|
||||||
@ -68,8 +68,8 @@ class PacketList extends Array {
|
|||||||
if (config.additionalAllowedPackets.length) {
|
if (config.additionalAllowedPackets.length) {
|
||||||
allowedPackets = { ...allowedPackets, ...util.constructAllowedPackets(config.additionalAllowedPackets) };
|
allowedPackets = { ...allowedPackets, ...util.constructAllowedPackets(config.additionalAllowedPackets) };
|
||||||
}
|
}
|
||||||
this.stream = stream.transformPair(bytes, async (readable, writable) => {
|
this.stream = streamTransformPair(bytes, async (readable, writable) => {
|
||||||
const writer = stream.getWriter(writable);
|
const writer = streamGetWriter(writable);
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
await writer.ready;
|
await writer.ready;
|
||||||
@ -125,7 +125,7 @@ class PacketList extends Array {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Wait until first few packets have been read
|
// Wait until first few packets have been read
|
||||||
const reader = stream.getReader(this.stream);
|
const reader = streamGetReader(this.stream);
|
||||||
while (true) {
|
while (true) {
|
||||||
const { done, value } = await reader.read();
|
const { done, value } = await reader.read();
|
||||||
if (!done) {
|
if (!done) {
|
||||||
@ -156,7 +156,7 @@ class PacketList extends Array {
|
|||||||
let bufferLength = 0;
|
let bufferLength = 0;
|
||||||
const minLength = 512;
|
const minLength = 512;
|
||||||
arr.push(writeTag(tag));
|
arr.push(writeTag(tag));
|
||||||
arr.push(stream.transform(packetbytes, value => {
|
arr.push(streamTransform(packetbytes, value => {
|
||||||
buffer.push(value);
|
buffer.push(value);
|
||||||
bufferLength += value.length;
|
bufferLength += value.length;
|
||||||
if (bufferLength >= minLength) {
|
if (bufferLength >= minLength) {
|
||||||
@ -171,7 +171,7 @@ class PacketList extends Array {
|
|||||||
} else {
|
} else {
|
||||||
if (util.isStream(packetbytes)) {
|
if (util.isStream(packetbytes)) {
|
||||||
let length = 0;
|
let length = 0;
|
||||||
arr.push(stream.transform(stream.clone(packetbytes), value => {
|
arr.push(streamTransform(streamClone(packetbytes), value => {
|
||||||
length += value.length;
|
length += value.length;
|
||||||
}, () => writeHeader(tag, length)));
|
}, () => writeHeader(tag, length)));
|
||||||
} else {
|
} else {
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
import crypto from '../crypto';
|
import { getRandomBytes } from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,7 +56,7 @@ class PaddingPacket {
|
|||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async createPadding(length) {
|
async createPadding(length) {
|
||||||
this.padding = await crypto.random.getRandomBytes(length);
|
this.padding = await getRandomBytes(length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
import KeyID from '../type/keyid';
|
import KeyID from '../type/keyid';
|
||||||
import defaultConfig from '../config';
|
import defaultConfig from '../config';
|
||||||
import crypto from '../crypto';
|
import { computeDigest, parsePublicKeyParams, serializeParams } from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
import { UnsupportedError } from './packet';
|
import { UnsupportedError } from './packet';
|
||||||
@ -126,7 +126,7 @@ class PublicKeyPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - A series of values comprising the key material.
|
// - A series of values comprising the key material.
|
||||||
const { read, publicParams } = crypto.parsePublicKeyParams(this.algorithm, bytes.subarray(pos));
|
const { read, publicParams } = parsePublicKeyParams(this.algorithm, bytes.subarray(pos));
|
||||||
// The deprecated OIDs for Ed25519Legacy and Curve25519Legacy are used in legacy version 4 keys and signatures.
|
// The deprecated OIDs for Ed25519Legacy and Curve25519Legacy are used in legacy version 4 keys and signatures.
|
||||||
// Implementations MUST NOT accept or generate v6 key material using the deprecated OIDs.
|
// Implementations MUST NOT accept or generate v6 key material using the deprecated OIDs.
|
||||||
if (
|
if (
|
||||||
@ -160,7 +160,7 @@ class PublicKeyPacket {
|
|||||||
// A one-octet number denoting the public-key algorithm of this key
|
// A one-octet number denoting the public-key algorithm of this key
|
||||||
arr.push(new Uint8Array([this.algorithm]));
|
arr.push(new Uint8Array([this.algorithm]));
|
||||||
|
|
||||||
const params = crypto.serializeParams(this.algorithm, this.publicParams);
|
const params = serializeParams(this.algorithm, this.publicParams);
|
||||||
if (this.version >= 5) {
|
if (this.version >= 5) {
|
||||||
// A four-octet scalar octet count for the following key material
|
// A four-octet scalar octet count for the following key material
|
||||||
arr.push(util.writeNumber(params.length, 4));
|
arr.push(util.writeNumber(params.length, 4));
|
||||||
@ -230,9 +230,9 @@ class PublicKeyPacket {
|
|||||||
const toHash = this.writeForHash(this.version);
|
const toHash = this.writeForHash(this.version);
|
||||||
|
|
||||||
if (this.version >= 5) {
|
if (this.version >= 5) {
|
||||||
this.fingerprint = await crypto.hash.sha256(toHash);
|
this.fingerprint = await computeDigest(enums.hash.sha256, toHash);
|
||||||
} else if (this.version === 4) {
|
} else if (this.version === 4) {
|
||||||
this.fingerprint = await crypto.hash.sha1(toHash);
|
this.fingerprint = await computeDigest(enums.hash.sha1, toHash);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unsupported key version');
|
throw new Error('Unsupported key version');
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
import KeyID from '../type/keyid';
|
import KeyID from '../type/keyid';
|
||||||
import crypto from '../crypto';
|
import { parseEncSessionKeyParams, publicKeyEncrypt, publicKeyDecrypt, getCipherParams, serializeParams } from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
import { UnsupportedError } from './packet';
|
import { UnsupportedError } from './packet';
|
||||||
@ -127,7 +127,7 @@ class PublicKeyEncryptedSessionKeyPacket {
|
|||||||
offset += this.publicKeyID.read(bytes.subarray(offset, offset + 8));
|
offset += this.publicKeyID.read(bytes.subarray(offset, offset + 8));
|
||||||
}
|
}
|
||||||
this.publicKeyAlgorithm = bytes[offset++];
|
this.publicKeyAlgorithm = bytes[offset++];
|
||||||
this.encrypted = crypto.parseEncSessionKeyParams(this.publicKeyAlgorithm, bytes.subarray(offset));
|
this.encrypted = parseEncSessionKeyParams(this.publicKeyAlgorithm, bytes.subarray(offset));
|
||||||
if (this.publicKeyAlgorithm === enums.publicKey.x25519 || this.publicKeyAlgorithm === enums.publicKey.x448) {
|
if (this.publicKeyAlgorithm === enums.publicKey.x25519 || this.publicKeyAlgorithm === enums.publicKey.x448) {
|
||||||
if (this.version === 3) {
|
if (this.version === 3) {
|
||||||
this.sessionKeyAlgorithm = enums.write(enums.symmetric, this.encrypted.C.algorithm);
|
this.sessionKeyAlgorithm = enums.write(enums.symmetric, this.encrypted.C.algorithm);
|
||||||
@ -163,7 +163,7 @@ class PublicKeyEncryptedSessionKeyPacket {
|
|||||||
|
|
||||||
arr.push(
|
arr.push(
|
||||||
new Uint8Array([this.publicKeyAlgorithm]),
|
new Uint8Array([this.publicKeyAlgorithm]),
|
||||||
crypto.serializeParams(this.publicKeyAlgorithm, this.encrypted)
|
serializeParams(this.publicKeyAlgorithm, this.encrypted)
|
||||||
);
|
);
|
||||||
|
|
||||||
return util.concatUint8Array(arr);
|
return util.concatUint8Array(arr);
|
||||||
@ -182,7 +182,7 @@ class PublicKeyEncryptedSessionKeyPacket {
|
|||||||
const sessionKeyAlgorithm = this.version === 3 ? this.sessionKeyAlgorithm : null;
|
const sessionKeyAlgorithm = this.version === 3 ? this.sessionKeyAlgorithm : null;
|
||||||
const fingerprint = key.version === 5 ? key.getFingerprintBytes().subarray(0, 20) : key.getFingerprintBytes();
|
const fingerprint = key.version === 5 ? key.getFingerprintBytes().subarray(0, 20) : key.getFingerprintBytes();
|
||||||
const encoded = encodeSessionKey(this.version, algo, sessionKeyAlgorithm, this.sessionKey);
|
const encoded = encodeSessionKey(this.version, algo, sessionKeyAlgorithm, this.sessionKey);
|
||||||
this.encrypted = await crypto.publicKeyEncrypt(
|
this.encrypted = await publicKeyEncrypt(
|
||||||
algo, sessionKeyAlgorithm, key.publicParams, encoded, fingerprint);
|
algo, sessionKeyAlgorithm, key.publicParams, encoded, fingerprint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ class PublicKeyEncryptedSessionKeyPacket {
|
|||||||
encodeSessionKey(this.version, this.publicKeyAlgorithm, randomSessionKey.sessionKeyAlgorithm, randomSessionKey.sessionKey) :
|
encodeSessionKey(this.version, this.publicKeyAlgorithm, randomSessionKey.sessionKeyAlgorithm, randomSessionKey.sessionKey) :
|
||||||
null;
|
null;
|
||||||
const fingerprint = key.version === 5 ? key.getFingerprintBytes().subarray(0, 20) : key.getFingerprintBytes();
|
const fingerprint = key.version === 5 ? key.getFingerprintBytes().subarray(0, 20) : key.getFingerprintBytes();
|
||||||
const decryptedData = await crypto.publicKeyDecrypt(this.publicKeyAlgorithm, key.publicParams, key.privateParams, this.encrypted, fingerprint, randomPayload);
|
const decryptedData = await publicKeyDecrypt(this.publicKeyAlgorithm, key.publicParams, key.privateParams, this.encrypted, fingerprint, randomPayload);
|
||||||
|
|
||||||
const { sessionKey, sessionKeyAlgorithm } = decodeSessionKey(this.version, this.publicKeyAlgorithm, decryptedData, randomSessionKey);
|
const { sessionKey, sessionKeyAlgorithm } = decodeSessionKey(this.version, this.publicKeyAlgorithm, decryptedData, randomSessionKey);
|
||||||
|
|
||||||
@ -213,7 +213,7 @@ class PublicKeyEncryptedSessionKeyPacket {
|
|||||||
const hasEncryptedAlgo = this.publicKeyAlgorithm !== enums.publicKey.x25519 && this.publicKeyAlgorithm !== enums.publicKey.x448;
|
const hasEncryptedAlgo = this.publicKeyAlgorithm !== enums.publicKey.x25519 && this.publicKeyAlgorithm !== enums.publicKey.x448;
|
||||||
this.sessionKeyAlgorithm = hasEncryptedAlgo ? sessionKeyAlgorithm : this.sessionKeyAlgorithm;
|
this.sessionKeyAlgorithm = hasEncryptedAlgo ? sessionKeyAlgorithm : this.sessionKeyAlgorithm;
|
||||||
|
|
||||||
if (sessionKey.length !== crypto.getCipherParams(this.sessionKeyAlgorithm).keySize) {
|
if (sessionKey.length !== getCipherParams(this.sessionKeyAlgorithm).keySize) {
|
||||||
throw new Error('Unexpected session key size');
|
throw new Error('Unexpected session key size');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
import PublicKeyPacket from './public_key';
|
import PublicKeyPacket from './public_key';
|
||||||
import { newS2KFromConfig, newS2KFromType } from '../type/s2k';
|
import { newS2KFromConfig, newS2KFromType } from '../type/s2k';
|
||||||
import crypto from '../crypto';
|
import { computeDigest, getCipherParams, parsePrivateKeyParams, serializeParams, generateParams, validateParams, getRandomBytes, cipherMode } from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
import defaultConfig from '../config';
|
import defaultConfig from '../config';
|
||||||
@ -174,7 +174,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
if (this.s2kUsage !== 253 || this.isLegacyAEAD) {
|
if (this.s2kUsage !== 253 || this.isLegacyAEAD) {
|
||||||
this.iv = bytes.subarray(
|
this.iv = bytes.subarray(
|
||||||
i,
|
i,
|
||||||
i + crypto.getCipherParams(this.symmetric).blockSize
|
i + getCipherParams(this.symmetric).blockSize
|
||||||
);
|
);
|
||||||
this.usedModernAEAD = false;
|
this.usedModernAEAD = false;
|
||||||
} else {
|
} else {
|
||||||
@ -183,7 +183,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
// is used as the nonce for the AEAD algorithm.
|
// is used as the nonce for the AEAD algorithm.
|
||||||
this.iv = bytes.subarray(
|
this.iv = bytes.subarray(
|
||||||
i,
|
i,
|
||||||
i + crypto.getAEADMode(this.aead).ivLength
|
i + cipherMode.getAEADMode(this.aead).ivLength
|
||||||
);
|
);
|
||||||
// the non-legacy AEAD encryption mechanism also authenticates public key params; no need for manual validation.
|
// the non-legacy AEAD encryption mechanism also authenticates public key params; no need for manual validation.
|
||||||
this.usedModernAEAD = true;
|
this.usedModernAEAD = true;
|
||||||
@ -221,7 +221,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const { read, privateParams } = crypto.parsePrivateKeyParams(this.algorithm, cleartext, this.publicParams);
|
const { read, privateParams } = parsePrivateKeyParams(this.algorithm, cleartext, this.publicParams);
|
||||||
if (read < cleartext.length) {
|
if (read < cleartext.length) {
|
||||||
throw new Error('Error reading MPIs');
|
throw new Error('Error reading MPIs');
|
||||||
}
|
}
|
||||||
@ -290,7 +290,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
|
|
||||||
if (!this.isDummy()) {
|
if (!this.isDummy()) {
|
||||||
if (!this.s2kUsage) {
|
if (!this.s2kUsage) {
|
||||||
this.keyMaterial = crypto.serializeParams(this.algorithm, this.privateParams);
|
this.keyMaterial = serializeParams(this.algorithm, this.privateParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.version === 5) {
|
if (this.version === 5) {
|
||||||
@ -385,15 +385,15 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
|
|
||||||
this.s2k = newS2KFromConfig(config);
|
this.s2k = newS2KFromConfig(config);
|
||||||
this.s2k.generateSalt();
|
this.s2k.generateSalt();
|
||||||
const cleartext = crypto.serializeParams(this.algorithm, this.privateParams);
|
const cleartext = serializeParams(this.algorithm, this.privateParams);
|
||||||
this.symmetric = enums.symmetric.aes256;
|
this.symmetric = enums.symmetric.aes256;
|
||||||
|
|
||||||
const { blockSize } = crypto.getCipherParams(this.symmetric);
|
const { blockSize } = getCipherParams(this.symmetric);
|
||||||
|
|
||||||
if (config.aeadProtect) {
|
if (config.aeadProtect) {
|
||||||
this.s2kUsage = 253;
|
this.s2kUsage = 253;
|
||||||
this.aead = config.preferredAEADAlgorithm;
|
this.aead = config.preferredAEADAlgorithm;
|
||||||
const mode = crypto.getAEADMode(this.aead);
|
const mode = cipherMode.getAEADMode(this.aead);
|
||||||
this.isLegacyAEAD = this.version === 5; // v4 is always re-encrypted with standard format instead.
|
this.isLegacyAEAD = this.version === 5; // v4 is always re-encrypted with standard format instead.
|
||||||
this.usedModernAEAD = !this.isLegacyAEAD; // legacy AEAD does not guarantee integrity of public key material
|
this.usedModernAEAD = !this.isLegacyAEAD; // legacy AEAD does not guarantee integrity of public key material
|
||||||
|
|
||||||
@ -401,7 +401,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
const key = await produceEncryptionKey(this.version, this.s2k, passphrase, this.symmetric, this.aead, serializedPacketTag, this.isLegacyAEAD);
|
const key = await produceEncryptionKey(this.version, this.s2k, passphrase, this.symmetric, this.aead, serializedPacketTag, this.isLegacyAEAD);
|
||||||
|
|
||||||
const modeInstance = await mode(this.symmetric, key);
|
const modeInstance = await mode(this.symmetric, key);
|
||||||
this.iv = this.isLegacyAEAD ? crypto.random.getRandomBytes(blockSize) : crypto.random.getRandomBytes(mode.ivLength);
|
this.iv = this.isLegacyAEAD ? getRandomBytes(blockSize) : getRandomBytes(mode.ivLength);
|
||||||
const associateData = this.isLegacyAEAD ?
|
const associateData = this.isLegacyAEAD ?
|
||||||
new Uint8Array() :
|
new Uint8Array() :
|
||||||
util.concatUint8Array([serializedPacketTag, this.writePublicKey()]);
|
util.concatUint8Array([serializedPacketTag, this.writePublicKey()]);
|
||||||
@ -411,10 +411,10 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
this.s2kUsage = 254;
|
this.s2kUsage = 254;
|
||||||
this.usedModernAEAD = false;
|
this.usedModernAEAD = false;
|
||||||
const key = await produceEncryptionKey(this.version, this.s2k, passphrase, this.symmetric);
|
const key = await produceEncryptionKey(this.version, this.s2k, passphrase, this.symmetric);
|
||||||
this.iv = crypto.random.getRandomBytes(blockSize);
|
this.iv = getRandomBytes(blockSize);
|
||||||
this.keyMaterial = await crypto.mode.cfb.encrypt(this.symmetric, key, util.concatUint8Array([
|
this.keyMaterial = await cipherMode.cfb.encrypt(this.symmetric, key, util.concatUint8Array([
|
||||||
cleartext,
|
cleartext,
|
||||||
await crypto.hash.sha1(cleartext, config)
|
await computeDigest(enums.hash.sha1, cleartext, config)
|
||||||
]), this.iv, config);
|
]), this.iv, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -454,7 +454,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
|
|
||||||
let cleartext;
|
let cleartext;
|
||||||
if (this.s2kUsage === 253) {
|
if (this.s2kUsage === 253) {
|
||||||
const mode = crypto.getAEADMode(this.aead, true);
|
const mode = cipherMode.getAEADMode(this.aead, true);
|
||||||
const modeInstance = await mode(this.symmetric, key);
|
const modeInstance = await mode(this.symmetric, key);
|
||||||
try {
|
try {
|
||||||
const associateData = this.isLegacyAEAD ?
|
const associateData = this.isLegacyAEAD ?
|
||||||
@ -468,10 +468,10 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const cleartextWithHash = await crypto.mode.cfb.decrypt(this.symmetric, key, this.keyMaterial, this.iv);
|
const cleartextWithHash = await cipherMode.cfb.decrypt(this.symmetric, key, this.keyMaterial, this.iv);
|
||||||
|
|
||||||
cleartext = cleartextWithHash.subarray(0, -20);
|
cleartext = cleartextWithHash.subarray(0, -20);
|
||||||
const hash = await crypto.hash.sha1(cleartext);
|
const hash = await computeDigest(enums.hash.sha1, cleartext);
|
||||||
|
|
||||||
if (!util.equalsUint8Array(hash, cleartextWithHash.subarray(-20))) {
|
if (!util.equalsUint8Array(hash, cleartextWithHash.subarray(-20))) {
|
||||||
throw new Error('Incorrect key passphrase');
|
throw new Error('Incorrect key passphrase');
|
||||||
@ -479,7 +479,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { privateParams } = crypto.parsePrivateKeyParams(this.algorithm, cleartext, this.publicParams);
|
const { privateParams } = parsePrivateKeyParams(this.algorithm, cleartext, this.publicParams);
|
||||||
this.privateParams = privateParams;
|
this.privateParams = privateParams;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new Error('Error reading MPIs');
|
throw new Error('Error reading MPIs');
|
||||||
@ -514,7 +514,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
let validParams;
|
let validParams;
|
||||||
try {
|
try {
|
||||||
// this can throw if some parameters are undefined
|
// this can throw if some parameters are undefined
|
||||||
validParams = await crypto.validateParams(this.algorithm, this.publicParams, this.privateParams);
|
validParams = await validateParams(this.algorithm, this.publicParams, this.privateParams);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
validParams = false;
|
validParams = false;
|
||||||
}
|
}
|
||||||
@ -532,7 +532,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
)) {
|
)) {
|
||||||
throw new Error(`Cannot generate v6 keys of type 'ecc' with curve ${curve}. Generate a key of type 'curve25519' instead`);
|
throw new Error(`Cannot generate v6 keys of type 'ecc' with curve ${curve}. Generate a key of type 'curve25519' instead`);
|
||||||
}
|
}
|
||||||
const { privateParams, publicParams } = await crypto.generateParams(this.algorithm, bits, curve);
|
const { privateParams, publicParams } = await generateParams(this.algorithm, bits, curve);
|
||||||
this.privateParams = privateParams;
|
this.privateParams = privateParams;
|
||||||
this.publicParams = publicParams;
|
this.publicParams = publicParams;
|
||||||
this.isEncrypted = false;
|
this.isEncrypted = false;
|
||||||
@ -574,7 +574,7 @@ async function produceEncryptionKey(keyVersion, s2k, passphrase, cipherAlgo, aea
|
|||||||
if (s2k.type === 'simple' && keyVersion === 6) {
|
if (s2k.type === 'simple' && keyVersion === 6) {
|
||||||
throw new Error('Using Simple S2K with version 6 keys is not allowed');
|
throw new Error('Using Simple S2K with version 6 keys is not allowed');
|
||||||
}
|
}
|
||||||
const { keySize } = crypto.getCipherParams(cipherAlgo);
|
const { keySize } = getCipherParams(cipherAlgo);
|
||||||
const derivedKey = await s2k.produceKey(passphrase, keySize);
|
const derivedKey = await s2k.produceKey(passphrase, keySize);
|
||||||
if (!aeadMode || keyVersion === 5 || isLegacyAEAD) {
|
if (!aeadMode || keyVersion === 5 || isLegacyAEAD) {
|
||||||
return derivedKey;
|
return derivedKey;
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { fromAsync as streamFromAsync, slice as streamSlice, readToEnd as streamReadToEnd, clone as streamClone, transform as streamTransform } from '@openpgp/web-stream-tools';
|
||||||
import { readSimpleLength, UnsupportedError, writeSimpleLength } from './packet';
|
import { readSimpleLength, UnsupportedError, writeSimpleLength } from './packet';
|
||||||
import KeyID from '../type/keyid';
|
import KeyID from '../type/keyid';
|
||||||
import crypto from '../crypto';
|
import { signature, serializeParams, getRandomBytes, getHashByteLength, computeDigest } from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
import defaultConfig from '../config';
|
import defaultConfig from '../config';
|
||||||
@ -166,7 +166,7 @@ class SignaturePacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const signatureMaterial = bytes.subarray(i, bytes.length);
|
const signatureMaterial = bytes.subarray(i, bytes.length);
|
||||||
const { read, signatureParams } = crypto.signature.parseSignatureParams(this.publicKeyAlgorithm, signatureMaterial);
|
const { read, signatureParams } = signature.parseSignatureParams(this.publicKeyAlgorithm, signatureMaterial);
|
||||||
if (read < signatureMaterial.length) {
|
if (read < signatureMaterial.length) {
|
||||||
throw new Error('Error reading MPIs');
|
throw new Error('Error reading MPIs');
|
||||||
}
|
}
|
||||||
@ -178,11 +178,11 @@ class SignaturePacket {
|
|||||||
*/
|
*/
|
||||||
writeParams() {
|
writeParams() {
|
||||||
if (this.params instanceof Promise) {
|
if (this.params instanceof Promise) {
|
||||||
return stream.fromAsync(
|
return streamFromAsync(
|
||||||
async () => crypto.serializeParams(this.publicKeyAlgorithm, await this.params)
|
async () => serializeParams(this.publicKeyAlgorithm, await this.params)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return crypto.serializeParams(this.publicKeyAlgorithm, this.params);
|
return serializeParams(this.publicKeyAlgorithm, this.params);
|
||||||
}
|
}
|
||||||
|
|
||||||
write() {
|
write() {
|
||||||
@ -221,7 +221,7 @@ class SignaturePacket {
|
|||||||
if (this.version === 6) {
|
if (this.version === 6) {
|
||||||
const saltLength = saltLengthForHash(this.hashAlgorithm);
|
const saltLength = saltLengthForHash(this.hashAlgorithm);
|
||||||
if (this.salt === null) {
|
if (this.salt === null) {
|
||||||
this.salt = crypto.random.getRandomBytes(saltLength);
|
this.salt = getRandomBytes(saltLength);
|
||||||
} else if (saltLength !== this.salt.length) {
|
} else if (saltLength !== this.salt.length) {
|
||||||
throw new Error('Provided salt does not have the required length');
|
throw new Error('Provided salt does not have the required length');
|
||||||
}
|
}
|
||||||
@ -230,7 +230,7 @@ class SignaturePacket {
|
|||||||
// since re-signing the same object is not supported, it's not expected to have multiple salt notations,
|
// since re-signing the same object is not supported, it's not expected to have multiple salt notations,
|
||||||
// but we guard against it as a sanity check
|
// but we guard against it as a sanity check
|
||||||
if (saltNotations.length === 0) {
|
if (saltNotations.length === 0) {
|
||||||
const saltValue = crypto.random.getRandomBytes(saltLengthForHash(this.hashAlgorithm));
|
const saltValue = getRandomBytes(saltLengthForHash(this.hashAlgorithm));
|
||||||
this.rawNotations.push({
|
this.rawNotations.push({
|
||||||
name: SALT_NOTATION_NAME,
|
name: SALT_NOTATION_NAME,
|
||||||
value: saltValue,
|
value: saltValue,
|
||||||
@ -255,9 +255,9 @@ class SignaturePacket {
|
|||||||
const toHash = this.toHash(this.signatureType, data, detached);
|
const toHash = this.toHash(this.signatureType, data, detached);
|
||||||
const hash = await this.hash(this.signatureType, data, toHash, detached);
|
const hash = await this.hash(this.signatureType, data, toHash, detached);
|
||||||
|
|
||||||
this.signedHashValue = stream.slice(stream.clone(hash), 0, 2);
|
this.signedHashValue = streamSlice(streamClone(hash), 0, 2);
|
||||||
const signed = async () => crypto.signature.sign(
|
const signed = async () => signature.sign(
|
||||||
this.publicKeyAlgorithm, this.hashAlgorithm, key.publicParams, key.privateParams, toHash, await stream.readToEnd(hash)
|
this.publicKeyAlgorithm, this.hashAlgorithm, key.publicParams, key.privateParams, toHash, await streamReadToEnd(hash)
|
||||||
);
|
);
|
||||||
if (util.isStream(hash)) {
|
if (util.isStream(hash)) {
|
||||||
this.params = signed();
|
this.params = signed();
|
||||||
@ -570,7 +570,7 @@ class SignaturePacket {
|
|||||||
this.signatureTargetPublicKeyAlgorithm = bytes[mypos++];
|
this.signatureTargetPublicKeyAlgorithm = bytes[mypos++];
|
||||||
this.signatureTargetHashAlgorithm = bytes[mypos++];
|
this.signatureTargetHashAlgorithm = bytes[mypos++];
|
||||||
|
|
||||||
const len = crypto.getHashByteLength(this.signatureTargetHashAlgorithm);
|
const len = getHashByteLength(this.signatureTargetHashAlgorithm);
|
||||||
|
|
||||||
this.signatureTargetHash = util.uint8ArrayToString(bytes.subarray(mypos, mypos + len));
|
this.signatureTargetHash = util.uint8ArrayToString(bytes.subarray(mypos, mypos + len));
|
||||||
break;
|
break;
|
||||||
@ -703,7 +703,7 @@ class SignaturePacket {
|
|||||||
|
|
||||||
calculateTrailer(data, detached) {
|
calculateTrailer(data, detached) {
|
||||||
let length = 0;
|
let length = 0;
|
||||||
return stream.transform(stream.clone(this.signatureData), value => {
|
return streamTransform(streamClone(this.signatureData), value => {
|
||||||
length += value.length;
|
length += value.length;
|
||||||
}, () => {
|
}, () => {
|
||||||
const arr = [];
|
const arr = [];
|
||||||
@ -738,7 +738,7 @@ class SignaturePacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!toHash) toHash = this.toHash(signatureType, data, detached);
|
if (!toHash) toHash = this.toHash(signatureType, data, detached);
|
||||||
return crypto.hash.digest(this.hashAlgorithm, toHash);
|
return computeDigest(this.hashAlgorithm, toHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -774,7 +774,7 @@ class SignaturePacket {
|
|||||||
toHash = this.toHash(signatureType, data, detached);
|
toHash = this.toHash(signatureType, data, detached);
|
||||||
hash = await this.hash(signatureType, data, toHash);
|
hash = await this.hash(signatureType, data, toHash);
|
||||||
}
|
}
|
||||||
hash = await stream.readToEnd(hash);
|
hash = await streamReadToEnd(hash);
|
||||||
if (this.signedHashValue[0] !== hash[0] ||
|
if (this.signedHashValue[0] !== hash[0] ||
|
||||||
this.signedHashValue[1] !== hash[1]) {
|
this.signedHashValue[1] !== hash[1]) {
|
||||||
throw new Error('Signed digest did not match');
|
throw new Error('Signed digest did not match');
|
||||||
@ -782,7 +782,7 @@ class SignaturePacket {
|
|||||||
|
|
||||||
this.params = await this.params;
|
this.params = await this.params;
|
||||||
|
|
||||||
this[verified] = await crypto.signature.verify(
|
this[verified] = await signature.verify(
|
||||||
this.publicKeyAlgorithm, this.hashAlgorithm, this.params, key.publicParams,
|
this.publicKeyAlgorithm, this.hashAlgorithm, this.params, key.publicParams,
|
||||||
toHash, hash
|
toHash, hash
|
||||||
);
|
);
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { slice as streamSlice, passiveClone as streamPassiveClone, readToEnd as streamReadToEnd, concat as streamConcat, fromAsync as streamFromAsync, getReader as streamGetReader, getWriter as streamGetWriter, clone as streamClone, pipe as streamPipe, transformPair as streamTransformPair, isArrayStream, parse as streamParse } from '@openpgp/web-stream-tools';
|
||||||
import crypto from '../crypto';
|
import { cipherMode, getRandomBytes, getCipherParams, computeDigest } from '../crypto';
|
||||||
import computeHKDF from '../crypto/hkdf';
|
import computeHKDF from '../crypto/hkdf';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
@ -82,7 +82,7 @@ class SymEncryptedIntegrityProtectedDataPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async read(bytes) {
|
async read(bytes) {
|
||||||
await stream.parse(bytes, async reader => {
|
await streamParse(bytes, async reader => {
|
||||||
this.version = await reader.readByte();
|
this.version = await reader.readByte();
|
||||||
// - A one-octet version number with value 1 or 2.
|
// - A one-octet version number with value 1 or 2.
|
||||||
if (this.version !== 1 && this.version !== 2) {
|
if (this.version !== 1 && this.version !== 2) {
|
||||||
@ -133,29 +133,29 @@ class SymEncryptedIntegrityProtectedDataPacket {
|
|||||||
// but we want to ensure that the input key isn't e.g. too short.
|
// but we want to ensure that the input key isn't e.g. too short.
|
||||||
// The check is done here, instead of on encrypted session key (ESK) encryption, because v6 ESK packets do not store the session key algorithm,
|
// The check is done here, instead of on encrypted session key (ESK) encryption, because v6 ESK packets do not store the session key algorithm,
|
||||||
// which is instead included in the SEIPDv2 data.
|
// which is instead included in the SEIPDv2 data.
|
||||||
const { blockSize, keySize } = crypto.getCipherParams(sessionKeyAlgorithm);
|
const { blockSize, keySize } = getCipherParams(sessionKeyAlgorithm);
|
||||||
if (key.length !== keySize) {
|
if (key.length !== keySize) {
|
||||||
throw new Error('Unexpected session key size');
|
throw new Error('Unexpected session key size');
|
||||||
}
|
}
|
||||||
|
|
||||||
let bytes = this.packets.write();
|
let bytes = this.packets.write();
|
||||||
if (stream.isArrayStream(bytes)) bytes = await stream.readToEnd(bytes);
|
if (isArrayStream(bytes)) bytes = await streamReadToEnd(bytes);
|
||||||
|
|
||||||
if (this.version === 2) {
|
if (this.version === 2) {
|
||||||
this.cipherAlgorithm = sessionKeyAlgorithm;
|
this.cipherAlgorithm = sessionKeyAlgorithm;
|
||||||
|
|
||||||
this.salt = crypto.random.getRandomBytes(32);
|
this.salt = getRandomBytes(32);
|
||||||
this.chunkSizeByte = config.aeadChunkSizeByte;
|
this.chunkSizeByte = config.aeadChunkSizeByte;
|
||||||
this.encrypted = await runAEAD(this, 'encrypt', key, bytes);
|
this.encrypted = await runAEAD(this, 'encrypt', key, bytes);
|
||||||
} else {
|
} else {
|
||||||
const prefix = await crypto.getPrefixRandom(sessionKeyAlgorithm);
|
const prefix = await cipherMode.cfb.getPrefixRandom(sessionKeyAlgorithm);
|
||||||
const mdc = new Uint8Array([0xD3, 0x14]); // modification detection code packet
|
const mdc = new Uint8Array([0xD3, 0x14]); // modification detection code packet
|
||||||
|
|
||||||
const tohash = util.concat([prefix, bytes, mdc]);
|
const tohash = util.concat([prefix, bytes, mdc]);
|
||||||
const hash = await crypto.hash.sha1(stream.passiveClone(tohash));
|
const hash = await computeDigest(enums.hash.sha1, streamPassiveClone(tohash));
|
||||||
const plaintext = util.concat([tohash, hash]);
|
const plaintext = util.concat([tohash, hash]);
|
||||||
|
|
||||||
this.encrypted = await crypto.mode.cfb.encrypt(sessionKeyAlgorithm, key, plaintext, new Uint8Array(blockSize), config);
|
this.encrypted = await cipherMode.cfb.encrypt(sessionKeyAlgorithm, key, plaintext, new Uint8Array(blockSize), config);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -175,12 +175,12 @@ class SymEncryptedIntegrityProtectedDataPacket {
|
|||||||
// but we want to ensure that the input key isn't e.g. too short.
|
// but we want to ensure that the input key isn't e.g. too short.
|
||||||
// The check is done here, instead of on encrypted session key (ESK) decryption, because v6 ESK packets do not store the session key algorithm,
|
// The check is done here, instead of on encrypted session key (ESK) decryption, because v6 ESK packets do not store the session key algorithm,
|
||||||
// which is instead included in the SEIPDv2 data.
|
// which is instead included in the SEIPDv2 data.
|
||||||
if (key.length !== crypto.getCipherParams(sessionKeyAlgorithm).keySize) {
|
if (key.length !== getCipherParams(sessionKeyAlgorithm).keySize) {
|
||||||
throw new Error('Unexpected session key size');
|
throw new Error('Unexpected session key size');
|
||||||
}
|
}
|
||||||
|
|
||||||
let encrypted = stream.clone(this.encrypted);
|
let encrypted = streamClone(this.encrypted);
|
||||||
if (stream.isArrayStream(encrypted)) encrypted = await stream.readToEnd(encrypted);
|
if (isArrayStream(encrypted)) encrypted = await streamReadToEnd(encrypted);
|
||||||
|
|
||||||
let packetbytes;
|
let packetbytes;
|
||||||
if (this.version === 2) {
|
if (this.version === 2) {
|
||||||
@ -190,27 +190,27 @@ class SymEncryptedIntegrityProtectedDataPacket {
|
|||||||
}
|
}
|
||||||
packetbytes = await runAEAD(this, 'decrypt', key, encrypted);
|
packetbytes = await runAEAD(this, 'decrypt', key, encrypted);
|
||||||
} else {
|
} else {
|
||||||
const { blockSize } = crypto.getCipherParams(sessionKeyAlgorithm);
|
const { blockSize } = getCipherParams(sessionKeyAlgorithm);
|
||||||
const decrypted = await crypto.mode.cfb.decrypt(sessionKeyAlgorithm, key, encrypted, new Uint8Array(blockSize));
|
const decrypted = await cipherMode.cfb.decrypt(sessionKeyAlgorithm, key, encrypted, new Uint8Array(blockSize));
|
||||||
|
|
||||||
// there must be a modification detection code packet as the
|
// there must be a modification detection code packet as the
|
||||||
// last packet and everything gets hashed except the hash itself
|
// last packet and everything gets hashed except the hash itself
|
||||||
const realHash = stream.slice(stream.passiveClone(decrypted), -20);
|
const realHash = streamSlice(streamPassiveClone(decrypted), -20);
|
||||||
const tohash = stream.slice(decrypted, 0, -20);
|
const tohash = streamSlice(decrypted, 0, -20);
|
||||||
const verifyHash = Promise.all([
|
const verifyHash = Promise.all([
|
||||||
stream.readToEnd(await crypto.hash.sha1(stream.passiveClone(tohash))),
|
streamReadToEnd(await computeDigest(enums.hash.sha1, streamPassiveClone(tohash))),
|
||||||
stream.readToEnd(realHash)
|
streamReadToEnd(realHash)
|
||||||
]).then(([hash, mdc]) => {
|
]).then(([hash, mdc]) => {
|
||||||
if (!util.equalsUint8Array(hash, mdc)) {
|
if (!util.equalsUint8Array(hash, mdc)) {
|
||||||
throw new Error('Modification detected.');
|
throw new Error('Modification detected.');
|
||||||
}
|
}
|
||||||
return new Uint8Array();
|
return new Uint8Array();
|
||||||
});
|
});
|
||||||
const bytes = stream.slice(tohash, blockSize + 2); // Remove random prefix
|
const bytes = streamSlice(tohash, blockSize + 2); // Remove random prefix
|
||||||
packetbytes = stream.slice(bytes, 0, -2); // Remove MDC packet
|
packetbytes = streamSlice(bytes, 0, -2); // Remove MDC packet
|
||||||
packetbytes = stream.concat([packetbytes, stream.fromAsync(() => verifyHash)]);
|
packetbytes = streamConcat([packetbytes, streamFromAsync(() => verifyHash)]);
|
||||||
if (!util.isStream(encrypted) || !config.allowUnauthenticatedStream) {
|
if (!util.isStream(encrypted) || !config.allowUnauthenticatedStream) {
|
||||||
packetbytes = await stream.readToEnd(packetbytes);
|
packetbytes = await streamReadToEnd(packetbytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +237,7 @@ export async function runAEAD(packet, fn, key, data) {
|
|||||||
// we allow `experimentalGCM` for AEADP for backwards compatibility, since v5 keys from OpenPGP.js v5 might be declaring
|
// we allow `experimentalGCM` for AEADP for backwards compatibility, since v5 keys from OpenPGP.js v5 might be declaring
|
||||||
// that preference, as the `gcm` ID had not been standardized at the time.
|
// that preference, as the `gcm` ID had not been standardized at the time.
|
||||||
// NB: AEADP are never automatically generate as part of message encryption by OpenPGP.js, the packet must be manually created.
|
// NB: AEADP are never automatically generate as part of message encryption by OpenPGP.js, the packet must be manually created.
|
||||||
const mode = crypto.getAEADMode(packet.aeadAlgorithm, isAEADP);
|
const mode = cipherMode.getAEADMode(packet.aeadAlgorithm, isAEADP);
|
||||||
const tagLengthIfDecrypting = fn === 'decrypt' ? mode.tagLength : 0;
|
const tagLengthIfDecrypting = fn === 'decrypt' ? mode.tagLength : 0;
|
||||||
const tagLengthIfEncrypting = fn === 'encrypt' ? mode.tagLength : 0;
|
const tagLengthIfEncrypting = fn === 'encrypt' ? mode.tagLength : 0;
|
||||||
const chunkSize = 2 ** (packet.chunkSizeByte + 6) + tagLengthIfDecrypting; // ((uint64_t)1 << (c + 6))
|
const chunkSize = 2 ** (packet.chunkSizeByte + 6) + tagLengthIfDecrypting; // ((uint64_t)1 << (c + 6))
|
||||||
@ -255,7 +255,7 @@ export async function runAEAD(packet, fn, key, data) {
|
|||||||
let iv;
|
let iv;
|
||||||
let ivView;
|
let ivView;
|
||||||
if (isSEIPDv2) {
|
if (isSEIPDv2) {
|
||||||
const { keySize } = crypto.getCipherParams(packet.cipherAlgorithm);
|
const { keySize } = getCipherParams(packet.cipherAlgorithm);
|
||||||
const { ivLength } = mode;
|
const { ivLength } = mode;
|
||||||
const info = new Uint8Array(adataBuffer, 0, 5);
|
const info = new Uint8Array(adataBuffer, 0, 5);
|
||||||
const derived = await computeHKDF(enums.hash.sha256, key, packet.salt, info, keySize + ivLength);
|
const derived = await computeHKDF(enums.hash.sha256, key, packet.salt, info, keySize + ivLength);
|
||||||
@ -268,17 +268,17 @@ export async function runAEAD(packet, fn, key, data) {
|
|||||||
// ivView is unused in this case
|
// ivView is unused in this case
|
||||||
}
|
}
|
||||||
const modeInstance = await mode(packet.cipherAlgorithm, key);
|
const modeInstance = await mode(packet.cipherAlgorithm, key);
|
||||||
return stream.transformPair(data, async (readable, writable) => {
|
return streamTransformPair(data, async (readable, writable) => {
|
||||||
if (util.isStream(readable) !== 'array') {
|
if (util.isStream(readable) !== 'array') {
|
||||||
const buffer = new TransformStream({}, {
|
const buffer = new TransformStream({}, {
|
||||||
highWaterMark: util.getHardwareConcurrency() * 2 ** (packet.chunkSizeByte + 6),
|
highWaterMark: util.getHardwareConcurrency() * 2 ** (packet.chunkSizeByte + 6),
|
||||||
size: array => array.length
|
size: array => array.length
|
||||||
});
|
});
|
||||||
stream.pipe(buffer.readable, writable);
|
streamPipe(buffer.readable, writable);
|
||||||
writable = buffer.writable;
|
writable = buffer.writable;
|
||||||
}
|
}
|
||||||
const reader = stream.getReader(readable);
|
const reader = streamGetReader(readable);
|
||||||
const writer = stream.getWriter(writable);
|
const writer = streamGetWriter(writable);
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
let chunk = await reader.readBytes(chunkSize + tagLengthIfDecrypting) || new Uint8Array();
|
let chunk = await reader.readBytes(chunkSize + tagLengthIfDecrypting) || new Uint8Array();
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
import { newS2KFromConfig, newS2KFromType } from '../type/s2k';
|
import { newS2KFromConfig, newS2KFromType } from '../type/s2k';
|
||||||
import defaultConfig from '../config';
|
import defaultConfig from '../config';
|
||||||
import crypto from '../crypto';
|
import { cipherMode, generateSessionKey, getCipherParams, getRandomBytes } from '../crypto';
|
||||||
import computeHKDF from '../crypto/hkdf';
|
import computeHKDF from '../crypto/hkdf';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
@ -105,7 +105,7 @@ class SymEncryptedSessionKeyPacket {
|
|||||||
offset += this.s2k.read(bytes.subarray(offset, bytes.length));
|
offset += this.s2k.read(bytes.subarray(offset, bytes.length));
|
||||||
|
|
||||||
if (this.version >= 5) {
|
if (this.version >= 5) {
|
||||||
const mode = crypto.getAEADMode(this.aeadAlgorithm, true);
|
const mode = cipherMode.getAEADMode(this.aeadAlgorithm, true);
|
||||||
|
|
||||||
// A starting initialization vector of size specified by the AEAD
|
// A starting initialization vector of size specified by the AEAD
|
||||||
// algorithm.
|
// algorithm.
|
||||||
@ -163,21 +163,21 @@ class SymEncryptedSessionKeyPacket {
|
|||||||
this.sessionKeyEncryptionAlgorithm :
|
this.sessionKeyEncryptionAlgorithm :
|
||||||
this.sessionKeyAlgorithm;
|
this.sessionKeyAlgorithm;
|
||||||
|
|
||||||
const { blockSize, keySize } = crypto.getCipherParams(algo);
|
const { blockSize, keySize } = getCipherParams(algo);
|
||||||
const key = await this.s2k.produceKey(passphrase, keySize);
|
const key = await this.s2k.produceKey(passphrase, keySize);
|
||||||
|
|
||||||
if (this.version >= 5) {
|
if (this.version >= 5) {
|
||||||
const mode = crypto.getAEADMode(this.aeadAlgorithm, true);
|
const mode = cipherMode.getAEADMode(this.aeadAlgorithm, true);
|
||||||
const adata = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, this.sessionKeyEncryptionAlgorithm, this.aeadAlgorithm]);
|
const adata = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, this.sessionKeyEncryptionAlgorithm, this.aeadAlgorithm]);
|
||||||
const encryptionKey = this.version === 6 ? await computeHKDF(enums.hash.sha256, key, new Uint8Array(), adata, keySize) : key;
|
const encryptionKey = this.version === 6 ? await computeHKDF(enums.hash.sha256, key, new Uint8Array(), adata, keySize) : key;
|
||||||
const modeInstance = await mode(algo, encryptionKey);
|
const modeInstance = await mode(algo, encryptionKey);
|
||||||
this.sessionKey = await modeInstance.decrypt(this.encrypted, this.iv, adata);
|
this.sessionKey = await modeInstance.decrypt(this.encrypted, this.iv, adata);
|
||||||
} else if (this.encrypted !== null) {
|
} else if (this.encrypted !== null) {
|
||||||
const decrypted = await crypto.mode.cfb.decrypt(algo, key, this.encrypted, new Uint8Array(blockSize));
|
const decrypted = await cipherMode.cfb.decrypt(algo, key, this.encrypted, new Uint8Array(blockSize));
|
||||||
|
|
||||||
this.sessionKeyAlgorithm = enums.write(enums.symmetric, decrypted[0]);
|
this.sessionKeyAlgorithm = enums.write(enums.symmetric, decrypted[0]);
|
||||||
this.sessionKey = decrypted.subarray(1, decrypted.length);
|
this.sessionKey = decrypted.subarray(1, decrypted.length);
|
||||||
if (this.sessionKey.length !== crypto.getCipherParams(this.sessionKeyAlgorithm).keySize) {
|
if (this.sessionKey.length !== getCipherParams(this.sessionKeyAlgorithm).keySize) {
|
||||||
throw new Error('Unexpected session key size');
|
throw new Error('Unexpected session key size');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -203,16 +203,16 @@ class SymEncryptedSessionKeyPacket {
|
|||||||
this.s2k = newS2KFromConfig(config);
|
this.s2k = newS2KFromConfig(config);
|
||||||
this.s2k.generateSalt();
|
this.s2k.generateSalt();
|
||||||
|
|
||||||
const { blockSize, keySize } = crypto.getCipherParams(algo);
|
const { blockSize, keySize } = getCipherParams(algo);
|
||||||
const key = await this.s2k.produceKey(passphrase, keySize);
|
const key = await this.s2k.produceKey(passphrase, keySize);
|
||||||
|
|
||||||
if (this.sessionKey === null) {
|
if (this.sessionKey === null) {
|
||||||
this.sessionKey = crypto.generateSessionKey(this.sessionKeyAlgorithm);
|
this.sessionKey = generateSessionKey(this.sessionKeyAlgorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.version >= 5) {
|
if (this.version >= 5) {
|
||||||
const mode = crypto.getAEADMode(this.aeadAlgorithm);
|
const mode = cipherMode.getAEADMode(this.aeadAlgorithm);
|
||||||
this.iv = crypto.random.getRandomBytes(mode.ivLength); // generate new random IV
|
this.iv = getRandomBytes(mode.ivLength); // generate new random IV
|
||||||
const adata = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, this.sessionKeyEncryptionAlgorithm, this.aeadAlgorithm]);
|
const adata = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, this.sessionKeyEncryptionAlgorithm, this.aeadAlgorithm]);
|
||||||
const encryptionKey = this.version === 6 ? await computeHKDF(enums.hash.sha256, key, new Uint8Array(), adata, keySize) : key;
|
const encryptionKey = this.version === 6 ? await computeHKDF(enums.hash.sha256, key, new Uint8Array(), adata, keySize) : key;
|
||||||
const modeInstance = await mode(algo, encryptionKey);
|
const modeInstance = await mode(algo, encryptionKey);
|
||||||
@ -222,7 +222,7 @@ class SymEncryptedSessionKeyPacket {
|
|||||||
new Uint8Array([this.sessionKeyAlgorithm]),
|
new Uint8Array([this.sessionKeyAlgorithm]),
|
||||||
this.sessionKey
|
this.sessionKey
|
||||||
]);
|
]);
|
||||||
this.encrypted = await crypto.mode.cfb.encrypt(algo, key, toEncrypt, new Uint8Array(blockSize), config);
|
this.encrypted = await cipherMode.cfb.encrypt(algo, key, toEncrypt, new Uint8Array(blockSize), config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { readToEnd as streamReadToEnd, clone as streamClone } from '@openpgp/web-stream-tools';
|
||||||
import crypto from '../crypto';
|
import { cipherMode, getCipherParams } from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
import defaultConfig from '../config';
|
import defaultConfig from '../config';
|
||||||
@ -86,9 +86,9 @@ class SymmetricallyEncryptedDataPacket {
|
|||||||
throw new Error('Message is not authenticated.');
|
throw new Error('Message is not authenticated.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { blockSize } = crypto.getCipherParams(sessionKeyAlgorithm);
|
const { blockSize } = getCipherParams(sessionKeyAlgorithm);
|
||||||
const encrypted = await stream.readToEnd(stream.clone(this.encrypted));
|
const encrypted = await streamReadToEnd(streamClone(this.encrypted));
|
||||||
const decrypted = await crypto.mode.cfb.decrypt(sessionKeyAlgorithm, key,
|
const decrypted = await cipherMode.cfb.decrypt(sessionKeyAlgorithm, key,
|
||||||
encrypted.subarray(blockSize + 2),
|
encrypted.subarray(blockSize + 2),
|
||||||
encrypted.subarray(2, blockSize + 2)
|
encrypted.subarray(2, blockSize + 2)
|
||||||
);
|
);
|
||||||
@ -107,11 +107,11 @@ class SymmetricallyEncryptedDataPacket {
|
|||||||
*/
|
*/
|
||||||
async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
|
async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
|
||||||
const data = this.packets.write();
|
const data = this.packets.write();
|
||||||
const { blockSize } = crypto.getCipherParams(sessionKeyAlgorithm);
|
const { blockSize } = getCipherParams(sessionKeyAlgorithm);
|
||||||
|
|
||||||
const prefix = await crypto.getPrefixRandom(sessionKeyAlgorithm);
|
const prefix = await cipherMode.cfb.getPrefixRandom(sessionKeyAlgorithm);
|
||||||
const FRE = await crypto.mode.cfb.encrypt(sessionKeyAlgorithm, key, prefix, new Uint8Array(blockSize), config);
|
const FRE = await cipherMode.cfb.encrypt(sessionKeyAlgorithm, key, prefix, new Uint8Array(blockSize), config);
|
||||||
const ciphertext = await crypto.mode.cfb.encrypt(sessionKeyAlgorithm, key, data, FRE.subarray(2), config);
|
const ciphertext = await cipherMode.cfb.encrypt(sessionKeyAlgorithm, key, data, FRE.subarray(2), config);
|
||||||
this.encrypted = util.concat([FRE, ciphertext]);
|
this.encrypted = util.concat([FRE, ciphertext]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import defaultConfig from '../../config';
|
import defaultConfig from '../../config';
|
||||||
import enums from '../../enums';
|
import enums from '../../enums';
|
||||||
import util from '../../util';
|
import util from '../../util';
|
||||||
import crypto from '../../crypto';
|
import { getRandomBytes } from '../../crypto';
|
||||||
|
|
||||||
const ARGON2_TYPE = 0x02; // id
|
const ARGON2_TYPE = 0x02; // id
|
||||||
const ARGON2_VERSION = 0x13;
|
const ARGON2_VERSION = 0x13;
|
||||||
@ -56,7 +56,7 @@ class Argon2S2K {
|
|||||||
}
|
}
|
||||||
|
|
||||||
generateSalt() {
|
generateSalt() {
|
||||||
this.salt = crypto.random.getRandomBytes(ARGON2_SALT_SIZE);
|
this.salt = getRandomBytes(ARGON2_SALT_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import defaultConfig from '../../config';
|
import defaultConfig from '../../config';
|
||||||
import crypto from '../../crypto';
|
import { getRandomBytes, computeDigest } from '../../crypto';
|
||||||
import enums from '../../enums';
|
import enums from '../../enums';
|
||||||
import { UnsupportedError } from '../../packet/packet';
|
import { UnsupportedError } from '../../packet/packet';
|
||||||
import util from '../../util';
|
import util from '../../util';
|
||||||
@ -60,7 +60,7 @@ class GenericS2K {
|
|||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case 'salted':
|
case 'salted':
|
||||||
case 'iterated':
|
case 'iterated':
|
||||||
this.salt = crypto.random.getRandomBytes(8);
|
this.salt = getRandomBytes(8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ class GenericS2K {
|
|||||||
default:
|
default:
|
||||||
throw new Error('Unknown s2k type.');
|
throw new Error('Unknown s2k type.');
|
||||||
}
|
}
|
||||||
const result = await crypto.hash.digest(this.algorithm, toHash);
|
const result = await computeDigest(this.algorithm, toHash);
|
||||||
arr.push(result);
|
arr.push(result);
|
||||||
rlength += result.length;
|
rlength += result.length;
|
||||||
prefixlen++;
|
prefixlen++;
|
||||||
|
20
src/util.js
20
src/util.js
@ -22,7 +22,7 @@
|
|||||||
* @module util
|
* @module util
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as stream from '@openpgp/web-stream-tools';
|
import { concat as streamConcat, transform as streamTransform, concatUint8Array, isStream, isUint8Array } from '@openpgp/web-stream-tools';
|
||||||
import { createRequire } from 'module'; // Must be stripped in browser built
|
import { createRequire } from 'module'; // Must be stripped in browser built
|
||||||
import enums from './enums';
|
import enums from './enums';
|
||||||
import defaultConfig from './config';
|
import defaultConfig from './config';
|
||||||
@ -45,9 +45,9 @@ const util = {
|
|||||||
return data instanceof Array;
|
return data instanceof Array;
|
||||||
},
|
},
|
||||||
|
|
||||||
isUint8Array: stream.isUint8Array,
|
isUint8Array: isUint8Array,
|
||||||
|
|
||||||
isStream: stream.isStream,
|
isStream: isStream,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load noble-curves lib on demand and return the requested curve function
|
* Load noble-curves lib on demand and return the requested curve function
|
||||||
@ -218,7 +218,7 @@ const util = {
|
|||||||
* @returns {Uint8Array} An array of 8-bit integers.
|
* @returns {Uint8Array} An array of 8-bit integers.
|
||||||
*/
|
*/
|
||||||
stringToUint8Array: function (str) {
|
stringToUint8Array: function (str) {
|
||||||
return stream.transform(str, str => {
|
return streamTransform(str, str => {
|
||||||
if (!util.isString(str)) {
|
if (!util.isString(str)) {
|
||||||
throw new Error('stringToUint8Array: Data must be in the form of a string');
|
throw new Error('stringToUint8Array: Data must be in the form of a string');
|
||||||
}
|
}
|
||||||
@ -259,7 +259,7 @@ const util = {
|
|||||||
function process(value, lastChunk = false) {
|
function process(value, lastChunk = false) {
|
||||||
return encoder.encode(value, { stream: !lastChunk });
|
return encoder.encode(value, { stream: !lastChunk });
|
||||||
}
|
}
|
||||||
return stream.transform(str, process, () => process('', true));
|
return streamTransform(str, process, () => process('', true));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -273,7 +273,7 @@ const util = {
|
|||||||
function process(value, lastChunk = false) {
|
function process(value, lastChunk = false) {
|
||||||
return decoder.decode(value, { stream: !lastChunk });
|
return decoder.decode(value, { stream: !lastChunk });
|
||||||
}
|
}
|
||||||
return stream.transform(utf8, process, () => process(new Uint8Array(), true));
|
return streamTransform(utf8, process, () => process(new Uint8Array(), true));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -282,14 +282,14 @@ const util = {
|
|||||||
* @param {Array<Uint8Array|String|ReadableStream>} Array - Of Uint8Arrays/Strings/Streams to concatenate
|
* @param {Array<Uint8Array|String|ReadableStream>} Array - Of Uint8Arrays/Strings/Streams to concatenate
|
||||||
* @returns {Uint8Array|String|ReadableStream} Concatenated array.
|
* @returns {Uint8Array|String|ReadableStream} Concatenated array.
|
||||||
*/
|
*/
|
||||||
concat: stream.concat,
|
concat: streamConcat,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Concat Uint8Arrays
|
* Concat Uint8Arrays
|
||||||
* @param {Array<Uint8Array>} Array - Of Uint8Arrays to concatenate
|
* @param {Array<Uint8Array>} Array - Of Uint8Arrays to concatenate
|
||||||
* @returns {Uint8Array} Concatenated array.
|
* @returns {Uint8Array} Concatenated array.
|
||||||
*/
|
*/
|
||||||
concatUint8Array: stream.concatUint8Array,
|
concatUint8Array: concatUint8Array,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check Uint8Array equality
|
* Check Uint8Array equality
|
||||||
@ -490,7 +490,7 @@ const util = {
|
|||||||
const LF = 10;
|
const LF = 10;
|
||||||
let carryOverCR = false;
|
let carryOverCR = false;
|
||||||
|
|
||||||
return stream.transform(data, bytes => {
|
return streamTransform(data, bytes => {
|
||||||
if (carryOverCR) {
|
if (carryOverCR) {
|
||||||
bytes = util.concatUint8Array([new Uint8Array([CR]), bytes]);
|
bytes = util.concatUint8Array([new Uint8Array([CR]), bytes]);
|
||||||
}
|
}
|
||||||
@ -540,7 +540,7 @@ const util = {
|
|||||||
const LF = 10;
|
const LF = 10;
|
||||||
let carryOverCR = false;
|
let carryOverCR = false;
|
||||||
|
|
||||||
return stream.transform(data, bytes => {
|
return streamTransform(data, bytes => {
|
||||||
if (carryOverCR && bytes[0] !== LF) {
|
if (carryOverCR && bytes[0] !== LF) {
|
||||||
bytes = util.concatUint8Array([new Uint8Array([CR]), bytes]);
|
bytes = util.concatUint8Array([new Uint8Array([CR]), bytes]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -3,7 +3,7 @@ import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/new
|
|||||||
chaiUse(chaiAsPromised);
|
chaiUse(chaiAsPromised);
|
||||||
|
|
||||||
import openpgp from '../initOpenpgp.js';
|
import openpgp from '../initOpenpgp.js';
|
||||||
import crypto from '../../src/crypto';
|
import * as crypto from '../../src/crypto';
|
||||||
import util from '../../src/util.js';
|
import util from '../../src/util.js';
|
||||||
|
|
||||||
export default () => describe('API functional testing', function() {
|
export default () => describe('API functional testing', function() {
|
||||||
@ -211,20 +211,20 @@ export default () => describe('API functional testing', function() {
|
|||||||
describe('Sign and verify', function () {
|
describe('Sign and verify', function () {
|
||||||
it('RSA', async function () {
|
it('RSA', async function () {
|
||||||
const RSAsignedData = await crypto.signature.sign(
|
const RSAsignedData = await crypto.signature.sign(
|
||||||
openpgp.enums.publicKey.rsaEncryptSign, openpgp.enums.hash.sha1, RSAPublicParams, RSAPrivateParams, data, await crypto.hash.digest(2, data)
|
openpgp.enums.publicKey.rsaEncryptSign, openpgp.enums.hash.sha1, RSAPublicParams, RSAPrivateParams, data, await crypto.computeDigest(2, data)
|
||||||
);
|
);
|
||||||
const success = await crypto.signature.verify(
|
const success = await crypto.signature.verify(
|
||||||
openpgp.enums.publicKey.rsaEncryptSign, openpgp.enums.hash.sha1, RSAsignedData, RSAPublicParams, data, await crypto.hash.digest(2, data)
|
openpgp.enums.publicKey.rsaEncryptSign, openpgp.enums.hash.sha1, RSAsignedData, RSAPublicParams, data, await crypto.computeDigest(2, data)
|
||||||
);
|
);
|
||||||
return expect(success).to.be.true;
|
return expect(success).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('DSA', async function () {
|
it('DSA', async function () {
|
||||||
const DSAsignedData = await crypto.signature.sign(
|
const DSAsignedData = await crypto.signature.sign(
|
||||||
openpgp.enums.publicKey.dsa, openpgp.enums.hash.sha1, DSAPublicParams, DSAPrivateParams, data, await crypto.hash.digest(2, data)
|
openpgp.enums.publicKey.dsa, openpgp.enums.hash.sha1, DSAPublicParams, DSAPrivateParams, data, await crypto.computeDigest(2, data)
|
||||||
);
|
);
|
||||||
const success = await crypto.signature.verify(
|
const success = await crypto.signature.verify(
|
||||||
openpgp.enums.publicKey.dsa, openpgp.enums.hash.sha1, DSAsignedData, DSAPublicParams, data, await crypto.hash.digest(2, data)
|
openpgp.enums.publicKey.dsa, openpgp.enums.hash.sha1, DSAsignedData, DSAPublicParams, data, await crypto.computeDigest(2, data)
|
||||||
);
|
);
|
||||||
|
|
||||||
return expect(success).to.be.true;
|
return expect(success).to.be.true;
|
||||||
@ -234,7 +234,7 @@ export default () => describe('API functional testing', function() {
|
|||||||
// key data from https://www.rfc-editor.org/rfc/rfc8032#section-7.4
|
// key data from https://www.rfc-editor.org/rfc/rfc8032#section-7.4
|
||||||
const seed = util.hexToUint8Array('d65df341ad13e008567688baedda8e9dcdc17dc024974ea5b4227b6530e339bff21f99e68ca6968f3cca6dfe0fb9f4fab4fa135d5542ea3f01');
|
const seed = util.hexToUint8Array('d65df341ad13e008567688baedda8e9dcdc17dc024974ea5b4227b6530e339bff21f99e68ca6968f3cca6dfe0fb9f4fab4fa135d5542ea3f01');
|
||||||
const A = util.hexToUint8Array('df9705f58edbab802c7f8363cfe5560ab1c6132c20a9f1dd163483a26f8ac53a39d6808bf4a1dfbd261b099bb03b3fb50906cb28bd8a081f00');
|
const A = util.hexToUint8Array('df9705f58edbab802c7f8363cfe5560ab1c6132c20a9f1dd163483a26f8ac53a39d6808bf4a1dfbd261b099bb03b3fb50906cb28bd8a081f00');
|
||||||
const toSign = await crypto.hash.digest(openpgp.enums.hash.sha512, data);
|
const toSign = await crypto.computeDigest(openpgp.enums.hash.sha512, data);
|
||||||
const signedData = await crypto.signature.sign(
|
const signedData = await crypto.signature.sign(
|
||||||
openpgp.enums.publicKey.ed448, openpgp.enums.hash.sha512, { A }, { seed }, data, toSign
|
openpgp.enums.publicKey.ed448, openpgp.enums.hash.sha512, { A }, { seed }, data, toSign
|
||||||
);
|
);
|
||||||
@ -257,8 +257,8 @@ export default () => describe('API functional testing', function() {
|
|||||||
const { blockSize } = crypto.getCipherParams(algo);
|
const { blockSize } = crypto.getCipherParams(algo);
|
||||||
const symmKey = crypto.generateSessionKey(algo);
|
const symmKey = crypto.generateSessionKey(algo);
|
||||||
const IV = new Uint8Array(blockSize);
|
const IV = new Uint8Array(blockSize);
|
||||||
const symmencData = await crypto.mode.cfb.encrypt(algo, symmKey, util.stringToUint8Array(plaintext), IV, config);
|
const symmencData = await crypto.cipherMode.cfb.encrypt(algo, symmKey, util.stringToUint8Array(plaintext), IV, config);
|
||||||
const text = util.uint8ArrayToString(await crypto.mode.cfb.decrypt(algo, symmKey, symmencData, new Uint8Array(blockSize)));
|
const text = util.uint8ArrayToString(await crypto.cipherMode.cfb.decrypt(algo, symmKey, symmencData, new Uint8Array(blockSize)));
|
||||||
expect(text).to.equal(plaintext);
|
expect(text).to.equal(plaintext);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/new
|
|||||||
chaiUse(chaiAsPromised);
|
chaiUse(chaiAsPromised);
|
||||||
|
|
||||||
import openpgp from '../initOpenpgp.js';
|
import openpgp from '../initOpenpgp.js';
|
||||||
import EAX from '../../src/crypto/mode/eax.js';
|
import { cipherMode } from '../../src/crypto';
|
||||||
import util from '../../src/util.js';
|
import util from '../../src/util.js';
|
||||||
|
|
||||||
function testAESEAX() {
|
function testAESEAX() {
|
||||||
@ -95,7 +95,8 @@ function testAESEAX() {
|
|||||||
const headerBytes = util.hexToUint8Array(vec.header);
|
const headerBytes = util.hexToUint8Array(vec.header);
|
||||||
const ctBytes = util.hexToUint8Array(vec.ct);
|
const ctBytes = util.hexToUint8Array(vec.ct);
|
||||||
|
|
||||||
const eax = await EAX(cipher, keyBytes);
|
const eaxMode = cipherMode.getAEADMode(openpgp.enums.aead.eax);
|
||||||
|
const eax = await eaxMode(cipher, keyBytes);
|
||||||
|
|
||||||
// encryption test
|
// encryption test
|
||||||
let ct = await eax.encrypt(msgBytes, nonceBytes, headerBytes);
|
let ct = await eax.encrypt(msgBytes, nonceBytes, headerBytes);
|
||||||
|
@ -5,7 +5,7 @@ chaiUse(chaiAsPromised);
|
|||||||
|
|
||||||
import openpgp from '../initOpenpgp.js';
|
import openpgp from '../initOpenpgp.js';
|
||||||
import * as elliptic_curves from '../../src/crypto/public_key/elliptic';
|
import * as elliptic_curves from '../../src/crypto/public_key/elliptic';
|
||||||
import hashMod from '../../src/crypto/hash';
|
import { computeDigest } from '../../src/crypto/hash';
|
||||||
import config from '../../src/config';
|
import config from '../../src/config';
|
||||||
import util from '../../src/util.js';
|
import util from '../../src/util.js';
|
||||||
|
|
||||||
@ -151,7 +151,7 @@ export default () => describe('Elliptic Curve Cryptography @lightweight', functi
|
|||||||
const curve = new elliptic_curves.CurveWithOID(curveName);
|
const curve = new elliptic_curves.CurveWithOID(curveName);
|
||||||
const oid = new OID(curve.oid);
|
const oid = new OID(curve.oid);
|
||||||
return ecdsa.verify(
|
return ecdsa.verify(
|
||||||
oid, hash, { r: new Uint8Array(r), s: new Uint8Array(s) }, message, new Uint8Array(pub), await hashMod.digest(hash, message)
|
oid, hash, { r: new Uint8Array(r), s: new Uint8Array(s) }, message, new Uint8Array(pub), await computeDigest(hash, message)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
const secp256k1_point = new Uint8Array([
|
const secp256k1_point = new Uint8Array([
|
||||||
@ -249,7 +249,7 @@ export default () => describe('Elliptic Curve Cryptography @lightweight', functi
|
|||||||
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
|
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
|
||||||
]);
|
]);
|
||||||
const messageDigest = await hashMod.digest(openpgp.enums.hash.sha512, message);
|
const messageDigest = await computeDigest(openpgp.enums.hash.sha512, message);
|
||||||
await testNativeAndFallback(async () => {
|
await testNativeAndFallback(async () => {
|
||||||
const signature = await elliptic_curves.ecdsa.sign(oid, openpgp.enums.hash.sha512, message, keyPublic, keyPrivate, messageDigest);
|
const signature = await elliptic_curves.ecdsa.sign(oid, openpgp.enums.hash.sha512, message, keyPublic, keyPrivate, messageDigest);
|
||||||
await expect(elliptic_curves.ecdsa.verify(oid, openpgp.enums.hash.sha512, signature, message, keyPublic, messageDigest)).to.eventually.be.true;
|
await expect(elliptic_curves.ecdsa.verify(oid, openpgp.enums.hash.sha512, signature, message, keyPublic, messageDigest)).to.eventually.be.true;
|
||||||
|
@ -4,10 +4,9 @@ import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/new
|
|||||||
chaiUse(chaiAsPromised);
|
chaiUse(chaiAsPromised);
|
||||||
|
|
||||||
import openpgp from '../initOpenpgp.js';
|
import openpgp from '../initOpenpgp.js';
|
||||||
import crypto from '../../src/crypto';
|
import * as crypto from '../../src/crypto';
|
||||||
import util from '../../src/util.js';
|
import util from '../../src/util.js';
|
||||||
|
|
||||||
|
|
||||||
export default () => describe('Symmetric AES-GCM (experimental)', function() {
|
export default () => describe('Symmetric AES-GCM (experimental)', function() {
|
||||||
let sinonSandbox;
|
let sinonSandbox;
|
||||||
let getWebCryptoStub;
|
let getWebCryptoStub;
|
||||||
@ -46,18 +45,19 @@ export default () => describe('Symmetric AES-GCM (experimental)', function() {
|
|||||||
}
|
}
|
||||||
const algo = openpgp.enums.write(openpgp.enums.symmetric, algoName);
|
const algo = openpgp.enums.write(openpgp.enums.symmetric, algoName);
|
||||||
const key = crypto.generateSessionKey(algo);
|
const key = crypto.generateSessionKey(algo);
|
||||||
const iv = crypto.random.getRandomBytes(crypto.mode.gcm.ivLength);
|
const gcmMode = crypto.cipherMode.getAEADMode(openpgp.enums.aead.gcm);
|
||||||
|
const iv = crypto.getRandomBytes(gcmMode.ivLength);
|
||||||
|
|
||||||
const nativeEncryptSpy = nodeCrypto ? sinonSandbox.spy(nodeCrypto, 'createCipheriv') : sinonSandbox.spy(webCrypto, 'encrypt');
|
const nativeEncryptSpy = nodeCrypto ? sinonSandbox.spy(nodeCrypto, 'createCipheriv') : sinonSandbox.spy(webCrypto, 'encrypt');
|
||||||
const nativeDecryptSpy = nodeCrypto ? sinonSandbox.spy(nodeCrypto, 'createDecipheriv') : sinonSandbox.spy(webCrypto, 'decrypt');
|
const nativeDecryptSpy = nodeCrypto ? sinonSandbox.spy(nodeCrypto, 'createDecipheriv') : sinonSandbox.spy(webCrypto, 'decrypt');
|
||||||
|
|
||||||
nativeEncrypt || disableNative();
|
nativeEncrypt || disableNative();
|
||||||
let modeInstance = await crypto.mode.gcm(algo, key);
|
let modeInstance = await gcmMode(algo, key);
|
||||||
const ciphertext = await modeInstance.encrypt(util.stringToUint8Array(plaintext), iv);
|
const ciphertext = await modeInstance.encrypt(util.stringToUint8Array(plaintext), iv);
|
||||||
enableNative();
|
enableNative();
|
||||||
|
|
||||||
nativeDecrypt || disableNative();
|
nativeDecrypt || disableNative();
|
||||||
modeInstance = await crypto.mode.gcm(algo, key);
|
modeInstance = await gcmMode(algo, key);
|
||||||
const decrypted = await modeInstance.decrypt(util.stringToUint8Array(util.uint8ArrayToString(ciphertext)), iv);
|
const decrypted = await modeInstance.decrypt(util.stringToUint8Array(util.uint8ArrayToString(ciphertext)), iv);
|
||||||
enableNative();
|
enableNative();
|
||||||
|
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
|
||||||
import md5 from '../../../src/crypto/hash/md5.js';
|
|
||||||
import util from '../../../src/util.js';
|
import util from '../../../src/util.js';
|
||||||
|
import { computeDigest } from '../../../src/crypto/hash';
|
||||||
|
import enums from '../../../src/enums.js';
|
||||||
|
|
||||||
export default () => it('MD5 with test vectors from RFC 1321', async function() {
|
export default () => it('MD5 with test vectors from RFC 1321', async function() {
|
||||||
expect(util.uint8ArrayToHex(await md5(util.stringToUint8Array('')), 'MD5("") = d41d8cd98f00b204e9800998ecf8427e')).to.equal('d41d8cd98f00b204e9800998ecf8427e');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.md5, util.stringToUint8Array('')), 'MD5("") = d41d8cd98f00b204e9800998ecf8427e')).to.equal('d41d8cd98f00b204e9800998ecf8427e');
|
||||||
expect(util.uint8ArrayToHex(await md5(util.stringToUint8Array('abc')), 'MD5("a") = 0cc175b9c0f1b6a831c399e269772661')).to.equal('900150983cd24fb0d6963f7d28e17f72');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.md5, util.stringToUint8Array('abc')), 'MD5("a") = 0cc175b9c0f1b6a831c399e269772661')).to.equal('900150983cd24fb0d6963f7d28e17f72');
|
||||||
expect(util.uint8ArrayToHex(await md5(util.stringToUint8Array('message digest')), 'MD5("message digest") = f96b697d7cb7938d525a2f31aaf161d0')).to.equal('f96b697d7cb7938d525a2f31aaf161d0');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.md5, util.stringToUint8Array('message digest')), 'MD5("message digest") = f96b697d7cb7938d525a2f31aaf161d0')).to.equal('f96b697d7cb7938d525a2f31aaf161d0');
|
||||||
expect(util.uint8ArrayToHex(await md5(util.stringToUint8Array('abcdefghijklmnopqrstuvwxyz')), 'MD5("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b')).to.equal('c3fcd3d76192e4007dfb496cca67e13b');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.md5, util.stringToUint8Array('abcdefghijklmnopqrstuvwxyz')), 'MD5("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b')).to.equal('c3fcd3d76192e4007dfb496cca67e13b');
|
||||||
expect(util.uint8ArrayToHex(await md5(util.stringToUint8Array('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')), 'MD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = d174ab98d277d9f5a5611c2c9f419d9f')).to.equal('d174ab98d277d9f5a5611c2c9f419d9f');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.md5, util.stringToUint8Array('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')), 'MD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = d174ab98d277d9f5a5611c2c9f419d9f')).to.equal('d174ab98d277d9f5a5611c2c9f419d9f');
|
||||||
expect(util.uint8ArrayToHex(await md5(util.stringToUint8Array('12345678901234567890123456789012345678901234567890123456789012345678901234567890')), 'MD5("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = 57edf4a22be3c955ac49da2e2107b67a')).to.equal('57edf4a22be3c955ac49da2e2107b67a');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.md5, util.stringToUint8Array('12345678901234567890123456789012345678901234567890123456789012345678901234567890')), 'MD5("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = 57edf4a22be3c955ac49da2e2107b67a')).to.equal('57edf4a22be3c955ac49da2e2107b67a');
|
||||||
});
|
});
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
|
||||||
import hash from '../../../src/crypto/hash';
|
import { computeDigest } from '../../../src/crypto/hash';
|
||||||
import util from '../../../src/util.js';
|
import util from '../../../src/util.js';
|
||||||
|
import enums from '../../../src/enums.js';
|
||||||
|
|
||||||
export default () => it('RIPE-MD 160 bits with test vectors from https://homes.esat.kuleuven.be/~bosselae/ripemd160.html', async function() {
|
export default () => it('RIPE-MD 160 bits with test vectors from https://homes.esat.kuleuven.be/~bosselae/ripemd160.html', async function() {
|
||||||
expect(util.uint8ArrayToHex(await hash.ripemd(util.stringToUint8Array('')), 'RMDstring("") = 9c1185a5c5e9fc54612808977ee8f548b2258d31')).to.equal('9c1185a5c5e9fc54612808977ee8f548b2258d31');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.ripemd, util.stringToUint8Array('')), 'RMDstring("") = 9c1185a5c5e9fc54612808977ee8f548b2258d31')).to.equal('9c1185a5c5e9fc54612808977ee8f548b2258d31');
|
||||||
expect(util.uint8ArrayToHex(await hash.ripemd(util.stringToUint8Array('a')), 'RMDstring("a") = 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe')).to.equal('0bdc9d2d256b3ee9daae347be6f4dc835a467ffe');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.ripemd, util.stringToUint8Array('a')), 'RMDstring("a") = 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe')).to.equal('0bdc9d2d256b3ee9daae347be6f4dc835a467ffe');
|
||||||
expect(util.uint8ArrayToHex(await hash.ripemd(util.stringToUint8Array('abc')), 'RMDstring("abc") = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc')).to.equal('8eb208f7e05d987a9b044a8e98c6b087f15a0bfc');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.ripemd, util.stringToUint8Array('abc')), 'RMDstring("abc") = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc')).to.equal('8eb208f7e05d987a9b044a8e98c6b087f15a0bfc');
|
||||||
expect(util.uint8ArrayToHex(await hash.ripemd(util.stringToUint8Array('message digest')), 'RMDstring("message digest") = 5d0689ef49d2fae572b881b123a85ffa21595f36')).to.equal('5d0689ef49d2fae572b881b123a85ffa21595f36');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.ripemd, util.stringToUint8Array('message digest')), 'RMDstring("message digest") = 5d0689ef49d2fae572b881b123a85ffa21595f36')).to.equal('5d0689ef49d2fae572b881b123a85ffa21595f36');
|
||||||
});
|
});
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
|
||||||
import hash from '../../../src/crypto/hash';
|
import { computeDigest } from '../../../src/crypto/hash';
|
||||||
import util from '../../../src/util.js';
|
import util from '../../../src/util.js';
|
||||||
|
import enums from '../../../src/enums.js';
|
||||||
|
|
||||||
export default () => it('SHA* with test vectors from NIST FIPS 180-2', async function() {
|
export default () => it('SHA* with test vectors from NIST FIPS 180-2', async function() {
|
||||||
expect(util.uint8ArrayToHex(await hash.sha1(util.stringToUint8Array('abc')), 'hash.sha1("abc") = a9993e364706816aba3e25717850c26c9cd0d89d')).to.equal('a9993e364706816aba3e25717850c26c9cd0d89d');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.sha1, util.stringToUint8Array('abc')), 'hash.sha1("abc") = a9993e364706816aba3e25717850c26c9cd0d89d')).to.equal('a9993e364706816aba3e25717850c26c9cd0d89d');
|
||||||
expect(util.uint8ArrayToHex(await hash.sha1(util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 84983e441c3bd26ebaae4aa1f95129e5e54670f1')).to.equal('84983e441c3bd26ebaae4aa1f95129e5e54670f1');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.sha1, util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 84983e441c3bd26ebaae4aa1f95129e5e54670f1')).to.equal('84983e441c3bd26ebaae4aa1f95129e5e54670f1');
|
||||||
expect(util.uint8ArrayToHex(await hash.sha224(util.stringToUint8Array('abc')), 'hash.sha224("abc") = 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7')).to.equal('23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.sha224, util.stringToUint8Array('abc')), 'hash.sha224("abc") = 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7')).to.equal('23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7');
|
||||||
expect(util.uint8ArrayToHex(await hash.sha224(util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha224("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525')).to.equal('75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.sha224, util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha224("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525')).to.equal('75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525');
|
||||||
expect(util.uint8ArrayToHex(await hash.sha256(util.stringToUint8Array('abc')), 'hash.sha256("abc") = ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad')).to.equal('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.sha256, util.stringToUint8Array('abc')), 'hash.sha256("abc") = ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad')).to.equal('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad');
|
||||||
expect(util.uint8ArrayToHex(await hash.sha256(util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1')).to.equal('248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.sha256, util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1')).to.equal('248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1');
|
||||||
expect(util.uint8ArrayToHex(await hash.sha384(util.stringToUint8Array('abc')), 'hash.sha384("abc") = cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7')).to.equal('cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.sha384, util.stringToUint8Array('abc')), 'hash.sha384("abc") = cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7')).to.equal('cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7');
|
||||||
expect(util.uint8ArrayToHex(await hash.sha384(util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha384("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b')).to.equal('3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.sha384, util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha384("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b')).to.equal('3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b');
|
||||||
expect(util.uint8ArrayToHex(await hash.sha512(util.stringToUint8Array('abc')), 'hash.sha512("abc") = ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f')).to.equal('ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.sha512, util.stringToUint8Array('abc')), 'hash.sha512("abc") = ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f')).to.equal('ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f');
|
||||||
expect(util.uint8ArrayToHex(await hash.sha512(util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha512("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445')).to.equal('204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.sha512, util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha512("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445')).to.equal('204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445');
|
||||||
expect(util.uint8ArrayToHex(await hash.sha3_256(util.stringToUint8Array('abc')), 'hash.sha3_256("abc") = 3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532')).to.equal('3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.sha3_256, util.stringToUint8Array('abc')), 'hash.sha3_256("abc") = 3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532')).to.equal('3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532');
|
||||||
expect(util.uint8ArrayToHex(await hash.sha3_256(util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha3_256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376')).to.equal('41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.sha3_256, util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha3_256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376')).to.equal('41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376');
|
||||||
expect(util.uint8ArrayToHex(await hash.sha3_512(util.stringToUint8Array('abc')), 'hash.sha3_512("abc") = b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0')).to.equal('b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.sha3_512, util.stringToUint8Array('abc')), 'hash.sha3_512("abc") = b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0')).to.equal('b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0');
|
||||||
expect(util.uint8ArrayToHex(await hash.sha3_512(util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha3_512("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e')).to.equal('04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e');
|
expect(util.uint8ArrayToHex(await computeDigest(enums.hash.sha3_512, util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha3_512("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e')).to.equal('04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e');
|
||||||
});
|
});
|
||||||
|
@ -6,7 +6,7 @@ import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/new
|
|||||||
chaiUse(chaiAsPromised);
|
chaiUse(chaiAsPromised);
|
||||||
|
|
||||||
import openpgp from '../initOpenpgp.js';
|
import openpgp from '../initOpenpgp.js';
|
||||||
import OCB from '../../src/crypto/mode/ocb.js';
|
import { cipherMode } from '../../src/crypto';
|
||||||
import util from '../../src/util.js';
|
import util from '../../src/util.js';
|
||||||
|
|
||||||
export default () => describe('Symmetric AES-OCB', function() {
|
export default () => describe('Symmetric AES-OCB', function() {
|
||||||
@ -122,7 +122,8 @@ export default () => describe('Symmetric AES-OCB', function() {
|
|||||||
const headerBytes = util.hexToUint8Array(vec.A);
|
const headerBytes = util.hexToUint8Array(vec.A);
|
||||||
const ctBytes = util.hexToUint8Array(vec.C);
|
const ctBytes = util.hexToUint8Array(vec.C);
|
||||||
|
|
||||||
const ocb = await OCB(cipher, keyBytes);
|
const ocbMode = cipherMode.getAEADMode(openpgp.enums.aead.ocb);
|
||||||
|
const ocb = await ocbMode(cipher, keyBytes);
|
||||||
|
|
||||||
// encryption test
|
// encryption test
|
||||||
let ct = await ocb.encrypt(msgBytes, nonceBytes, headerBytes);
|
let ct = await ocb.encrypt(msgBytes, nonceBytes, headerBytes);
|
||||||
@ -163,7 +164,8 @@ export default () => describe('Symmetric AES-OCB', function() {
|
|||||||
k[k.length - 1] = taglen;
|
k[k.length - 1] = taglen;
|
||||||
|
|
||||||
const algo = openpgp.enums.write(openpgp.enums.symmetric, 'aes' + keylen);
|
const algo = openpgp.enums.write(openpgp.enums.symmetric, 'aes' + keylen);
|
||||||
const ocb = await OCB(algo, k);
|
const ocbMode = cipherMode.getAEADMode(openpgp.enums.aead.ocb);
|
||||||
|
const ocb = await ocbMode(algo, k);
|
||||||
|
|
||||||
const c = [];
|
const c = [];
|
||||||
let n;
|
let n;
|
||||||
|
@ -4,7 +4,7 @@ import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/new
|
|||||||
chaiUse(chaiAsPromised);
|
chaiUse(chaiAsPromised);
|
||||||
|
|
||||||
import openpgp from '../initOpenpgp.js';
|
import openpgp from '../initOpenpgp.js';
|
||||||
import crypto from '../../src/crypto';
|
import * as crypto from '../../src/crypto';
|
||||||
import * as random from '../../src/crypto/random.js';
|
import * as random from '../../src/crypto/random.js';
|
||||||
import util from '../../src/util.js';
|
import util from '../../src/util.js';
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ export default () => describe('basic RSA cryptography', function () {
|
|||||||
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
|
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
|
||||||
const message = random.getRandomBytes(64);
|
const message = random.getRandomBytes(64);
|
||||||
const hashAlgo = openpgp.enums.write(openpgp.enums.hash, 'sha256');
|
const hashAlgo = openpgp.enums.write(openpgp.enums.hash, 'sha256');
|
||||||
const hashed = await crypto.hash.digest(hashAlgo, message);
|
const hashed = await crypto.computeDigest(hashAlgo, message);
|
||||||
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
|
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
|
||||||
const signature = await crypto.publicKey.rsa.sign(hashAlgo, message, n, e, d, p, q, u, hashed);
|
const signature = await crypto.publicKey.rsa.sign(hashAlgo, message, n, e, d, p, q, u, hashed);
|
||||||
expect(signature).to.exist;
|
expect(signature).to.exist;
|
||||||
@ -113,7 +113,7 @@ export default () => describe('basic RSA cryptography', function () {
|
|||||||
const message = random.getRandomBytes(64);
|
const message = random.getRandomBytes(64);
|
||||||
const hashName = 'sha256';
|
const hashName = 'sha256';
|
||||||
const hashAlgo = openpgp.enums.write(openpgp.enums.hash, hashName);
|
const hashAlgo = openpgp.enums.write(openpgp.enums.hash, hashName);
|
||||||
const hashed = await crypto.hash.digest(hashAlgo, message);
|
const hashed = await crypto.computeDigest(hashAlgo, message);
|
||||||
enableNative();
|
enableNative();
|
||||||
const signatureNative = await crypto.publicKey.rsa.sign(hashAlgo, message, n, e, d, p, q, u, hashed);
|
const signatureNative = await crypto.publicKey.rsa.sign(hashAlgo, message, n, e, d, p, q, u, hashed);
|
||||||
disableNative();
|
disableNative();
|
||||||
@ -130,7 +130,7 @@ export default () => describe('basic RSA cryptography', function () {
|
|||||||
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
|
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
|
||||||
const message = random.getRandomBytes(64);
|
const message = random.getRandomBytes(64);
|
||||||
const hashAlgo = openpgp.enums.write(openpgp.enums.hash, hashName);
|
const hashAlgo = openpgp.enums.write(openpgp.enums.hash, hashName);
|
||||||
const hashed = await crypto.hash.digest(hashAlgo, message);
|
const hashed = await crypto.computeDigest(hashAlgo, message);
|
||||||
enableNative();
|
enableNative();
|
||||||
await expect(crypto.publicKey.rsa.sign(hashAlgo, message, n, e, d, p, q, u, hashed)).to.be.rejectedWith(/Digest size cannot exceed key modulus size/);
|
await expect(crypto.publicKey.rsa.sign(hashAlgo, message, n, e, d, p, q, u, hashed)).to.be.rejectedWith(/Digest size cannot exceed key modulus size/);
|
||||||
disableNative();
|
disableNative();
|
||||||
@ -146,7 +146,7 @@ export default () => describe('basic RSA cryptography', function () {
|
|||||||
const message = random.getRandomBytes(64);
|
const message = random.getRandomBytes(64);
|
||||||
const hashName = 'sha256';
|
const hashName = 'sha256';
|
||||||
const hashAlgo = openpgp.enums.write(openpgp.enums.hash, hashName);
|
const hashAlgo = openpgp.enums.write(openpgp.enums.hash, hashName);
|
||||||
const hashed = await crypto.hash.digest(hashAlgo, message);
|
const hashed = await crypto.computeDigest(hashAlgo, message);
|
||||||
enableNative();
|
enableNative();
|
||||||
const signatureNative = await crypto.publicKey.rsa.sign(hashAlgo, message, n, e, d, p, q, u, hashed);
|
const signatureNative = await crypto.publicKey.rsa.sign(hashAlgo, message, n, e, d, p, q, u, hashed);
|
||||||
const verifyNative = await crypto.publicKey.rsa.verify(hashAlgo, message, signatureNative, n, e);
|
const verifyNative = await crypto.publicKey.rsa.verify(hashAlgo, message, signatureNative, n, e);
|
||||||
|
@ -7,8 +7,7 @@ import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/new
|
|||||||
chaiUse(chaiAsPromised);
|
chaiUse(chaiAsPromised);
|
||||||
|
|
||||||
import openpgp from '../initOpenpgp.js';
|
import openpgp from '../initOpenpgp.js';
|
||||||
import crypto from '../../src/crypto';
|
import * as crypto from '../../src/crypto';
|
||||||
import * as random from '../../src/crypto/random.js';
|
|
||||||
import util from '../../src/util.js';
|
import util from '../../src/util.js';
|
||||||
import keyIDType from '../../src/type/keyid.js';
|
import keyIDType from '../../src/type/keyid.js';
|
||||||
import { getPreferredCipherSuite } from '../../src/key';
|
import { getPreferredCipherSuite } from '../../src/key';
|
||||||
@ -3706,7 +3705,7 @@ XfA3pqV4mTzF
|
|||||||
const data = new globalThis.ReadableStream({
|
const data = new globalThis.ReadableStream({
|
||||||
pull(controller) {
|
pull(controller) {
|
||||||
if (i++ < 4) {
|
if (i++ < 4) {
|
||||||
const randomBytes = random.getRandomBytes(10);
|
const randomBytes = crypto.getRandomBytes(10);
|
||||||
controller.enqueue(randomBytes);
|
controller.enqueue(randomBytes);
|
||||||
plaintext.push(randomBytes.slice());
|
plaintext.push(randomBytes.slice());
|
||||||
} else {
|
} else {
|
||||||
|
@ -6,7 +6,7 @@ import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/new
|
|||||||
chaiUse(chaiAsPromised);
|
chaiUse(chaiAsPromised);
|
||||||
|
|
||||||
import openpgp from '../initOpenpgp.js';
|
import openpgp from '../initOpenpgp.js';
|
||||||
import crypto from '../../src/crypto';
|
import * as crypto from '../../src/crypto';
|
||||||
import util from '../../src/util.js';
|
import util from '../../src/util.js';
|
||||||
import * as packet from '../../src/packet';
|
import * as packet from '../../src/packet';
|
||||||
import * as random from '../../src/crypto/random';
|
import * as random from '../../src/crypto/random';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user