From 6da1c53de7852000fd63bacf1809b7e1ea17cf11 Mon Sep 17 00:00:00 2001 From: larabr Date: Mon, 22 Nov 2021 11:51:27 +0100 Subject: [PATCH] Replace strings with integer algorithm identifiers in packet classes (#1410) In several packet classes, we used to store string identifiers for public-key, aead, cipher or hash algorithms. To make the code consistent and to avoid having to convert to/from string values, we now always store integer values instead, e.g. `enums.symmetric.aes128` is used instead of `'aes128'`. This is not expected to be a breaking change for most library users. Note that the type of `Key.getAlgorithmInfo()` and of the session key objects returned and accepted by top-level functions remain unchanged. Affected classes (type changes for some properties and method's arguments): - `PublicKeyPacket`, `PublicSubkeyPacket`, `SecretKeyPacket`, `SecretSubkeyPacket` - `SymEncryptedIntegrityProtectedDataPacket`, `AEADEncryptedDataPacket`, `SymmetricallyEncryptedDataPacket` - `LiteralDataPacket`, `CompressedDataPacket` - `PublicKeyEncryptedSessionKey`, `SymEncryptedSessionKeyPacket` - `SignaturePacket` Other potentially breaking changes: - Removed property `AEADEncryptedDataPacket.aeadAlgo`, since it was redudant given `.aeadAlgorithm`. - Renamed `AEADEncryptedDataPacket.cipherAlgo` -> `.cipherAlgorithm` --- openpgp.d.ts | 25 ++++--- src/crypto/cipher/aes.js | 5 +- src/crypto/crypto.js | 29 +++++++- src/crypto/hash/index.js | 36 +++++----- src/crypto/mode/cfb.js | 40 ++++++++--- src/crypto/mode/eax.js | 7 +- src/crypto/mode/gcm.js | 7 +- src/crypto/mode/ocb.js | 7 +- src/crypto/public_key/elliptic/curves.js | 5 ++ src/crypto/public_key/elliptic/ecdh.js | 10 +-- src/enums.js | 17 ++++- src/key/helper.js | 24 +++---- src/message.js | 48 ++++++++------ src/packet/aead_encrypted_data.js | 38 ++++++----- src/packet/compressed_data.js | 25 +++---- src/packet/literal_data.js | 12 ++-- src/packet/one_pass_signature.js | 8 ++- src/packet/public_key.js | 14 ++-- .../public_key_encrypted_session_key.js | 24 ++++--- src/packet/secret_key.js | 63 ++++++++---------- src/packet/signature.js | 32 ++++----- .../sym_encrypted_integrity_protected_data.js | 15 +++-- src/packet/sym_encrypted_session_key.js | 62 ++++++++++------- src/packet/symmetrically_encrypted_data.js | 14 ++-- src/type/s2k.js | 25 +++---- test/crypto/crypto.js | 19 +++--- test/crypto/eax.js | 4 +- test/crypto/gcm.js | 11 ++-- test/crypto/ocb.js | 7 +- test/crypto/rsa.js | 4 +- test/general/config.js | 2 +- test/general/openpgp.js | 14 ++-- test/general/packet.js | 66 +++++++++---------- test/typescript/definitions.ts | 2 +- 34 files changed, 407 insertions(+), 314 deletions(-) diff --git a/openpgp.d.ts b/openpgp.d.ts index f8da6e7c2..ad7497545 100644 --- a/openpgp.d.ts +++ b/openpgp.d.ts @@ -185,8 +185,8 @@ export function decryptSessionKeys>(options: { messa export function readMessage>(options: { armoredMessage: T, config?: PartialConfig }): Promise>; export function readMessage>(options: { binaryMessage: T, config?: PartialConfig }): Promise>; -export function createMessage>(options: { text: T, filename?: string, date?: Date, type?: DataPacketType }): Promise>; -export function createMessage>(options: { binary: T, filename?: string, date?: Date, type?: DataPacketType }): Promise>; +export function createMessage>(options: { text: T, filename?: string, date?: Date, format?: enums.literalFormatNames }): Promise>; +export function createMessage>(options: { binary: T, filename?: string, date?: Date, format?: enums.literalFormatNames }): Promise>; export function encrypt>(options: EncryptOptions & { message: Message, format?: 'armored' }): Promise< T extends WebStream ? WebStream : @@ -359,7 +359,7 @@ declare abstract class BasePacket { * - A Subkey Packet cannot always be used when a Primary Key Packet is expected (and vice versa). */ declare abstract class BasePublicKeyPacket extends BasePacket { - public algorithm: enums.publicKeyNames; + public algorithm: enums.publicKey; public created: Date; public version: number; public getAlgorithmInfo(): AlgorithmInfo; @@ -417,8 +417,8 @@ export class SymEncryptedIntegrityProtectedDataPacket extends BasePacket { export class AEADEncryptedDataPacket extends BasePacket { static readonly tag: enums.packet.aeadEncryptedData; - private decrypt(sessionKeyAlgorithm: string, sessionKey: Uint8Array, config?: Config): void; - private encrypt(sessionKeyAlgorithm: string, sessionKey: Uint8Array, config?: Config): void; + private decrypt(sessionKeyAlgorithm: enums.symmetric, sessionKey: Uint8Array, config?: Config): void; + private encrypt(sessionKeyAlgorithm: enums.symmetric, sessionKey: Uint8Array, config?: Config): void; private crypt(fn: Function, sessionKey: Uint8Array, data: MaybeStream): MaybeStream } @@ -438,8 +438,8 @@ export class LiteralDataPacket extends BasePacket { static readonly tag: enums.packet.literalData; private getText(clone?: boolean): MaybeStream; private getBytes(clone?: boolean): MaybeStream; - private setText(text: MaybeStream, format?: DataPacketType); - private setBytes(bytes: MaybeStream, format?: DataPacketType); + private setText(text: MaybeStream, format?: enums.literal); + private setBytes(bytes: MaybeStream, format: enums.literal); private setFilename(filename: string); private getFilename(): string; private writeHeader(): Uint8Array; @@ -534,8 +534,6 @@ export type AnyPacket = BasePacket; export type AnySecretKeyPacket = SecretKeyPacket | SecretSubkeyPacket; export type AnyKeyPacket = BasePublicKeyPacket; -type DataPacketType = 'utf8' | 'binary' | 'text' | 'mime'; - type AllowedPackets = Map; // mapping to Packet classes (i.e. typeof LiteralDataPacket etc.) export class PacketList extends Array { static fromBinary(bytes: MaybeStream, allowedPackets: AllowedPackets, config?: Config): PacketList; // the packet types depend on`allowedPackets` @@ -630,7 +628,6 @@ interface SignOptions { message: CleartextMessage | Message>; signingKeys?: MaybeArray; format?: 'armored' | 'binary' | 'object'; - dataType?: DataPacketType; detached?: boolean; signingKeyIDs?: MaybeArray; date?: Date; @@ -876,4 +873,12 @@ export namespace enums { ocb = 2, experimentalGCM = 100 // Private algorithm } + + export type literalFormatNames = 'utf8' | 'binary' | 'text' | 'mime' + enum literal { + binary = 98, + text = 116, + utf8 = 117, + mime = 109 + } } diff --git a/src/crypto/cipher/aes.js b/src/crypto/cipher/aes.js index ea61cc71f..8a985079c 100644 --- a/src/crypto/cipher/aes.js +++ b/src/crypto/cipher/aes.js @@ -1,6 +1,9 @@ import { AES_ECB } from '@openpgp/asmcrypto.js/dist_es8/aes/ecb'; -// TODO use webCrypto or nodeCrypto when possible. +/** + * Javascript AES implementation. + * This is used as fallback if the native Crypto APIs are not available. + */ function aes(length) { const C = function(key) { const aesECB = new AES_ECB(key); diff --git a/src/crypto/crypto.js b/src/crypto/crypto.js index 27bbdd209..ed950d43e 100644 --- a/src/crypto/crypto.js +++ b/src/crypto/crypto.js @@ -26,6 +26,7 @@ import publicKey from './public_key'; import * as cipher from './cipher'; +import mode from './mode'; import { getRandomBytes } from './random'; import ECDHSymkey from '../type/ecdh_symkey'; import KDFParams from '../type/kdf_params'; @@ -348,7 +349,8 @@ export async function validateParams(algo, publicParams, privateParams) { * @async */ export async function getPrefixRandom(algo) { - const prefixrandom = await getRandomBytes(cipher[algo].blockSize); + const { blockSize } = getCipher(algo); + const prefixrandom = await getRandomBytes(blockSize); const repeat = new Uint8Array([prefixrandom[prefixrandom.length - 2], prefixrandom[prefixrandom.length - 1]]); return util.concat([prefixrandom, repeat]); } @@ -361,5 +363,28 @@ export async function getPrefixRandom(algo) { * @async */ export function generateSessionKey(algo) { - return getRandomBytes(cipher[algo].keySize); + const { keySize } = getCipher(algo); + return getRandomBytes(keySize); +} + +/** + * Get implementation of the given AEAD mode + * @param {enums.aead} algo + * @returns {Object} + * @throws {Error} on invalid algo + */ +export function getAEADMode(algo) { + const algoName = enums.read(enums.aead, algo); + return mode[algoName]; +} + +/** + * Get implementation of the given cipher + * @param {enums.symmetric} algo + * @returns {Object} + * @throws {Error} on invalid algo + */ +export function getCipher(algo) { + const algoName = enums.read(enums.symmetric, algo); + return cipher[algoName]; } diff --git a/src/crypto/hash/index.js b/src/crypto/hash/index.js index 76deb9c6b..cfec8d381 100644 --- a/src/crypto/hash/index.js +++ b/src/crypto/hash/index.js @@ -16,6 +16,7 @@ import * as stream from '@openpgp/web-stream-tools'; import md5 from './md5'; import util from '../../util'; import defaultConfig from '../../config'; +import enums from '../../enums'; const webCrypto = util.getWebCrypto(); const nodeCrypto = util.getNodeCrypto(); @@ -110,26 +111,19 @@ export default { */ digest: function(algo, data) { switch (algo) { - case 1: - // - MD5 [HAC] + case enums.hash.md5: return this.md5(data); - case 2: - // - SHA-1 [FIPS180] + case enums.hash.sha1: return this.sha1(data); - case 3: - // - RIPE-MD/160 [HAC] + case enums.hash.ripemd: return this.ripemd(data); - case 8: - // - SHA256 [FIPS180] + case enums.hash.sha256: return this.sha256(data); - case 9: - // - SHA384 [FIPS180] + case enums.hash.sha384: return this.sha384(data); - case 10: - // - SHA512 [FIPS180] + case enums.hash.sha512: return this.sha512(data); - case 11: - // - SHA224 [FIPS180] + case enums.hash.sha224: return this.sha224(data); default: throw new Error('Invalid hash function.'); @@ -143,18 +137,18 @@ export default { */ getHashByteLength: function(algo) { switch (algo) { - case 1: // - MD5 [HAC] + case enums.hash.md5: return 16; - case 2: // - SHA-1 [FIPS180] - case 3: // - RIPE-MD/160 [HAC] + case enums.hash.sha1: + case enums.hash.ripemd: return 20; - case 8: // - SHA256 [FIPS180] + case enums.hash.sha256: return 32; - case 9: // - SHA384 [FIPS180] + case enums.hash.sha384: return 48; - case 10: // - SHA512 [FIPS180] + case enums.hash.sha512: return 64; - case 11: // - SHA224 [FIPS180] + case enums.hash.sha224: return 28; default: throw new Error('Invalid hash algorithm.'); diff --git a/src/crypto/mode/cfb.js b/src/crypto/mode/cfb.js index c1162e996..1871bcda9 100644 --- a/src/crypto/mode/cfb.js +++ b/src/crypto/mode/cfb.js @@ -27,6 +27,7 @@ import { AES_CFB } from '@openpgp/asmcrypto.js/dist_es8/aes/cfb'; import * as stream from '@openpgp/web-stream-tools'; import * as cipher from '../cipher'; import util from '../../util'; +import enums from '../../enums'; const webCrypto = util.getWebCrypto(); const nodeCrypto = util.getNodeCrypto(); @@ -43,15 +44,25 @@ const nodeAlgos = { /* twofish is not implemented in OpenSSL */ }; +/** + * CFB encryption + * @param {enums.symmetric} algo - block cipher algorithm + * @param {Uint8Array} key + * @param {MaybeStream} plaintext + * @param {Uint8Array} iv + * @param {Object} config - full configuration, defaults to openpgp.config + * @returns MaybeStream + */ export async function encrypt(algo, key, plaintext, iv, config) { - if (util.getNodeCrypto() && nodeAlgos[algo]) { // Node crypto library. + const algoName = enums.read(enums.symmetric, algo); + if (util.getNodeCrypto() && nodeAlgos[algoName]) { // Node crypto library. return nodeEncrypt(algo, key, plaintext, iv); } - if (algo.substr(0, 3) === 'aes') { + if (algoName.substr(0, 3) === 'aes') { return aesEncrypt(algo, key, plaintext, iv, config); } - const cipherfn = new cipher[algo](key); + const cipherfn = new cipher[algoName](key); const block_size = cipherfn.blockSize; const blockc = iv.slice(); @@ -76,15 +87,24 @@ export async function encrypt(algo, key, plaintext, iv, config) { return stream.transform(plaintext, process, process); } +/** + * CFB decryption + * @param {enums.symmetric} algo - block cipher algorithm + * @param {Uint8Array} key + * @param {MaybeStream} ciphertext + * @param {Uint8Array} iv + * @returns MaybeStream + */ export async function decrypt(algo, key, ciphertext, iv) { - if (util.getNodeCrypto() && nodeAlgos[algo]) { // Node crypto library. + const algoName = enums.read(enums.symmetric, algo); + if (util.getNodeCrypto() && nodeAlgos[algoName]) { // Node crypto library. return nodeDecrypt(algo, key, ciphertext, iv); } - if (algo.substr(0, 3) === 'aes') { + if (algoName.substr(0, 3) === 'aes') { return aesDecrypt(algo, key, ciphertext, iv); } - const cipherfn = new cipher[algo](key); + const cipherfn = new cipher[algoName](key); const block_size = cipherfn.blockSize; let blockp = iv; @@ -140,7 +160,7 @@ function xorMut(a, b) { async function webEncrypt(algo, key, pt, iv) { const ALGO = 'AES-CBC'; const _key = await webCrypto.importKey('raw', key, { name: ALGO }, false, ['encrypt']); - const { blockSize } = cipher[algo]; + const { blockSize } = crypto.getCipher(algo); const cbc_pt = util.concatUint8Array([new Uint8Array(blockSize), pt]); const ct = new Uint8Array(await webCrypto.encrypt({ name: ALGO, iv }, _key, cbc_pt)).subarray(0, pt.length); xorMut(ct, pt); @@ -148,11 +168,13 @@ async function webEncrypt(algo, key, pt, iv) { } function nodeEncrypt(algo, key, pt, iv) { - const cipherObj = new nodeCrypto.createCipheriv(nodeAlgos[algo], key, iv); + const algoName = enums.read(enums.symmetric, algo); + const cipherObj = new nodeCrypto.createCipheriv(nodeAlgos[algoName], key, iv); return stream.transform(pt, value => new Uint8Array(cipherObj.update(value))); } function nodeDecrypt(algo, key, ct, iv) { - const decipherObj = new nodeCrypto.createDecipheriv(nodeAlgos[algo], key, iv); + const algoName = enums.read(enums.symmetric, algo); + const decipherObj = new nodeCrypto.createDecipheriv(nodeAlgos[algoName], key, iv); return stream.transform(ct, value => new Uint8Array(decipherObj.update(value))); } diff --git a/src/crypto/mode/eax.js b/src/crypto/mode/eax.js index 6d3e434c4..cf68c4600 100644 --- a/src/crypto/mode/eax.js +++ b/src/crypto/mode/eax.js @@ -25,6 +25,7 @@ import { AES_CTR } from '@openpgp/asmcrypto.js/dist_es8/aes/ctr'; import CMAC from '../cmac'; import util from '../../util'; +import enums from '../../enums'; const webCrypto = util.getWebCrypto(); const nodeCrypto = util.getNodeCrypto(); @@ -74,11 +75,13 @@ async function CTR(key) { /** * Class to en/decrypt using EAX mode. - * @param {String} cipher - The symmetric cipher algorithm to use e.g. 'aes128' + * @param {enums.symmetric} cipher - The symmetric cipher algorithm to use * @param {Uint8Array} key - The encryption key */ async function EAX(cipher, key) { - if (cipher.substr(0, 3) !== 'aes') { + if (cipher !== enums.symmetric.aes128 && + cipher !== enums.symmetric.aes192 && + cipher !== enums.symmetric.aes256) { throw new Error('EAX mode supports only AES cipher'); } diff --git a/src/crypto/mode/gcm.js b/src/crypto/mode/gcm.js index 4532eb962..424b7e1af 100644 --- a/src/crypto/mode/gcm.js +++ b/src/crypto/mode/gcm.js @@ -24,6 +24,7 @@ import { AES_GCM } from '@openpgp/asmcrypto.js/dist_es8/aes/gcm'; import util from '../../util'; +import enums from '../../enums'; const webCrypto = util.getWebCrypto(); const nodeCrypto = util.getNodeCrypto(); @@ -36,11 +37,13 @@ const ALGO = 'AES-GCM'; /** * Class to en/decrypt using GCM mode. - * @param {String} cipher - The symmetric cipher algorithm to use e.g. 'aes128' + * @param {enums.symmetric} cipher - The symmetric cipher algorithm to use * @param {Uint8Array} key - The encryption key */ async function GCM(cipher, key) { - if (cipher.substr(0, 3) !== 'aes') { + if (cipher !== enums.symmetric.aes128 && + cipher !== enums.symmetric.aes192 && + cipher !== enums.symmetric.aes256) { throw new Error('GCM mode supports only AES cipher'); } diff --git a/src/crypto/mode/ocb.js b/src/crypto/mode/ocb.js index 9a6e60fec..868b0ebc2 100644 --- a/src/crypto/mode/ocb.js +++ b/src/crypto/mode/ocb.js @@ -23,7 +23,7 @@ import * as ciphers from '../cipher'; import util from '../../util'; - +import enums from '../../enums'; const blockLength = 16; const ivLength = 15; @@ -59,7 +59,7 @@ const one = new Uint8Array([1]); /** * Class to en/decrypt using OCB mode. - * @param {String} cipher - The symmetric cipher algorithm to use e.g. 'aes128' + * @param {enums.symmetric} cipher - The symmetric cipher algorithm to use * @param {Uint8Array} key - The encryption key */ async function OCB(cipher, key) { @@ -72,7 +72,8 @@ async function OCB(cipher, key) { constructKeyVariables(cipher, key); function constructKeyVariables(cipher, key) { - const aes = new ciphers[cipher](key); + const cipherName = enums.read(enums.symmetric, cipher); + const aes = new ciphers[cipherName](key); encipher = aes.encrypt.bind(aes); decipher = aes.decrypt.bind(aes); diff --git a/src/crypto/public_key/elliptic/curves.js b/src/crypto/public_key/elliptic/curves.js index 02db72b5d..e3a0f686e 100644 --- a/src/crypto/public_key/elliptic/curves.js +++ b/src/crypto/public_key/elliptic/curves.js @@ -220,6 +220,11 @@ async function generate(curve) { }; } +/** + * Get preferred hash algo to use with the given curve + * @param {module:type/oid} oid - curve oid + * @returns {enums.hash} hash algorithm + */ function getPreferredHashAlgo(oid) { return curves[enums.write(enums.curve, oid.toHex())].hash; } diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js index d09f52df8..a5de71871 100644 --- a/src/crypto/public_key/elliptic/ecdh.js +++ b/src/crypto/public_key/elliptic/ecdh.js @@ -24,7 +24,6 @@ import nacl from '@openpgp/tweetnacl/nacl-fast-light.js'; import { Curve, jwkToRawPublic, rawPublicToJWK, privateToJWK, validateStandardParams } from './curves'; import * as aesKW from '../../aes_kw'; -import * as cipher from '../../cipher'; import { getRandomBytes } from '../../random'; import hash from '../../hash'; import enums from '../../../enums'; @@ -32,6 +31,7 @@ import util from '../../../util'; import { b64ToUint8Array } from '../../../encoding/base64'; import * as pkcs5 from '../../pkcs5'; import { keyFromPublic, keyFromPrivate, getIndutnyCurve } from './indutnyKey'; +import { getCipher } from '../../crypto'; const webCrypto = util.getWebCrypto(); const nodeCrypto = util.getNodeCrypto(); @@ -132,8 +132,8 @@ export async function encrypt(oid, kdfParams, data, Q, fingerprint) { const curve = new Curve(oid); const { publicKey, sharedKey } = await genPublicEphemeralKey(curve, Q); const param = buildEcdhParam(enums.publicKey.ecdh, oid, kdfParams, fingerprint); - const cipherAlgo = enums.read(enums.symmetric, kdfParams.cipher); - const Z = await kdf(kdfParams.hash, sharedKey, cipher[cipherAlgo].keySize, param); + const { keySize } = getCipher(kdfParams.cipher); + const Z = await kdf(kdfParams.hash, sharedKey, keySize, param); const wrappedKey = aesKW.wrap(Z, m); return { publicKey, wrappedKey }; } @@ -192,12 +192,12 @@ export async function decrypt(oid, kdfParams, V, C, Q, d, fingerprint) { const curve = new Curve(oid); const { sharedKey } = await genPrivateEphemeralKey(curve, V, Q, d); const param = buildEcdhParam(enums.publicKey.ecdh, oid, kdfParams, fingerprint); - const cipherAlgo = enums.read(enums.symmetric, kdfParams.cipher); + const { keySize } = getCipher(kdfParams.cipher); let err; for (let i = 0; i < 3; i++) { try { // Work around old go crypto bug and old OpenPGP.js bug, respectively. - const Z = await kdf(kdfParams.hash, sharedKey, cipher[cipherAlgo].keySize, param, i === 1, i === 2); + const Z = await kdf(kdfParams.hash, sharedKey, keySize, param, i === 1, i === 2); return pkcs5.decode(aesKW.unwrap(Z, C)); } catch (e) { err = e; diff --git a/src/enums.js b/src/enums.js index 16c316013..3f2e15aba 100644 --- a/src/enums.js +++ b/src/enums.js @@ -448,7 +448,13 @@ export default { v5Keys: 4 }, - /** Asserts validity and converts from string/integer to integer. */ + /** + * Asserts validity of given value and converts from string/integer to integer. + * @param {Object} type target enum type + * @param {String|Integer} e value to check and/or convert + * @returns {Integer} enum value if it exists + * @throws {Error} if the value is invalid + */ write: function(type, e) { if (typeof e === 'number') { e = this.read(type, e); @@ -461,7 +467,13 @@ export default { throw new Error('Invalid enum value.'); }, - /** Converts from an integer to string. */ + /** + * Converts enum integer value to the corresponding string, if it exists. + * @param {Object} type target enum type + * @param {Integer} e value to convert + * @returns {String} name of enum value if it exists + * @throws {Error} if the value is invalid + */ read: function(type, e) { if (!type[byValue]) { type[byValue] = []; @@ -476,5 +488,4 @@ export default { throw new Error('Invalid enum value.'); } - }; diff --git a/src/key/helper.js b/src/key/helper.js index a24d3f1cc..0720dde23 100644 --- a/src/key/helper.js +++ b/src/key/helper.js @@ -19,7 +19,7 @@ import defaultConfig from '../config'; export async function generateSecretSubkey(options, config) { const secretSubkeyPacket = new SecretSubkeyPacket(options.date, config); secretSubkeyPacket.packets = null; - secretSubkeyPacket.algorithm = enums.read(enums.publicKey, options.algorithm); + secretSubkeyPacket.algorithm = enums.write(enums.publicKey, options.algorithm); await secretSubkeyPacket.generate(options.rsaBits, options.curve); await secretSubkeyPacket.computeFingerprintAndKeyID(); return secretSubkeyPacket; @@ -28,7 +28,7 @@ export async function generateSecretSubkey(options, config) { export async function generateSecretKey(options, config) { const secretKeyPacket = new SecretKeyPacket(options.date, config); secretKeyPacket.packets = null; - secretKeyPacket.algorithm = enums.read(enums.publicKey, options.algorithm); + secretKeyPacket.algorithm = enums.write(enums.publicKey, options.algorithm); await secretKeyPacket.generate(options.rsaBits, options.curve, options.config); await secretKeyPacket.computeFingerprintAndKeyID(); return secretKeyPacket; @@ -115,7 +115,7 @@ export async function createBindingSignature(subkey, primaryKey, options, config * @param {Date} [date] - Use the given date for verification instead of the current time * @param {Object} [userID] - User ID * @param {Object} config - full configuration - * @returns {Promise} + * @returns {Promise} * @async */ export async function getPreferredHashAlgo(key, keyPacket, date = new Date(), userID = {}, config) { @@ -135,9 +135,9 @@ export async function getPreferredHashAlgo(key, keyPacket, date = new Date(), us case SecretSubkeyPacket.prototype: case PublicSubkeyPacket.prototype: switch (keyPacket.algorithm) { - case 'ecdh': - case 'ecdsa': - case 'eddsa': + case enums.publicKey.ecdh: + case enums.publicKey.ecdsa: + case enums.publicKey.eddsa: prefAlgo = crypto.publicKey.elliptic.getPreferredHashAlgo(keyPacket.publicParams.oid); } } @@ -147,7 +147,7 @@ export async function getPreferredHashAlgo(key, keyPacket, date = new Date(), us /** * Returns the preferred symmetric/aead/compression algorithm for a set of keys - * @param {symmetric|aead|compression} type - Type of preference to return + * @param {'symmetric'|'aead'|'compression'} type - Type of preference to return * @param {Array} [keys] - Set of keys * @param {Date} [date] - Use the given date for verification instead of the current time * @param {Array} [userIDs] - User IDs @@ -361,7 +361,7 @@ export function sanitizeKeyOptions(options, subkeyDefaults = {}) { } export function isValidSigningKeyPacket(keyPacket, signature) { - const keyAlgo = enums.write(enums.publicKey, keyPacket.algorithm); + const keyAlgo = keyPacket.algorithm; return keyAlgo !== enums.publicKey.rsaEncrypt && keyAlgo !== enums.publicKey.elgamal && keyAlgo !== enums.publicKey.ecdh && @@ -370,7 +370,7 @@ export function isValidSigningKeyPacket(keyPacket, signature) { } export function isValidEncryptionKeyPacket(keyPacket, signature) { - const keyAlgo = enums.write(enums.publicKey, keyPacket.algorithm); + const keyAlgo = keyPacket.algorithm; return keyAlgo !== enums.publicKey.dsa && keyAlgo !== enums.publicKey.rsaSign && keyAlgo !== enums.publicKey.ecdsa && @@ -400,10 +400,10 @@ export function isValidDecryptionKeyPacket(signature, config) { */ export function checkKeyRequirements(keyPacket, config) { const keyAlgo = enums.write(enums.publicKey, keyPacket.algorithm); + const algoInfo = keyPacket.getAlgorithmInfo(); if (config.rejectPublicKeyAlgorithms.has(keyAlgo)) { - throw new Error(`${keyPacket.algorithm} keys are considered too weak.`); + throw new Error(`${algoInfo.algorithm} keys are considered too weak.`); } - const algoInfo = keyPacket.getAlgorithmInfo(); switch (keyAlgo) { case enums.publicKey.rsaEncryptSign: case enums.publicKey.rsaSign: @@ -416,7 +416,7 @@ export function checkKeyRequirements(keyPacket, config) { case enums.publicKey.eddsa: case enums.publicKey.ecdh: if (config.rejectCurves.has(algoInfo.curve)) { - throw new Error(`Support for ${keyPacket.algorithm} keys using curve ${algoInfo.curve} is disabled.`); + throw new Error(`Support for ${algoInfo.algorithm} keys using curve ${algoInfo.curve} is disabled.`); } break; default: diff --git a/src/message.js b/src/message.js index 950c3f6c6..d94c6e809 100644 --- a/src/message.js +++ b/src/message.js @@ -107,7 +107,7 @@ export class Message { * @async */ async decrypt(decryptionKeys, passwords, sessionKeys, date = new Date(), config = defaultConfig) { - const keyObjs = sessionKeys || await this.decryptSessionKeys(decryptionKeys, passwords, date, config); + const sessionKeyObjs = sessionKeys || await this.decryptSessionKeys(decryptionKeys, passwords, date, config); const symEncryptedPacketlist = this.packets.filterByTag( enums.packet.symmetricallyEncryptedData, @@ -121,13 +121,14 @@ export class Message { const symEncryptedPacket = symEncryptedPacketlist[0]; let exception = null; - const decryptedPromise = Promise.all(keyObjs.map(async keyObj => { - if (!keyObj || !util.isUint8Array(keyObj.data) || !util.isString(keyObj.algorithm)) { + const decryptedPromise = Promise.all(sessionKeyObjs.map(async ({ algorithm: algorithmName, data }) => { + if (!util.isUint8Array(data) || !util.isString(algorithmName)) { throw new Error('Invalid session key for decryption.'); } try { - await symEncryptedPacket.decrypt(keyObj.algorithm, keyObj.data, config); + const algo = enums.write(enums.symmetric, algorithmName); + await symEncryptedPacket.decrypt(algo, data, config); } catch (e) { util.printDebugError(e); exception = e; @@ -216,7 +217,7 @@ export class Message { } try { await keyPacket.decrypt(decryptionKeyPacket); - if (!algos.includes(enums.write(enums.symmetric, keyPacket.sessionKeyAlgorithm))) { + if (!algos.includes(keyPacket.sessionKeyAlgorithm)) { throw new Error('A non-preferred symmetric algorithm was used.'); } keyPackets.push(keyPacket); @@ -247,7 +248,10 @@ export class Message { }); } - return keyPackets.map(packet => ({ data: packet.sessionKey, algorithm: packet.sessionKeyAlgorithm })); + return keyPackets.map(packet => ({ + data: packet.sessionKey, + algorithm: enums.read(enums.symmetric, packet.sessionKeyAlgorithm) + })); } throw exception || new Error('Session key decryption failed.'); } @@ -295,13 +299,14 @@ export class Message { * @async */ static async generateSessionKey(encryptionKeys = [], date = new Date(), userIDs = [], config = defaultConfig) { - const algorithm = enums.read(enums.symmetric, await getPreferredAlgo('symmetric', encryptionKeys, date, userIDs, config)); - const aeadAlgorithm = config.aeadProtect && await isAEADSupported(encryptionKeys, date, userIDs, config) ? + const algo = await getPreferredAlgo('symmetric', encryptionKeys, date, userIDs, config); + const algorithmName = enums.read(enums.symmetric, algo); + const aeadAlgorithmName = config.aeadProtect && await isAEADSupported(encryptionKeys, date, userIDs, config) ? enums.read(enums.aead, await getPreferredAlgo('aead', encryptionKeys, date, userIDs, config)) : undefined; - const sessionKeyData = await crypto.generateSessionKey(algorithm); - return { data: sessionKeyData, algorithm, aeadAlgorithm }; + const sessionKeyData = await crypto.generateSessionKey(algo); + return { data: sessionKeyData, algorithm: algorithmName, aeadAlgorithm: aeadAlgorithmName }; } /** @@ -330,19 +335,20 @@ export class Message { throw new Error('No keys, passwords, or session key provided.'); } - const { data: sessionKeyData, algorithm, aeadAlgorithm } = sessionKey; + const { data: sessionKeyData, algorithm: algorithmName, aeadAlgorithm: aeadAlgorithmName } = sessionKey; - const msg = await Message.encryptSessionKey(sessionKeyData, algorithm, aeadAlgorithm, encryptionKeys, passwords, wildcard, encryptionKeyIDs, date, userIDs, config); + const msg = await Message.encryptSessionKey(sessionKeyData, algorithmName, aeadAlgorithmName, encryptionKeys, passwords, wildcard, encryptionKeyIDs, date, userIDs, config); let symEncryptedPacket; - if (aeadAlgorithm) { + if (aeadAlgorithmName) { symEncryptedPacket = new AEADEncryptedDataPacket(); - symEncryptedPacket.aeadAlgorithm = aeadAlgorithm; + symEncryptedPacket.aeadAlgorithm = enums.write(enums.aead, aeadAlgorithmName); } else { symEncryptedPacket = new SymEncryptedIntegrityProtectedDataPacket(); } symEncryptedPacket.packets = this.packets; + const algorithm = enums.write(enums.symmetric, algorithmName); await symEncryptedPacket.encrypt(algorithm, sessionKeyData, config); msg.packets.push(symEncryptedPacket); @@ -353,8 +359,8 @@ export class Message { /** * Encrypt a session key either with public keys, passwords, or both at once. * @param {Uint8Array} sessionKey - session key for encryption - * @param {String} algorithm - session key algorithm - * @param {String} [aeadAlgorithm] - AEAD algorithm, e.g. 'eax' or 'ocb' + * @param {String} algorithmName - session key algorithm + * @param {String} [aeadAlgorithmName] - AEAD algorithm, e.g. 'eax' or 'ocb' * @param {Array} [encryptionKeys] - Public key(s) for message encryption * @param {Array} [passwords] - For message encryption * @param {Boolean} [wildcard] - Use a key ID of 0 instead of the public key IDs @@ -365,8 +371,10 @@ export class Message { * @returns {Promise} New message with encrypted content. * @async */ - static async encryptSessionKey(sessionKey, algorithm, aeadAlgorithm, encryptionKeys, passwords, wildcard = false, encryptionKeyIDs = [], date = new Date(), userIDs = [], config = defaultConfig) { + static async encryptSessionKey(sessionKey, algorithmName, aeadAlgorithmName, encryptionKeys, passwords, wildcard = false, encryptionKeyIDs = [], date = new Date(), userIDs = [], config = defaultConfig) { const packetlist = new PacketList(); + const algorithm = enums.write(enums.symmetric, algorithmName); + const aeadAlgorithm = aeadAlgorithmName && enums.write(enums.aead, aeadAlgorithmName); if (encryptionKeys) { const results = await Promise.all(encryptionKeys.map(async function(primaryKey, i) { @@ -499,7 +507,7 @@ export class Message { } const compressed = new CompressedDataPacket(config); - compressed.algorithm = enums.read(enums.compression, algo); + compressed.algorithm = algo; compressed.packets = this.packets; const packetList = new PacketList(); @@ -866,9 +874,9 @@ export async function createMessage({ text, binary, filename, date = new Date(), } const literalDataPacket = new LiteralDataPacket(date); if (text !== undefined) { - literalDataPacket.setText(input, format); + literalDataPacket.setText(input, enums.write(enums.literal, format)); } else { - literalDataPacket.setBytes(input, format); + literalDataPacket.setBytes(input, enums.write(enums.literal, format)); } if (filename !== undefined) { literalDataPacket.setFilename(filename); diff --git a/src/packet/aead_encrypted_data.js b/src/packet/aead_encrypted_data.js index d913cb852..01a305f75 100644 --- a/src/packet/aead_encrypted_data.js +++ b/src/packet/aead_encrypted_data.js @@ -52,9 +52,10 @@ class AEADEncryptedDataPacket { constructor() { this.version = VERSION; - this.cipherAlgo = null; - this.aeadAlgorithm = 'eax'; - this.aeadAlgo = null; + /** @type {enums.symmetric} */ + this.cipherAlgorithm = null; + /** @type {enums.aead} */ + this.aeadAlgorithm = enums.aead.eax; this.chunkSizeByte = null; this.iv = null; this.encrypted = null; @@ -64,6 +65,7 @@ class AEADEncryptedDataPacket { /** * Parse an encrypted payload of bytes in the order: version, IV, ciphertext (see specification) * @param {Uint8Array | ReadableStream} bytes + * @throws {Error} on parsing failure */ async read(bytes) { await stream.parse(bytes, async reader => { @@ -71,10 +73,11 @@ class AEADEncryptedDataPacket { if (version !== VERSION) { // The only currently defined value is 1. throw new UnsupportedError(`Version ${version} of the AEAD-encrypted data packet is not supported.`); } - this.cipherAlgo = await reader.readByte(); - this.aeadAlgo = await reader.readByte(); + this.cipherAlgorithm = await reader.readByte(); + this.aeadAlgorithm = await reader.readByte(); this.chunkSizeByte = await reader.readByte(); - const mode = crypto.mode[enums.read(enums.aead, this.aeadAlgo)]; + + const mode = crypto.getAEADMode(this.aeadAlgorithm); this.iv = await reader.readBytes(mode.ivLength); this.encrypted = reader.remainder(); }); @@ -85,12 +88,12 @@ class AEADEncryptedDataPacket { * @returns {Uint8Array | ReadableStream} The encrypted payload. */ write() { - return util.concat([new Uint8Array([this.version, this.cipherAlgo, this.aeadAlgo, this.chunkSizeByte]), this.iv, this.encrypted]); + return util.concat([new Uint8Array([this.version, this.cipherAlgorithm, this.aeadAlgorithm, this.chunkSizeByte]), this.iv, this.encrypted]); } /** * Decrypt the encrypted payload. - * @param {String} sessionKeyAlgorithm - The session key's cipher algorithm e.g. 'aes128' + * @param {enums.symmetric} sessionKeyAlgorithm - The session key's cipher algorithm * @param {Uint8Array} key - The session key used to encrypt the payload * @param {Object} [config] - Full configuration, defaults to openpgp.config * @throws {Error} if decryption was not successful @@ -105,18 +108,18 @@ class AEADEncryptedDataPacket { } /** - * Encrypt the packet list payload. - * @param {String} sessionKeyAlgorithm - The session key's cipher algorithm e.g. 'aes128' + * Encrypt the packet payload. + * @param {enums.symmetric} sessionKeyAlgorithm - The session key's cipher algorithm * @param {Uint8Array} key - The session key used to encrypt the payload * @param {Object} [config] - Full configuration, defaults to openpgp.config * @throws {Error} if encryption was not successful * @async */ async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) { - this.cipherAlgo = enums.write(enums.symmetric, sessionKeyAlgorithm); - this.aeadAlgo = enums.write(enums.aead, this.aeadAlgorithm); - const mode = crypto.mode[enums.read(enums.aead, this.aeadAlgo)]; - this.iv = await crypto.random.getRandomBytes(mode.ivLength); // generate new random IV + this.cipherAlgorithm = sessionKeyAlgorithm; + + const { ivLength } = crypto.getAEADMode(this.aeadAlgorithm); + this.iv = await crypto.random.getRandomBytes(ivLength); // generate new random IV this.chunkSizeByte = config.aeadChunkSizeByte; const data = this.packets.write(); this.encrypted = await this.crypt('encrypt', key, data); @@ -131,9 +134,8 @@ class AEADEncryptedDataPacket { * @async */ async crypt(fn, key, data) { - const cipher = enums.read(enums.symmetric, this.cipherAlgo); - const mode = crypto.mode[enums.read(enums.aead, this.aeadAlgo)]; - const modeInstance = await mode(cipher, key); + const mode = crypto.getAEADMode(this.aeadAlgorithm); + const modeInstance = await mode(this.cipherAlgorithm, key); const tagLengthIfDecrypting = fn === 'decrypt' ? mode.tagLength : 0; const tagLengthIfEncrypting = fn === 'encrypt' ? mode.tagLength : 0; const chunkSize = 2 ** (this.chunkSizeByte + 6) + tagLengthIfDecrypting; // ((uint64_t)1 << (c + 6)) @@ -142,7 +144,7 @@ class AEADEncryptedDataPacket { const adataTagArray = new Uint8Array(adataBuffer); const adataView = new DataView(adataBuffer); const chunkIndexArray = new Uint8Array(adataBuffer, 5, 8); - adataArray.set([0xC0 | AEADEncryptedDataPacket.tag, this.version, this.cipherAlgo, this.aeadAlgo, this.chunkSizeByte], 0); + adataArray.set([0xC0 | AEADEncryptedDataPacket.tag, this.version, this.cipherAlgorithm, this.aeadAlgorithm, this.chunkSizeByte], 0); let chunkIndex = 0; let latestPromise = Promise.resolve(); let cryptedBytes = 0; diff --git a/src/packet/compressed_data.js b/src/packet/compressed_data.js index 59befa812..e924a46cf 100644 --- a/src/packet/compressed_data.js +++ b/src/packet/compressed_data.js @@ -60,9 +60,9 @@ class CompressedDataPacket { this.packets = null; /** * Compression algorithm - * @type {compression} + * @type {enums.compression} */ - this.algorithm = enums.read(enums.compression, config.preferredCompressionAlgorithm); + this.algorithm = config.preferredCompressionAlgorithm; /** * Compressed packet data @@ -85,7 +85,7 @@ class CompressedDataPacket { await stream.parse(bytes, async reader => { // One octet that gives the algorithm used to compress the packet. - this.algorithm = enums.read(enums.compression, await reader.readByte()); + this.algorithm = await reader.readByte(); // Compressed data, which makes up the remainder of the packet. this.compressed = reader.remainder(); @@ -104,7 +104,7 @@ class CompressedDataPacket { this.compress(); } - return util.concat([new Uint8Array([enums.write(enums.compression, this.algorithm)]), this.compressed]); + return util.concat([new Uint8Array([this.algorithm]), this.compressed]); } @@ -114,23 +114,26 @@ class CompressedDataPacket { * @param {Object} [config] - Full configuration, defaults to openpgp.config */ async decompress(config = defaultConfig) { - - if (!decompress_fns[this.algorithm]) { - throw new Error(this.algorithm + ' decompression not supported'); + const compressionName = enums.read(enums.compression, this.algorithm); + const decompressionFn = decompress_fns[compressionName]; + if (!decompressionFn) { + throw new Error(`${compressionName} decompression not supported`); } - this.packets = await PacketList.fromBinary(decompress_fns[this.algorithm](this.compressed), allowedPackets, config); + this.packets = await PacketList.fromBinary(decompressionFn(this.compressed), allowedPackets, config); } /** * Compress the packet data (member decompressedData) */ compress() { - if (!compress_fns[this.algorithm]) { - throw new Error(this.algorithm + ' compression not supported'); + const compressionName = enums.read(enums.compression, this.algorithm); + const compressionFn = compress_fns[compressionName]; + if (!compressionFn) { + throw new Error(`${compressionName} compression not supported`); } - this.compressed = compress_fns[this.algorithm](this.packets.write(), this.deflateLevel); + this.compressed = compressionFn(this.packets.write(), this.deflateLevel); } } diff --git a/src/packet/literal_data.js b/src/packet/literal_data.js index 5488ffbbf..8740fc53a 100644 --- a/src/packet/literal_data.js +++ b/src/packet/literal_data.js @@ -35,7 +35,7 @@ class LiteralDataPacket { * @param {Date} date - The creation date of the literal package */ constructor(date = new Date()) { - this.format = 'utf8'; // default format for literal data packets + this.format = enums.literal.utf8; // default format for literal data packets this.date = util.normalizeDate(date); this.text = null; // textual data representation this.data = null; // literal data representation @@ -46,9 +46,9 @@ class LiteralDataPacket { * Set the packet data to a javascript native string, end of line * will be normalized to \r\n and by default text is converted to UTF8 * @param {String | ReadableStream} text - Any native javascript string - * @param {utf8|binary|text|mime} [format] - The format of the string of bytes + * @param {enums.literal} [format] - The format of the string of bytes */ - setText(text, format = 'utf8') { + setText(text, format = enums.literal.utf8) { this.format = format; this.text = text; this.data = null; @@ -70,7 +70,7 @@ class LiteralDataPacket { /** * Set the packet data to value represented by the provided string of bytes. * @param {Uint8Array | ReadableStream} bytes - The string of bytes - * @param {utf8|binary|text|mime} format - The format of the string of bytes + * @param {enums.literal} format - The format of the string of bytes */ setBytes(bytes, format) { this.format = format; @@ -123,7 +123,7 @@ class LiteralDataPacket { async read(bytes) { await stream.parse(bytes, async reader => { // - A one-octet field that describes how the data is formatted. - const format = enums.read(enums.literal, await reader.readByte()); + const format = await reader.readByte(); // enums.literal const filename_len = await reader.readByte(); this.filename = util.decodeUTF8(await reader.readBytes(filename_len)); @@ -145,7 +145,7 @@ class LiteralDataPacket { const filename = util.encodeUTF8(this.filename); const filename_length = new Uint8Array([filename.length]); - const format = new Uint8Array([enums.write(enums.literal, this.format)]); + const format = new Uint8Array([this.format]); const date = util.writeDate(this.date); return util.concatUint8Array([format, filename_length, filename, date]); diff --git a/src/packet/one_pass_signature.js b/src/packet/one_pass_signature.js index 6ca206b70..54e8697d2 100644 --- a/src/packet/one_pass_signature.js +++ b/src/packet/one_pass_signature.js @@ -46,16 +46,20 @@ class OnePassSignaturePacket { * A one-octet signature type. * Signature types are described in * {@link https://tools.ietf.org/html/rfc4880#section-5.2.1|RFC4880 Section 5.2.1}. + * @type {enums.signature} + */ this.signatureType = null; /** * A one-octet number describing the hash algorithm used. * @see {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC4880 9.4} + * @type {enums.hash} */ this.hashAlgorithm = null; /** * A one-octet number describing the public-key algorithm used. * @see {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC4880 9.1} + * @type {enums.publicKey} */ this.publicKeyAlgorithm = null; /** An eight-octet number holding the Key ID of the signing key. */ @@ -109,9 +113,7 @@ class OnePassSignaturePacket { * @returns {Uint8Array} A Uint8Array representation of a one-pass signature packet. */ write() { - const start = new Uint8Array([VERSION, enums.write(enums.signature, this.signatureType), - enums.write(enums.hash, this.hashAlgorithm), - enums.write(enums.publicKey, this.publicKeyAlgorithm)]); + const start = new Uint8Array([VERSION, this.signatureType, this.hashAlgorithm, this.publicKeyAlgorithm]); const end = new Uint8Array([this.flags]); diff --git a/src/packet/public_key.js b/src/packet/public_key.js index 7c273e6e0..4a1ef7888 100644 --- a/src/packet/public_key.js +++ b/src/packet/public_key.js @@ -55,7 +55,7 @@ class PublicKeyPacket { this.created = util.normalizeDate(date); /** * Public key algorithm. - * @type {String} + * @type {enums.publicKey} */ this.algorithm = null; /** @@ -115,8 +115,7 @@ class PublicKeyPacket { pos += 4; // - A one-octet number denoting the public-key algorithm of this key. - this.algorithm = enums.read(enums.publicKey, bytes[pos++]); - const algo = enums.write(enums.publicKey, this.algorithm); + this.algorithm = bytes[pos++]; if (this.version === 5) { // - A four-octet scalar octet count for the following key material. @@ -125,7 +124,7 @@ class PublicKeyPacket { // - A series of values comprising the key material. try { - const { read, publicParams } = crypto.parsePublicKeyParams(algo, bytes.subarray(pos)); + const { read, publicParams } = crypto.parsePublicKeyParams(this.algorithm, bytes.subarray(pos)); this.publicParams = publicParams; pos += read; } catch (err) { @@ -149,10 +148,9 @@ class PublicKeyPacket { arr.push(new Uint8Array([this.version])); arr.push(util.writeDate(this.created)); // A one-octet number denoting the public-key algorithm of this key - const algo = enums.write(enums.publicKey, this.algorithm); - arr.push(new Uint8Array([algo])); + arr.push(new Uint8Array([this.algorithm])); - const params = crypto.serializeParams(algo, this.publicParams); + const params = crypto.serializeParams(this.algorithm, this.publicParams); if (this.version === 5) { // A four-octet scalar octet count for the following key material arr.push(util.writeNumber(params.length, 4)); @@ -261,7 +259,7 @@ class PublicKeyPacket { */ getAlgorithmInfo() { const result = {}; - result.algorithm = this.algorithm; + result.algorithm = enums.read(enums.publicKey, this.algorithm); // RSA, DSA or ElGamal public modulo const modulo = this.publicParams.n || this.publicParams.p; if (modulo) { diff --git a/src/packet/public_key_encrypted_session_key.js b/src/packet/public_key_encrypted_session_key.js index 582d355d6..c0bedee7f 100644 --- a/src/packet/public_key_encrypted_session_key.js +++ b/src/packet/public_key_encrypted_session_key.js @@ -51,6 +51,10 @@ class PublicKeyEncryptedSessionKeyPacket { this.publicKeyAlgorithm = null; this.sessionKey = null; + /** + * Algorithm to encrypt the message with + * @type {enums.symmetric} + */ this.sessionKeyAlgorithm = null; /** @type {Object} */ @@ -68,10 +72,8 @@ class PublicKeyEncryptedSessionKeyPacket { throw new UnsupportedError(`Version ${this.version} of the PKESK packet is unsupported.`); } this.publicKeyID.read(bytes.subarray(1, bytes.length)); - this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes[9]); - - const algo = enums.write(enums.publicKey, this.publicKeyAlgorithm); - this.encrypted = crypto.parseEncSessionKeyParams(algo, bytes.subarray(10)); + this.publicKeyAlgorithm = bytes[9]; + this.encrypted = crypto.parseEncSessionKeyParams(this.publicKeyAlgorithm, bytes.subarray(10)); } /** @@ -80,13 +82,11 @@ class PublicKeyEncryptedSessionKeyPacket { * @returns {Uint8Array} The Uint8Array representation. */ write() { - const algo = enums.write(enums.publicKey, this.publicKeyAlgorithm); - const arr = [ new Uint8Array([this.version]), this.publicKeyID.write(), - new Uint8Array([enums.write(enums.publicKey, this.publicKeyAlgorithm)]), - crypto.serializeParams(algo, this.encrypted) + new Uint8Array([this.publicKeyAlgorithm]), + crypto.serializeParams(this.publicKeyAlgorithm, this.encrypted) ]; return util.concatUint8Array(arr); @@ -117,20 +117,18 @@ class PublicKeyEncryptedSessionKeyPacket { * @async */ async decrypt(key) { - const algo = enums.write(enums.publicKey, this.publicKeyAlgorithm); - const keyAlgo = enums.write(enums.publicKey, key.algorithm); // check that session key algo matches the secret key algo - if (algo !== keyAlgo) { + if (this.publicKeyAlgorithm !== key.algorithm) { throw new Error('Decryption error'); } - const decoded = await crypto.publicKeyDecrypt(algo, key.publicParams, key.privateParams, this.encrypted, key.getFingerprintBytes()); + const decoded = await crypto.publicKeyDecrypt(this.publicKeyAlgorithm, key.publicParams, key.privateParams, this.encrypted, key.getFingerprintBytes()); const checksum = decoded.subarray(decoded.length - 2); const sessionKey = decoded.subarray(1, decoded.length - 2); if (!util.equalsUint8Array(checksum, util.writeChecksum(sessionKey))) { throw new Error('Decryption error'); } else { this.sessionKey = sessionKey; - this.sessionKeyAlgorithm = enums.read(enums.symmetric, decoded[0]); + this.sessionKeyAlgorithm = enums.write(enums.symmetric, decoded[0]); } } } diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js index 76584b767..c1ef8c3e5 100644 --- a/src/packet/secret_key.js +++ b/src/packet/secret_key.js @@ -49,7 +49,7 @@ class SecretKeyPacket extends PublicKeyPacket { this.isEncrypted = null; /** * S2K usage - * @type {Integer} + * @type {enums.symmetric} */ this.s2kUsage = 0; /** @@ -58,13 +58,13 @@ class SecretKeyPacket extends PublicKeyPacket { */ this.s2k = null; /** - * Symmetric algorithm - * @type {String} + * Symmetric algorithm to encrypt the key with + * @type {enums.symmetric} */ this.symmetric = null; /** - * AEAD algorithm - * @type {String} + * AEAD algorithm to encrypt the key with (if AEAD protection is enabled) + * @type {enums.aead} */ this.aead = null; /** @@ -79,7 +79,7 @@ class SecretKeyPacket extends PublicKeyPacket { /** * Internal parser for private keys as specified in * {@link https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-04#section-5.5.3|RFC4880bis-04 section 5.5.3} - * @param {String} bytes - Input string to read the packet from + * @param {Uint8Array} bytes - Input string to read the packet from * @async */ async read(bytes) { @@ -102,13 +102,11 @@ class SecretKeyPacket extends PublicKeyPacket { // one-octet symmetric encryption algorithm. if (this.s2kUsage === 255 || this.s2kUsage === 254 || this.s2kUsage === 253) { this.symmetric = bytes[i++]; - this.symmetric = enums.read(enums.symmetric, this.symmetric); // - [Optional] If string-to-key usage octet was 253, a one-octet // AEAD algorithm. if (this.s2kUsage === 253) { this.aead = bytes[i++]; - this.aead = enums.read(enums.aead, this.aead); } // - [Optional] If string-to-key usage octet was 255, 254, or 253, a @@ -122,7 +120,6 @@ class SecretKeyPacket extends PublicKeyPacket { } } else if (this.s2kUsage) { this.symmetric = this.s2kUsage; - this.symmetric = enums.read(enums.symmetric, this.symmetric); } // - [Optional] If secret data is encrypted (string-to-key usage octet @@ -131,7 +128,7 @@ class SecretKeyPacket extends PublicKeyPacket { if (this.s2kUsage) { this.iv = bytes.subarray( i, - i + crypto.cipher[this.symmetric].blockSize + i + crypto.getCipher(this.symmetric).blockSize ); i += this.iv.length; @@ -155,8 +152,7 @@ class SecretKeyPacket extends PublicKeyPacket { throw new Error('Key checksum mismatch'); } try { - const algo = enums.write(enums.publicKey, this.algorithm); - const { privateParams } = crypto.parsePrivateKeyParams(algo, cleartext, this.publicParams); + const { privateParams } = crypto.parsePrivateKeyParams(this.algorithm, cleartext, this.publicParams); this.privateParams = privateParams; } catch (err) { throw new Error('Error reading MPIs'); @@ -177,12 +173,12 @@ class SecretKeyPacket extends PublicKeyPacket { // - [Optional] If string-to-key usage octet was 255, 254, or 253, a // one- octet symmetric encryption algorithm. if (this.s2kUsage === 255 || this.s2kUsage === 254 || this.s2kUsage === 253) { - optionalFieldsArr.push(enums.write(enums.symmetric, this.symmetric)); + optionalFieldsArr.push(this.symmetric); // - [Optional] If string-to-key usage octet was 253, a one-octet // AEAD algorithm. if (this.s2kUsage === 253) { - optionalFieldsArr.push(enums.write(enums.aead, this.aead)); + optionalFieldsArr.push(this.aead); } // - [Optional] If string-to-key usage octet was 255, 254, or 253, a @@ -205,8 +201,7 @@ class SecretKeyPacket extends PublicKeyPacket { if (!this.isDummy()) { if (!this.s2kUsage) { - const algo = enums.write(enums.publicKey, this.algorithm); - this.keyMaterial = crypto.serializeParams(algo, this.privateParams); + this.keyMaterial = crypto.serializeParams(this.algorithm, this.privateParams); } if (this.version === 5) { @@ -258,7 +253,7 @@ class SecretKeyPacket extends PublicKeyPacket { this.s2k.c = 0; this.s2k.type = 'gnu-dummy'; this.s2kUsage = 254; - this.symmetric = 'aes256'; + this.symmetric = enums.symmetric.aes256; } /** @@ -289,17 +284,17 @@ class SecretKeyPacket extends PublicKeyPacket { this.s2k = new S2K(config); this.s2k.salt = await crypto.random.getRandomBytes(8); - const algo = enums.write(enums.publicKey, this.algorithm); - const cleartext = crypto.serializeParams(algo, this.privateParams); - this.symmetric = 'aes256'; + const cleartext = crypto.serializeParams(this.algorithm, this.privateParams); + this.symmetric = enums.symmetric.aes256; const key = await produceEncryptionKey(this.s2k, passphrase, this.symmetric); - const blockLen = crypto.cipher[this.symmetric].blockSize; - this.iv = await crypto.random.getRandomBytes(blockLen); + + const { blockSize } = crypto.getCipher(this.symmetric); + this.iv = await crypto.random.getRandomBytes(blockSize); if (config.aeadProtect) { this.s2kUsage = 253; - this.aead = 'eax'; - const mode = crypto.mode[this.aead]; + this.aead = enums.aead.eax; + const mode = crypto.getAEADMode(this.aead); const modeInstance = await mode(this.symmetric, key); this.keyMaterial = await modeInstance.encrypt(cleartext, this.iv.subarray(0, mode.ivLength), new Uint8Array()); } else { @@ -340,9 +335,9 @@ class SecretKeyPacket extends PublicKeyPacket { let cleartext; if (this.s2kUsage === 253) { - const mode = crypto.mode[this.aead]; + const mode = crypto.getAEADMode(this.aead); + const modeInstance = await mode(this.symmetric, key); try { - const modeInstance = await mode(this.symmetric, key); cleartext = await modeInstance.decrypt(this.keyMaterial, this.iv.subarray(0, mode.ivLength), new Uint8Array()); } catch (err) { if (err.message === 'Authentication tag mismatch') { @@ -362,8 +357,7 @@ class SecretKeyPacket extends PublicKeyPacket { } try { - const algo = enums.write(enums.publicKey, this.algorithm); - const { privateParams } = crypto.parsePrivateKeyParams(algo, cleartext, this.publicParams); + const { privateParams } = crypto.parsePrivateKeyParams(this.algorithm, cleartext, this.publicParams); this.privateParams = privateParams; } catch (err) { throw new Error('Error reading MPIs'); @@ -387,12 +381,10 @@ class SecretKeyPacket extends PublicKeyPacket { throw new Error('Key is not decrypted'); } - const algo = enums.write(enums.publicKey, this.algorithm); - let validParams; try { // this can throw if some parameters are undefined - validParams = await crypto.validateParams(algo, this.publicParams, this.privateParams); + validParams = await crypto.validateParams(this.algorithm, this.publicParams, this.privateParams); } catch (_) { validParams = false; } @@ -402,8 +394,7 @@ class SecretKeyPacket extends PublicKeyPacket { } async generate(bits, curve) { - const algo = enums.write(enums.publicKey, this.algorithm); - const { privateParams, publicParams } = await crypto.generateParams(algo, bits, curve); + const { privateParams, publicParams } = await crypto.generateParams(this.algorithm, bits, curve); this.privateParams = privateParams; this.publicParams = publicParams; this.isEncrypted = false; @@ -428,10 +419,8 @@ class SecretKeyPacket extends PublicKeyPacket { } async function produceEncryptionKey(s2k, passphrase, algorithm) { - return s2k.produceKey( - passphrase, - crypto.cipher[algorithm].keySize - ); + const { keySize } = crypto.getCipher(algorithm); + return s2k.produceKey(passphrase, keySize); } export default SecretKeyPacket; diff --git a/src/packet/signature.js b/src/packet/signature.js index 78d74c799..d0b01d0a3 100644 --- a/src/packet/signature.js +++ b/src/packet/signature.js @@ -50,8 +50,11 @@ class SignaturePacket { constructor() { this.version = null; + /** @type {enums.signature} */ this.signatureType = null; + /** @type {enums.hash} */ this.hashAlgorithm = null; + /** @type {enums.publicKey} */ this.publicKeyAlgorithm = null; this.signatureData = null; @@ -170,16 +173,12 @@ class SignaturePacket { * @async */ async sign(key, data, date = new Date(), detached = false) { - const signatureType = enums.write(enums.signature, this.signatureType); - const publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm); - const hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm); - if (key.version === 5) { this.version = 5; } else { this.version = 4; } - const arr = [new Uint8Array([this.version, signatureType, publicKeyAlgorithm, hashAlgorithm])]; + const arr = [new Uint8Array([this.version, this.signatureType, this.publicKeyAlgorithm, this.hashAlgorithm])]; this.created = util.normalizeDate(date); this.issuerKeyVersion = key.version; @@ -191,12 +190,12 @@ class SignaturePacket { this.signatureData = util.concat(arr); - const toHash = this.toHash(signatureType, data, detached); - const hash = await this.hash(signatureType, data, toHash, detached); + const toHash = this.toHash(this.signatureType, data, detached); + const hash = await this.hash(this.signatureType, data, toHash, detached); this.signedHashValue = stream.slice(stream.clone(hash), 0, 2); const signed = async () => crypto.signature.sign( - publicKeyAlgorithm, hashAlgorithm, key.publicParams, key.privateParams, toHash, await stream.readToEnd(hash) + this.publicKeyAlgorithm, this.hashAlgorithm, key.publicParams, key.privateParams, toHash, await stream.readToEnd(hash) ); if (util.isStream(hash)) { this.params = signed(); @@ -644,9 +643,8 @@ class SignaturePacket { } async hash(signatureType, data, toHash, detached = false) { - const hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm); if (!toHash) toHash = this.toHash(signatureType, data, detached); - return crypto.hash.digest(hashAlgorithm, toHash); + return crypto.hash.digest(this.hashAlgorithm, toHash); } /** @@ -662,12 +660,10 @@ class SignaturePacket { * @async */ async verify(key, signatureType, data, date = new Date(), detached = false, config = defaultConfig) { - const publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm); - const hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm); if (!this.issuerKeyID.equals(key.getKeyID())) { throw new Error('Signature was not issued by the given public key'); } - if (publicKeyAlgorithm !== enums.write(enums.publicKey, key.algorithm)) { + if (this.publicKeyAlgorithm !== key.algorithm) { throw new Error('Public key algorithm used to sign signature does not match issuer key algorithm.'); } @@ -693,7 +689,7 @@ class SignaturePacket { this.params = await this.params; this[verified] = await crypto.signature.verify( - publicKeyAlgorithm, hashAlgorithm, this.params, key.publicParams, + this.publicKeyAlgorithm, this.hashAlgorithm, this.params, key.publicParams, toHash, hash ); @@ -709,12 +705,12 @@ class SignaturePacket { if (normDate && normDate >= this.getExpirationTime()) { throw new Error('Signature is expired'); } - if (config.rejectHashAlgorithms.has(hashAlgorithm)) { - throw new Error('Insecure hash algorithm: ' + enums.read(enums.hash, hashAlgorithm).toUpperCase()); + if (config.rejectHashAlgorithms.has(this.hashAlgorithm)) { + throw new Error('Insecure hash algorithm: ' + enums.read(enums.hash, this.hashAlgorithm).toUpperCase()); } - if (config.rejectMessageHashAlgorithms.has(hashAlgorithm) && + if (config.rejectMessageHashAlgorithms.has(this.hashAlgorithm) && [enums.signature.binary, enums.signature.text].includes(this.signatureType)) { - throw new Error('Insecure message hash algorithm: ' + enums.read(enums.hash, hashAlgorithm).toUpperCase()); + throw new Error('Insecure message hash algorithm: ' + enums.read(enums.hash, this.hashAlgorithm).toUpperCase()); } this.rawNotations.forEach(({ name, critical }) => { if (critical && (config.knownNotations.indexOf(name) < 0)) { diff --git a/src/packet/sym_encrypted_integrity_protected_data.js b/src/packet/sym_encrypted_integrity_protected_data.js index e081aff76..d1099a9f6 100644 --- a/src/packet/sym_encrypted_integrity_protected_data.js +++ b/src/packet/sym_encrypted_integrity_protected_data.js @@ -80,13 +80,16 @@ class SymEncryptedIntegrityProtectedDataPacket { /** * Encrypt the payload in the packet. - * @param {String} sessionKeyAlgorithm - The selected symmetric encryption algorithm to be used e.g. 'aes128' + * @param {enums.symmetric} sessionKeyAlgorithm - The symmetric encryption algorithm to use * @param {Uint8Array} key - The key of cipher blocksize length to be used * @param {Object} [config] - Full configuration, defaults to openpgp.config * @returns {Promise} + * @throws {Error} on encryption failure * @async */ async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) { + const { blockSize } = crypto.getCipher(sessionKeyAlgorithm); + let bytes = this.packets.write(); if (stream.isArrayStream(bytes)) bytes = await stream.readToEnd(bytes); const prefix = await crypto.getPrefixRandom(sessionKeyAlgorithm); @@ -96,22 +99,24 @@ class SymEncryptedIntegrityProtectedDataPacket { const hash = await crypto.hash.sha1(stream.passiveClone(tohash)); const plaintext = util.concat([tohash, hash]); - this.encrypted = await crypto.mode.cfb.encrypt(sessionKeyAlgorithm, key, plaintext, new Uint8Array(crypto.cipher[sessionKeyAlgorithm].blockSize), config); + this.encrypted = await crypto.mode.cfb.encrypt(sessionKeyAlgorithm, key, plaintext, new Uint8Array(blockSize), config); return true; } /** * Decrypts the encrypted data contained in the packet. - * @param {String} sessionKeyAlgorithm - The selected symmetric encryption algorithm to be used e.g. 'aes128' + * @param {enums.symmetric} sessionKeyAlgorithm - The selected symmetric encryption algorithm to be used * @param {Uint8Array} key - The key of cipher blocksize length to be used * @param {Object} [config] - Full configuration, defaults to openpgp.config * @returns {Promise} + * @throws {Error} on decryption failure * @async */ async decrypt(sessionKeyAlgorithm, key, config = defaultConfig) { + const { blockSize } = crypto.getCipher(sessionKeyAlgorithm); let encrypted = stream.clone(this.encrypted); if (stream.isArrayStream(encrypted)) encrypted = await stream.readToEnd(encrypted); - const decrypted = await crypto.mode.cfb.decrypt(sessionKeyAlgorithm, key, encrypted, new Uint8Array(crypto.cipher[sessionKeyAlgorithm].blockSize)); + const decrypted = await crypto.mode.cfb.decrypt(sessionKeyAlgorithm, key, encrypted, new Uint8Array(blockSize)); // there must be a modification detection code packet as the // last packet and everything gets hashed except the hash itself @@ -126,7 +131,7 @@ class SymEncryptedIntegrityProtectedDataPacket { } return new Uint8Array(); }); - const bytes = stream.slice(tohash, crypto.cipher[sessionKeyAlgorithm].blockSize + 2); // Remove random prefix + const bytes = stream.slice(tohash, blockSize + 2); // Remove random prefix let packetbytes = stream.slice(bytes, 0, -2); // Remove MDC packet packetbytes = stream.concat([packetbytes, stream.fromAsync(() => verifyHash)]); if (!util.isStream(encrypted) || !config.allowUnauthenticatedStream) { diff --git a/src/packet/sym_encrypted_session_key.js b/src/packet/sym_encrypted_session_key.js index ceaaeb9b8..ca8acba31 100644 --- a/src/packet/sym_encrypted_session_key.js +++ b/src/packet/sym_encrypted_session_key.js @@ -46,9 +46,21 @@ class SymEncryptedSessionKeyPacket { constructor(config = defaultConfig) { this.version = config.aeadProtect ? 5 : 4; this.sessionKey = null; + /** + * Algorithm to encrypt the session key with + * @type {enums.symmetric} + */ this.sessionKeyEncryptionAlgorithm = null; - this.sessionKeyAlgorithm = 'aes256'; - this.aeadAlgorithm = enums.read(enums.aead, config.preferredAEADAlgorithm); + /** + * Algorithm to encrypt the message with + * @type {enums.symmetric} + */ + this.sessionKeyAlgorithm = enums.symmetric.aes256; + /** + * AEAD mode to encrypt the session key with (if AEAD protection is enabled) + * @type {enums.aead} + */ + this.aeadAlgorithm = enums.write(enums.aead, config.preferredAEADAlgorithm); this.encrypted = null; this.s2k = null; this.iv = null; @@ -69,11 +81,11 @@ class SymEncryptedSessionKeyPacket { } // A one-octet number describing the symmetric algorithm used. - const algo = enums.read(enums.symmetric, bytes[offset++]); + const algo = bytes[offset++]; if (this.version === 5) { // A one-octet AEAD algorithm. - this.aeadAlgorithm = enums.read(enums.aead, bytes[offset++]); + this.aeadAlgorithm = bytes[offset++]; } // A string-to-key (S2K) specifier, length as defined above. @@ -81,7 +93,7 @@ class SymEncryptedSessionKeyPacket { offset += this.s2k.read(bytes.subarray(offset, bytes.length)); if (this.version === 5) { - const mode = crypto.mode[this.aeadAlgorithm]; + const mode = crypto.getAEADMode(this.aeadAlgorithm); // A starting initialization vector of size specified by the AEAD // algorithm. @@ -111,9 +123,9 @@ class SymEncryptedSessionKeyPacket { let bytes; if (this.version === 5) { - bytes = util.concatUint8Array([new Uint8Array([this.version, enums.write(enums.symmetric, algo), enums.write(enums.aead, this.aeadAlgorithm)]), this.s2k.write(), this.iv, this.encrypted]); + bytes = util.concatUint8Array([new Uint8Array([this.version, algo, this.aeadAlgorithm]), this.s2k.write(), this.iv, this.encrypted]); } else { - bytes = util.concatUint8Array([new Uint8Array([this.version, enums.write(enums.symmetric, algo)]), this.s2k.write()]); + bytes = util.concatUint8Array([new Uint8Array([this.version, algo]), this.s2k.write()]); if (this.encrypted !== null) { bytes = util.concatUint8Array([bytes, this.encrypted]); @@ -124,7 +136,7 @@ class SymEncryptedSessionKeyPacket { } /** - * Decrypts the session key + * Decrypts the session key with the given passphrase * @param {String} passphrase - The passphrase in string form * @throws {Error} if decryption was not successful * @async @@ -134,18 +146,18 @@ class SymEncryptedSessionKeyPacket { this.sessionKeyEncryptionAlgorithm : this.sessionKeyAlgorithm; - const length = crypto.cipher[algo].keySize; - const key = await this.s2k.produceKey(passphrase, length); + const { blockSize, keySize } = crypto.getCipher(algo); + const key = await this.s2k.produceKey(passphrase, keySize); if (this.version === 5) { - const mode = crypto.mode[this.aeadAlgorithm]; - const adata = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, enums.write(enums.symmetric, this.sessionKeyEncryptionAlgorithm), enums.write(enums.aead, this.aeadAlgorithm)]); + const mode = crypto.getAEADMode(this.aeadAlgorithm); + const adata = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, this.sessionKeyEncryptionAlgorithm, this.aeadAlgorithm]); const modeInstance = await mode(algo, key); this.sessionKey = await modeInstance.decrypt(this.encrypted, this.iv, adata); } else if (this.encrypted !== null) { - const decrypted = await crypto.mode.cfb.decrypt(algo, key, this.encrypted, new Uint8Array(crypto.cipher[algo].blockSize)); + const decrypted = await crypto.mode.cfb.decrypt(algo, key, this.encrypted, new Uint8Array(blockSize)); - this.sessionKeyAlgorithm = enums.read(enums.symmetric, decrypted[0]); + this.sessionKeyAlgorithm = enums.write(enums.symmetric, decrypted[0]); this.sessionKey = decrypted.subarray(1, decrypted.length); } else { this.sessionKey = key; @@ -153,7 +165,7 @@ class SymEncryptedSessionKeyPacket { } /** - * Encrypts the session key + * Encrypts the session key with the given passphrase * @param {String} passphrase - The passphrase in string form * @param {Object} [config] - Full configuration, defaults to openpgp.config * @throws {Error} if encryption was not successful @@ -169,23 +181,25 @@ class SymEncryptedSessionKeyPacket { this.s2k = new S2K(config); this.s2k.salt = await crypto.random.getRandomBytes(8); - const length = crypto.cipher[algo].keySize; - const key = await this.s2k.produceKey(passphrase, length); + const { blockSize, keySize } = crypto.getCipher(algo); + const encryptionKey = await this.s2k.produceKey(passphrase, keySize); if (this.sessionKey === null) { this.sessionKey = await crypto.generateSessionKey(this.sessionKeyAlgorithm); } if (this.version === 5) { - const mode = crypto.mode[this.aeadAlgorithm]; + const mode = crypto.getAEADMode(this.aeadAlgorithm); this.iv = await crypto.random.getRandomBytes(mode.ivLength); // generate new random IV - const adata = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, enums.write(enums.symmetric, this.sessionKeyEncryptionAlgorithm), enums.write(enums.aead, this.aeadAlgorithm)]); - const modeInstance = await mode(algo, key); - this.encrypted = await modeInstance.encrypt(this.sessionKey, this.iv, adata); + const associatedData = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, this.sessionKeyEncryptionAlgorithm, this.aeadAlgorithm]); + const modeInstance = await mode(algo, encryptionKey); + this.encrypted = await modeInstance.encrypt(this.sessionKey, this.iv, associatedData); } else { - const algo_enum = new Uint8Array([enums.write(enums.symmetric, this.sessionKeyAlgorithm)]); - const private_key = util.concatUint8Array([algo_enum, this.sessionKey]); - this.encrypted = await crypto.mode.cfb.encrypt(algo, key, private_key, new Uint8Array(crypto.cipher[algo].blockSize), config); + const toEncrypt = util.concatUint8Array([ + new Uint8Array([this.sessionKeyAlgorithm]), + this.sessionKey + ]); + this.encrypted = await crypto.mode.cfb.encrypt(algo, encryptionKey, toEncrypt, new Uint8Array(blockSize), config); } } } diff --git a/src/packet/symmetrically_encrypted_data.js b/src/packet/symmetrically_encrypted_data.js index 265ecda70..ff4fd3d34 100644 --- a/src/packet/symmetrically_encrypted_data.js +++ b/src/packet/symmetrically_encrypted_data.js @@ -86,10 +86,11 @@ class SymmetricallyEncryptedDataPacket { throw new Error('Message is not authenticated.'); } + const { blockSize } = crypto.getCipher(sessionKeyAlgorithm); const encrypted = await stream.readToEnd(stream.clone(this.encrypted)); const decrypted = await crypto.mode.cfb.decrypt(sessionKeyAlgorithm, key, - encrypted.subarray(crypto.cipher[sessionKeyAlgorithm].blockSize + 2), - encrypted.subarray(2, crypto.cipher[sessionKeyAlgorithm].blockSize + 2) + encrypted.subarray(blockSize + 2), + encrypted.subarray(2, blockSize + 2) ); this.packets = await PacketList.fromBinary(decrypted, allowedPackets, config); @@ -104,12 +105,13 @@ class SymmetricallyEncryptedDataPacket { * @throws {Error} if encryption was not successful * @async */ - async encrypt(algo, key, config = defaultConfig) { + async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) { const data = this.packets.write(); + const { blockSize } = crypto.getCipher(sessionKeyAlgorithm); - const prefix = await crypto.getPrefixRandom(algo); - const FRE = await crypto.mode.cfb.encrypt(algo, key, prefix, new Uint8Array(crypto.cipher[algo].blockSize), config); - const ciphertext = await crypto.mode.cfb.encrypt(algo, key, data, FRE.subarray(2), config); + const prefix = await crypto.getPrefixRandom(sessionKeyAlgorithm); + const FRE = await crypto.mode.cfb.encrypt(sessionKeyAlgorithm, key, prefix, new Uint8Array(blockSize), config); + const ciphertext = await crypto.mode.cfb.encrypt(sessionKeyAlgorithm, key, data, FRE.subarray(2), config); this.encrypted = util.concat([FRE, ciphertext]); } } diff --git a/src/type/s2k.js b/src/type/s2k.js index 9fcf56555..abd33e9d8 100644 --- a/src/type/s2k.js +++ b/src/type/s2k.js @@ -38,14 +38,20 @@ class S2K { * @param {Object} [config] - Full configuration, defaults to openpgp.config */ constructor(config = defaultConfig) { - /** @type {module:enums.hash} */ - this.algorithm = 'sha256'; - /** @type {module:enums.s2k} */ + /** + * Hash function identifier, or 0 for gnu-dummy keys + * @type {module:enums.hash | 0} + */ + this.algorithm = enums.hash.sha256; + /** + * enums.s2k identifier or 'gnu-dummy' + * @type {String} + */ this.type = 'iterated'; /** @type {Integer} */ this.c = config.s2kIterationCountByte; /** Eight bytes of salt in a binary string. - * @type {String} + * @type {Uint8Array} */ this.salt = null; } @@ -59,16 +65,13 @@ class S2K { /** * Parsing function for a string-to-key specifier ({@link https://tools.ietf.org/html/rfc4880#section-3.7|RFC 4880 3.7}). - * @param {String} bytes - Payload of string-to-key specifier + * @param {Uint8Array} bytes - Payload of string-to-key specifier * @returns {Integer} Actual length of the object. */ read(bytes) { let i = 0; this.type = enums.read(enums.s2k, bytes[i++]); this.algorithm = bytes[i++]; - if (this.type !== 'gnu') { - this.algorithm = enums.read(enums.hash, this.algorithm); - } switch (this.type) { case 'simple': @@ -117,8 +120,7 @@ class S2K { if (this.type === 'gnu-dummy') { return new Uint8Array([101, 0, ...util.stringToUint8Array('GNU'), 1]); } - - const arr = [new Uint8Array([enums.write(enums.s2k, this.type), enums.write(enums.hash, this.algorithm)])]; + const arr = [new Uint8Array([enums.write(enums.s2k, this.type), this.algorithm])]; switch (this.type) { case 'simple': @@ -149,7 +151,6 @@ class S2K { */ async produceKey(passphrase, numBytes) { passphrase = util.encodeUTF8(passphrase); - const algorithm = enums.write(enums.hash, this.algorithm); const arr = []; let rlength = 0; @@ -180,7 +181,7 @@ class S2K { default: throw new Error('Unknown s2k type.'); } - const result = await crypto.hash.digest(algorithm, toHash); + const result = await crypto.hash.digest(this.algorithm, toHash); arr.push(result); rlength += result.length; prefixlen++; diff --git a/test/crypto/crypto.js b/test/crypto/crypto.js index 5668ead4f..baeb759fb 100644 --- a/test/crypto/crypto.js +++ b/test/crypto/crypto.js @@ -233,17 +233,18 @@ module.exports = () => describe('API functional testing', function() { }); describe('Encrypt and decrypt', function () { - let symmAlgos = Object.keys(openpgp.enums.symmetric); - symmAlgos = symmAlgos.filter(function(algo) { - return algo !== 'idea' && algo !== 'plaintext'; - }); + const symmAlgoNames = Object.keys(openpgp.enums.symmetric).filter( + algo => algo !== 'idea' && algo !== 'plaintext' + ); async function testCFB(plaintext) { - await Promise.all(symmAlgos.map(async function(algo) { + await Promise.all(symmAlgoNames.map(async function(algoName) { + const algo = openpgp.enums.write(openpgp.enums.symmetric, algoName); + const { blockSize } = crypto.getCipher(algo); const symmKey = await crypto.generateSessionKey(algo); - const IV = new Uint8Array(crypto.cipher[algo].blockSize); + const IV = new Uint8Array(blockSize); const symmencData = await crypto.mode.cfb.encrypt(algo, symmKey, util.stringToUint8Array(plaintext), IV, openpgp.config); - const text = util.uint8ArrayToString(await crypto.mode.cfb.decrypt(algo, symmKey, symmencData, new Uint8Array(crypto.cipher[algo].blockSize))); + const text = util.uint8ArrayToString(await crypto.mode.cfb.decrypt(algo, symmKey, symmencData, new Uint8Array(blockSize))); expect(text).to.equal(plaintext); })); } @@ -255,7 +256,7 @@ module.exports = () => describe('API functional testing', function() { }); it('Asymmetric using RSA with eme_pkcs1 padding', async function () { - const symmKey = await crypto.generateSessionKey('aes256'); + const symmKey = await crypto.generateSessionKey(openpgp.enums.symmetric.aes256); return crypto.publicKeyEncrypt(algoRSA, RSAPublicParams, symmKey).then(RSAEncryptedData => { return crypto.publicKeyDecrypt( algoRSA, RSAPublicParams, RSAPrivateParams, RSAEncryptedData @@ -266,7 +267,7 @@ module.exports = () => describe('API functional testing', function() { }); it('Asymmetric using Elgamal with eme_pkcs1 padding', async function () { - const symmKey = await crypto.generateSessionKey('aes256'); + const symmKey = await crypto.generateSessionKey(openpgp.enums.symmetric.aes256); return crypto.publicKeyEncrypt(algoElGamal, elGamalPublicParams, symmKey).then(ElgamalEncryptedData => { return crypto.publicKeyDecrypt( algoElGamal, elGamalPublicParams, elGamalPrivateParams, ElgamalEncryptedData diff --git a/test/crypto/eax.js b/test/crypto/eax.js index d137ac02e..b7280b048 100644 --- a/test/crypto/eax.js +++ b/test/crypto/eax.js @@ -1,7 +1,7 @@ // Modified by ProtonTech AG // Adapted from https://github.com/artjomb/cryptojs-extension/blob/8c61d159/test/eax.js - +const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..'); const EAX = require('../../src/crypto/mode/eax'); const util = require('../../src/util'); @@ -87,7 +87,7 @@ function testAESEAX() { } ]; - const cipher = 'aes128'; + const cipher = openpgp.enums.symmetric.aes128; await Promise.all(vectors.map(async vec => { const keyBytes = util.hexToUint8Array(vec.key); diff --git a/test/crypto/gcm.js b/test/crypto/gcm.js index 57aa83f48..0ffc40cb5 100644 --- a/test/crypto/gcm.js +++ b/test/crypto/gcm.js @@ -34,16 +34,17 @@ module.exports = () => describe('Symmetric AES-GCM (experimental)', function() { }; function testAESGCM(plaintext, nativeEncrypt, nativeDecrypt) { - const aesAlgos = Object.keys(openpgp.enums.symmetric).filter( - algo => algo.substr(0,3) === 'aes' + const aesAlgoNames = Object.keys(openpgp.enums.symmetric).filter( + algoName => algoName.substr(0,3) === 'aes' ); - aesAlgos.forEach(function(algo) { - it(algo, async function() { + aesAlgoNames.forEach(function(algoName) { + it(algoName, async function() { const nodeCrypto = util.getNodeCrypto(); const webCrypto = util.getWebCrypto(); if (!nodeCrypto && !webCrypto) { this.skip(); // eslint-disable-line no-invalid-this } + const algo = openpgp.enums.write(openpgp.enums.symmetric, algoName); const key = await crypto.generateSessionKey(algo); const iv = await crypto.random.getRandomBytes(crypto.mode.gcm.ivLength); @@ -63,7 +64,7 @@ module.exports = () => describe('Symmetric AES-GCM (experimental)', function() { const decryptedStr = util.uint8ArrayToString(decrypted); expect(decryptedStr).to.equal(plaintext); - if (algo !== 'aes192') { // not implemented by webcrypto + if (algo !== openpgp.enums.symmetric.aes192) { // not implemented by webcrypto // sanity check: native crypto was indeed on/off expect(nativeEncryptSpy.called).to.equal(nativeEncrypt); expect(nativeDecryptSpy.called).to.equal(nativeDecrypt); diff --git a/test/crypto/ocb.js b/test/crypto/ocb.js index 588a888d7..b1cf846d0 100644 --- a/test/crypto/ocb.js +++ b/test/crypto/ocb.js @@ -1,7 +1,7 @@ // Modified by ProtonTech AG // Adapted from https://github.com/artjomb/cryptojs-extension/blob/8c61d159/test/eax.js - +const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..'); const OCB = require('../../src/crypto/mode/ocb'); const util = require('../../src/util'); @@ -115,7 +115,7 @@ module.exports = () => describe('Symmetric AES-OCB', function() { } ]; - const cipher = 'aes128'; + const cipher = openpgp.enums.symmetric.aes128; await Promise.all(vectors.map(async vec => { const msgBytes = util.hexToUint8Array(vec.P); @@ -163,7 +163,8 @@ module.exports = () => describe('Symmetric AES-OCB', function() { const k = new Uint8Array(keylen / 8); k[k.length - 1] = taglen; - const ocb = await OCB('aes' + keylen, k); + const algo = openpgp.enums.write(openpgp.enums.symmetric, 'aes' + keylen); + const ocb = await OCB(algo, k); const c = []; let n; diff --git a/test/crypto/rsa.js b/test/crypto/rsa.js index 4f4a5d55d..bc1f4198c 100644 --- a/test/crypto/rsa.js +++ b/test/crypto/rsa.js @@ -79,7 +79,7 @@ module.exports = () => describe('basic RSA cryptography', function () { const bits = 1024; const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits); const { n, e, d, p, q, u } = { ...publicParams, ...privateParams }; - const message = await crypto.generateSessionKey('aes256'); + const message = await crypto.generateSessionKey(openpgp.enums.symmetric.aes256); const encrypted = await crypto.publicKey.rsa.encrypt(message, n, e); const decrypted = await crypto.publicKey.rsa.decrypt(encrypted, n, e, d, p, q, u); expect(decrypted).to.deep.equal(message); @@ -92,7 +92,7 @@ module.exports = () => describe('basic RSA cryptography', function () { const bits = 1024; const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits); const { n, e, d, p, q, u } = { ...publicParams, ...privateParams }; - const message = await crypto.generateSessionKey('aes256'); + const message = await crypto.generateSessionKey(openpgp.enums.symmetric.aes256); disableNative(); const encryptedBn = await crypto.publicKey.rsa.encrypt(message, n, e); enableNative(); diff --git a/test/general/config.js b/test/general/config.js index acaffbeb4..b892292a1 100644 --- a/test/general/config.js +++ b/test/general/config.js @@ -223,7 +223,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z expect(encData2.constructor.tag).to.equal(openpgp.enums.packet.aeadEncryptedData); const { packets: [compressed] } = await encrypted2.decrypt(null, passwords, null, encrypted2.fromStream, openpgp.config); expect(compressed.constructor.tag).to.equal(openpgp.enums.packet.compressedData); - expect(compressed.algorithm).to.equal('zip'); + expect(compressed.algorithm).to.equal(openpgp.enums.compression.zip); const userIDs = { name: 'Test User', email: 'text2@example.com' }; const { privateKey: key } = await openpgp.generateKey({ userIDs, format: 'object' }); diff --git a/test/general/openpgp.js b/test/general/openpgp.js index a7e1ed8a5..acdad24b8 100644 --- a/test/general/openpgp.js +++ b/test/general/openpgp.js @@ -834,7 +834,7 @@ Be4ubVrj5KjhX2PVNEJd3XZRzaXZE2aAMQ== -----END PGP PUBLIC KEY BLOCK-----`; function withCompression(tests) { - const compressionTypes = Object.keys(openpgp.enums.compression).map(k => openpgp.enums.compression[k]); + const compressionTypes = Object.values(openpgp.enums.compression); compressionTypes.forEach(function (compression) { const compressionName = openpgp.enums.read(openpgp.enums.compression, compression); @@ -870,9 +870,9 @@ function withCompression(tests) { } expect(compressSpy.called).to.be.true; - expect(compressSpy.thisValues[0].algorithm).to.equal(compressionName); + expect(compressSpy.thisValues[0].algorithm).to.equal(compression); expect(decompressSpy.called).to.be.true; - expect(decompressSpy.thisValues[0].algorithm).to.equal(compressionName); + expect(decompressSpy.thisValues[0].algorithm).to.equal(compression); } ); }); @@ -2307,7 +2307,7 @@ aOU= it('should encrypt using custom session key and decrypt using session key', async function () { const sessionKey = { - data: await crypto.generateSessionKey('aes256'), + data: await crypto.generateSessionKey(openpgp.enums.symmetric.aes256), algorithm: 'aes256' }; const encOpt = { @@ -2330,7 +2330,7 @@ aOU= it('should encrypt using custom session key and decrypt using private key', async function () { const sessionKey = { - data: await crypto.generateSessionKey('aes128'), + data: await crypto.generateSessionKey(openpgp.enums.symmetric.aes128), algorithm: 'aes128' }; const encOpt = { @@ -3481,7 +3481,7 @@ aOU= }).then(async function (message) { const literals = message.packets.filterByTag(openpgp.enums.packet.literalData); expect(literals.length).to.equal(1); - expect(literals[0].format).to.equal('binary'); + expect(literals[0].format).to.equal(openpgp.enums.literal.binary); expect(+literals[0].date).to.equal(+future); const signatures = await message.verify([publicKey_2038_2045], future, undefined, openpgp.config); expect(await stream.readToEnd(message.getLiteralData())).to.deep.equal(data); @@ -3510,7 +3510,7 @@ aOU= }).then(async function (message) { const literals = message.packets.filterByTag(openpgp.enums.packet.literalData); expect(literals.length).to.equal(1); - expect(literals[0].format).to.equal('mime'); + expect(literals[0].format).to.equal(openpgp.enums.literal.mime); expect(+literals[0].date).to.equal(+future); const signatures = await message.verify([publicKey_2038_2045], future, undefined, openpgp.config); expect(await stream.readToEnd(message.getLiteralData())).to.deep.equal(data); diff --git a/test/general/packet.js b/test/general/packet.js index e86b79fc0..1da54623c 100644 --- a/test/general/packet.js +++ b/test/general/packet.js @@ -88,7 +88,7 @@ module.exports = () => describe('Packet', function() { message.push(enc); const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]); - const algo = 'aes256'; + const algo = openpgp.enums.symmetric.aes256; await enc.encrypt(algo, key, undefined, openpgp.config); @@ -120,7 +120,7 @@ module.exports = () => describe('Packet', function() { message.push(enc); const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]); - const algo = 'aes256'; + const algo = openpgp.enums.symmetric.aes256; await enc.encrypt(algo, key, undefined, openpgp.config); @@ -134,7 +134,7 @@ module.exports = () => describe('Packet', function() { it('Sym. encrypted integrity protected packet', async function() { const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]); - const algo = 'aes256'; + const algo = openpgp.enums.symmetric.aes256; const testText = input.createSomeMessage(); const literal = new openpgp.LiteralDataPacket(); @@ -160,7 +160,7 @@ module.exports = () => describe('Packet', function() { try { const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]); - const algo = 'aes256'; + const algo = openpgp.enums.symmetric.aes256; const testText = input.createSomeMessage(); const literal = new openpgp.LiteralDataPacket(); literal.setText(testText); @@ -212,12 +212,12 @@ module.exports = () => describe('Packet', function() { const testText = input.createSomeMessage(); const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]); - const algo = 'aes256'; + const algo = openpgp.enums.symmetric.aes256; const literal = new openpgp.LiteralDataPacket(); literal.setText(testText); const enc = new openpgp.AEADEncryptedDataPacket(); - enc.aeadAlgorithm = 'experimentalGCM'; + enc.aeadAlgorithm = openpgp.enums.aead.experimentalGCM; enc.packets = new openpgp.PacketList(); enc.packets.push(literal); const msg = new openpgp.PacketList(); @@ -254,7 +254,7 @@ module.exports = () => describe('Packet', function() { const iv = util.hexToUint8Array('b7 32 37 9f 73 c4 92 8d e2 5f ac fe 65 17 ec 10'.replace(/\s+/g, '')); const key = util.hexToUint8Array('86 f1 ef b8 69 52 32 9f 24 ac d3 bf d0 e5 34 6d'.replace(/\s+/g, '')); - const algo = 'aes128'; + const algo = openpgp.enums.symmetric.aes128; const literal = new openpgp.LiteralDataPacket(0); literal.setBytes(util.stringToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary); @@ -296,16 +296,15 @@ module.exports = () => describe('Packet', function() { const parsed = new openpgp.PacketList(); await parsed.read(msgbytes, allAllowedPackets); + const [skesk, seip] = parsed; - return parsed[0].decrypt('test').then(() => { - const key = parsed[0].sessionKey; - return parsed[1].decrypt(parsed[0].sessionKeyAlgorithm, key).then(async () => { - const compressed = parsed[1].packets[0]; + await skesk.decrypt('test'); + return seip.decrypt(skesk.sessionKeyAlgorithm, skesk.sessionKey).then(async () => { + const compressed = seip.packets[0]; - const result = await stringify(compressed.packets[0].data); + const result = await stringify(compressed.packets[0].data); - expect(result).to.equal('Hello world!\n'); - }); + expect(result).to.equal('Hello world!\n'); }); }); @@ -319,15 +318,16 @@ module.exports = () => describe('Packet', function() { const msg2 = new openpgp.PacketList(); enc.sessionKey = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]); - enc.publicKeyAlgorithm = 'rsaEncryptSign'; - enc.sessionKeyAlgorithm = 'aes256'; + enc.publicKeyAlgorithm = openpgp.enums.publicKey.rsaEncryptSign; + enc.sessionKeyAlgorithm = openpgp.enums.symmetric.aes256; enc.publicKeyID.bytes = '12345678'; return enc.encrypt({ publicParams, getFingerprintBytes() {} }).then(async () => { msg.push(enc); await msg2.read(msg.write(), allAllowedPackets); - return msg2[0].decrypt({ algorithm: 'rsaEncryptSign', publicParams, privateParams, getFingerprintBytes() {} }).then(() => { + const privateKey = { algorithm: openpgp.enums.publicKey.rsaEncryptSign, publicParams, privateParams, getFingerprintBytes() {} }; + return msg2[0].decrypt(privateKey).then(() => { expect(stringify(msg2[0].sessionKey)).to.equal(stringify(enc.sessionKey)); expect(msg2[0].sessionKeyAlgorithm).to.equal(enc.sessionKeyAlgorithm); }); @@ -366,8 +366,8 @@ module.exports = () => describe('Packet', function() { const secret = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]); enc.sessionKey = secret; - enc.publicKeyAlgorithm = 'rsaEncryptSign'; - enc.sessionKeyAlgorithm = 'aes256'; + enc.publicKeyAlgorithm = openpgp.enums.publicKey.rsaEncryptSign; + enc.sessionKeyAlgorithm = openpgp.enums.symmetric.aes256; enc.publicKeyID.bytes = '12345678'; return enc.encrypt(key).then(() => { @@ -447,7 +447,7 @@ module.exports = () => describe('Packet', function() { try { const passphrase = 'hello'; - const algo = 'aes256'; + const algo = openpgp.enums.symmetric.aes256; const testText = input.createSomeMessage(); const literal = new openpgp.LiteralDataPacket(); @@ -486,7 +486,7 @@ module.exports = () => describe('Packet', function() { try { const passphrase = 'hello'; - const algo = 'aes256'; + const algo = openpgp.enums.symmetric.aes256; const testText = input.createSomeMessage(); const literal = new openpgp.LiteralDataPacket(); @@ -557,7 +557,7 @@ module.exports = () => describe('Packet', function() { try { const passphrase = 'password'; - const algo = 'aes128'; + const algo = openpgp.enums.symmetric.aes128; const literal = new openpgp.LiteralDataPacket(0); literal.setBytes(util.stringToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary); @@ -634,24 +634,24 @@ module.exports = () => describe('Packet', function() { try { const passphrase = 'password'; - const algo = 'aes128'; + const algo = openpgp.enums.symmetric.aes128; const literal = new openpgp.LiteralDataPacket(0); literal.setBytes(util.stringToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary); literal.filename = ''; - const key_enc = new openpgp.SymEncryptedSessionKeyPacket(); - key_enc.sessionKeyAlgorithm = algo; + const skesk = new openpgp.SymEncryptedSessionKeyPacket(); + skesk.sessionKeyAlgorithm = algo; const enc = new openpgp.AEADEncryptedDataPacket(); enc.packets = new openpgp.PacketList(); enc.packets.push(literal); - enc.aeadAlgorithm = key_enc.aeadAlgorithm = 'ocb'; + enc.aeadAlgorithm = skesk.aeadAlgorithm = openpgp.enums.aead.ocb; const msg = new openpgp.PacketList(); - msg.push(key_enc); + msg.push(skesk); msg.push(enc); - await key_enc.encrypt(passphrase, openpgp.config); + await skesk.encrypt(passphrase, openpgp.config); - const key = key_enc.sessionKey; + const key = skesk.sessionKey; await enc.encrypt(algo, key, undefined, openpgp.config); const data = msg.write(); @@ -840,7 +840,7 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+ const secretKeyPacket = new openpgp.SecretKeyPacket(); secretKeyPacket.privateParams = privateParams; secretKeyPacket.publicParams = publicParams; - secretKeyPacket.algorithm = 'rsaSign'; + secretKeyPacket.algorithm = openpgp.enums.publicKey.rsaSign; secretKeyPacket.isEncrypted = false; await secretKeyPacket.encrypt('hello', { ...openpgp.config, aeadProtect: true }); expect(secretKeyPacket.s2kUsage).to.equal(253); @@ -864,7 +864,7 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+ packet.privateParams = { key: new Uint8Array([1, 2, 3]) }; packet.publicParams = { pubKey: new Uint8Array([4, 5, 6]) }; - packet.algorithm = 'rsaSign'; + packet.algorithm = openpgp.enums.publicKey.rsaSign; packet.isEncrypted = false; packet.s2kUsage = 0; @@ -896,7 +896,7 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+ const secretKeyPacket = new openpgp.SecretKeyPacket(); secretKeyPacket.privateParams = privateParams; secretKeyPacket.publicParams = publicParams; - secretKeyPacket.algorithm = 'rsaSign'; + secretKeyPacket.algorithm = openpgp.enums.publicKey.rsaSign; secretKeyPacket.isEncrypted = false; await secretKeyPacket.encrypt('hello', { ...openpgp.config, aeadProtect: false }); expect(secretKeyPacket.s2kUsage).to.equal(254); @@ -917,7 +917,7 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+ key.publicParams = publicParams; key.privateParams = privateParams; - key.algorithm = 'rsaSign'; + key.algorithm = openpgp.enums.publicKey.rsaSign; await key.computeFingerprintAndKeyID(); const signed = new openpgp.PacketList(); diff --git a/test/typescript/definitions.ts b/test/typescript/definitions.ts index 10d169c4f..deeedba01 100644 --- a/test/typescript/definitions.ts +++ b/test/typescript/definitions.ts @@ -68,7 +68,7 @@ import { // Encrypt text message (armored) const text = 'hello'; - const textMessage = await createMessage({ text: 'hello' }); + const textMessage = await createMessage({ text: 'hello', format: 'text' }); const encryptedArmor: string = await encrypt({ encryptionKeys: publicKeys, message: textMessage }); expect(encryptedArmor).to.include('-----BEGIN PGP MESSAGE-----');