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`
This commit is contained in:
larabr 2021-11-22 11:51:27 +01:00 committed by GitHub
parent 03fa68dbb6
commit 6da1c53de7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 408 additions and 315 deletions

25
openpgp.d.ts vendored
View File

@ -185,8 +185,8 @@ export function decryptSessionKeys<T extends MaybeStream<Data>>(options: { messa
export function readMessage<T extends MaybeStream<string>>(options: { armoredMessage: T, config?: PartialConfig }): Promise<Message<T>>; export function readMessage<T extends MaybeStream<string>>(options: { armoredMessage: T, config?: PartialConfig }): Promise<Message<T>>;
export function readMessage<T extends MaybeStream<Uint8Array>>(options: { binaryMessage: T, config?: PartialConfig }): Promise<Message<T>>; export function readMessage<T extends MaybeStream<Uint8Array>>(options: { binaryMessage: T, config?: PartialConfig }): Promise<Message<T>>;
export function createMessage<T extends MaybeStream<string>>(options: { text: T, filename?: string, date?: Date, type?: DataPacketType }): Promise<Message<T>>; export function createMessage<T extends MaybeStream<string>>(options: { text: T, filename?: string, date?: Date, format?: enums.literalFormatNames }): Promise<Message<T>>;
export function createMessage<T extends MaybeStream<Uint8Array>>(options: { binary: T, filename?: string, date?: Date, type?: DataPacketType }): Promise<Message<T>>; export function createMessage<T extends MaybeStream<Uint8Array>>(options: { binary: T, filename?: string, date?: Date, format?: enums.literalFormatNames }): Promise<Message<T>>;
export function encrypt<T extends MaybeStream<Data>>(options: EncryptOptions & { message: Message<T>, format?: 'armored' }): Promise< export function encrypt<T extends MaybeStream<Data>>(options: EncryptOptions & { message: Message<T>, format?: 'armored' }): Promise<
T extends WebStream<infer X> ? WebStream<string> : T extends WebStream<infer X> ? WebStream<string> :
@ -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). * - A Subkey Packet cannot always be used when a Primary Key Packet is expected (and vice versa).
*/ */
declare abstract class BasePublicKeyPacket extends BasePacket { declare abstract class BasePublicKeyPacket extends BasePacket {
public algorithm: enums.publicKeyNames; public algorithm: enums.publicKey;
public created: Date; public created: Date;
public version: number; public version: number;
public getAlgorithmInfo(): AlgorithmInfo; public getAlgorithmInfo(): AlgorithmInfo;
@ -417,8 +417,8 @@ export class SymEncryptedIntegrityProtectedDataPacket extends BasePacket {
export class AEADEncryptedDataPacket extends BasePacket { export class AEADEncryptedDataPacket extends BasePacket {
static readonly tag: enums.packet.aeadEncryptedData; static readonly tag: enums.packet.aeadEncryptedData;
private decrypt(sessionKeyAlgorithm: string, sessionKey: Uint8Array, config?: Config): void; private decrypt(sessionKeyAlgorithm: enums.symmetric, sessionKey: Uint8Array, config?: Config): void;
private encrypt(sessionKeyAlgorithm: string, sessionKey: Uint8Array, config?: Config): void; private encrypt(sessionKeyAlgorithm: enums.symmetric, sessionKey: Uint8Array, config?: Config): void;
private crypt(fn: Function, sessionKey: Uint8Array, data: MaybeStream<Uint8Array>): MaybeStream<Uint8Array> private crypt(fn: Function, sessionKey: Uint8Array, data: MaybeStream<Uint8Array>): MaybeStream<Uint8Array>
} }
@ -438,8 +438,8 @@ export class LiteralDataPacket extends BasePacket {
static readonly tag: enums.packet.literalData; static readonly tag: enums.packet.literalData;
private getText(clone?: boolean): MaybeStream<string>; private getText(clone?: boolean): MaybeStream<string>;
private getBytes(clone?: boolean): MaybeStream<Uint8Array>; private getBytes(clone?: boolean): MaybeStream<Uint8Array>;
private setText(text: MaybeStream<string>, format?: DataPacketType); private setText(text: MaybeStream<string>, format?: enums.literal);
private setBytes(bytes: MaybeStream<Uint8Array>, format?: DataPacketType); private setBytes(bytes: MaybeStream<Uint8Array>, format: enums.literal);
private setFilename(filename: string); private setFilename(filename: string);
private getFilename(): string; private getFilename(): string;
private writeHeader(): Uint8Array; private writeHeader(): Uint8Array;
@ -534,8 +534,6 @@ export type AnyPacket = BasePacket;
export type AnySecretKeyPacket = SecretKeyPacket | SecretSubkeyPacket; export type AnySecretKeyPacket = SecretKeyPacket | SecretSubkeyPacket;
export type AnyKeyPacket = BasePublicKeyPacket; export type AnyKeyPacket = BasePublicKeyPacket;
type DataPacketType = 'utf8' | 'binary' | 'text' | 'mime';
type AllowedPackets = Map<enums.packet, object>; // mapping to Packet classes (i.e. typeof LiteralDataPacket etc.) type AllowedPackets = Map<enums.packet, object>; // mapping to Packet classes (i.e. typeof LiteralDataPacket etc.)
export class PacketList<T extends AnyPacket> extends Array<T> { export class PacketList<T extends AnyPacket> extends Array<T> {
static fromBinary(bytes: MaybeStream<Uint8Array>, allowedPackets: AllowedPackets, config?: Config): PacketList<AnyPacket>; // the packet types depend on`allowedPackets` static fromBinary(bytes: MaybeStream<Uint8Array>, allowedPackets: AllowedPackets, config?: Config): PacketList<AnyPacket>; // the packet types depend on`allowedPackets`
@ -630,7 +628,6 @@ interface SignOptions {
message: CleartextMessage | Message<MaybeStream<Data>>; message: CleartextMessage | Message<MaybeStream<Data>>;
signingKeys?: MaybeArray<PrivateKey>; signingKeys?: MaybeArray<PrivateKey>;
format?: 'armored' | 'binary' | 'object'; format?: 'armored' | 'binary' | 'object';
dataType?: DataPacketType;
detached?: boolean; detached?: boolean;
signingKeyIDs?: MaybeArray<KeyID>; signingKeyIDs?: MaybeArray<KeyID>;
date?: Date; date?: Date;
@ -876,4 +873,12 @@ export namespace enums {
ocb = 2, ocb = 2,
experimentalGCM = 100 // Private algorithm experimentalGCM = 100 // Private algorithm
} }
export type literalFormatNames = 'utf8' | 'binary' | 'text' | 'mime'
enum literal {
binary = 98,
text = 116,
utf8 = 117,
mime = 109
}
} }

View File

@ -1,6 +1,9 @@
import { AES_ECB } from '@openpgp/asmcrypto.js/dist_es8/aes/ecb'; 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) { function aes(length) {
const C = function(key) { const C = function(key) {
const aesECB = new AES_ECB(key); const aesECB = new AES_ECB(key);

View File

@ -26,6 +26,7 @@
import publicKey from './public_key'; import publicKey from './public_key';
import * as cipher from './cipher'; import * as cipher from './cipher';
import mode from './mode';
import { getRandomBytes } from './random'; import { getRandomBytes } from './random';
import ECDHSymkey from '../type/ecdh_symkey'; import ECDHSymkey from '../type/ecdh_symkey';
import KDFParams from '../type/kdf_params'; import KDFParams from '../type/kdf_params';
@ -348,7 +349,8 @@ export async function validateParams(algo, publicParams, privateParams) {
* @async * @async
*/ */
export async function getPrefixRandom(algo) { 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]]); const repeat = new Uint8Array([prefixrandom[prefixrandom.length - 2], prefixrandom[prefixrandom.length - 1]]);
return util.concat([prefixrandom, repeat]); return util.concat([prefixrandom, repeat]);
} }
@ -361,5 +363,28 @@ export async function getPrefixRandom(algo) {
* @async * @async
*/ */
export function generateSessionKey(algo) { 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];
} }

View File

@ -16,6 +16,7 @@ import * as stream from '@openpgp/web-stream-tools';
import md5 from './md5'; import md5 from './md5';
import util from '../../util'; import util from '../../util';
import defaultConfig from '../../config'; import defaultConfig from '../../config';
import enums from '../../enums';
const webCrypto = util.getWebCrypto(); const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto(); const nodeCrypto = util.getNodeCrypto();
@ -110,26 +111,19 @@ export default {
*/ */
digest: function(algo, data) { digest: function(algo, data) {
switch (algo) { switch (algo) {
case 1: case enums.hash.md5:
// - MD5 [HAC]
return this.md5(data); return this.md5(data);
case 2: case enums.hash.sha1:
// - SHA-1 [FIPS180]
return this.sha1(data); return this.sha1(data);
case 3: case enums.hash.ripemd:
// - RIPE-MD/160 [HAC]
return this.ripemd(data); return this.ripemd(data);
case 8: case enums.hash.sha256:
// - SHA256 [FIPS180]
return this.sha256(data); return this.sha256(data);
case 9: case enums.hash.sha384:
// - SHA384 [FIPS180]
return this.sha384(data); return this.sha384(data);
case 10: case enums.hash.sha512:
// - SHA512 [FIPS180]
return this.sha512(data); return this.sha512(data);
case 11: case enums.hash.sha224:
// - SHA224 [FIPS180]
return this.sha224(data); return this.sha224(data);
default: default:
throw new Error('Invalid hash function.'); throw new Error('Invalid hash function.');
@ -143,18 +137,18 @@ export default {
*/ */
getHashByteLength: function(algo) { getHashByteLength: function(algo) {
switch (algo) { switch (algo) {
case 1: // - MD5 [HAC] case enums.hash.md5:
return 16; return 16;
case 2: // - SHA-1 [FIPS180] case enums.hash.sha1:
case 3: // - RIPE-MD/160 [HAC] case enums.hash.ripemd:
return 20; return 20;
case 8: // - SHA256 [FIPS180] case enums.hash.sha256:
return 32; return 32;
case 9: // - SHA384 [FIPS180] case enums.hash.sha384:
return 48; return 48;
case 10: // - SHA512 [FIPS180] case enums.hash.sha512:
return 64; return 64;
case 11: // - SHA224 [FIPS180] case enums.hash.sha224:
return 28; return 28;
default: default:
throw new Error('Invalid hash algorithm.'); throw new Error('Invalid hash algorithm.');

View File

@ -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 stream from '@openpgp/web-stream-tools';
import * as cipher from '../cipher'; import * as cipher from '../cipher';
import util from '../../util'; import util from '../../util';
import enums from '../../enums';
const webCrypto = util.getWebCrypto(); const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto(); const nodeCrypto = util.getNodeCrypto();
@ -43,15 +44,25 @@ const nodeAlgos = {
/* twofish is not implemented in OpenSSL */ /* twofish is not implemented in OpenSSL */
}; };
/**
* CFB encryption
* @param {enums.symmetric} algo - block cipher algorithm
* @param {Uint8Array} key
* @param {MaybeStream<Uint8Array>} plaintext
* @param {Uint8Array} iv
* @param {Object} config - full configuration, defaults to openpgp.config
* @returns MaybeStream<Uint8Array>
*/
export async function encrypt(algo, key, plaintext, iv, config) { 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); 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); 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 block_size = cipherfn.blockSize;
const blockc = iv.slice(); const blockc = iv.slice();
@ -76,15 +87,24 @@ export async function encrypt(algo, key, plaintext, iv, config) {
return stream.transform(plaintext, process, process); return stream.transform(plaintext, process, process);
} }
/**
* CFB decryption
* @param {enums.symmetric} algo - block cipher algorithm
* @param {Uint8Array} key
* @param {MaybeStream<Uint8Array>} ciphertext
* @param {Uint8Array} iv
* @returns MaybeStream<Uint8Array>
*/
export async function decrypt(algo, key, ciphertext, iv) { 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); return nodeDecrypt(algo, key, ciphertext, iv);
} }
if (algo.substr(0, 3) === 'aes') { if (algoName.substr(0, 3) === 'aes') {
return aesDecrypt(algo, key, ciphertext, iv); return aesDecrypt(algo, key, ciphertext, iv);
} }
const cipherfn = new cipher[algo](key); const cipherfn = new cipher[algoName](key);
const block_size = cipherfn.blockSize; const block_size = cipherfn.blockSize;
let blockp = iv; let blockp = iv;
@ -140,7 +160,7 @@ function xorMut(a, b) {
async function webEncrypt(algo, key, pt, iv) { async function webEncrypt(algo, key, pt, iv) {
const ALGO = 'AES-CBC'; const ALGO = 'AES-CBC';
const _key = await webCrypto.importKey('raw', key, { name: ALGO }, false, ['encrypt']); 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 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); const ct = new Uint8Array(await webCrypto.encrypt({ name: ALGO, iv }, _key, cbc_pt)).subarray(0, pt.length);
xorMut(ct, pt); xorMut(ct, pt);
@ -148,11 +168,13 @@ async function webEncrypt(algo, key, pt, iv) {
} }
function nodeEncrypt(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))); return stream.transform(pt, value => new Uint8Array(cipherObj.update(value)));
} }
function nodeDecrypt(algo, key, ct, iv) { 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))); return stream.transform(ct, value => new Uint8Array(decipherObj.update(value)));
} }

View File

@ -25,6 +25,7 @@
import { AES_CTR } from '@openpgp/asmcrypto.js/dist_es8/aes/ctr'; import { AES_CTR } from '@openpgp/asmcrypto.js/dist_es8/aes/ctr';
import CMAC from '../cmac'; import CMAC from '../cmac';
import util from '../../util'; import util from '../../util';
import enums from '../../enums';
const webCrypto = util.getWebCrypto(); const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto(); const nodeCrypto = util.getNodeCrypto();
@ -74,11 +75,13 @@ async function CTR(key) {
/** /**
* Class to en/decrypt using EAX mode. * 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 * @param {Uint8Array} key - The encryption key
*/ */
async function EAX(cipher, 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'); throw new Error('EAX mode supports only AES cipher');
} }

View File

@ -24,6 +24,7 @@
import { AES_GCM } from '@openpgp/asmcrypto.js/dist_es8/aes/gcm'; import { AES_GCM } from '@openpgp/asmcrypto.js/dist_es8/aes/gcm';
import util from '../../util'; import util from '../../util';
import enums from '../../enums';
const webCrypto = util.getWebCrypto(); const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto(); const nodeCrypto = util.getNodeCrypto();
@ -36,11 +37,13 @@ const ALGO = 'AES-GCM';
/** /**
* Class to en/decrypt using GCM mode. * 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 * @param {Uint8Array} key - The encryption key
*/ */
async function GCM(cipher, 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'); throw new Error('GCM mode supports only AES cipher');
} }

View File

@ -23,7 +23,7 @@
import * as ciphers from '../cipher'; import * as ciphers from '../cipher';
import util from '../../util'; import util from '../../util';
import enums from '../../enums';
const blockLength = 16; const blockLength = 16;
const ivLength = 15; const ivLength = 15;
@ -59,7 +59,7 @@ const one = new Uint8Array([1]);
/** /**
* Class to en/decrypt using OCB mode. * 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 * @param {Uint8Array} key - The encryption key
*/ */
async function OCB(cipher, key) { async function OCB(cipher, key) {
@ -72,7 +72,8 @@ async function OCB(cipher, key) {
constructKeyVariables(cipher, key); constructKeyVariables(cipher, key);
function 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); encipher = aes.encrypt.bind(aes);
decipher = aes.decrypt.bind(aes); decipher = aes.decrypt.bind(aes);

View File

@ -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) { function getPreferredHashAlgo(oid) {
return curves[enums.write(enums.curve, oid.toHex())].hash; return curves[enums.write(enums.curve, oid.toHex())].hash;
} }

View File

@ -24,7 +24,6 @@
import nacl from '@openpgp/tweetnacl/nacl-fast-light.js'; import nacl from '@openpgp/tweetnacl/nacl-fast-light.js';
import { Curve, jwkToRawPublic, rawPublicToJWK, privateToJWK, validateStandardParams } from './curves'; import { Curve, jwkToRawPublic, rawPublicToJWK, privateToJWK, validateStandardParams } from './curves';
import * as aesKW from '../../aes_kw'; import * as aesKW from '../../aes_kw';
import * as cipher from '../../cipher';
import { getRandomBytes } from '../../random'; import { getRandomBytes } from '../../random';
import hash from '../../hash'; import hash from '../../hash';
import enums from '../../../enums'; import enums from '../../../enums';
@ -32,6 +31,7 @@ import util from '../../../util';
import { b64ToUint8Array } from '../../../encoding/base64'; import { b64ToUint8Array } from '../../../encoding/base64';
import * as pkcs5 from '../../pkcs5'; import * as pkcs5 from '../../pkcs5';
import { keyFromPublic, keyFromPrivate, getIndutnyCurve } from './indutnyKey'; import { keyFromPublic, keyFromPrivate, getIndutnyCurve } from './indutnyKey';
import { getCipher } from '../../crypto';
const webCrypto = util.getWebCrypto(); const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto(); const nodeCrypto = util.getNodeCrypto();
@ -132,8 +132,8 @@ export async function encrypt(oid, kdfParams, data, Q, fingerprint) {
const curve = new Curve(oid); const curve = new Curve(oid);
const { publicKey, sharedKey } = await genPublicEphemeralKey(curve, Q); const { publicKey, sharedKey } = await genPublicEphemeralKey(curve, Q);
const param = buildEcdhParam(enums.publicKey.ecdh, oid, kdfParams, fingerprint); const param = buildEcdhParam(enums.publicKey.ecdh, oid, kdfParams, fingerprint);
const cipherAlgo = enums.read(enums.symmetric, kdfParams.cipher); const { keySize } = getCipher(kdfParams.cipher);
const Z = await kdf(kdfParams.hash, sharedKey, cipher[cipherAlgo].keySize, param); const Z = await kdf(kdfParams.hash, sharedKey, keySize, param);
const wrappedKey = aesKW.wrap(Z, m); const wrappedKey = aesKW.wrap(Z, m);
return { publicKey, wrappedKey }; return { publicKey, wrappedKey };
} }
@ -192,12 +192,12 @@ export async function decrypt(oid, kdfParams, V, C, Q, d, fingerprint) {
const curve = new Curve(oid); const curve = new Curve(oid);
const { sharedKey } = await genPrivateEphemeralKey(curve, V, Q, d); const { sharedKey } = await genPrivateEphemeralKey(curve, V, Q, d);
const param = buildEcdhParam(enums.publicKey.ecdh, oid, kdfParams, fingerprint); const param = buildEcdhParam(enums.publicKey.ecdh, oid, kdfParams, fingerprint);
const cipherAlgo = enums.read(enums.symmetric, kdfParams.cipher); const { keySize } = getCipher(kdfParams.cipher);
let err; let err;
for (let i = 0; i < 3; i++) { for (let i = 0; i < 3; i++) {
try { try {
// Work around old go crypto bug and old OpenPGP.js bug, respectively. // 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)); return pkcs5.decode(aesKW.unwrap(Z, C));
} catch (e) { } catch (e) {
err = e; err = e;

View File

@ -448,7 +448,13 @@ export default {
v5Keys: 4 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) { write: function(type, e) {
if (typeof e === 'number') { if (typeof e === 'number') {
e = this.read(type, e); e = this.read(type, e);
@ -461,7 +467,13 @@ export default {
throw new Error('Invalid enum value.'); 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) { read: function(type, e) {
if (!type[byValue]) { if (!type[byValue]) {
type[byValue] = []; type[byValue] = [];
@ -476,5 +488,4 @@ export default {
throw new Error('Invalid enum value.'); throw new Error('Invalid enum value.');
} }
}; };

View File

@ -19,7 +19,7 @@ import defaultConfig from '../config';
export async function generateSecretSubkey(options, config) { export async function generateSecretSubkey(options, config) {
const secretSubkeyPacket = new SecretSubkeyPacket(options.date, config); const secretSubkeyPacket = new SecretSubkeyPacket(options.date, config);
secretSubkeyPacket.packets = null; 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.generate(options.rsaBits, options.curve);
await secretSubkeyPacket.computeFingerprintAndKeyID(); await secretSubkeyPacket.computeFingerprintAndKeyID();
return secretSubkeyPacket; return secretSubkeyPacket;
@ -28,7 +28,7 @@ export async function generateSecretSubkey(options, config) {
export async function generateSecretKey(options, config) { export async function generateSecretKey(options, config) {
const secretKeyPacket = new SecretKeyPacket(options.date, config); const secretKeyPacket = new SecretKeyPacket(options.date, config);
secretKeyPacket.packets = null; 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.generate(options.rsaBits, options.curve, options.config);
await secretKeyPacket.computeFingerprintAndKeyID(); await secretKeyPacket.computeFingerprintAndKeyID();
return secretKeyPacket; 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 {Date} [date] - Use the given date for verification instead of the current time
* @param {Object} [userID] - User ID * @param {Object} [userID] - User ID
* @param {Object} config - full configuration * @param {Object} config - full configuration
* @returns {Promise<String>} * @returns {Promise<enums.hash>}
* @async * @async
*/ */
export async function getPreferredHashAlgo(key, keyPacket, date = new Date(), userID = {}, config) { 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 SecretSubkeyPacket.prototype:
case PublicSubkeyPacket.prototype: case PublicSubkeyPacket.prototype:
switch (keyPacket.algorithm) { switch (keyPacket.algorithm) {
case 'ecdh': case enums.publicKey.ecdh:
case 'ecdsa': case enums.publicKey.ecdsa:
case 'eddsa': case enums.publicKey.eddsa:
prefAlgo = crypto.publicKey.elliptic.getPreferredHashAlgo(keyPacket.publicParams.oid); 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 * 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<Key>} [keys] - Set of keys * @param {Array<Key>} [keys] - Set of keys
* @param {Date} [date] - Use the given date for verification instead of the current time * @param {Date} [date] - Use the given date for verification instead of the current time
* @param {Array} [userIDs] - User IDs * @param {Array} [userIDs] - User IDs
@ -361,7 +361,7 @@ export function sanitizeKeyOptions(options, subkeyDefaults = {}) {
} }
export function isValidSigningKeyPacket(keyPacket, signature) { export function isValidSigningKeyPacket(keyPacket, signature) {
const keyAlgo = enums.write(enums.publicKey, keyPacket.algorithm); const keyAlgo = keyPacket.algorithm;
return keyAlgo !== enums.publicKey.rsaEncrypt && return keyAlgo !== enums.publicKey.rsaEncrypt &&
keyAlgo !== enums.publicKey.elgamal && keyAlgo !== enums.publicKey.elgamal &&
keyAlgo !== enums.publicKey.ecdh && keyAlgo !== enums.publicKey.ecdh &&
@ -370,7 +370,7 @@ export function isValidSigningKeyPacket(keyPacket, signature) {
} }
export function isValidEncryptionKeyPacket(keyPacket, signature) { export function isValidEncryptionKeyPacket(keyPacket, signature) {
const keyAlgo = enums.write(enums.publicKey, keyPacket.algorithm); const keyAlgo = keyPacket.algorithm;
return keyAlgo !== enums.publicKey.dsa && return keyAlgo !== enums.publicKey.dsa &&
keyAlgo !== enums.publicKey.rsaSign && keyAlgo !== enums.publicKey.rsaSign &&
keyAlgo !== enums.publicKey.ecdsa && keyAlgo !== enums.publicKey.ecdsa &&
@ -400,10 +400,10 @@ export function isValidDecryptionKeyPacket(signature, config) {
*/ */
export function checkKeyRequirements(keyPacket, config) { export function checkKeyRequirements(keyPacket, config) {
const keyAlgo = enums.write(enums.publicKey, keyPacket.algorithm); const keyAlgo = enums.write(enums.publicKey, keyPacket.algorithm);
if (config.rejectPublicKeyAlgorithms.has(keyAlgo)) {
throw new Error(`${keyPacket.algorithm} keys are considered too weak.`);
}
const algoInfo = keyPacket.getAlgorithmInfo(); const algoInfo = keyPacket.getAlgorithmInfo();
if (config.rejectPublicKeyAlgorithms.has(keyAlgo)) {
throw new Error(`${algoInfo.algorithm} keys are considered too weak.`);
}
switch (keyAlgo) { switch (keyAlgo) {
case enums.publicKey.rsaEncryptSign: case enums.publicKey.rsaEncryptSign:
case enums.publicKey.rsaSign: case enums.publicKey.rsaSign:
@ -416,7 +416,7 @@ export function checkKeyRequirements(keyPacket, config) {
case enums.publicKey.eddsa: case enums.publicKey.eddsa:
case enums.publicKey.ecdh: case enums.publicKey.ecdh:
if (config.rejectCurves.has(algoInfo.curve)) { 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; break;
default: default:

View File

@ -107,7 +107,7 @@ export class Message {
* @async * @async
*/ */
async decrypt(decryptionKeys, passwords, sessionKeys, date = new Date(), config = defaultConfig) { 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( const symEncryptedPacketlist = this.packets.filterByTag(
enums.packet.symmetricallyEncryptedData, enums.packet.symmetricallyEncryptedData,
@ -121,13 +121,14 @@ export class Message {
const symEncryptedPacket = symEncryptedPacketlist[0]; const symEncryptedPacket = symEncryptedPacketlist[0];
let exception = null; let exception = null;
const decryptedPromise = Promise.all(keyObjs.map(async keyObj => { const decryptedPromise = Promise.all(sessionKeyObjs.map(async ({ algorithm: algorithmName, data }) => {
if (!keyObj || !util.isUint8Array(keyObj.data) || !util.isString(keyObj.algorithm)) { if (!util.isUint8Array(data) || !util.isString(algorithmName)) {
throw new Error('Invalid session key for decryption.'); throw new Error('Invalid session key for decryption.');
} }
try { try {
await symEncryptedPacket.decrypt(keyObj.algorithm, keyObj.data, config); const algo = enums.write(enums.symmetric, algorithmName);
await symEncryptedPacket.decrypt(algo, data, config);
} catch (e) { } catch (e) {
util.printDebugError(e); util.printDebugError(e);
exception = e; exception = e;
@ -216,7 +217,7 @@ export class Message {
} }
try { try {
await keyPacket.decrypt(decryptionKeyPacket); 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.'); throw new Error('A non-preferred symmetric algorithm was used.');
} }
keyPackets.push(keyPacket); 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.'); throw exception || new Error('Session key decryption failed.');
} }
@ -295,13 +299,14 @@ export class Message {
* @async * @async
*/ */
static async generateSessionKey(encryptionKeys = [], date = new Date(), userIDs = [], config = defaultConfig) { static async generateSessionKey(encryptionKeys = [], date = new Date(), userIDs = [], config = defaultConfig) {
const algorithm = enums.read(enums.symmetric, await getPreferredAlgo('symmetric', encryptionKeys, date, userIDs, config)); const algo = await getPreferredAlgo('symmetric', encryptionKeys, date, userIDs, config);
const aeadAlgorithm = config.aeadProtect && await isAEADSupported(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)) : enums.read(enums.aead, await getPreferredAlgo('aead', encryptionKeys, date, userIDs, config)) :
undefined; undefined;
const sessionKeyData = await crypto.generateSessionKey(algorithm); const sessionKeyData = await crypto.generateSessionKey(algo);
return { data: sessionKeyData, algorithm, aeadAlgorithm }; return { data: sessionKeyData, algorithm: algorithmName, aeadAlgorithm: aeadAlgorithmName };
} }
/** /**
@ -330,19 +335,20 @@ export class Message {
throw new Error('No keys, passwords, or session key provided.'); 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; let symEncryptedPacket;
if (aeadAlgorithm) { if (aeadAlgorithmName) {
symEncryptedPacket = new AEADEncryptedDataPacket(); symEncryptedPacket = new AEADEncryptedDataPacket();
symEncryptedPacket.aeadAlgorithm = aeadAlgorithm; symEncryptedPacket.aeadAlgorithm = enums.write(enums.aead, aeadAlgorithmName);
} else { } else {
symEncryptedPacket = new SymEncryptedIntegrityProtectedDataPacket(); symEncryptedPacket = new SymEncryptedIntegrityProtectedDataPacket();
} }
symEncryptedPacket.packets = this.packets; symEncryptedPacket.packets = this.packets;
const algorithm = enums.write(enums.symmetric, algorithmName);
await symEncryptedPacket.encrypt(algorithm, sessionKeyData, config); await symEncryptedPacket.encrypt(algorithm, sessionKeyData, config);
msg.packets.push(symEncryptedPacket); msg.packets.push(symEncryptedPacket);
@ -353,8 +359,8 @@ export class Message {
/** /**
* Encrypt a session key either with public keys, passwords, or both at once. * Encrypt a session key either with public keys, passwords, or both at once.
* @param {Uint8Array} sessionKey - session key for encryption * @param {Uint8Array} sessionKey - session key for encryption
* @param {String} algorithm - session key algorithm * @param {String} algorithmName - session key algorithm
* @param {String} [aeadAlgorithm] - AEAD algorithm, e.g. 'eax' or 'ocb' * @param {String} [aeadAlgorithmName] - AEAD algorithm, e.g. 'eax' or 'ocb'
* @param {Array<PublicKey>} [encryptionKeys] - Public key(s) for message encryption * @param {Array<PublicKey>} [encryptionKeys] - Public key(s) for message encryption
* @param {Array<String>} [passwords] - For message encryption * @param {Array<String>} [passwords] - For message encryption
* @param {Boolean} [wildcard] - Use a key ID of 0 instead of the public key IDs * @param {Boolean} [wildcard] - Use a key ID of 0 instead of the public key IDs
@ -365,8 +371,10 @@ export class Message {
* @returns {Promise<Message>} New message with encrypted content. * @returns {Promise<Message>} New message with encrypted content.
* @async * @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 packetlist = new PacketList();
const algorithm = enums.write(enums.symmetric, algorithmName);
const aeadAlgorithm = aeadAlgorithmName && enums.write(enums.aead, aeadAlgorithmName);
if (encryptionKeys) { if (encryptionKeys) {
const results = await Promise.all(encryptionKeys.map(async function(primaryKey, i) { const results = await Promise.all(encryptionKeys.map(async function(primaryKey, i) {
@ -499,7 +507,7 @@ export class Message {
} }
const compressed = new CompressedDataPacket(config); const compressed = new CompressedDataPacket(config);
compressed.algorithm = enums.read(enums.compression, algo); compressed.algorithm = algo;
compressed.packets = this.packets; compressed.packets = this.packets;
const packetList = new PacketList(); const packetList = new PacketList();
@ -866,9 +874,9 @@ export async function createMessage({ text, binary, filename, date = new Date(),
} }
const literalDataPacket = new LiteralDataPacket(date); const literalDataPacket = new LiteralDataPacket(date);
if (text !== undefined) { if (text !== undefined) {
literalDataPacket.setText(input, format); literalDataPacket.setText(input, enums.write(enums.literal, format));
} else { } else {
literalDataPacket.setBytes(input, format); literalDataPacket.setBytes(input, enums.write(enums.literal, format));
} }
if (filename !== undefined) { if (filename !== undefined) {
literalDataPacket.setFilename(filename); literalDataPacket.setFilename(filename);

View File

@ -52,9 +52,10 @@ class AEADEncryptedDataPacket {
constructor() { constructor() {
this.version = VERSION; this.version = VERSION;
this.cipherAlgo = null; /** @type {enums.symmetric} */
this.aeadAlgorithm = 'eax'; this.cipherAlgorithm = null;
this.aeadAlgo = null; /** @type {enums.aead} */
this.aeadAlgorithm = enums.aead.eax;
this.chunkSizeByte = null; this.chunkSizeByte = null;
this.iv = null; this.iv = null;
this.encrypted = null; this.encrypted = null;
@ -64,6 +65,7 @@ class AEADEncryptedDataPacket {
/** /**
* Parse an encrypted payload of bytes in the order: version, IV, ciphertext (see specification) * Parse an encrypted payload of bytes in the order: version, IV, ciphertext (see specification)
* @param {Uint8Array | ReadableStream<Uint8Array>} bytes * @param {Uint8Array | ReadableStream<Uint8Array>} bytes
* @throws {Error} on parsing failure
*/ */
async read(bytes) { async read(bytes) {
await stream.parse(bytes, async reader => { await stream.parse(bytes, async reader => {
@ -71,10 +73,11 @@ class AEADEncryptedDataPacket {
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.`);
} }
this.cipherAlgo = await reader.readByte(); this.cipherAlgorithm = await reader.readByte();
this.aeadAlgo = await reader.readByte(); this.aeadAlgorithm = await reader.readByte();
this.chunkSizeByte = 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.iv = await reader.readBytes(mode.ivLength);
this.encrypted = reader.remainder(); this.encrypted = reader.remainder();
}); });
@ -85,12 +88,12 @@ class AEADEncryptedDataPacket {
* @returns {Uint8Array | ReadableStream<Uint8Array>} The encrypted payload. * @returns {Uint8Array | ReadableStream<Uint8Array>} The encrypted payload.
*/ */
write() { 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. * 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 {Uint8Array} key - The session key used to encrypt the payload
* @param {Object} [config] - Full configuration, defaults to openpgp.config * @param {Object} [config] - Full configuration, defaults to openpgp.config
* @throws {Error} if decryption was not successful * @throws {Error} if decryption was not successful
@ -105,18 +108,18 @@ class AEADEncryptedDataPacket {
} }
/** /**
* Encrypt the packet list payload. * Encrypt the packet 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 {Uint8Array} key - The session key used to encrypt the payload
* @param {Object} [config] - Full configuration, defaults to openpgp.config * @param {Object} [config] - Full configuration, defaults to openpgp.config
* @throws {Error} if encryption was not successful * @throws {Error} if encryption was not successful
* @async * @async
*/ */
async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) { async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
this.cipherAlgo = enums.write(enums.symmetric, sessionKeyAlgorithm); this.cipherAlgorithm = sessionKeyAlgorithm;
this.aeadAlgo = enums.write(enums.aead, this.aeadAlgorithm);
const mode = crypto.mode[enums.read(enums.aead, this.aeadAlgo)]; const { ivLength } = crypto.getAEADMode(this.aeadAlgorithm);
this.iv = await crypto.random.getRandomBytes(mode.ivLength); // generate new random IV this.iv = await crypto.random.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 this.crypt('encrypt', key, data); this.encrypted = await this.crypt('encrypt', key, data);
@ -131,9 +134,8 @@ class AEADEncryptedDataPacket {
* @async * @async
*/ */
async crypt(fn, key, data) { async crypt(fn, key, data) {
const cipher = enums.read(enums.symmetric, this.cipherAlgo); const mode = crypto.getAEADMode(this.aeadAlgorithm);
const mode = crypto.mode[enums.read(enums.aead, this.aeadAlgo)]; const modeInstance = await mode(this.cipherAlgorithm, key);
const modeInstance = await mode(cipher, key);
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 ** (this.chunkSizeByte + 6) + tagLengthIfDecrypting; // ((uint64_t)1 << (c + 6)) const chunkSize = 2 ** (this.chunkSizeByte + 6) + tagLengthIfDecrypting; // ((uint64_t)1 << (c + 6))
@ -142,7 +144,7 @@ class AEADEncryptedDataPacket {
const adataTagArray = new Uint8Array(adataBuffer); const adataTagArray = new Uint8Array(adataBuffer);
const adataView = new DataView(adataBuffer); const adataView = new DataView(adataBuffer);
const chunkIndexArray = new Uint8Array(adataBuffer, 5, 8); 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 chunkIndex = 0;
let latestPromise = Promise.resolve(); let latestPromise = Promise.resolve();
let cryptedBytes = 0; let cryptedBytes = 0;

View File

@ -60,9 +60,9 @@ class CompressedDataPacket {
this.packets = null; this.packets = null;
/** /**
* Compression algorithm * Compression algorithm
* @type {compression} * @type {enums.compression}
*/ */
this.algorithm = enums.read(enums.compression, config.preferredCompressionAlgorithm); this.algorithm = config.preferredCompressionAlgorithm;
/** /**
* Compressed packet data * Compressed packet data
@ -85,7 +85,7 @@ class CompressedDataPacket {
await stream.parse(bytes, async reader => { await stream.parse(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 = enums.read(enums.compression, await reader.readByte()); this.algorithm = await reader.readByte();
// Compressed data, which makes up the remainder of the packet. // Compressed data, which makes up the remainder of the packet.
this.compressed = reader.remainder(); this.compressed = reader.remainder();
@ -104,7 +104,7 @@ class CompressedDataPacket {
this.compress(); 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 * @param {Object} [config] - Full configuration, defaults to openpgp.config
*/ */
async decompress(config = defaultConfig) { async decompress(config = defaultConfig) {
const compressionName = enums.read(enums.compression, this.algorithm);
if (!decompress_fns[this.algorithm]) { const decompressionFn = decompress_fns[compressionName];
throw new Error(this.algorithm + ' decompression not supported'); 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 the packet data (member decompressedData)
*/ */
compress() { compress() {
if (!compress_fns[this.algorithm]) { const compressionName = enums.read(enums.compression, this.algorithm);
throw new Error(this.algorithm + ' compression not supported'); 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);
} }
} }

View File

@ -35,7 +35,7 @@ class LiteralDataPacket {
* @param {Date} date - The creation date of the literal package * @param {Date} date - The creation date of the literal package
*/ */
constructor(date = new Date()) { 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.date = util.normalizeDate(date);
this.text = null; // textual data representation this.text = null; // textual data representation
this.data = null; // literal 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 * 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 * will be normalized to \r\n and by default text is converted to UTF8
* @param {String | ReadableStream<String>} text - Any native javascript string * @param {String | ReadableStream<String>} 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.format = format;
this.text = text; this.text = text;
this.data = null; this.data = null;
@ -70,7 +70,7 @@ class LiteralDataPacket {
/** /**
* Set the packet data to value represented by the provided string of bytes. * Set the packet data to value represented by the provided string of bytes.
* @param {Uint8Array | ReadableStream<Uint8Array>} bytes - The string of bytes * @param {Uint8Array | ReadableStream<Uint8Array>} 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) { setBytes(bytes, format) {
this.format = format; this.format = format;
@ -123,7 +123,7 @@ class LiteralDataPacket {
async read(bytes) { async read(bytes) {
await stream.parse(bytes, async reader => { await stream.parse(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 = enums.read(enums.literal, await reader.readByte()); const format = await reader.readByte(); // enums.literal
const filename_len = await reader.readByte(); const filename_len = await reader.readByte();
this.filename = util.decodeUTF8(await reader.readBytes(filename_len)); this.filename = util.decodeUTF8(await reader.readBytes(filename_len));
@ -145,7 +145,7 @@ class LiteralDataPacket {
const filename = util.encodeUTF8(this.filename); const filename = util.encodeUTF8(this.filename);
const filename_length = new Uint8Array([filename.length]); 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); const date = util.writeDate(this.date);
return util.concatUint8Array([format, filename_length, filename, date]); return util.concatUint8Array([format, filename_length, filename, date]);

View File

@ -46,16 +46,20 @@ class OnePassSignaturePacket {
* A one-octet signature type. * A one-octet signature type.
* Signature types are described in * Signature types are described in
* {@link https://tools.ietf.org/html/rfc4880#section-5.2.1|RFC4880 Section 5.2.1}. * {@link https://tools.ietf.org/html/rfc4880#section-5.2.1|RFC4880 Section 5.2.1}.
* @type {enums.signature}
*/ */
this.signatureType = null; this.signatureType = null;
/** /**
* A one-octet number describing the hash algorithm used. * A one-octet number describing the hash algorithm used.
* @see {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC4880 9.4} * @see {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC4880 9.4}
* @type {enums.hash}
*/ */
this.hashAlgorithm = null; this.hashAlgorithm = null;
/** /**
* A one-octet number describing the public-key algorithm used. * A one-octet number describing the public-key algorithm used.
* @see {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC4880 9.1} * @see {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC4880 9.1}
* @type {enums.publicKey}
*/ */
this.publicKeyAlgorithm = null; this.publicKeyAlgorithm = null;
/** An eight-octet number holding the Key ID of the signing key. */ /** 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. * @returns {Uint8Array} A Uint8Array representation of a one-pass signature packet.
*/ */
write() { write() {
const start = new Uint8Array([VERSION, enums.write(enums.signature, this.signatureType), const start = new Uint8Array([VERSION, this.signatureType, this.hashAlgorithm, this.publicKeyAlgorithm]);
enums.write(enums.hash, this.hashAlgorithm),
enums.write(enums.publicKey, this.publicKeyAlgorithm)]);
const end = new Uint8Array([this.flags]); const end = new Uint8Array([this.flags]);

View File

@ -55,7 +55,7 @@ class PublicKeyPacket {
this.created = util.normalizeDate(date); this.created = util.normalizeDate(date);
/** /**
* Public key algorithm. * Public key algorithm.
* @type {String} * @type {enums.publicKey}
*/ */
this.algorithm = null; this.algorithm = null;
/** /**
@ -115,8 +115,7 @@ class PublicKeyPacket {
pos += 4; pos += 4;
// - A one-octet number denoting the public-key algorithm of this key. // - A one-octet number denoting the public-key algorithm of this key.
this.algorithm = enums.read(enums.publicKey, bytes[pos++]); this.algorithm = bytes[pos++];
const algo = enums.write(enums.publicKey, this.algorithm);
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.
@ -125,7 +124,7 @@ class PublicKeyPacket {
// - A series of values comprising the key material. // - A series of values comprising the key material.
try { try {
const { read, publicParams } = crypto.parsePublicKeyParams(algo, bytes.subarray(pos)); const { read, publicParams } = crypto.parsePublicKeyParams(this.algorithm, bytes.subarray(pos));
this.publicParams = publicParams; this.publicParams = publicParams;
pos += read; pos += read;
} catch (err) { } catch (err) {
@ -149,10 +148,9 @@ class PublicKeyPacket {
arr.push(new Uint8Array([this.version])); arr.push(new Uint8Array([this.version]));
arr.push(util.writeDate(this.created)); arr.push(util.writeDate(this.created));
// A one-octet number denoting the public-key algorithm of this key // A one-octet number denoting the public-key algorithm of this key
const algo = enums.write(enums.publicKey, this.algorithm); arr.push(new Uint8Array([this.algorithm]));
arr.push(new Uint8Array([algo]));
const params = crypto.serializeParams(algo, this.publicParams); const params = crypto.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));
@ -261,7 +259,7 @@ class PublicKeyPacket {
*/ */
getAlgorithmInfo() { getAlgorithmInfo() {
const result = {}; const result = {};
result.algorithm = this.algorithm; result.algorithm = enums.read(enums.publicKey, this.algorithm);
// RSA, DSA or ElGamal public modulo // RSA, DSA or ElGamal public modulo
const modulo = this.publicParams.n || this.publicParams.p; const modulo = this.publicParams.n || this.publicParams.p;
if (modulo) { if (modulo) {

View File

@ -51,6 +51,10 @@ class PublicKeyEncryptedSessionKeyPacket {
this.publicKeyAlgorithm = null; this.publicKeyAlgorithm = null;
this.sessionKey = null; this.sessionKey = null;
/**
* Algorithm to encrypt the message with
* @type {enums.symmetric}
*/
this.sessionKeyAlgorithm = null; this.sessionKeyAlgorithm = null;
/** @type {Object} */ /** @type {Object} */
@ -68,10 +72,8 @@ class PublicKeyEncryptedSessionKeyPacket {
throw new UnsupportedError(`Version ${this.version} of the PKESK packet is unsupported.`); throw new UnsupportedError(`Version ${this.version} of the PKESK packet is unsupported.`);
} }
this.publicKeyID.read(bytes.subarray(1, bytes.length)); this.publicKeyID.read(bytes.subarray(1, bytes.length));
this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes[9]); this.publicKeyAlgorithm = bytes[9];
this.encrypted = crypto.parseEncSessionKeyParams(this.publicKeyAlgorithm, bytes.subarray(10));
const algo = enums.write(enums.publicKey, this.publicKeyAlgorithm);
this.encrypted = crypto.parseEncSessionKeyParams(algo, bytes.subarray(10));
} }
/** /**
@ -80,13 +82,11 @@ class PublicKeyEncryptedSessionKeyPacket {
* @returns {Uint8Array} The Uint8Array representation. * @returns {Uint8Array} The Uint8Array representation.
*/ */
write() { write() {
const algo = enums.write(enums.publicKey, this.publicKeyAlgorithm);
const arr = [ const arr = [
new Uint8Array([this.version]), new Uint8Array([this.version]),
this.publicKeyID.write(), this.publicKeyID.write(),
new Uint8Array([enums.write(enums.publicKey, this.publicKeyAlgorithm)]), new Uint8Array([this.publicKeyAlgorithm]),
crypto.serializeParams(algo, this.encrypted) crypto.serializeParams(this.publicKeyAlgorithm, this.encrypted)
]; ];
return util.concatUint8Array(arr); return util.concatUint8Array(arr);
@ -117,20 +117,18 @@ class PublicKeyEncryptedSessionKeyPacket {
* @async * @async
*/ */
async decrypt(key) { 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 // check that session key algo matches the secret key algo
if (algo !== keyAlgo) { if (this.publicKeyAlgorithm !== key.algorithm) {
throw new Error('Decryption error'); 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 checksum = decoded.subarray(decoded.length - 2);
const sessionKey = decoded.subarray(1, decoded.length - 2); const sessionKey = decoded.subarray(1, decoded.length - 2);
if (!util.equalsUint8Array(checksum, util.writeChecksum(sessionKey))) { if (!util.equalsUint8Array(checksum, util.writeChecksum(sessionKey))) {
throw new Error('Decryption error'); throw new Error('Decryption error');
} else { } else {
this.sessionKey = sessionKey; this.sessionKey = sessionKey;
this.sessionKeyAlgorithm = enums.read(enums.symmetric, decoded[0]); this.sessionKeyAlgorithm = enums.write(enums.symmetric, decoded[0]);
} }
} }
} }

View File

@ -49,7 +49,7 @@ class SecretKeyPacket extends PublicKeyPacket {
this.isEncrypted = null; this.isEncrypted = null;
/** /**
* S2K usage * S2K usage
* @type {Integer} * @type {enums.symmetric}
*/ */
this.s2kUsage = 0; this.s2kUsage = 0;
/** /**
@ -58,13 +58,13 @@ class SecretKeyPacket extends PublicKeyPacket {
*/ */
this.s2k = null; this.s2k = null;
/** /**
* Symmetric algorithm * Symmetric algorithm to encrypt the key with
* @type {String} * @type {enums.symmetric}
*/ */
this.symmetric = null; this.symmetric = null;
/** /**
* AEAD algorithm * AEAD algorithm to encrypt the key with (if AEAD protection is enabled)
* @type {String} * @type {enums.aead}
*/ */
this.aead = null; this.aead = null;
/** /**
@ -79,7 +79,7 @@ class SecretKeyPacket extends PublicKeyPacket {
/** /**
* Internal parser for private keys as specified in * 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} * {@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
*/ */
async read(bytes) { async read(bytes) {
@ -102,13 +102,11 @@ class SecretKeyPacket extends PublicKeyPacket {
// one-octet symmetric encryption algorithm. // one-octet symmetric encryption algorithm.
if (this.s2kUsage === 255 || this.s2kUsage === 254 || this.s2kUsage === 253) { if (this.s2kUsage === 255 || this.s2kUsage === 254 || this.s2kUsage === 253) {
this.symmetric = bytes[i++]; this.symmetric = bytes[i++];
this.symmetric = enums.read(enums.symmetric, this.symmetric);
// - [Optional] If string-to-key usage octet was 253, a one-octet // - [Optional] If string-to-key usage octet was 253, a one-octet
// AEAD algorithm. // AEAD algorithm.
if (this.s2kUsage === 253) { if (this.s2kUsage === 253) {
this.aead = bytes[i++]; 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 // - [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) { } else if (this.s2kUsage) {
this.symmetric = 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 // - [Optional] If secret data is encrypted (string-to-key usage octet
@ -131,7 +128,7 @@ class SecretKeyPacket extends PublicKeyPacket {
if (this.s2kUsage) { if (this.s2kUsage) {
this.iv = bytes.subarray( this.iv = bytes.subarray(
i, i,
i + crypto.cipher[this.symmetric].blockSize i + crypto.getCipher(this.symmetric).blockSize
); );
i += this.iv.length; i += this.iv.length;
@ -155,8 +152,7 @@ class SecretKeyPacket extends PublicKeyPacket {
throw new Error('Key checksum mismatch'); throw new Error('Key checksum mismatch');
} }
try { try {
const algo = enums.write(enums.publicKey, this.algorithm); const { privateParams } = crypto.parsePrivateKeyParams(this.algorithm, cleartext, this.publicParams);
const { privateParams } = crypto.parsePrivateKeyParams(algo, 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');
@ -177,12 +173,12 @@ class SecretKeyPacket extends PublicKeyPacket {
// - [Optional] If string-to-key usage octet was 255, 254, or 253, a // - [Optional] If string-to-key usage octet was 255, 254, or 253, a
// one- octet symmetric encryption algorithm. // one- octet symmetric encryption algorithm.
if (this.s2kUsage === 255 || this.s2kUsage === 254 || this.s2kUsage === 253) { 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 // - [Optional] If string-to-key usage octet was 253, a one-octet
// AEAD algorithm. // AEAD algorithm.
if (this.s2kUsage === 253) { 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 // - [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.isDummy()) {
if (!this.s2kUsage) { if (!this.s2kUsage) {
const algo = enums.write(enums.publicKey, this.algorithm); this.keyMaterial = crypto.serializeParams(this.algorithm, this.privateParams);
this.keyMaterial = crypto.serializeParams(algo, this.privateParams);
} }
if (this.version === 5) { if (this.version === 5) {
@ -258,7 +253,7 @@ class SecretKeyPacket extends PublicKeyPacket {
this.s2k.c = 0; this.s2k.c = 0;
this.s2k.type = 'gnu-dummy'; this.s2k.type = 'gnu-dummy';
this.s2kUsage = 254; 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 = new S2K(config);
this.s2k.salt = await crypto.random.getRandomBytes(8); this.s2k.salt = await crypto.random.getRandomBytes(8);
const algo = enums.write(enums.publicKey, this.algorithm); const cleartext = crypto.serializeParams(this.algorithm, this.privateParams);
const cleartext = crypto.serializeParams(algo, this.privateParams); this.symmetric = enums.symmetric.aes256;
this.symmetric = 'aes256';
const key = await produceEncryptionKey(this.s2k, passphrase, this.symmetric); 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) { if (config.aeadProtect) {
this.s2kUsage = 253; this.s2kUsage = 253;
this.aead = 'eax'; this.aead = enums.aead.eax;
const mode = crypto.mode[this.aead]; const mode = crypto.getAEADMode(this.aead);
const modeInstance = await mode(this.symmetric, key); const modeInstance = await mode(this.symmetric, key);
this.keyMaterial = await modeInstance.encrypt(cleartext, this.iv.subarray(0, mode.ivLength), new Uint8Array()); this.keyMaterial = await modeInstance.encrypt(cleartext, this.iv.subarray(0, mode.ivLength), new Uint8Array());
} else { } else {
@ -340,9 +335,9 @@ class SecretKeyPacket extends PublicKeyPacket {
let cleartext; let cleartext;
if (this.s2kUsage === 253) { if (this.s2kUsage === 253) {
const mode = crypto.mode[this.aead]; const mode = crypto.getAEADMode(this.aead);
const modeInstance = await mode(this.symmetric, key);
try { try {
const modeInstance = await mode(this.symmetric, key);
cleartext = await modeInstance.decrypt(this.keyMaterial, this.iv.subarray(0, mode.ivLength), new Uint8Array()); cleartext = await modeInstance.decrypt(this.keyMaterial, this.iv.subarray(0, mode.ivLength), new Uint8Array());
} catch (err) { } catch (err) {
if (err.message === 'Authentication tag mismatch') { if (err.message === 'Authentication tag mismatch') {
@ -362,8 +357,7 @@ class SecretKeyPacket extends PublicKeyPacket {
} }
try { try {
const algo = enums.write(enums.publicKey, this.algorithm); const { privateParams } = crypto.parsePrivateKeyParams(this.algorithm, cleartext, this.publicParams);
const { privateParams } = crypto.parsePrivateKeyParams(algo, 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');
@ -387,12 +381,10 @@ class SecretKeyPacket extends PublicKeyPacket {
throw new Error('Key is not decrypted'); throw new Error('Key is not decrypted');
} }
const algo = enums.write(enums.publicKey, this.algorithm);
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(algo, this.publicParams, this.privateParams); validParams = await crypto.validateParams(this.algorithm, this.publicParams, this.privateParams);
} catch (_) { } catch (_) {
validParams = false; validParams = false;
} }
@ -402,8 +394,7 @@ class SecretKeyPacket extends PublicKeyPacket {
} }
async generate(bits, curve) { async generate(bits, curve) {
const algo = enums.write(enums.publicKey, this.algorithm); const { privateParams, publicParams } = await crypto.generateParams(this.algorithm, bits, curve);
const { privateParams, publicParams } = await crypto.generateParams(algo, bits, curve);
this.privateParams = privateParams; this.privateParams = privateParams;
this.publicParams = publicParams; this.publicParams = publicParams;
this.isEncrypted = false; this.isEncrypted = false;
@ -428,10 +419,8 @@ class SecretKeyPacket extends PublicKeyPacket {
} }
async function produceEncryptionKey(s2k, passphrase, algorithm) { async function produceEncryptionKey(s2k, passphrase, algorithm) {
return s2k.produceKey( const { keySize } = crypto.getCipher(algorithm);
passphrase, return s2k.produceKey(passphrase, keySize);
crypto.cipher[algorithm].keySize
);
} }
export default SecretKeyPacket; export default SecretKeyPacket;

View File

@ -50,8 +50,11 @@ class SignaturePacket {
constructor() { constructor() {
this.version = null; this.version = null;
/** @type {enums.signature} */
this.signatureType = null; this.signatureType = null;
/** @type {enums.hash} */
this.hashAlgorithm = null; this.hashAlgorithm = null;
/** @type {enums.publicKey} */
this.publicKeyAlgorithm = null; this.publicKeyAlgorithm = null;
this.signatureData = null; this.signatureData = null;
@ -170,16 +173,12 @@ class SignaturePacket {
* @async * @async
*/ */
async sign(key, data, date = new Date(), detached = false) { 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) { if (key.version === 5) {
this.version = 5; this.version = 5;
} else { } else {
this.version = 4; 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.created = util.normalizeDate(date);
this.issuerKeyVersion = key.version; this.issuerKeyVersion = key.version;
@ -191,12 +190,12 @@ class SignaturePacket {
this.signatureData = util.concat(arr); this.signatureData = util.concat(arr);
const toHash = this.toHash(signatureType, data, detached); const toHash = this.toHash(this.signatureType, data, detached);
const hash = await this.hash(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 = stream.slice(stream.clone(hash), 0, 2);
const signed = async () => crypto.signature.sign( 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)) { if (util.isStream(hash)) {
this.params = signed(); this.params = signed();
@ -644,9 +643,8 @@ class SignaturePacket {
} }
async hash(signatureType, data, toHash, detached = false) { async hash(signatureType, data, toHash, detached = false) {
const hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm);
if (!toHash) toHash = this.toHash(signatureType, data, detached); 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
*/ */
async verify(key, signatureType, data, date = new Date(), detached = false, config = defaultConfig) { 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())) { if (!this.issuerKeyID.equals(key.getKeyID())) {
throw new Error('Signature was not issued by the given public key'); 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.'); 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.params = await this.params;
this[verified] = await crypto.signature.verify( this[verified] = await crypto.signature.verify(
publicKeyAlgorithm, hashAlgorithm, this.params, key.publicParams, this.publicKeyAlgorithm, this.hashAlgorithm, this.params, key.publicParams,
toHash, hash toHash, hash
); );
@ -709,12 +705,12 @@ class SignaturePacket {
if (normDate && normDate >= this.getExpirationTime()) { if (normDate && normDate >= this.getExpirationTime()) {
throw new Error('Signature is expired'); throw new Error('Signature is expired');
} }
if (config.rejectHashAlgorithms.has(hashAlgorithm)) { if (config.rejectHashAlgorithms.has(this.hashAlgorithm)) {
throw new Error('Insecure hash algorithm: ' + enums.read(enums.hash, hashAlgorithm).toUpperCase()); 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)) { [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 }) => { this.rawNotations.forEach(({ name, critical }) => {
if (critical && (config.knownNotations.indexOf(name) < 0)) { if (critical && (config.knownNotations.indexOf(name) < 0)) {

View File

@ -80,13 +80,16 @@ class SymEncryptedIntegrityProtectedDataPacket {
/** /**
* Encrypt the payload in the packet. * 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 {Uint8Array} key - The key of cipher blocksize length to be used
* @param {Object} [config] - Full configuration, defaults to openpgp.config * @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise<Boolean>} * @returns {Promise<Boolean>}
* @throws {Error} on encryption failure
* @async * @async
*/ */
async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) { async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
const { blockSize } = crypto.getCipher(sessionKeyAlgorithm);
let bytes = this.packets.write(); let bytes = this.packets.write();
if (stream.isArrayStream(bytes)) bytes = await stream.readToEnd(bytes); if (stream.isArrayStream(bytes)) bytes = await stream.readToEnd(bytes);
const prefix = await crypto.getPrefixRandom(sessionKeyAlgorithm); const prefix = await crypto.getPrefixRandom(sessionKeyAlgorithm);
@ -96,22 +99,24 @@ class SymEncryptedIntegrityProtectedDataPacket {
const hash = await crypto.hash.sha1(stream.passiveClone(tohash)); const hash = await crypto.hash.sha1(stream.passiveClone(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(crypto.cipher[sessionKeyAlgorithm].blockSize), config); this.encrypted = await crypto.mode.cfb.encrypt(sessionKeyAlgorithm, key, plaintext, new Uint8Array(blockSize), config);
return true; return true;
} }
/** /**
* Decrypts the encrypted data contained in the packet. * 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 {Uint8Array} key - The key of cipher blocksize length to be used
* @param {Object} [config] - Full configuration, defaults to openpgp.config * @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise<Boolean>} * @returns {Promise<Boolean>}
* @throws {Error} on decryption failure
* @async * @async
*/ */
async decrypt(sessionKeyAlgorithm, key, config = defaultConfig) { async decrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
const { blockSize } = crypto.getCipher(sessionKeyAlgorithm);
let encrypted = stream.clone(this.encrypted); let encrypted = stream.clone(this.encrypted);
if (stream.isArrayStream(encrypted)) encrypted = await stream.readToEnd(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 // 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
@ -126,7 +131,7 @@ class SymEncryptedIntegrityProtectedDataPacket {
} }
return new Uint8Array(); 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 let packetbytes = stream.slice(bytes, 0, -2); // Remove MDC packet
packetbytes = stream.concat([packetbytes, stream.fromAsync(() => verifyHash)]); packetbytes = stream.concat([packetbytes, stream.fromAsync(() => verifyHash)]);
if (!util.isStream(encrypted) || !config.allowUnauthenticatedStream) { if (!util.isStream(encrypted) || !config.allowUnauthenticatedStream) {

View File

@ -46,9 +46,21 @@ class SymEncryptedSessionKeyPacket {
constructor(config = defaultConfig) { constructor(config = defaultConfig) {
this.version = config.aeadProtect ? 5 : 4; this.version = config.aeadProtect ? 5 : 4;
this.sessionKey = null; this.sessionKey = null;
/**
* Algorithm to encrypt the session key with
* @type {enums.symmetric}
*/
this.sessionKeyEncryptionAlgorithm = null; 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.encrypted = null;
this.s2k = null; this.s2k = null;
this.iv = null; this.iv = null;
@ -69,11 +81,11 @@ class SymEncryptedSessionKeyPacket {
} }
// A one-octet number describing the symmetric algorithm used. // 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) { if (this.version === 5) {
// A one-octet AEAD algorithm. // 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. // 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)); offset += this.s2k.read(bytes.subarray(offset, bytes.length));
if (this.version === 5) { 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 // A starting initialization vector of size specified by the AEAD
// algorithm. // algorithm.
@ -111,9 +123,9 @@ class SymEncryptedSessionKeyPacket {
let bytes; let bytes;
if (this.version === 5) { 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 { } 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) { if (this.encrypted !== null) {
bytes = util.concatUint8Array([bytes, this.encrypted]); 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 * @param {String} passphrase - The passphrase in string form
* @throws {Error} if decryption was not successful * @throws {Error} if decryption was not successful
* @async * @async
@ -134,18 +146,18 @@ class SymEncryptedSessionKeyPacket {
this.sessionKeyEncryptionAlgorithm : this.sessionKeyEncryptionAlgorithm :
this.sessionKeyAlgorithm; this.sessionKeyAlgorithm;
const length = crypto.cipher[algo].keySize; const { blockSize, keySize } = crypto.getCipher(algo);
const key = await this.s2k.produceKey(passphrase, length); const key = await this.s2k.produceKey(passphrase, keySize);
if (this.version === 5) { if (this.version === 5) {
const mode = crypto.mode[this.aeadAlgorithm]; const mode = crypto.getAEADMode(this.aeadAlgorithm);
const adata = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, enums.write(enums.symmetric, this.sessionKeyEncryptionAlgorithm), enums.write(enums.aead, this.aeadAlgorithm)]); const adata = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, this.sessionKeyEncryptionAlgorithm, this.aeadAlgorithm]);
const modeInstance = await mode(algo, key); const modeInstance = await mode(algo, key);
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(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); this.sessionKey = decrypted.subarray(1, decrypted.length);
} else { } else {
this.sessionKey = key; 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 {String} passphrase - The passphrase in string form
* @param {Object} [config] - Full configuration, defaults to openpgp.config * @param {Object} [config] - Full configuration, defaults to openpgp.config
* @throws {Error} if encryption was not successful * @throws {Error} if encryption was not successful
@ -169,23 +181,25 @@ class SymEncryptedSessionKeyPacket {
this.s2k = new S2K(config); this.s2k = new S2K(config);
this.s2k.salt = await crypto.random.getRandomBytes(8); this.s2k.salt = await crypto.random.getRandomBytes(8);
const length = crypto.cipher[algo].keySize; const { blockSize, keySize } = crypto.getCipher(algo);
const key = await this.s2k.produceKey(passphrase, length); const encryptionKey = await this.s2k.produceKey(passphrase, keySize);
if (this.sessionKey === null) { if (this.sessionKey === null) {
this.sessionKey = await crypto.generateSessionKey(this.sessionKeyAlgorithm); this.sessionKey = await crypto.generateSessionKey(this.sessionKeyAlgorithm);
} }
if (this.version === 5) { 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 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 associatedData = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, this.sessionKeyEncryptionAlgorithm, this.aeadAlgorithm]);
const modeInstance = await mode(algo, key); const modeInstance = await mode(algo, encryptionKey);
this.encrypted = await modeInstance.encrypt(this.sessionKey, this.iv, adata); this.encrypted = await modeInstance.encrypt(this.sessionKey, this.iv, associatedData);
} else { } else {
const algo_enum = new Uint8Array([enums.write(enums.symmetric, this.sessionKeyAlgorithm)]); const toEncrypt = util.concatUint8Array([
const private_key = util.concatUint8Array([algo_enum, this.sessionKey]); new Uint8Array([this.sessionKeyAlgorithm]),
this.encrypted = await crypto.mode.cfb.encrypt(algo, key, private_key, new Uint8Array(crypto.cipher[algo].blockSize), config); this.sessionKey
]);
this.encrypted = await crypto.mode.cfb.encrypt(algo, encryptionKey, toEncrypt, new Uint8Array(blockSize), config);
} }
} }
} }

View File

@ -86,10 +86,11 @@ class SymmetricallyEncryptedDataPacket {
throw new Error('Message is not authenticated.'); throw new Error('Message is not authenticated.');
} }
const { blockSize } = crypto.getCipher(sessionKeyAlgorithm);
const encrypted = await stream.readToEnd(stream.clone(this.encrypted)); const encrypted = await stream.readToEnd(stream.clone(this.encrypted));
const decrypted = await crypto.mode.cfb.decrypt(sessionKeyAlgorithm, key, const decrypted = await crypto.mode.cfb.decrypt(sessionKeyAlgorithm, key,
encrypted.subarray(crypto.cipher[sessionKeyAlgorithm].blockSize + 2), encrypted.subarray(blockSize + 2),
encrypted.subarray(2, crypto.cipher[sessionKeyAlgorithm].blockSize + 2) encrypted.subarray(2, blockSize + 2)
); );
this.packets = await PacketList.fromBinary(decrypted, allowedPackets, config); this.packets = await PacketList.fromBinary(decrypted, allowedPackets, config);
@ -104,12 +105,13 @@ class SymmetricallyEncryptedDataPacket {
* @throws {Error} if encryption was not successful * @throws {Error} if encryption was not successful
* @async * @async
*/ */
async encrypt(algo, key, config = defaultConfig) { async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
const data = this.packets.write(); const data = this.packets.write();
const { blockSize } = crypto.getCipher(sessionKeyAlgorithm);
const prefix = await crypto.getPrefixRandom(algo); const prefix = await crypto.getPrefixRandom(sessionKeyAlgorithm);
const FRE = await crypto.mode.cfb.encrypt(algo, key, prefix, new Uint8Array(crypto.cipher[algo].blockSize), config); const FRE = await crypto.mode.cfb.encrypt(sessionKeyAlgorithm, key, prefix, new Uint8Array(blockSize), config);
const ciphertext = await crypto.mode.cfb.encrypt(algo, key, data, FRE.subarray(2), config); const ciphertext = await crypto.mode.cfb.encrypt(sessionKeyAlgorithm, key, data, FRE.subarray(2), config);
this.encrypted = util.concat([FRE, ciphertext]); this.encrypted = util.concat([FRE, ciphertext]);
} }
} }

View File

@ -38,14 +38,20 @@ class S2K {
* @param {Object} [config] - Full configuration, defaults to openpgp.config * @param {Object} [config] - Full configuration, defaults to openpgp.config
*/ */
constructor(config = defaultConfig) { constructor(config = defaultConfig) {
/** @type {module:enums.hash} */ /**
this.algorithm = 'sha256'; * Hash function identifier, or 0 for gnu-dummy keys
/** @type {module:enums.s2k} */ * @type {module:enums.hash | 0}
*/
this.algorithm = enums.hash.sha256;
/**
* enums.s2k identifier or 'gnu-dummy'
* @type {String}
*/
this.type = 'iterated'; this.type = 'iterated';
/** @type {Integer} */ /** @type {Integer} */
this.c = config.s2kIterationCountByte; this.c = config.s2kIterationCountByte;
/** Eight bytes of salt in a binary string. /** Eight bytes of salt in a binary string.
* @type {String} * @type {Uint8Array}
*/ */
this.salt = null; 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}). * 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. * @returns {Integer} Actual length of the object.
*/ */
read(bytes) { read(bytes) {
let i = 0; let i = 0;
this.type = enums.read(enums.s2k, bytes[i++]); this.type = enums.read(enums.s2k, bytes[i++]);
this.algorithm = bytes[i++]; this.algorithm = bytes[i++];
if (this.type !== 'gnu') {
this.algorithm = enums.read(enums.hash, this.algorithm);
}
switch (this.type) { switch (this.type) {
case 'simple': case 'simple':
@ -117,8 +120,7 @@ class S2K {
if (this.type === 'gnu-dummy') { if (this.type === 'gnu-dummy') {
return new Uint8Array([101, 0, ...util.stringToUint8Array('GNU'), 1]); return new Uint8Array([101, 0, ...util.stringToUint8Array('GNU'), 1]);
} }
const arr = [new Uint8Array([enums.write(enums.s2k, this.type), this.algorithm])];
const arr = [new Uint8Array([enums.write(enums.s2k, this.type), enums.write(enums.hash, this.algorithm)])];
switch (this.type) { switch (this.type) {
case 'simple': case 'simple':
@ -149,7 +151,6 @@ class S2K {
*/ */
async produceKey(passphrase, numBytes) { async produceKey(passphrase, numBytes) {
passphrase = util.encodeUTF8(passphrase); passphrase = util.encodeUTF8(passphrase);
const algorithm = enums.write(enums.hash, this.algorithm);
const arr = []; const arr = [];
let rlength = 0; let rlength = 0;
@ -180,7 +181,7 @@ class S2K {
default: default:
throw new Error('Unknown s2k type.'); 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); arr.push(result);
rlength += result.length; rlength += result.length;
prefixlen++; prefixlen++;

View File

@ -233,17 +233,18 @@ module.exports = () => describe('API functional testing', function() {
}); });
describe('Encrypt and decrypt', function () { describe('Encrypt and decrypt', function () {
let symmAlgos = Object.keys(openpgp.enums.symmetric); const symmAlgoNames = Object.keys(openpgp.enums.symmetric).filter(
symmAlgos = symmAlgos.filter(function(algo) { algo => algo !== 'idea' && algo !== 'plaintext'
return algo !== 'idea' && algo !== 'plaintext'; );
});
async function testCFB(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 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 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); 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 () { 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.publicKeyEncrypt(algoRSA, RSAPublicParams, symmKey).then(RSAEncryptedData => {
return crypto.publicKeyDecrypt( return crypto.publicKeyDecrypt(
algoRSA, RSAPublicParams, RSAPrivateParams, RSAEncryptedData 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 () { 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.publicKeyEncrypt(algoElGamal, elGamalPublicParams, symmKey).then(ElgamalEncryptedData => {
return crypto.publicKeyDecrypt( return crypto.publicKeyDecrypt(
algoElGamal, elGamalPublicParams, elGamalPrivateParams, ElgamalEncryptedData algoElGamal, elGamalPublicParams, elGamalPrivateParams, ElgamalEncryptedData

View File

@ -1,7 +1,7 @@
// Modified by ProtonTech AG // Modified by ProtonTech AG
// Adapted from https://github.com/artjomb/cryptojs-extension/blob/8c61d159/test/eax.js // 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 EAX = require('../../src/crypto/mode/eax');
const util = require('../../src/util'); 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 => { await Promise.all(vectors.map(async vec => {
const keyBytes = util.hexToUint8Array(vec.key); const keyBytes = util.hexToUint8Array(vec.key);

View File

@ -34,16 +34,17 @@ module.exports = () => describe('Symmetric AES-GCM (experimental)', function() {
}; };
function testAESGCM(plaintext, nativeEncrypt, nativeDecrypt) { function testAESGCM(plaintext, nativeEncrypt, nativeDecrypt) {
const aesAlgos = Object.keys(openpgp.enums.symmetric).filter( const aesAlgoNames = Object.keys(openpgp.enums.symmetric).filter(
algo => algo.substr(0,3) === 'aes' algoName => algoName.substr(0,3) === 'aes'
); );
aesAlgos.forEach(function(algo) { aesAlgoNames.forEach(function(algoName) {
it(algo, async function() { it(algoName, async function() {
const nodeCrypto = util.getNodeCrypto(); const nodeCrypto = util.getNodeCrypto();
const webCrypto = util.getWebCrypto(); const webCrypto = util.getWebCrypto();
if (!nodeCrypto && !webCrypto) { if (!nodeCrypto && !webCrypto) {
this.skip(); // eslint-disable-line no-invalid-this this.skip(); // eslint-disable-line no-invalid-this
} }
const algo = openpgp.enums.write(openpgp.enums.symmetric, algoName);
const key = await crypto.generateSessionKey(algo); const key = await crypto.generateSessionKey(algo);
const iv = await crypto.random.getRandomBytes(crypto.mode.gcm.ivLength); 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); const decryptedStr = util.uint8ArrayToString(decrypted);
expect(decryptedStr).to.equal(plaintext); 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 // sanity check: native crypto was indeed on/off
expect(nativeEncryptSpy.called).to.equal(nativeEncrypt); expect(nativeEncryptSpy.called).to.equal(nativeEncrypt);
expect(nativeDecryptSpy.called).to.equal(nativeDecrypt); expect(nativeDecryptSpy.called).to.equal(nativeDecrypt);

View File

@ -1,7 +1,7 @@
// Modified by ProtonTech AG // Modified by ProtonTech AG
// Adapted from https://github.com/artjomb/cryptojs-extension/blob/8c61d159/test/eax.js // 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 OCB = require('../../src/crypto/mode/ocb');
const util = require('../../src/util'); 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 => { await Promise.all(vectors.map(async vec => {
const msgBytes = util.hexToUint8Array(vec.P); const msgBytes = util.hexToUint8Array(vec.P);
@ -163,7 +163,8 @@ module.exports = () => describe('Symmetric AES-OCB', function() {
const k = new Uint8Array(keylen / 8); const k = new Uint8Array(keylen / 8);
k[k.length - 1] = taglen; 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 = []; const c = [];
let n; let n;

View File

@ -79,7 +79,7 @@ module.exports = () => describe('basic RSA cryptography', function () {
const bits = 1024; const bits = 1024;
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits); const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams }; 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 encrypted = await crypto.publicKey.rsa.encrypt(message, n, e);
const decrypted = await crypto.publicKey.rsa.decrypt(encrypted, n, e, d, p, q, u); const decrypted = await crypto.publicKey.rsa.decrypt(encrypted, n, e, d, p, q, u);
expect(decrypted).to.deep.equal(message); expect(decrypted).to.deep.equal(message);
@ -92,7 +92,7 @@ module.exports = () => describe('basic RSA cryptography', function () {
const bits = 1024; const bits = 1024;
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits); const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams }; 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(); disableNative();
const encryptedBn = await crypto.publicKey.rsa.encrypt(message, n, e); const encryptedBn = await crypto.publicKey.rsa.encrypt(message, n, e);
enableNative(); enableNative();

View File

@ -223,7 +223,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
expect(encData2.constructor.tag).to.equal(openpgp.enums.packet.aeadEncryptedData); expect(encData2.constructor.tag).to.equal(openpgp.enums.packet.aeadEncryptedData);
const { packets: [compressed] } = await encrypted2.decrypt(null, passwords, null, encrypted2.fromStream, openpgp.config); 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.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 userIDs = { name: 'Test User', email: 'text2@example.com' };
const { privateKey: key } = await openpgp.generateKey({ userIDs, format: 'object' }); const { privateKey: key } = await openpgp.generateKey({ userIDs, format: 'object' });

View File

@ -834,7 +834,7 @@ Be4ubVrj5KjhX2PVNEJd3XZRzaXZE2aAMQ==
-----END PGP PUBLIC KEY BLOCK-----`; -----END PGP PUBLIC KEY BLOCK-----`;
function withCompression(tests) { 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) { compressionTypes.forEach(function (compression) {
const compressionName = openpgp.enums.read(openpgp.enums.compression, 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.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.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 () { it('should encrypt using custom session key and decrypt using session key', async function () {
const sessionKey = { const sessionKey = {
data: await crypto.generateSessionKey('aes256'), data: await crypto.generateSessionKey(openpgp.enums.symmetric.aes256),
algorithm: 'aes256' algorithm: 'aes256'
}; };
const encOpt = { const encOpt = {
@ -2330,7 +2330,7 @@ aOU=
it('should encrypt using custom session key and decrypt using private key', async function () { it('should encrypt using custom session key and decrypt using private key', async function () {
const sessionKey = { const sessionKey = {
data: await crypto.generateSessionKey('aes128'), data: await crypto.generateSessionKey(openpgp.enums.symmetric.aes128),
algorithm: 'aes128' algorithm: 'aes128'
}; };
const encOpt = { const encOpt = {
@ -3481,7 +3481,7 @@ aOU=
}).then(async function (message) { }).then(async function (message) {
const literals = message.packets.filterByTag(openpgp.enums.packet.literalData); const literals = message.packets.filterByTag(openpgp.enums.packet.literalData);
expect(literals.length).to.equal(1); 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); expect(+literals[0].date).to.equal(+future);
const signatures = await message.verify([publicKey_2038_2045], future, undefined, openpgp.config); const signatures = await message.verify([publicKey_2038_2045], future, undefined, openpgp.config);
expect(await stream.readToEnd(message.getLiteralData())).to.deep.equal(data); expect(await stream.readToEnd(message.getLiteralData())).to.deep.equal(data);
@ -3510,7 +3510,7 @@ aOU=
}).then(async function (message) { }).then(async function (message) {
const literals = message.packets.filterByTag(openpgp.enums.packet.literalData); const literals = message.packets.filterByTag(openpgp.enums.packet.literalData);
expect(literals.length).to.equal(1); 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); expect(+literals[0].date).to.equal(+future);
const signatures = await message.verify([publicKey_2038_2045], future, undefined, openpgp.config); const signatures = await message.verify([publicKey_2038_2045], future, undefined, openpgp.config);
expect(await stream.readToEnd(message.getLiteralData())).to.deep.equal(data); expect(await stream.readToEnd(message.getLiteralData())).to.deep.equal(data);

View File

@ -88,7 +88,7 @@ module.exports = () => describe('Packet', function() {
message.push(enc); 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 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); await enc.encrypt(algo, key, undefined, openpgp.config);
@ -120,7 +120,7 @@ module.exports = () => describe('Packet', function() {
message.push(enc); 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 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); 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() { 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 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 testText = input.createSomeMessage();
const literal = new openpgp.LiteralDataPacket(); const literal = new openpgp.LiteralDataPacket();
@ -160,7 +160,7 @@ module.exports = () => describe('Packet', function() {
try { 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 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 testText = input.createSomeMessage();
const literal = new openpgp.LiteralDataPacket(); const literal = new openpgp.LiteralDataPacket();
literal.setText(testText); literal.setText(testText);
@ -212,12 +212,12 @@ module.exports = () => describe('Packet', function() {
const testText = input.createSomeMessage(); 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 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(); const literal = new openpgp.LiteralDataPacket();
literal.setText(testText); literal.setText(testText);
const enc = new openpgp.AEADEncryptedDataPacket(); const enc = new openpgp.AEADEncryptedDataPacket();
enc.aeadAlgorithm = 'experimentalGCM'; enc.aeadAlgorithm = openpgp.enums.aead.experimentalGCM;
enc.packets = new openpgp.PacketList(); enc.packets = new openpgp.PacketList();
enc.packets.push(literal); enc.packets.push(literal);
const msg = new openpgp.PacketList(); 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 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 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); const literal = new openpgp.LiteralDataPacket(0);
literal.setBytes(util.stringToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary); 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(); const parsed = new openpgp.PacketList();
await parsed.read(msgbytes, allAllowedPackets); await parsed.read(msgbytes, allAllowedPackets);
const [skesk, seip] = parsed;
return parsed[0].decrypt('test').then(() => { await skesk.decrypt('test');
const key = parsed[0].sessionKey; return seip.decrypt(skesk.sessionKeyAlgorithm, skesk.sessionKey).then(async () => {
return parsed[1].decrypt(parsed[0].sessionKeyAlgorithm, key).then(async () => { const compressed = seip.packets[0];
const compressed = parsed[1].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(); 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.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.publicKeyAlgorithm = openpgp.enums.publicKey.rsaEncryptSign;
enc.sessionKeyAlgorithm = 'aes256'; enc.sessionKeyAlgorithm = openpgp.enums.symmetric.aes256;
enc.publicKeyID.bytes = '12345678'; enc.publicKeyID.bytes = '12345678';
return enc.encrypt({ publicParams, getFingerprintBytes() {} }).then(async () => { return enc.encrypt({ publicParams, getFingerprintBytes() {} }).then(async () => {
msg.push(enc); msg.push(enc);
await msg2.read(msg.write(), allAllowedPackets); 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(stringify(msg2[0].sessionKey)).to.equal(stringify(enc.sessionKey));
expect(msg2[0].sessionKeyAlgorithm).to.equal(enc.sessionKeyAlgorithm); 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]); 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.sessionKey = secret;
enc.publicKeyAlgorithm = 'rsaEncryptSign'; enc.publicKeyAlgorithm = openpgp.enums.publicKey.rsaEncryptSign;
enc.sessionKeyAlgorithm = 'aes256'; enc.sessionKeyAlgorithm = openpgp.enums.symmetric.aes256;
enc.publicKeyID.bytes = '12345678'; enc.publicKeyID.bytes = '12345678';
return enc.encrypt(key).then(() => { return enc.encrypt(key).then(() => {
@ -447,7 +447,7 @@ module.exports = () => describe('Packet', function() {
try { try {
const passphrase = 'hello'; const passphrase = 'hello';
const algo = 'aes256'; const algo = openpgp.enums.symmetric.aes256;
const testText = input.createSomeMessage(); const testText = input.createSomeMessage();
const literal = new openpgp.LiteralDataPacket(); const literal = new openpgp.LiteralDataPacket();
@ -486,7 +486,7 @@ module.exports = () => describe('Packet', function() {
try { try {
const passphrase = 'hello'; const passphrase = 'hello';
const algo = 'aes256'; const algo = openpgp.enums.symmetric.aes256;
const testText = input.createSomeMessage(); const testText = input.createSomeMessage();
const literal = new openpgp.LiteralDataPacket(); const literal = new openpgp.LiteralDataPacket();
@ -557,7 +557,7 @@ module.exports = () => describe('Packet', function() {
try { try {
const passphrase = 'password'; const passphrase = 'password';
const algo = 'aes128'; const algo = openpgp.enums.symmetric.aes128;
const literal = new openpgp.LiteralDataPacket(0); const literal = new openpgp.LiteralDataPacket(0);
literal.setBytes(util.stringToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary); literal.setBytes(util.stringToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary);
@ -634,24 +634,24 @@ module.exports = () => describe('Packet', function() {
try { try {
const passphrase = 'password'; const passphrase = 'password';
const algo = 'aes128'; const algo = openpgp.enums.symmetric.aes128;
const literal = new openpgp.LiteralDataPacket(0); const literal = new openpgp.LiteralDataPacket(0);
literal.setBytes(util.stringToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary); literal.setBytes(util.stringToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary);
literal.filename = ''; literal.filename = '';
const key_enc = new openpgp.SymEncryptedSessionKeyPacket(); const skesk = new openpgp.SymEncryptedSessionKeyPacket();
key_enc.sessionKeyAlgorithm = algo; skesk.sessionKeyAlgorithm = algo;
const enc = new openpgp.AEADEncryptedDataPacket(); const enc = new openpgp.AEADEncryptedDataPacket();
enc.packets = new openpgp.PacketList(); enc.packets = new openpgp.PacketList();
enc.packets.push(literal); enc.packets.push(literal);
enc.aeadAlgorithm = key_enc.aeadAlgorithm = 'ocb'; enc.aeadAlgorithm = skesk.aeadAlgorithm = openpgp.enums.aead.ocb;
const msg = new openpgp.PacketList(); const msg = new openpgp.PacketList();
msg.push(key_enc); msg.push(skesk);
msg.push(enc); 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); await enc.encrypt(algo, key, undefined, openpgp.config);
const data = msg.write(); const data = msg.write();
@ -840,7 +840,7 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+
const secretKeyPacket = new openpgp.SecretKeyPacket(); const secretKeyPacket = new openpgp.SecretKeyPacket();
secretKeyPacket.privateParams = privateParams; secretKeyPacket.privateParams = privateParams;
secretKeyPacket.publicParams = publicParams; secretKeyPacket.publicParams = publicParams;
secretKeyPacket.algorithm = 'rsaSign'; secretKeyPacket.algorithm = openpgp.enums.publicKey.rsaSign;
secretKeyPacket.isEncrypted = false; secretKeyPacket.isEncrypted = false;
await secretKeyPacket.encrypt('hello', { ...openpgp.config, aeadProtect: true }); await secretKeyPacket.encrypt('hello', { ...openpgp.config, aeadProtect: true });
expect(secretKeyPacket.s2kUsage).to.equal(253); expect(secretKeyPacket.s2kUsage).to.equal(253);
@ -864,7 +864,7 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+
packet.privateParams = { key: new Uint8Array([1, 2, 3]) }; packet.privateParams = { key: new Uint8Array([1, 2, 3]) };
packet.publicParams = { pubKey: new Uint8Array([4, 5, 6]) }; packet.publicParams = { pubKey: new Uint8Array([4, 5, 6]) };
packet.algorithm = 'rsaSign'; packet.algorithm = openpgp.enums.publicKey.rsaSign;
packet.isEncrypted = false; packet.isEncrypted = false;
packet.s2kUsage = 0; packet.s2kUsage = 0;
@ -896,7 +896,7 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+
const secretKeyPacket = new openpgp.SecretKeyPacket(); const secretKeyPacket = new openpgp.SecretKeyPacket();
secretKeyPacket.privateParams = privateParams; secretKeyPacket.privateParams = privateParams;
secretKeyPacket.publicParams = publicParams; secretKeyPacket.publicParams = publicParams;
secretKeyPacket.algorithm = 'rsaSign'; secretKeyPacket.algorithm = openpgp.enums.publicKey.rsaSign;
secretKeyPacket.isEncrypted = false; secretKeyPacket.isEncrypted = false;
await secretKeyPacket.encrypt('hello', { ...openpgp.config, aeadProtect: false }); await secretKeyPacket.encrypt('hello', { ...openpgp.config, aeadProtect: false });
expect(secretKeyPacket.s2kUsage).to.equal(254); expect(secretKeyPacket.s2kUsage).to.equal(254);
@ -917,7 +917,7 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+
key.publicParams = publicParams; key.publicParams = publicParams;
key.privateParams = privateParams; key.privateParams = privateParams;
key.algorithm = 'rsaSign'; key.algorithm = openpgp.enums.publicKey.rsaSign;
await key.computeFingerprintAndKeyID(); await key.computeFingerprintAndKeyID();
const signed = new openpgp.PacketList(); const signed = new openpgp.PacketList();

View File

@ -68,7 +68,7 @@ import {
// Encrypt text message (armored) // Encrypt text message (armored)
const text = 'hello'; 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 }); const encryptedArmor: string = await encrypt({ encryptionKeys: publicKeys, message: textMessage });
expect(encryptedArmor).to.include('-----BEGIN PGP MESSAGE-----'); expect(encryptedArmor).to.include('-----BEGIN PGP MESSAGE-----');