Replace armor option with format in openpgp.encrypt, sign and encryptSessionKey (#1354)

Breaking changes:
- a new `format` option has been added to `openpgp.encrypt`, `sign` and
`encryptSessionKey` to select the format of the output message. `format`
replaces the existing `armor` option, and accepts three values:
   * if `format: 'armor'` (default), an armored signed/encrypted message is
returned (same as `armor: true`).
   * if `format: 'binary'`,  a binary signed/encrypted message is returned (same
as `armor: false`).
   * if `format: 'object'`, a Message or Signature object is returned (this was
not supported before).
This change is to uniform the output format selection across all top-level
functions (following up to #1345).

- All top-level functions now throw if unrecognised options are passed, to make
library users aware that those options are not being applied.
This commit is contained in:
larabr 2021-07-19 18:12:42 +02:00 committed by GitHub
parent 53f54e1e19
commit ce70484738
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 443 additions and 120 deletions

View File

@ -177,7 +177,7 @@ Encryption will use the algorithm specified in config.preferredSymmetricAlgorith
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message, // input as Message object message, // input as Message object
passwords: ['secret stuff'], // multiple passwords possible passwords: ['secret stuff'], // multiple passwords possible
armor: false // don't ASCII armor (for Uint8Array output) format: 'binary' // don't ASCII armor (for Uint8Array output)
}); });
console.log(encrypted); // Uint8Array console.log(encrypted); // Uint8Array
@ -358,7 +358,7 @@ Where the value can be any of:
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message, // input as Message object message, // input as Message object
passwords: ['secret stuff'], // multiple passwords possible passwords: ['secret stuff'], // multiple passwords possible
armor: false // don't ASCII armor (for Uint8Array output) format: 'binary' // don't ASCII armor (for Uint8Array output)
}); });
console.log(encrypted); // raw encrypted packets as ReadableStream<Uint8Array> console.log(encrypted); // raw encrypted packets as ReadableStream<Uint8Array>

40
openpgp.d.ts vendored
View File

@ -172,11 +172,14 @@ export class CleartextMessage {
/* ############## v5 MSG #################### */ /* ############## v5 MSG #################### */
export function generateSessionKey(options: { encryptionKeys: MaybeArray<PublicKey>, date?: Date, encryptionUserIDs?: MaybeArray<UserID>, config?: PartialConfig }): Promise<SessionKey>; export function generateSessionKey(options: { encryptionKeys: MaybeArray<PublicKey>, date?: Date, encryptionUserIDs?: MaybeArray<UserID>, config?: PartialConfig }): Promise<SessionKey>;
export function encryptSessionKey(options: SessionKey & { export function encryptSessionKey(options: SessionKey & {
encryptionKeys?: MaybeArray<PublicKey>, passwords?: MaybeArray<string>, armor?: true, wildcard?: boolean, encryptionKeyIDs?: MaybeArray<KeyID>, date?: Date, encryptionUserIDs?: MaybeArray<UserID>, config?: PartialConfig encryptionKeys?: MaybeArray<PublicKey>, passwords?: MaybeArray<string>, format?: 'armor', wildcard?: boolean, encryptionKeyIDs?: MaybeArray<KeyID>, date?: Date, encryptionUserIDs?: MaybeArray<UserID>, config?: PartialConfig
}) : Promise<string>; }) : Promise<string>;
export function encryptSessionKey(options: SessionKey & { export function encryptSessionKey(options: SessionKey & {
encryptionKeys?: MaybeArray<PublicKey>, passwords?: MaybeArray<string>, armor: false, wildcard?: boolean, encryptionKeyIDs?: MaybeArray<KeyID>, date?: Date, encryptionUserIDs?: MaybeArray<UserID>, config?: PartialConfig encryptionKeys?: MaybeArray<PublicKey>, passwords?: MaybeArray<string>, format: 'binary', wildcard?: boolean, encryptionKeyIDs?: MaybeArray<KeyID>, date?: Date, encryptionUserIDs?: MaybeArray<UserID>, config?: PartialConfig
}) : Promise<Uint8Array>; }) : Promise<Uint8Array>;
export function encryptSessionKey(options: SessionKey & {
encryptionKeys?: MaybeArray<PublicKey>, passwords?: MaybeArray<string>, format: 'object', wildcard?: boolean, encryptionKeyIDs?: MaybeArray<KeyID>, date?: Date, encryptionUserIDs?: MaybeArray<UserID>, config?: PartialConfig
}) : Promise<Message<Data>>;
export function decryptSessionKeys<T extends MaybeStream<Data>>(options: { message: Message<T>, decryptionKeys?: MaybeArray<PrivateKey>, passwords?: MaybeArray<string>, date?: Date, config?: PartialConfig }): Promise<SessionKey[]>; export function decryptSessionKeys<T extends MaybeStream<Data>>(options: { message: Message<T>, decryptionKeys?: MaybeArray<PrivateKey>, passwords?: MaybeArray<string>, date?: Date, config?: PartialConfig }): Promise<SessionKey[]>;
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>>;
@ -185,28 +188,31 @@ export function readMessage<T extends MaybeStream<Uint8Array>>(options: { binary
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, type?: DataPacketType }): 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, type?: DataPacketType }): Promise<Message<T>>;
export function encrypt<T extends MaybeStream<Data>>(options: EncryptOptions & { message: Message<T>, armor: false }): Promise< export function encrypt<T extends MaybeStream<Data>>(options: EncryptOptions & { message: Message<T>, format?: 'armor' }): Promise<
T extends WebStream<infer X> ? WebStream<Uint8Array> :
T extends NodeStream<infer X> ? NodeStream<Uint8Array> :
Uint8Array
>;
export function encrypt<T extends MaybeStream<Data>>(options: EncryptOptions & { message: Message<T> }): Promise<
T extends WebStream<infer X> ? WebStream<string> : T extends WebStream<infer X> ? WebStream<string> :
T extends NodeStream<infer X> ? NodeStream<string> : T extends NodeStream<infer X> ? NodeStream<string> :
string string
>; >;
export function encrypt<T extends MaybeStream<Data>>(options: EncryptOptions & { message: Message<T>, format: 'binary' }): Promise<
T extends WebStream<infer X> ? WebStream<Uint8Array> :
T extends NodeStream<infer X> ? NodeStream<Uint8Array> :
Uint8Array
>;
export function encrypt<T extends MaybeStream<Data>>(options: EncryptOptions & { message: Message<T>, format: 'object' }): Promise<Message<T>>;
export function sign<T extends MaybeStream<Data>>(options: SignOptions & { message: Message<T>, armor: false }): Promise< export function sign<T extends MaybeStream<Data>>(options: SignOptions & { message: Message<T>, format?: 'armor' }): Promise<
T extends WebStream<infer X> ? WebStream<Uint8Array> :
T extends NodeStream<infer X> ? NodeStream<Uint8Array> :
Uint8Array
>;
export function sign<T extends MaybeStream<Data>>(options: SignOptions & { message: Message<T> }): Promise<
T extends WebStream<infer X> ? WebStream<string> : T extends WebStream<infer X> ? WebStream<string> :
T extends NodeStream<infer X> ? NodeStream<string> : T extends NodeStream<infer X> ? NodeStream<string> :
string string
>; >;
export function sign(options: SignOptions & { message: CleartextMessage }): Promise<string>; export function sign<T extends MaybeStream<Data>>(options: SignOptions & { message: Message<T>, format: 'binary' }): Promise<
T extends WebStream<infer X> ? WebStream<Uint8Array> :
T extends NodeStream<infer X> ? NodeStream<Uint8Array> :
Uint8Array
>;
export function sign<T extends MaybeStream<Data>>(options: SignOptions & { message: Message<T>, format: 'object' }): Promise<Message<T>>;
export function sign(options: SignOptions & { message: CleartextMessage, format?: 'armor' }): Promise<string>;
export function sign(options: SignOptions & { message: CleartextMessage, format: 'object' }): Promise<CleartextMessage>;
export function decrypt<T extends MaybeStream<Data>>(options: DecryptOptions & { message: Message<T>, format: 'binary' }): Promise<DecryptMessageResult & { export function decrypt<T extends MaybeStream<Data>>(options: DecryptOptions & { message: Message<T>, format: 'binary' }): Promise<DecryptMessageResult & {
data: data:
@ -577,7 +583,7 @@ interface EncryptOptions {
/** (optional) session key */ /** (optional) session key */
sessionKey?: SessionKey; sessionKey?: SessionKey;
/** if the return values should be ascii armored or the message/signature objects */ /** if the return values should be ascii armored or the message/signature objects */
armor?: boolean; format?: 'armor' | 'binary' | 'object';
/** (optional) if the signature should be detached (if true, signature will be added to returned object) */ /** (optional) if the signature should be detached (if true, signature will be added to returned object) */
signature?: Signature; signature?: Signature;
/** (optional) encrypt as of a certain date */ /** (optional) encrypt as of a certain date */
@ -620,7 +626,7 @@ interface DecryptOptions {
interface SignOptions { interface SignOptions {
message: CleartextMessage | Message<MaybeStream<Data>>; message: CleartextMessage | Message<MaybeStream<Data>>;
signingKeys?: MaybeArray<PrivateKey>; signingKeys?: MaybeArray<PrivateKey>;
armor?: boolean; format?: 'armor' | 'binary' | 'object';
dataType?: DataPacketType; dataType?: DataPacketType;
detached?: boolean; detached?: boolean;
signingKeyIDs?: MaybeArray<KeyID>; signingKeyIDs?: MaybeArray<KeyID>;

View File

@ -132,7 +132,7 @@ export class CleartextMessage {
* @async * @async
* @static * @static
*/ */
export async function readCleartextMessage({ cleartextMessage, config }) { export async function readCleartextMessage({ cleartextMessage, config, ...rest }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
if (!cleartextMessage) { if (!cleartextMessage) {
throw new Error('readCleartextMessage: must pass options object containing `cleartextMessage`'); throw new Error('readCleartextMessage: must pass options object containing `cleartextMessage`');
@ -140,6 +140,8 @@ export async function readCleartextMessage({ cleartextMessage, config }) {
if (!util.isString(cleartextMessage)) { if (!util.isString(cleartextMessage)) {
throw new Error('readCleartextMessage: options.cleartextMessage must be a string'); throw new Error('readCleartextMessage: options.cleartextMessage must be a string');
} }
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
const input = await unarmor(cleartextMessage); const input = await unarmor(cleartextMessage);
if (input.type !== enums.armor.signed) { if (input.type !== enums.armor.signed) {
throw new Error('No cleartext signed message.'); throw new Error('No cleartext signed message.');
@ -203,12 +205,14 @@ function verifyHeaders(headers, packetlist) {
* @static * @static
* @async * @async
*/ */
export async function createCleartextMessage({ text }) { export async function createCleartextMessage({ text, ...rest }) {
if (!text) { if (!text) {
throw new Error('createCleartextMessage: must pass options object containing `text`'); throw new Error('createCleartextMessage: must pass options object containing `text`');
} }
if (!util.isString(text)) { if (!util.isString(text)) {
throw new Error('createCleartextMessage: options.text must be a string'); throw new Error('createCleartextMessage: options.text must be a string');
} }
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
return new CleartextMessage(text); return new CleartextMessage(text);
} }

View File

@ -275,7 +275,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
* @async * @async
* @static * @static
*/ */
export async function readKey({ armoredKey, binaryKey, config }) { export async function readKey({ armoredKey, binaryKey, config, ...rest }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
if (!armoredKey && !binaryKey) { if (!armoredKey && !binaryKey) {
throw new Error('readKey: must pass options object containing `armoredKey` or `binaryKey`'); throw new Error('readKey: must pass options object containing `armoredKey` or `binaryKey`');
@ -286,6 +286,8 @@ export async function readKey({ armoredKey, binaryKey, config }) {
if (binaryKey && !util.isUint8Array(binaryKey)) { if (binaryKey && !util.isUint8Array(binaryKey)) {
throw new Error('readKey: options.binaryKey must be a Uint8Array'); throw new Error('readKey: options.binaryKey must be a Uint8Array');
} }
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
let input; let input;
if (armoredKey) { if (armoredKey) {
const { type, data } = await unarmor(armoredKey, config); const { type, data } = await unarmor(armoredKey, config);
@ -310,7 +312,7 @@ export async function readKey({ armoredKey, binaryKey, config }) {
* @async * @async
* @static * @static
*/ */
export async function readPrivateKey({ armoredKey, binaryKey, config }) { export async function readPrivateKey({ armoredKey, binaryKey, config, ...rest }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
if (!armoredKey && !binaryKey) { if (!armoredKey && !binaryKey) {
throw new Error('readPrivateKey: must pass options object containing `armoredKey` or `binaryKey`'); throw new Error('readPrivateKey: must pass options object containing `armoredKey` or `binaryKey`');
@ -321,6 +323,8 @@ export async function readPrivateKey({ armoredKey, binaryKey, config }) {
if (binaryKey && !util.isUint8Array(binaryKey)) { if (binaryKey && !util.isUint8Array(binaryKey)) {
throw new Error('readPrivateKey: options.binaryKey must be a Uint8Array'); throw new Error('readPrivateKey: options.binaryKey must be a Uint8Array');
} }
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
let input; let input;
if (armoredKey) { if (armoredKey) {
const { type, data } = await unarmor(armoredKey, config); const { type, data } = await unarmor(armoredKey, config);
@ -345,7 +349,7 @@ export async function readPrivateKey({ armoredKey, binaryKey, config }) {
* @async * @async
* @static * @static
*/ */
export async function readKeys({ armoredKeys, binaryKeys, config }) { export async function readKeys({ armoredKeys, binaryKeys, config, ...rest }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
let input = armoredKeys || binaryKeys; let input = armoredKeys || binaryKeys;
if (!input) { if (!input) {
@ -357,6 +361,8 @@ export async function readKeys({ armoredKeys, binaryKeys, config }) {
if (binaryKeys && !util.isUint8Array(binaryKeys)) { if (binaryKeys && !util.isUint8Array(binaryKeys)) {
throw new Error('readKeys: options.binaryKeys must be a Uint8Array'); throw new Error('readKeys: options.binaryKeys must be a Uint8Array');
} }
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (armoredKeys) { if (armoredKeys) {
const { type, data } = await unarmor(armoredKeys, config); const { type, data } = await unarmor(armoredKeys, config);
if (type !== enums.armor.publicKey && type !== enums.armor.privateKey) { if (type !== enums.armor.publicKey && type !== enums.armor.privateKey) {

View File

@ -790,7 +790,7 @@ export async function createVerificationObjects(signatureList, literalDataList,
* @async * @async
* @static * @static
*/ */
export async function readMessage({ armoredMessage, binaryMessage, config }) { export async function readMessage({ armoredMessage, binaryMessage, config, ...rest }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
let input = armoredMessage || binaryMessage; let input = armoredMessage || binaryMessage;
if (!input) { if (!input) {
@ -802,6 +802,8 @@ export async function readMessage({ armoredMessage, binaryMessage, config }) {
if (binaryMessage && !util.isUint8Array(binaryMessage) && !util.isStream(binaryMessage)) { if (binaryMessage && !util.isUint8Array(binaryMessage) && !util.isStream(binaryMessage)) {
throw new Error('readMessage: options.binaryMessage must be a Uint8Array or stream'); throw new Error('readMessage: options.binaryMessage must be a Uint8Array or stream');
} }
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
const streamType = util.isStream(input); const streamType = util.isStream(input);
if (streamType) { if (streamType) {
await stream.loadStreamsPonyfill(); await stream.loadStreamsPonyfill();
@ -832,7 +834,7 @@ export async function readMessage({ armoredMessage, binaryMessage, config }) {
* @async * @async
* @static * @static
*/ */
export async function createMessage({ text, binary, filename, date = new Date(), format = text !== undefined ? 'utf8' : 'binary' }) { export async function createMessage({ text, binary, filename, date = new Date(), format = text !== undefined ? 'utf8' : 'binary', ...rest }) {
let input = text !== undefined ? text : binary; let input = text !== undefined ? text : binary;
if (input === undefined) { if (input === undefined) {
throw new Error('createMessage: must pass options object containing `text` or `binary`'); throw new Error('createMessage: must pass options object containing `text` or `binary`');
@ -843,6 +845,8 @@ export async function createMessage({ text, binary, filename, date = new Date(),
if (binary && !util.isUint8Array(binary) && !util.isStream(binary)) { if (binary && !util.isUint8Array(binary) && !util.isStream(binary)) {
throw new Error('createMessage: options.binary must be a Uint8Array or stream'); throw new Error('createMessage: options.binary must be a Uint8Array or stream');
} }
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
const streamType = util.isStream(input); const streamType = util.isStream(input);
if (streamType) { if (streamType) {
await stream.loadStreamsPonyfill(); await stream.loadStreamsPonyfill();

View File

@ -32,6 +32,7 @@ import util from './util';
/** /**
* Generates a new OpenPGP key pair. Supports RSA and ECC keys. By default, primary and subkeys will be of same type. * Generates a new OpenPGP key pair. Supports RSA and ECC keys. By default, primary and subkeys will be of same type.
* The generated primary key will have signing capabilities. By default, one subkey with encryption capabilities is also generated.
* @param {Object} options * @param {Object} options
* @param {Object|Array<Object>} options.userIDs - User IDs as objects: `{ name: 'Jo Doe', email: 'info@jo.com' }` * @param {Object|Array<Object>} options.userIDs - User IDs as objects: `{ name: 'Jo Doe', email: 'info@jo.com' }`
* @param {'ecc'|'rsa'} [options.type='ecc'] - The primary key algorithm type: ECC (default) or RSA * @param {'ecc'|'rsa'} [options.type='ecc'] - The primary key algorithm type: ECC (default) or RSA
@ -51,9 +52,11 @@ import util from './util';
* @async * @async
* @static * @static
*/ */
export async function generateKey({ userIDs = [], passphrase = '', type = 'ecc', rsaBits = 4096, curve = 'curve25519', keyExpirationTime = 0, date = new Date(), subkeys = [{}], format = 'armor', config }) { export async function generateKey({ userIDs = [], passphrase = '', type = 'ecc', rsaBits = 4096, curve = 'curve25519', keyExpirationTime = 0, date = new Date(), subkeys = [{}], format = 'armor', config, ...rest }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
userIDs = toArray(userIDs); userIDs = toArray(userIDs);
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (userIDs.length === 0) { if (userIDs.length === 0) {
throw new Error('UserIDs are required for key generation'); throw new Error('UserIDs are required for key generation');
} }
@ -66,8 +69,8 @@ export async function generateKey({ userIDs = [], passphrase = '', type = 'ecc',
const { key, revocationCertificate } = await generate(options, config); const { key, revocationCertificate } = await generate(options, config);
return { return {
privateKey: formatKey(key, format, config), privateKey: formatObject(key, format, config),
publicKey: formatKey(key.toPublic(), format, config), publicKey: formatObject(key.toPublic(), format, config),
revocationCertificate revocationCertificate
}; };
} catch (err) { } catch (err) {
@ -90,9 +93,11 @@ export async function generateKey({ userIDs = [], passphrase = '', type = 'ecc',
* @async * @async
* @static * @static
*/ */
export async function reformatKey({ privateKey, userIDs = [], passphrase = '', keyExpirationTime = 0, date, format = 'armor', config }) { export async function reformatKey({ privateKey, userIDs = [], passphrase = '', keyExpirationTime = 0, date, format = 'armor', config, ...rest }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
userIDs = toArray(userIDs); userIDs = toArray(userIDs);
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (userIDs.length === 0) { if (userIDs.length === 0) {
throw new Error('UserIDs are required for key reformat'); throw new Error('UserIDs are required for key reformat');
} }
@ -102,8 +107,8 @@ export async function reformatKey({ privateKey, userIDs = [], passphrase = '', k
const { key: reformattedKey, revocationCertificate } = await reformat(options, config); const { key: reformattedKey, revocationCertificate } = await reformat(options, config);
return { return {
privateKey: formatKey(reformattedKey, format, config), privateKey: formatObject(reformattedKey, format, config),
publicKey: formatKey(reformattedKey.toPublic(), format, config), publicKey: formatObject(reformattedKey.toPublic(), format, config),
revocationCertificate revocationCertificate
}; };
} catch (err) { } catch (err) {
@ -129,19 +134,21 @@ export async function reformatKey({ privateKey, userIDs = [], passphrase = '', k
* @async * @async
* @static * @static
*/ */
export async function revokeKey({ key, revocationCertificate, reasonForRevocation, date = new Date(), format = 'armor', config }) { export async function revokeKey({ key, revocationCertificate, reasonForRevocation, date = new Date(), format = 'armor', config, ...rest }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
try { try {
const revokedKey = revocationCertificate ? const revokedKey = revocationCertificate ?
await key.applyRevocationCertificate(revocationCertificate, date, config) : await key.applyRevocationCertificate(revocationCertificate, date, config) :
await key.revoke(reasonForRevocation, date, config); await key.revoke(reasonForRevocation, date, config);
return revokedKey.isPrivate() ? { return revokedKey.isPrivate() ? {
privateKey: formatKey(revokedKey, format, config), privateKey: formatObject(revokedKey, format, config),
publicKey: formatKey(revokedKey.toPublic(), format, config) publicKey: formatObject(revokedKey.toPublic(), format, config)
} : { } : {
privateKey: null, privateKey: null,
publicKey: formatKey(revokedKey, format, config) publicKey: formatObject(revokedKey, format, config)
}; };
} catch (err) { } catch (err) {
throw util.wrapError('Error revoking key', err); throw util.wrapError('Error revoking key', err);
@ -158,8 +165,10 @@ export async function revokeKey({ key, revocationCertificate, reasonForRevocatio
* @returns {Promise<PrivateKey>} The unlocked key object. * @returns {Promise<PrivateKey>} The unlocked key object.
* @async * @async
*/ */
export async function decryptKey({ privateKey, passphrase, config }) { export async function decryptKey({ privateKey, passphrase, config, ...rest }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (!privateKey.isPrivate()) { if (!privateKey.isPrivate()) {
throw new Error('Cannot decrypt a public key'); throw new Error('Cannot decrypt a public key');
} }
@ -190,8 +199,10 @@ export async function decryptKey({ privateKey, passphrase, config }) {
* @returns {Promise<PrivateKey>} The locked key object. * @returns {Promise<PrivateKey>} The locked key object.
* @async * @async
*/ */
export async function encryptKey({ privateKey, passphrase, config }) { export async function encryptKey({ privateKey, passphrase, config, ...rest }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (!privateKey.isPrivate()) { if (!privateKey.isPrivate()) {
throw new Error('Cannot encrypt a public key'); throw new Error('Cannot encrypt a public key');
} }
@ -233,7 +244,7 @@ export async function encryptKey({ privateKey, passphrase, config }) {
* @param {PrivateKey|PrivateKey[]} [options.signingKeys] - Private keys for signing. If omitted message will not be signed * @param {PrivateKey|PrivateKey[]} [options.signingKeys] - Private keys for signing. If omitted message will not be signed
* @param {String|String[]} [options.passwords] - Array of passwords or a single password to encrypt the message * @param {String|String[]} [options.passwords] - Array of passwords or a single password to encrypt the message
* @param {Object} [options.sessionKey] - Session key in the form: `{ data:Uint8Array, algorithm:String }` * @param {Object} [options.sessionKey] - Session key in the form: `{ data:Uint8Array, algorithm:String }`
* @param {Boolean} [options.armor=true] - Whether the return values should be ascii armored (true, the default) or binary (false) * @param {'armor'|'binary'|'object'} [options.format='armor'] - Format of the returned message
* @param {Signature} [options.signature] - A detached signature to add to the encrypted message * @param {Signature} [options.signature] - A detached signature to add to the encrypted message
* @param {Boolean} [options.wildcard=false] - Use a key ID of 0 instead of the public key IDs * @param {Boolean} [options.wildcard=false] - Use a key ID of 0 instead of the public key IDs
* @param {KeyID|KeyID[]} [options.signingKeyIDs=latest-created valid signing (sub)keys] - Array of key IDs to use for signing. Each `signingKeyIDs[i]` corresponds to `signingKeys[i]` * @param {KeyID|KeyID[]} [options.signingKeyIDs=latest-created valid signing (sub)keys] - Array of key IDs to use for signing. Each `signingKeyIDs[i]` corresponds to `signingKeys[i]`
@ -246,20 +257,22 @@ export async function encryptKey({ privateKey, passphrase, config }) {
* @async * @async
* @static * @static
*/ */
export async function encrypt({ message, encryptionKeys, signingKeys, passwords, sessionKey, armor = true, signature = null, wildcard = false, signingKeyIDs = [], encryptionKeyIDs = [], date = new Date(), signingUserIDs = [], encryptionUserIDs = [], config, ...rest }) { export async function encrypt({ message, encryptionKeys, signingKeys, passwords, sessionKey, format = 'armor', signature = null, wildcard = false, signingKeyIDs = [], encryptionKeyIDs = [], date = new Date(), signingUserIDs = [], encryptionUserIDs = [], config, ...rest }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
checkMessage(message); encryptionKeys = toArray(encryptionKeys); signingKeys = toArray(signingKeys); passwords = toArray(passwords); checkMessage(message); checkOutputMessageFormat(format);
encryptionKeys = toArray(encryptionKeys); signingKeys = toArray(signingKeys); passwords = toArray(passwords);
signingKeyIDs = toArray(signingKeyIDs); encryptionKeyIDs = toArray(encryptionKeyIDs); signingUserIDs = toArray(signingUserIDs); encryptionUserIDs = toArray(encryptionUserIDs); signingKeyIDs = toArray(signingKeyIDs); encryptionKeyIDs = toArray(encryptionKeyIDs); signingUserIDs = toArray(signingUserIDs); encryptionUserIDs = toArray(encryptionUserIDs);
if (rest.detached) { if (rest.detached) {
throw new Error("The `detached` option has been removed from openpgp.encrypt, separately call openpgp.sign instead. Don't forget to remove the `privateKeys` option as well."); throw new Error("The `detached` option has been removed from openpgp.encrypt, separately call openpgp.sign instead. Don't forget to remove the `privateKeys` option as well.");
} }
if (rest.publicKeys) throw new Error('The `publicKeys` option has been removed from openpgp.encrypt, pass `encryptionKeys` instead'); if (rest.publicKeys) throw new Error('The `publicKeys` option has been removed from openpgp.encrypt, pass `encryptionKeys` instead');
if (rest.privateKeys) throw new Error('The `privateKeys` option has been removed from openpgp.encrypt, pass `signingKeys` instead'); if (rest.privateKeys) throw new Error('The `privateKeys` option has been removed from openpgp.encrypt, pass `signingKeys` instead');
if (rest.armor !== undefined) throw new Error('The `armor` option has been removed from openpgp.encrypt, pass `format` instead.');
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (!signingKeys) { if (!signingKeys) {
signingKeys = []; signingKeys = [];
} }
const streaming = message.fromStream; const streaming = message.fromStream;
try { try {
if (signingKeys.length || signature) { // sign the message only if signing keys or signature is specified if (signingKeys.length || signature) { // sign the message only if signing keys or signature is specified
@ -270,6 +283,9 @@ export async function encrypt({ message, encryptionKeys, signingKeys, passwords,
config config
); );
message = await message.encrypt(encryptionKeys, passwords, sessionKey, wildcard, encryptionKeyIDs, date, encryptionUserIDs, config); message = await message.encrypt(encryptionKeys, passwords, sessionKey, wildcard, encryptionKeyIDs, date, encryptionUserIDs, config);
if (format === 'object') return message;
// serialize data
const armor = format === 'armor';
const data = armor ? message.armor(config) : message.write(); const data = armor ? message.armor(config) : message.write();
return convertStream(data, streaming, armor ? 'utf8' : 'binary'); return convertStream(data, streaming, armor ? 'utf8' : 'binary');
} catch (err) { } catch (err) {
@ -313,6 +329,7 @@ export async function decrypt({ message, decryptionKeys, passwords, sessionKeys,
checkMessage(message); verificationKeys = toArray(verificationKeys); decryptionKeys = toArray(decryptionKeys); passwords = toArray(passwords); sessionKeys = toArray(sessionKeys); checkMessage(message); verificationKeys = toArray(verificationKeys); decryptionKeys = toArray(decryptionKeys); passwords = toArray(passwords); sessionKeys = toArray(sessionKeys);
if (rest.privateKeys) throw new Error('The `privateKeys` option has been removed from openpgp.decrypt, pass `decryptionKeys` instead'); if (rest.privateKeys) throw new Error('The `privateKeys` option has been removed from openpgp.decrypt, pass `decryptionKeys` instead');
if (rest.publicKeys) throw new Error('The `publicKeys` option has been removed from openpgp.decrypt, pass `verificationKeys` instead'); if (rest.publicKeys) throw new Error('The `publicKeys` option has been removed from openpgp.decrypt, pass `verificationKeys` instead');
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
try { try {
const decrypted = await message.decrypt(decryptionKeys, passwords, sessionKeys, date, config); const decrypted = await message.decrypt(decryptionKeys, passwords, sessionKeys, date, config);
@ -359,24 +376,28 @@ export async function decrypt({ message, decryptionKeys, passwords, sessionKeys,
* @param {Object} options * @param {Object} options
* @param {CleartextMessage|Message} options.message - (cleartext) message to be signed * @param {CleartextMessage|Message} options.message - (cleartext) message to be signed
* @param {PrivateKey|PrivateKey[]} options.signingKeys - Array of keys or single key with decrypted secret key data to sign cleartext * @param {PrivateKey|PrivateKey[]} options.signingKeys - Array of keys or single key with decrypted secret key data to sign cleartext
* @param {Boolean} [options.armor=true] - Whether the return values should be ascii armored (true, the default) or binary (false) * @param {'armor'|'binary'|'object'} [options.format='armor'] - Format of the returned message
* @param {Boolean} [options.detached=false] - If the return value should contain a detached signature * @param {Boolean} [options.detached=false] - If the return value should contain a detached signature
* @param {KeyID|KeyID[]} [options.signingKeyIDs=latest-created valid signing (sub)keys] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to signingKeys[i] * @param {KeyID|KeyID[]} [options.signingKeyIDs=latest-created valid signing (sub)keys] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to signingKeys[i]
* @param {Date} [options.date=current date] - Override the creation date of the signature * @param {Date} [options.date=current date] - Override the creation date of the signature
* @param {Object|Object[]} [options.signingUserIDs=primary user IDs] - Array of user IDs to sign with, one per key in `signingKeys`, e.g. `[{ name: 'Steve Sender', email: 'steve@openpgp.org' }]` * @param {Object|Object[]} [options.signingUserIDs=primary user IDs] - Array of user IDs to sign with, one per key in `signingKeys`, e.g. `[{ name: 'Steve Sender', email: 'steve@openpgp.org' }]`
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config} * @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise<MaybeStream<String>|MaybeStream<Uint8Array>>} Signed message (string if `armor` was true, the default; Uint8Array if `armor` was false). * @returns {Promise<MaybeStream<String|Uint8Array>>} Signed message (string if `armor` was true, the default; Uint8Array if `armor` was false).
* @async * @async
* @static * @static
*/ */
export async function sign({ message, signingKeys, armor = true, detached = false, signingKeyIDs = [], date = new Date(), signingUserIDs = [], config, ...rest }) { export async function sign({ message, signingKeys, format = 'armor', detached = false, signingKeyIDs = [], date = new Date(), signingUserIDs = [], config, ...rest }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
checkCleartextOrMessage(message); checkCleartextOrMessage(message); checkOutputMessageFormat(format);
if (rest.privateKeys) throw new Error('The `privateKeys` option has been removed from openpgp.sign, pass `signingKeys` instead');
if (message instanceof CleartextMessage && !armor) throw new Error("Can't sign non-armored cleartext message");
if (message instanceof CleartextMessage && detached) throw new Error("Can't detach-sign a cleartext message");
signingKeys = toArray(signingKeys); signingKeyIDs = toArray(signingKeyIDs); signingUserIDs = toArray(signingUserIDs); signingKeys = toArray(signingKeys); signingKeyIDs = toArray(signingKeyIDs); signingUserIDs = toArray(signingUserIDs);
if (rest.privateKeys) throw new Error('The `privateKeys` option has been removed from openpgp.sign, pass `signingKeys` instead');
if (rest.armor !== undefined) throw new Error('The `armor` option has been removed from openpgp.sign, pass `format` instead.');
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (message instanceof CleartextMessage && format === 'binary') throw new Error('Cannot return signed cleartext message in binary format');
if (message instanceof CleartextMessage && detached) throw new Error('Cannot detach-sign a cleartext message');
if (!signingKeys || signingKeys.length === 0) { if (!signingKeys || signingKeys.length === 0) {
throw new Error('No signing keys provided'); throw new Error('No signing keys provided');
} }
@ -388,6 +409,9 @@ export async function sign({ message, signingKeys, armor = true, detached = fals
} else { } else {
signature = await message.sign(signingKeys, undefined, signingKeyIDs, date, signingUserIDs, config); signature = await message.sign(signingKeys, undefined, signingKeyIDs, date, signingUserIDs, config);
} }
if (format === 'object') return signature;
const armor = format === 'armor';
signature = armor ? signature.armor(config) : signature.write(); signature = armor ? signature.armor(config) : signature.write();
if (detached) { if (detached) {
signature = stream.transformPair(message.packets.write(), async (readable, writable) => { signature = stream.transformPair(message.packets.write(), async (readable, writable) => {
@ -431,13 +455,13 @@ export async function sign({ message, signingKeys, armor = true, detached = fals
*/ */
export async function verify({ message, verificationKeys, expectSigned = false, format = 'utf8', signature = null, date = new Date(), config, ...rest }) { export async function verify({ message, verificationKeys, expectSigned = false, format = 'utf8', signature = null, date = new Date(), config, ...rest }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
checkCleartextOrMessage(message); checkCleartextOrMessage(message); verificationKeys = toArray(verificationKeys);
if (rest.publicKeys) throw new Error('The `publicKeys` option has been removed from openpgp.verify, pass `verificationKeys` instead'); if (rest.publicKeys) throw new Error('The `publicKeys` option has been removed from openpgp.verify, pass `verificationKeys` instead');
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (message instanceof CleartextMessage && format === 'binary') throw new Error("Can't return cleartext message data as binary"); if (message instanceof CleartextMessage && format === 'binary') throw new Error("Can't return cleartext message data as binary");
if (message instanceof CleartextMessage && signature) throw new Error("Can't verify detached cleartext signature"); if (message instanceof CleartextMessage && signature) throw new Error("Can't verify detached cleartext signature");
verificationKeys = toArray(verificationKeys);
try { try {
const result = {}; const result = {};
if (signature) { if (signature) {
@ -487,6 +511,7 @@ export async function generateSessionKey({ encryptionKeys, date = new Date(), en
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
encryptionKeys = toArray(encryptionKeys); encryptionUserIDs = toArray(encryptionUserIDs); encryptionKeys = toArray(encryptionKeys); encryptionUserIDs = toArray(encryptionUserIDs);
if (rest.publicKeys) throw new Error('The `publicKeys` option has been removed from openpgp.generateSessionKey, pass `encryptionKeys` instead'); if (rest.publicKeys) throw new Error('The `publicKeys` option has been removed from openpgp.generateSessionKey, pass `encryptionKeys` instead');
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
try { try {
const sessionKeys = await Message.generateSessionKey(encryptionKeys, date, encryptionUserIDs, config); const sessionKeys = await Message.generateSessionKey(encryptionKeys, date, encryptionUserIDs, config);
@ -505,7 +530,7 @@ export async function generateSessionKey({ encryptionKeys, date = new Date(), en
* @param {String} [options.aeadAlgorithm] - AEAD algorithm, e.g. 'eax' or 'ocb' * @param {String} [options.aeadAlgorithm] - AEAD algorithm, e.g. 'eax' or 'ocb'
* @param {PublicKey|PublicKey[]} [options.encryptionKeys] - Array of public keys or single key, used to encrypt the key * @param {PublicKey|PublicKey[]} [options.encryptionKeys] - Array of public keys or single key, used to encrypt the key
* @param {String|String[]} [options.passwords] - Passwords for the message * @param {String|String[]} [options.passwords] - Passwords for the message
* @param {Boolean} [options.armor=true] - Whether the return values should be ascii armored (true, the default) or binary (false) * @param {'armor'|'binary'} [options.format='armor'] - Format of the returned value
* @param {Boolean} [options.wildcard=false] - Use a key ID of 0 instead of the public key IDs * @param {Boolean} [options.wildcard=false] - Use a key ID of 0 instead of the public key IDs
* @param {KeyID|KeyID[]} [options.encryptionKeyIDs=latest-created valid encryption (sub)keys] - Array of key IDs to use for encryption. Each encryptionKeyIDs[i] corresponds to encryptionKeys[i] * @param {KeyID|KeyID[]} [options.encryptionKeyIDs=latest-created valid encryption (sub)keys] - Array of key IDs to use for encryption. Each encryptionKeyIDs[i] corresponds to encryptionKeys[i]
* @param {Date} [options.date=current date] - Override the date * @param {Date} [options.date=current date] - Override the date
@ -515,14 +540,16 @@ export async function generateSessionKey({ encryptionKeys, date = new Date(), en
* @async * @async
* @static * @static
*/ */
export async function encryptSessionKey({ data, algorithm, aeadAlgorithm, encryptionKeys, passwords, armor = true, wildcard = false, encryptionKeyIDs = [], date = new Date(), encryptionUserIDs = [], config, ...rest }) { export async function encryptSessionKey({ data, algorithm, aeadAlgorithm, encryptionKeys, passwords, format = 'armor', wildcard = false, encryptionKeyIDs = [], date = new Date(), encryptionUserIDs = [], config, ...rest }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
checkBinary(data); checkString(algorithm, 'algorithm'); encryptionKeys = toArray(encryptionKeys); passwords = toArray(passwords); encryptionKeyIDs = toArray(encryptionKeyIDs); encryptionUserIDs = toArray(encryptionUserIDs); checkBinary(data); checkString(algorithm, 'algorithm'); checkOutputMessageFormat(format);
encryptionKeys = toArray(encryptionKeys); passwords = toArray(passwords); encryptionKeyIDs = toArray(encryptionKeyIDs); encryptionUserIDs = toArray(encryptionUserIDs);
if (rest.publicKeys) throw new Error('The `publicKeys` option has been removed from openpgp.encryptSessionKey, pass `encryptionKeys` instead'); if (rest.publicKeys) throw new Error('The `publicKeys` option has been removed from openpgp.encryptSessionKey, pass `encryptionKeys` instead');
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
try { try {
const message = await Message.encryptSessionKey(data, algorithm, aeadAlgorithm, encryptionKeys, passwords, wildcard, encryptionKeyIDs, date, encryptionUserIDs, config); const message = await Message.encryptSessionKey(data, algorithm, aeadAlgorithm, encryptionKeys, passwords, wildcard, encryptionKeyIDs, date, encryptionUserIDs, config);
return armor ? message.armor(config) : message.write(); return formatObject(message, format, config);
} catch (err) { } catch (err) {
throw util.wrapError('Error encrypting session key', err); throw util.wrapError('Error encrypting session key', err);
} }
@ -547,6 +574,7 @@ export async function decryptSessionKeys({ message, decryptionKeys, passwords, d
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
checkMessage(message); decryptionKeys = toArray(decryptionKeys); passwords = toArray(passwords); checkMessage(message); decryptionKeys = toArray(decryptionKeys); passwords = toArray(passwords);
if (rest.privateKeys) throw new Error('The `privateKeys` option has been removed from openpgp.decryptSessionKeys, pass `decryptionKeys` instead'); if (rest.privateKeys) throw new Error('The `privateKeys` option has been removed from openpgp.decryptSessionKeys, pass `decryptionKeys` instead');
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
try { try {
const sessionKeys = await message.decryptSessionKeys(decryptionKeys, passwords, date, config); const sessionKeys = await message.decryptSessionKeys(decryptionKeys, passwords, date, config);
@ -588,6 +616,11 @@ function checkCleartextOrMessage(message) {
throw new Error('Parameter [message] needs to be of type Message or CleartextMessage'); throw new Error('Parameter [message] needs to be of type Message or CleartextMessage');
} }
} }
function checkOutputMessageFormat(format) {
if (format !== 'armor' && format !== 'binary' && format !== 'object') {
throw new Error(`Unsupported format ${format}`);
}
}
/** /**
* Normalize parameter to an array if it is not undefined. * Normalize parameter to an array if it is not undefined.
@ -652,20 +685,20 @@ function linkStreams(result, message) {
} }
/** /**
* Convert the key object to the given format * Convert the object to the given format
* @param {Key} key * @param {Key|Message} object
* @param {'armor'|'binary'|'object'} format * @param {'armor'|'binary'|'object'} format
* @param {Object} config - Full configuration * @param {Object} config - Full configuration
* @returns {String|Uint8Array|Object} * @returns {String|Uint8Array|Object}
*/ */
function formatKey(key, format, config) { function formatObject(object, format, config) {
switch (format) { switch (format) {
case 'object': case 'object':
return key; return object;
case 'armor': case 'armor':
return key.armor(config); return object.armor(config);
case 'binary': case 'binary':
return key.write(); return object.write();
default: default:
throw new Error(`Unsupported format ${format}`); throw new Error(`Unsupported format ${format}`);
} }

View File

@ -71,7 +71,7 @@ export class Signature {
* @async * @async
* @static * @static
*/ */
export async function readSignature({ armoredSignature, binarySignature, config }) { export async function readSignature({ armoredSignature, binarySignature, config, ...rest }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
let input = armoredSignature || binarySignature; let input = armoredSignature || binarySignature;
if (!input) { if (!input) {
@ -83,6 +83,8 @@ export async function readSignature({ armoredSignature, binarySignature, config
if (binarySignature && !util.isUint8Array(binarySignature)) { if (binarySignature && !util.isUint8Array(binarySignature)) {
throw new Error('readSignature: options.binarySignature must be a Uint8Array'); throw new Error('readSignature: options.binarySignature must be a Uint8Array');
} }
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (armoredSignature) { if (armoredSignature) {
const { type, data } = await unarmor(input, config); const { type, data } = await unarmor(input, config);
if (type !== enums.armor.signature) { if (type !== enums.armor.signature) {

View File

@ -182,11 +182,11 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
const userIDs = { name: 'Test User', email: 'text2@example.com' }; const userIDs = { name: 'Test User', email: 'text2@example.com' };
const { privateKey } = await openpgp.generateKey({ userIDs, format: 'object' }); const { privateKey } = await openpgp.generateKey({ userIDs, format: 'object' });
const encKey = await openpgp.encryptKey({ privateKey, userIDs, passphrase }); const encKey = await openpgp.encryptKey({ privateKey, passphrase });
expect(encKey.keyPacket.s2k.c).to.equal(openpgp.config.s2kIterationCountByte); expect(encKey.keyPacket.s2k.c).to.equal(openpgp.config.s2kIterationCountByte);
const config = { s2kIterationCountByte: 123 }; const config = { s2kIterationCountByte: 123 };
const encKey2 = await openpgp.encryptKey({ privateKey, userIDs, passphrase, config }); const encKey2 = await openpgp.encryptKey({ privateKey, passphrase, config });
expect(encKey2.keyPacket.s2k.c).to.equal(config.s2kIterationCountByte); expect(encKey2.keyPacket.s2k.c).to.equal(config.s2kIterationCountByte);
} finally { } finally {
openpgp.config.s2kIterationCountByte = s2kIterationCountByteVal; openpgp.config.s2kIterationCountByte = s2kIterationCountByteVal;

View File

@ -2591,7 +2591,7 @@ function versionSpecificTests() {
expect(newKey.users.length).to.equal(1); expect(newKey.users.length).to.equal(1);
expect(newKey.users[0].userID.userID).to.equal('test <a@b.com>'); expect(newKey.users[0].userID.userID).to.equal('test <a@b.com>');
expect(newKey.isDecrypted()).to.be.true; expect(newKey.isDecrypted()).to.be.true;
return openpgp.sign({ message: await openpgp.createCleartextMessage({ text: 'hello' }), signingKeys: newKey, armor: true }).then(async function(signed) { return openpgp.sign({ message: await openpgp.createCleartextMessage({ text: 'hello' }), signingKeys: newKey }).then(async function(signed) {
return openpgp.verify( return openpgp.verify(
{ message: await openpgp.readCleartextMessage({ cleartextMessage: signed }), verificationKeys: newKeyPublic } { message: await openpgp.readCleartextMessage({ cleartextMessage: signed }), verificationKeys: newKeyPublic }
).then(async function(verified) { ).then(async function(verified) {
@ -2629,7 +2629,7 @@ function versionSpecificTests() {
const opt2 = { privateKey, userIDs: userID2, format: 'object' }; const opt2 = { privateKey, userIDs: userID2, format: 'object' };
return openpgp.reformatKey(opt2).then(async function({ privateKey: newKey, publicKey: newKeyPublic }) { return openpgp.reformatKey(opt2).then(async function({ privateKey: newKey, publicKey: newKeyPublic }) {
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: newKey.toPublic(), signingKeys: newKey, armor: true, config: { minRSABits: 1024 } message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: newKey.toPublic(), signingKeys: newKey, config: { minRSABits: 1024 }
}); });
const decrypted = await openpgp.decrypt({ const decrypted = await openpgp.decrypt({
message: await openpgp.readMessage({ armoredMessage: encrypted }), decryptionKeys: newKey, verificationKeys: newKeyPublic, config: { minRSABits: 1024 } message: await openpgp.readMessage({ armoredMessage: encrypted }), decryptionKeys: newKey, verificationKeys: newKeyPublic, config: { minRSABits: 1024 }
@ -3442,10 +3442,10 @@ VYGdb3eNlV8CfoEC
expect(sessionKey.algorithm).to.equal('aes128'); expect(sessionKey.algorithm).to.equal('aes128');
const config = { minRSABits: 1024 }; const config = { minRSABits: 1024 };
await openpgp.encrypt({ await openpgp.encrypt({
message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, encryptionUserIDs: { name: 'Test User', email: 'b@c.com' }, armor: false, config message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, encryptionUserIDs: { name: 'Test User', email: 'b@c.com' }, format: 'binary', config
}); });
await expect(openpgp.encrypt({ await expect(openpgp.encrypt({
message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, encryptionUserIDs: { name: 'Test User', email: 'c@c.com' }, armor: false, config message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, encryptionUserIDs: { name: 'Test User', email: 'c@c.com' }, format: 'binary', config
})).to.be.rejectedWith('Could not find user that matches that user ID'); })).to.be.rejectedWith('Could not find user that matches that user ID');
}); });
@ -3456,7 +3456,7 @@ VYGdb3eNlV8CfoEC
privateKey: await openpgp.readKey({ armoredKey: uidlessKey }), privateKey: await openpgp.readKey({ armoredKey: uidlessKey }),
passphrase: 'correct horse battery staple' passphrase: 'correct horse battery staple'
}); });
await expect(openpgp.encrypt({ message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, armor: false })).to.be.rejectedWith('Could not find primary user'); await expect(openpgp.encrypt({ message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, format: 'binary' })).to.be.rejectedWith('Could not find primary user');
}); });
it('Sign - specific user', async function() { it('Sign - specific user', async function() {
@ -3476,17 +3476,17 @@ VYGdb3eNlV8CfoEC
privateKey.users[1].selfCertifications[0].preferredHashAlgorithms = [openpgp.enums.hash.sha512]; privateKey.users[1].selfCertifications[0].preferredHashAlgorithms = [openpgp.enums.hash.sha512];
const config = { minRSABits: 1024 }; const config = { minRSABits: 1024 };
const signed = await openpgp.sign({ const signed = await openpgp.sign({
message: await openpgp.createMessage({ text: 'hello' }), signingKeys: privateKey, signingUserIDs: { name: 'Test McTestington', email: 'test@example.com' }, armor: false, config message: await openpgp.createMessage({ text: 'hello' }), signingKeys: privateKey, signingUserIDs: { name: 'Test McTestington', email: 'test@example.com' }, format: 'binary', config
}); });
const signature = await openpgp.readMessage({ binaryMessage: signed }); const signature = await openpgp.readMessage({ binaryMessage: signed });
expect(signature.packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512); expect(signature.packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512);
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message: await openpgp.createMessage({ text: 'hello' }), passwords: 'test', signingKeys: privateKey, signingUserIDs: { name: 'Test McTestington', email: 'test@example.com' }, armor: false, config message: await openpgp.createMessage({ text: 'hello' }), passwords: 'test', signingKeys: privateKey, signingUserIDs: { name: 'Test McTestington', email: 'test@example.com' }, format: 'binary', config
}); });
const { signatures } = await openpgp.decrypt({ message: await openpgp.readMessage({ binaryMessage: encrypted }), passwords: 'test' }); const { signatures } = await openpgp.decrypt({ message: await openpgp.readMessage({ binaryMessage: encrypted }), passwords: 'test' });
expect((await signatures[0].signature).packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512); expect((await signatures[0].signature).packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512);
await expect(openpgp.encrypt({ await expect(openpgp.encrypt({
message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, signingUserIDs: { name: 'Not Test McTestington', email: 'test@example.com' }, armor: false, config message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, signingUserIDs: { name: 'Not Test McTestington', email: 'test@example.com' }, format: 'binary', config
})).to.be.rejectedWith('Could not find user that matches that user ID'); })).to.be.rejectedWith('Could not find user that matches that user ID');
}); });
@ -3768,7 +3768,7 @@ VYGdb3eNlV8CfoEC
expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('eddsa'); expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('eddsa');
await subkey.verify(); await subkey.verify();
expect(await newPrivateKey.getSigningKey()).to.be.equal(subkey); expect(await newPrivateKey.getSigningKey()).to.be.equal(subkey);
const signed = await openpgp.sign({ message: await openpgp.createMessage({ text: 'the data to signed' }), signingKeys: newPrivateKey, armor:false }); const signed = await openpgp.sign({ message: await openpgp.createMessage({ text: 'the data to signed' }), signingKeys: newPrivateKey, format: 'binary' });
const message = await openpgp.readMessage({ binaryMessage: signed }); const message = await openpgp.readMessage({ binaryMessage: signed });
const { signatures } = await openpgp.verify({ message, verificationKeys: [newPrivateKey.toPublic()] }); const { signatures } = await openpgp.verify({ message, verificationKeys: [newPrivateKey.toPublic()] });
expect(signatures).to.exist; expect(signatures).to.exist;
@ -3790,7 +3790,7 @@ VYGdb3eNlV8CfoEC
const publicKey = newPrivateKey.toPublic(); const publicKey = newPrivateKey.toPublic();
await subkey.verify(); await subkey.verify();
expect(await newPrivateKey.getEncryptionKey()).to.be.equal(subkey); expect(await newPrivateKey.getEncryptionKey()).to.be.equal(subkey);
const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ text: vData }), encryptionKeys: publicKey, armor:false }); const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ text: vData }), encryptionKeys: publicKey, format: 'binary' });
expect(encrypted).to.be.exist; expect(encrypted).to.be.exist;
const message = await openpgp.readMessage({ binaryMessage: encrypted }); const message = await openpgp.readMessage({ binaryMessage: encrypted });
const pkSessionKeys = message.packets.filterByTag(openpgp.enums.packet.publicKeyEncryptedSessionKey); const pkSessionKeys = message.packets.filterByTag(openpgp.enums.packet.publicKeyEncryptedSessionKey);
@ -3817,7 +3817,7 @@ VYGdb3eNlV8CfoEC
expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('rsaEncryptSign'); expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('rsaEncryptSign');
await subkey.verify(); await subkey.verify();
expect(await newPrivateKey.getSigningKey()).to.be.equal(subkey); expect(await newPrivateKey.getSigningKey()).to.be.equal(subkey);
const signed = await openpgp.sign({ message: await openpgp.createMessage({ text: 'the data to signed' }), signingKeys: newPrivateKey, armor:false }); const signed = await openpgp.sign({ message: await openpgp.createMessage({ text: 'the data to signed' }), signingKeys: newPrivateKey, format: 'binary' });
const message = await openpgp.readMessage({ binaryMessage: signed }); const message = await openpgp.readMessage({ binaryMessage: signed });
const { signatures } = await openpgp.verify({ message, verificationKeys: [newPrivateKey.toPublic()] }); const { signatures } = await openpgp.verify({ message, verificationKeys: [newPrivateKey.toPublic()] });
expect(signatures).to.exist; expect(signatures).to.exist;
@ -3840,7 +3840,7 @@ VYGdb3eNlV8CfoEC
const publicKey = newPrivateKey.toPublic(); const publicKey = newPrivateKey.toPublic();
const vData = 'the data to encrypted!'; const vData = 'the data to encrypted!';
expect(await newPrivateKey.getEncryptionKey()).to.be.equal(subkey); expect(await newPrivateKey.getEncryptionKey()).to.be.equal(subkey);
const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ text: vData }), encryptionKeys: publicKey, armor:false }); const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ text: vData }), encryptionKeys: publicKey, format: 'binary' });
expect(encrypted).to.be.exist; expect(encrypted).to.be.exist;
const message = await openpgp.readMessage({ binaryMessage: encrypted }); const message = await openpgp.readMessage({ binaryMessage: encrypted });
const pkSessionKeys = message.packets.filterByTag(openpgp.enums.packet.publicKeyEncryptedSessionKey); const pkSessionKeys = message.packets.filterByTag(openpgp.enums.packet.publicKeyEncryptedSessionKey);

View File

@ -1639,6 +1639,187 @@ aOU=
message: await openpgp.createMessage({ text: plaintext }) message: await openpgp.createMessage({ text: plaintext })
})).to.be.rejectedWith(/No signing keys provided/); })).to.be.rejectedWith(/No signing keys provided/);
}); });
it('should output cleartext message of expected format', async function() {
const text = 'test';
const message = await openpgp.createCleartextMessage({ text });
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
passphrase
});
const config = { minRSABits: 1024 };
const cleartextMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'armor' });
const parsedArmored = await openpgp.readCleartextMessage({ cleartextMessage });
expect(parsedArmored.text).to.equal(text);
expect(parsedArmored.signature.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
await expect(openpgp.sign({ message, signingKeys: privateKey, config, format: 'binary' })).to.be.rejectedWith('');
const objectMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'object' });
expect(objectMessage.signature.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
const verified = await openpgp.verify({ message: objectMessage, verificationKeys: privateKey, expectSigned: true, config });
expect(verified.data).to.equal(text);
});
it('should output message of expected format', async function() {
const text = 'test';
const message = await openpgp.createMessage({ text });
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
passphrase
});
const config = { minRSABits: 1024 };
const armoredMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'armor' });
const parsedArmored = await openpgp.readMessage({ armoredMessage });
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
const binaryMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'binary' });
const parsedBinary = await openpgp.readMessage({ binaryMessage });
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
const objectMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'object' });
expect(objectMessage.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
const verified = await openpgp.verify({ message: objectMessage, verificationKeys: privateKey, expectSigned: true, config });
expect(verified.data).to.equal(text);
});
it('should output message of expected format', async function() {
const text = 'test';
const message = await openpgp.createMessage({ text });
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
passphrase
});
const config = { minRSABits: 1024 };
const armoredMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'armor' });
const parsedArmored = await openpgp.readMessage({ armoredMessage });
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
const binaryMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'binary' });
const parsedBinary = await openpgp.readMessage({ binaryMessage });
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
const objectMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'object' });
expect(objectMessage.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
const verified = await openpgp.verify({ message: objectMessage, verificationKeys: privateKey, expectSigned: true, config });
expect(verified.data).to.equal(text);
});
it('should output message of expected format (with streaming)', async function() {
const text = 'test';
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
passphrase
});
const config = { minRSABits: 1024 };
const armoredMessage = await openpgp.sign({
message: await openpgp.createMessage({ text: stream.toStream(text) }),
signingKeys: privateKey,
format: 'armor',
config
});
const parsedArmored = await openpgp.readMessage({ armoredMessage });
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
const binaryMessage = await openpgp.sign({
message: await openpgp.createMessage({ text: stream.toStream(text) }),
signingKeys: privateKey,
format: 'binary',
config
});
const parsedBinary = await openpgp.readMessage({ binaryMessage });
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
const objectMessage = await openpgp.sign({
message: await openpgp.createMessage({ text: stream.toStream(text) }),
signingKeys: privateKey,
format: 'object',
config
});
expect(objectMessage.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
objectMessage.packets[1].data = await stream.readToEnd(objectMessage.packets[1].data);
objectMessage.packets[2].signedHashValue = await stream.readToEnd(objectMessage.packets[2].signedHashValue);
const { data: streamedData } = await openpgp.verify({ message: objectMessage, verificationKeys: privateKey, expectSigned: true, config });
expect(await stream.readToEnd(streamedData)).to.equal(text);
expect(streamedData).to.equal(text);
});
it('should output message of expected format (detached)', async function() {
const text = 'test';
const message = await openpgp.createMessage({ text });
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
passphrase
});
const config = { minRSABits: 1024 };
const armoredSignature = await openpgp.sign({ message, signingKeys: privateKey, detached: true, config, format: 'armor' });
const parsedArmored = await openpgp.readSignature({ armoredSignature });
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
const binarySignature = await openpgp.sign({ message, signingKeys: privateKey, detached: true, config, format: 'binary' });
const parsedBinary = await openpgp.readSignature({ binarySignature });
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
const objectSignature = await openpgp.sign({ message, signingKeys: privateKey, detached: true, config, format: 'object' });
expect(objectSignature.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
const verified = await openpgp.verify({ message, signature: objectSignature, verificationKeys: privateKey, expectSigned: true, config });
expect(verified.data).to.equal(text);
});
it('should output message of expected format (detached, with streaming)', async function() {
const text = 'test';
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
passphrase
});
const config = { minRSABits: 1024 };
const armoredSignature = await openpgp.sign({
message: await openpgp.createMessage({ text: stream.toStream(text) }),
signingKeys: privateKey,
detached: true,
format: 'armor',
config
});
const parsedArmored = await openpgp.readSignature({ armoredSignature: await stream.readToEnd(armoredSignature) });
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
const binarySignature = await openpgp.sign({
message: await openpgp.createMessage({ text: stream.toStream(text) }),
signingKeys: privateKey,
detached: true,
format: 'binary',
config
});
const parsedBinary = await openpgp.readSignature({ binarySignature: await stream.readToEnd(binarySignature) });
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
const streamedMessage = await openpgp.createMessage({ text: stream.toStream(text) });
const objectSignature = await openpgp.sign({
message: streamedMessage,
signingKeys: privateKey,
detached: true,
format: 'object',
config
});
expect(objectSignature.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
const armoredStreamedMessage = streamedMessage.armor(); // consume input message stream, to allow to read the signed hash
objectSignature.packets[0].signedHashValue = await stream.readToEnd(objectSignature.packets[0].signedHashValue);
const { data: streamedData } = await openpgp.verify({
message: await openpgp.readMessage({ armoredMessage: armoredStreamedMessage }),
signature: objectSignature,
verificationKeys: privateKey,
expectSigned: true,
config
});
expect(await stream.readToEnd(streamedData)).to.equal(text);
});
}); });
describe('encrypt - unit tests', function() { describe('encrypt - unit tests', function() {
@ -1648,6 +1829,87 @@ aOU=
openpgp.encrypt({ message: await openpgp.createMessage({ text: 'test' }), encryptionKeys: expiredKey }) openpgp.encrypt({ message: await openpgp.createMessage({ text: 'test' }), encryptionKeys: expiredKey })
).to.be.rejectedWith(/Primary key is expired/); ).to.be.rejectedWith(/Primary key is expired/);
}); });
it('should output message of expected format', async function() {
const passwords = 'password';
const text = 'test';
const message = await openpgp.createMessage({ text });
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
passphrase
});
const armoredMessage = await openpgp.encrypt({ message, passwords, format: 'armor' });
const parsedArmored = await openpgp.readMessage({ armoredMessage });
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
const binaryMessage = await openpgp.encrypt({ message, passwords, format: 'binary' });
const parsedBinary = await openpgp.readMessage({ binaryMessage });
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
const config = { minRSABits: 1024 };
const objectMessage = await openpgp.encrypt({ message, passwords, signingKeys: privateKey, config, format: 'object' });
expect(objectMessage.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
const decrypted = await openpgp.decrypt({ message: objectMessage, passwords, verificationKeys: privateKey, expectSigned: true, config });
expect(decrypted.data).to.equal(text);
});
it('should output message of expected format (with streaming)', async function() {
const passwords = 'password';
const text = 'test';
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
passphrase
});
const armoredMessage = await openpgp.encrypt({
message: await openpgp.createMessage({ text: stream.toStream(text) }),
passwords,
format: 'armor'
});
const parsedArmored = await openpgp.readMessage({ armoredMessage });
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
const binaryMessage = await openpgp.encrypt({
message: await openpgp.createMessage({ text: stream.toStream(text) }),
passwords,
format: 'binary'
});
const parsedBinary = await openpgp.readMessage({ binaryMessage });
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
const config = { minRSABits: 1024 };
const objectMessage = await openpgp.encrypt({
message: await openpgp.createMessage({ text: stream.toStream(text) }),
passwords,
signingKeys: privateKey,
format: 'object',
config
});
expect(objectMessage.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
const { data: streamedData } = await openpgp.decrypt({ message: objectMessage, passwords, verificationKeys: privateKey, expectSigned: true, config });
expect(await stream.readToEnd(streamedData)).to.equal(text);
});
});
describe('encryptSessionKey - unit tests', function() {
it('should output message of expected format', async function() {
const passwords = 'password';
const sessionKey = { data: new Uint8Array(16).fill(1), algorithm: 'aes128' };
const armoredMessage = await openpgp.encryptSessionKey({ ...sessionKey, passwords, format: 'armor' });
const parsedArmored = await openpgp.readMessage({ armoredMessage });
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
const binaryMessage = await openpgp.encryptSessionKey({ ...sessionKey, passwords, format: 'binary' });
const parsedBinary = await openpgp.readMessage({ binaryMessage });
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
const objectMessage = await openpgp.encryptSessionKey({ ...sessionKey, passwords, format: 'object' });
expect(objectMessage.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
const [decryptedSessionKey] = await openpgp.decryptSessionKeys({ message: objectMessage, passwords });
expect(decryptedSessionKey).to.deep.equal(sessionKey);
});
}); });
describe('encrypt, decrypt, sign, verify - integration tests', function() { describe('encrypt, decrypt, sign, verify - integration tests', function() {
@ -1783,7 +2045,7 @@ aOU=
data: sk, data: sk,
algorithm: 'aes128', algorithm: 'aes128',
encryptionKeys: publicKey, encryptionKeys: publicKey,
armor: false format: 'binary'
}).then(async function(encrypted) { }).then(async function(encrypted) {
const message = await openpgp.readMessage({ binaryMessage: encrypted }); const message = await openpgp.readMessage({ binaryMessage: encrypted });
return openpgp.decryptSessionKeys({ return openpgp.decryptSessionKeys({
@ -1800,7 +2062,7 @@ aOU=
data: sk, data: sk,
algorithm: 'aes128', algorithm: 'aes128',
passwords: password1, passwords: password1,
armor: false format: 'binary'
}).then(async function(encrypted) { }).then(async function(encrypted) {
const message = await openpgp.readMessage({ binaryMessage: encrypted }); const message = await openpgp.readMessage({ binaryMessage: encrypted });
return openpgp.decryptSessionKeys({ return openpgp.decryptSessionKeys({
@ -1817,7 +2079,7 @@ aOU=
data: sk, data: sk,
algorithm: 'aes128', algorithm: 'aes128',
encryptionKeys: publicKey, encryptionKeys: publicKey,
armor: false format: 'binary'
}).then(async function(encrypted) { }).then(async function(encrypted) {
const message = await openpgp.readMessage({ binaryMessage: encrypted }); const message = await openpgp.readMessage({ binaryMessage: encrypted });
const invalidPrivateKey = await openpgp.readKey({ armoredKey: priv_key }); const invalidPrivateKey = await openpgp.readKey({ armoredKey: priv_key });
@ -2552,7 +2814,7 @@ aOU=
it('should fail to decrypt unarmored message with garbage data appended', async function() { it('should fail to decrypt unarmored message with garbage data appended', async function() {
const key = privateKey; const key = privateKey;
const message = await openpgp.encrypt({ message: await openpgp.createMessage({ text: 'test' }), encryptionKeys: key, signingKeys: key, armor: false }); const message = await openpgp.encrypt({ message: await openpgp.createMessage({ text: 'test' }), encryptionKeys: key, signingKeys: key, format: 'binary' });
const encrypted = util.concat([message, new Uint8Array([11])]); const encrypted = util.concat([message, new Uint8Array([11])]);
await expect((async () => { await expect((async () => {
await openpgp.decrypt({ message: await openpgp.readMessage({ binaryMessage: encrypted }), decryptionKeys: key, verificationKeys: key }); await openpgp.decrypt({ message: await openpgp.readMessage({ binaryMessage: encrypted }), decryptionKeys: key, verificationKeys: key });
@ -2705,7 +2967,7 @@ aOU=
const encOpt = { const encOpt = {
message: await openpgp.createMessage({ text: plaintext }), message: await openpgp.createMessage({ text: plaintext }),
passwords: password1, passwords: password1,
armor: false format: 'binary'
}; };
const decOpt = { const decOpt = {
passwords: password1 passwords: password1
@ -2723,7 +2985,7 @@ aOU=
const encOpt = { const encOpt = {
message: await openpgp.createMessage({ binary: new Uint8Array([0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01]) }), message: await openpgp.createMessage({ binary: new Uint8Array([0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01]) }),
passwords: password1, passwords: password1,
armor: false format: 'binary'
}; };
const decOpt = { const decOpt = {
passwords: password1, passwords: password1,
@ -2950,7 +3212,7 @@ aOU=
const signOpt = { const signOpt = {
message, message,
signingKeys: privateKey, signingKeys: privateKey,
armor: false format: 'binary'
}; };
const verifyOpt = { const verifyOpt = {
verificationKeys: publicKey verificationKeys: publicKey
@ -2974,7 +3236,7 @@ aOU=
message, message,
signingKeys: privateKey, signingKeys: privateKey,
detached: true, detached: true,
armor: false format: 'binary'
}; };
const verifyOpt = { const verifyOpt = {
message, message,
@ -3002,7 +3264,7 @@ aOU=
signingKeys: privateKey_1337, signingKeys: privateKey_1337,
detached: true, detached: true,
date: past, date: past,
armor: false format: 'binary'
}; };
const verifyOpt = { const verifyOpt = {
message, message,
@ -3040,7 +3302,7 @@ aOU=
signingKeys: privateKey_2038_2045, signingKeys: privateKey_2038_2045,
detached: true, detached: true,
date: future, date: future,
armor: false format: 'binary'
}; };
const verifyOpt = { const verifyOpt = {
verificationKeys: publicKey_2038_2045, verificationKeys: publicKey_2038_2045,
@ -3066,7 +3328,7 @@ aOU=
const signOpt = { const signOpt = {
message: await openpgp.createMessage({ binary: data }), message: await openpgp.createMessage({ binary: data }),
signingKeys: privateKey, signingKeys: privateKey,
armor: false format: 'binary'
}; };
const verifyOpt = { const verifyOpt = {
verificationKeys: publicKey, verificationKeys: publicKey,
@ -3105,7 +3367,7 @@ aOU=
const signOpt = { const signOpt = {
message: await openpgp.createMessage({ binary: dataStream }), message: await openpgp.createMessage({ binary: dataStream }),
signingKeys: privateKey, signingKeys: privateKey,
armor: false format: 'binary'
}; };
const verifyOpt = { const verifyOpt = {
verificationKeys: publicKey, verificationKeys: publicKey,
@ -3140,7 +3402,7 @@ aOU=
message: await openpgp.createMessage({ text: plaintext, date: future }), message: await openpgp.createMessage({ text: plaintext, date: future }),
encryptionKeys: publicKey_2038_2045, encryptionKeys: publicKey_2038_2045,
date: future, date: future,
armor: false format: 'binary'
}; };
return openpgp.encrypt(encryptOpt).then(async function (encrypted) { return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
@ -3161,7 +3423,7 @@ aOU=
message: await openpgp.createMessage({ binary: data, date: past }), message: await openpgp.createMessage({ binary: data, date: past }),
encryptionKeys: publicKey_2000_2008, encryptionKeys: publicKey_2000_2008,
date: past, date: past,
armor: false format: 'binary'
}; };
return openpgp.encrypt(encryptOpt).then(async function (encrypted) { return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
@ -3182,7 +3444,7 @@ aOU=
encryptionKeys: publicKey_2000_2008, encryptionKeys: publicKey_2000_2008,
signingKeys: privateKey_2000_2008, signingKeys: privateKey_2000_2008,
date: past, date: past,
armor: false format: 'binary'
}; };
return openpgp.encrypt(encryptOpt).then(async function (encrypted) { return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
@ -3210,7 +3472,7 @@ aOU=
encryptionKeys: publicKey_2038_2045, encryptionKeys: publicKey_2038_2045,
signingKeys: privateKey_2038_2045, signingKeys: privateKey_2038_2045,
date: future, date: future,
armor: false format: 'binary'
}; };
return openpgp.encrypt(encryptOpt).then(async function (encrypted) { return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
@ -3239,7 +3501,7 @@ aOU=
encryptionKeys: publicKey_2038_2045, encryptionKeys: publicKey_2038_2045,
signingKeys: privateKey_2038_2045, signingKeys: privateKey_2038_2045,
date: future, date: future,
armor: false format: 'binary'
}; };
return openpgp.encrypt(encryptOpt).then(async function (encrypted) { return openpgp.encrypt(encryptOpt).then(async function (encrypted) {

View File

@ -1462,7 +1462,7 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
}); });
const config = { minRSABits: 1024 }; const config = { minRSABits: 1024 };
return openpgp.sign({ signingKeys: privKey, message: await openpgp.createMessage({ binary: plaintext }), armor: false, config }).then(async signed => { return openpgp.sign({ signingKeys: privKey, message: await openpgp.createMessage({ binary: plaintext }), format: 'binary', config }).then(async signed => {
const message = await openpgp.readMessage({ binaryMessage: signed }); const message = await openpgp.readMessage({ binaryMessage: signed });
return openpgp.verify({ verificationKeys: pubKey, message, format: 'binary', config }); return openpgp.verify({ verificationKeys: pubKey, message, format: 'binary', config });

View File

@ -257,7 +257,7 @@ function tests() {
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message: await openpgp.createMessage({ binary: data }), message: await openpgp.createMessage({ binary: data }),
passwords: ['test'], passwords: ['test'],
armor: false format: 'binary'
}); });
expect(stream.isStream(encrypted)).to.equal(expectedType); expect(stream.isStream(encrypted)).to.equal(expectedType);
@ -285,7 +285,7 @@ function tests() {
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message: await openpgp.createMessage({ binary: data }), message: await openpgp.createMessage({ binary: data }),
passwords: ['test'], passwords: ['test'],
armor: false format: 'binary'
}); });
expect(stream.isStream(encrypted)).to.equal(expectedType); expect(stream.isStream(encrypted)).to.equal(expectedType);
@ -316,7 +316,7 @@ function tests() {
message: await openpgp.createMessage({ binary: data }), message: await openpgp.createMessage({ binary: data }),
encryptionKeys: pubKey, encryptionKeys: pubKey,
signingKeys: privKey, signingKeys: privKey,
armor: false, format: 'binary',
config: { minRSABits: 1024 } config: { minRSABits: 1024 }
}); });
expect(stream.isStream(encrypted)).to.equal(expectedType); expect(stream.isStream(encrypted)).to.equal(expectedType);
@ -352,7 +352,7 @@ function tests() {
message: await openpgp.createMessage({ binary: data }), message: await openpgp.createMessage({ binary: data }),
encryptionKeys: pub, encryptionKeys: pub,
signingKeys: priv, signingKeys: priv,
armor: false format: 'binary'
}); });
expect(stream.isStream(encrypted)).to.equal(expectedType); expect(stream.isStream(encrypted)).to.equal(expectedType);
@ -387,7 +387,7 @@ function tests() {
message: await openpgp.createMessage({ binary: data }), message: await openpgp.createMessage({ binary: data }),
encryptionKeys: pub, encryptionKeys: pub,
signingKeys: priv, signingKeys: priv,
armor: false format: 'binary'
}); });
expect(stream.isStream(encrypted)).to.equal(expectedType); expect(stream.isStream(encrypted)).to.equal(expectedType);
@ -814,7 +814,7 @@ function tests() {
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message: await openpgp.createMessage({ binary: data }), message: await openpgp.createMessage({ binary: data }),
passwords: ['test'], passwords: ['test'],
armor: false format: 'binary'
}); });
expect(stream.isStream(encrypted)).to.equal(expectedType); expect(stream.isStream(encrypted)).to.equal(expectedType);
@ -1035,7 +1035,7 @@ module.exports = () => describe('Streaming', function() {
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message: await openpgp.createMessage({ binary: data }), message: await openpgp.createMessage({ binary: data }),
passwords: ['test'], passwords: ['test'],
armor: false format: 'binary'
}); });
expect(stream.isStream(encrypted)).to.equal('node'); expect(stream.isStream(encrypted)).to.equal('node');

View File

@ -21,14 +21,12 @@ async function generateTestData() {
type: 'rsa', type: 'rsa',
rsaBits: 2048, rsaBits: 2048,
subkeys: [], subkeys: [],
sign: false,
format: 'object' format: 'object'
}); });
const signed = await openpgp.sign({ const signed = await openpgp.sign({
message: await createCleartextMessage({ text: 'I am batman' }), message: await createCleartextMessage({ text: 'I am batman' }),
signingKeys: victimPrivKey, signingKeys: victimPrivKey
armor: true
}); });
return { return {
victimPubKey: victimPrivKey.toPublic(), victimPubKey: victimPrivKey.toPublic(),
@ -37,7 +35,7 @@ async function generateTestData() {
}; };
} }
async function testSubkeyTrust() { module.exports = () => it('Does not trust subkeys without Primary Key Binding Signature', async function() {
// attacker only has his own private key, // attacker only has his own private key,
// the victim's public key and a signed message // the victim's public key and a signed message
const { victimPubKey, attackerPrivKey, signed } = await generateTestData(); const { victimPubKey, attackerPrivKey, signed } = await generateTestData();
@ -68,8 +66,7 @@ async function testSubkeyTrust() {
message: await readCleartextMessage({ cleartextMessage: signed }), message: await readCleartextMessage({ cleartextMessage: signed }),
verificationKeys: fakeKey verificationKeys: fakeKey
}); });
// expect the signature to have the expected keyID, but be invalid due to fake key binding signature in the subkey
expect(verifyAttackerIsBatman.signatures[0].keyID.equals(victimPubKey.subkeys[0].getKeyID())).to.be.true; expect(verifyAttackerIsBatman.signatures[0].keyID.equals(victimPubKey.subkeys[0].getKeyID())).to.be.true;
await expect(verifyAttackerIsBatman.signatures[0].verified).to.be.rejectedWith(/Could not find valid signing key packet/); await expect(verifyAttackerIsBatman.signatures[0].verified).to.be.rejectedWith(/Could not find valid signing key packet/);
} });
module.exports = () => it('Does not trust subkeys without Primary Key Binding Signature', testSubkeyTrust);

View File

@ -12,13 +12,13 @@ import {
readMessage, createMessage, Message, createCleartextMessage, readMessage, createMessage, Message, createCleartextMessage,
encrypt, decrypt, sign, verify, config, enums, encrypt, decrypt, sign, verify, config, enums,
generateSessionKey, encryptSessionKey, decryptSessionKeys, generateSessionKey, encryptSessionKey, decryptSessionKeys,
LiteralDataPacket, PacketList, CompressedDataPacket, PublicKeyPacket, PublicSubkeyPacket, SecretKeyPacket, SecretSubkeyPacket LiteralDataPacket, PacketList, CompressedDataPacket, PublicKeyPacket, PublicSubkeyPacket, SecretKeyPacket, SecretSubkeyPacket, CleartextMessage
} from '../..'; } from '../..';
(async () => { (async () => {
// Generate keys // Generate keys
const keyOptions = { userIDs: [{ email: "user@corp.co" }], config: { v5Keys: true } }; const keyOptions = { userIDs: [{ email: 'user@corp.co' }], config: { v5Keys: true } };
const { privateKey: privateKeyArmored, publicKey: publicKeyArmored } = await generateKey(keyOptions); const { privateKey: privateKeyArmored, publicKey: publicKeyArmored } = await generateKey(keyOptions);
const { privateKey: privateKeyBinary } = await generateKey({ ...keyOptions, format: 'binary' }); const { privateKey: privateKeyBinary } = await generateKey({ ...keyOptions, format: 'binary' });
const { privateKey, publicKey, revocationCertificate } = await generateKey({ ...keyOptions, format: 'object' }); const { privateKey, publicKey, revocationCertificate } = await generateKey({ ...keyOptions, format: 'object' });
@ -75,7 +75,7 @@ import {
// Encrypt binary message (unarmored) // Encrypt binary message (unarmored)
const binary = new Uint8Array([1, 2]); const binary = new Uint8Array([1, 2]);
const binaryMessage = await createMessage({ binary }); const binaryMessage = await createMessage({ binary });
const encryptedBinary: Uint8Array = await encrypt({ encryptionKeys: publicKeys, message: binaryMessage, armor: false }); const encryptedBinary: Uint8Array = await encrypt({ encryptionKeys: publicKeys, message: binaryMessage, format: 'binary' });
expect(encryptedBinary).to.be.instanceOf(Uint8Array); expect(encryptedBinary).to.be.instanceOf(Uint8Array);
// Decrypt text message (armored) // Decrypt text message (armored)
@ -91,14 +91,17 @@ import {
expect(decryptedBinaryData).to.deep.equal(binary); expect(decryptedBinaryData).to.deep.equal(binary);
// Encrypt message (inspect packets) // Encrypt message (inspect packets)
const encryptedMessage = await readMessage({ binaryMessage: encryptedBinary }); const encryptedBinaryObject: Message<Uint8Array> = await encrypt({ encryptionKeys: publicKeys, message: binaryMessage, format: 'object' });
expect(encryptedMessage).to.be.instanceOf(Message); expect(encryptedBinaryObject).to.be.instanceOf(Message);
const encryptedTextObject: Message<string> = await encrypt({ encryptionKeys: publicKeys, message: textMessage, format: 'object' });
expect(encryptedTextObject).to.be.instanceOf(Message);
// Session key functions // Session key functions
// Get session keys from encrypted message
const sessionKeys = await decryptSessionKeys({ message: await readMessage({ binaryMessage: encryptedBinary }), decryptionKeys: privateKeys }); const sessionKeys = await decryptSessionKeys({ message: await readMessage({ binaryMessage: encryptedBinary }), decryptionKeys: privateKeys });
expect(sessionKeys).to.have.length(1); expect(sessionKeys).to.have.length(1);
// eslint-disable-next-line no-unused-vars
const encryptedSessionKeys: string = await encryptSessionKey({ ...sessionKeys[0], passwords: 'pass', algorithm: 'aes128', aeadAlgorithm: 'eax' }); const encryptedSessionKeys: string = await encryptSessionKey({ ...sessionKeys[0], passwords: 'pass', algorithm: 'aes128', aeadAlgorithm: 'eax' });
expect(encryptedSessionKeys).to.include('-----BEGIN PGP MESSAGE-----');
const newSessionKey = await generateSessionKey({ encryptionKeys: privateKey.toPublic() }); const newSessionKey = await generateSessionKey({ encryptionKeys: privateKey.toPublic() });
expect(newSessionKey.data).to.exist; expect(newSessionKey.data).to.exist;
expect(newSessionKey.algorithm).to.exist; expect(newSessionKey.algorithm).to.exist;
@ -107,6 +110,8 @@ import {
const cleartextMessage = await createCleartextMessage({ text: 'hello' }); const cleartextMessage = await createCleartextMessage({ text: 'hello' });
const clearSignedArmor = await sign({ signingKeys: privateKeys, message: cleartextMessage }); const clearSignedArmor = await sign({ signingKeys: privateKeys, message: cleartextMessage });
expect(clearSignedArmor).to.include('-----BEGIN PGP SIGNED MESSAGE-----'); expect(clearSignedArmor).to.include('-----BEGIN PGP SIGNED MESSAGE-----');
const clearSignedObject: CleartextMessage = await sign({ signingKeys: privateKeys, message: cleartextMessage, format: 'object' });
expect(clearSignedObject).to.be.instanceOf(CleartextMessage);
// @ts-expect-error PublicKey not assignable to PrivateKey // @ts-expect-error PublicKey not assignable to PrivateKey
try { await sign({ signingKeys: publicKeys, message: cleartextMessage }); } catch (e) {} try { await sign({ signingKeys: publicKeys, message: cleartextMessage }); } catch (e) {}
// @ts-expect-error Key not assignable to PrivateKey // @ts-expect-error Key not assignable to PrivateKey
@ -115,10 +120,14 @@ import {
// Sign text message (armored) // Sign text message (armored)
const textSignedArmor: string = await sign({ signingKeys: privateKeys, message: textMessage }); const textSignedArmor: string = await sign({ signingKeys: privateKeys, message: textMessage });
expect(textSignedArmor).to.include('-----BEGIN PGP MESSAGE-----'); expect(textSignedArmor).to.include('-----BEGIN PGP MESSAGE-----');
// Sign text message (unarmored) // Sign text message (unarmored)
const textSignedBinary: Uint8Array = await sign({ signingKeys: privateKeys, message: binaryMessage, armor: false }); const textSignedBinary: Uint8Array = await sign({ signingKeys: privateKeys, message: binaryMessage, format: 'binary' });
expect(textSignedBinary).to.be.instanceOf(Uint8Array); expect(textSignedBinary).to.be.instanceOf(Uint8Array);
// Sign text and binary messages (inspect packages)
const binarySignedObject: Message<Uint8Array> = await sign({ signingKeys: privateKeys, message: binaryMessage, format: 'object' });
expect(binarySignedObject).to.be.instanceOf(Message);
const textSignedObject: Message<string> = await sign({ signingKeys: privateKeys, message: textMessage, format: 'object' });
expect(textSignedObject).to.be.instanceOf(Message);
// Verify signed text message (armored) // Verify signed text message (armored)
const signedMessage = await readMessage({ armoredMessage: textSignedArmor }); const signedMessage = await readMessage({ armoredMessage: textSignedArmor });
@ -168,7 +177,7 @@ import {
// // Detached - sign binary message (unarmored) // // Detached - sign binary message (unarmored)
// const message = await createMessage({ text }); // const message = await createMessage({ text });
// const signed = await sign({ privateKeys, message, detached: true, armor: false }); // const signed = await sign({ privateKeys, message, detached: true, format: 'binary' });
// console.log(signed); // Uint8Array // console.log(signed); // Uint8Array
// // Streaming - encrypt text message on Node.js (armored) // // Streaming - encrypt text message on Node.js (armored)
@ -182,7 +191,7 @@ import {
// // Streaming - encrypt binary message on Node.js (unarmored) // // Streaming - encrypt binary message on Node.js (unarmored)
// const data = fs.createReadStream(filename); // const data = fs.createReadStream(filename);
// const message = await createMessage({ binary: data }); // const message = await createMessage({ binary: data });
// const encrypted = await encrypt({ publicKeys, message, armor: false }); // const encrypted = await encrypt({ publicKeys, message, format: 'binary' });
// encrypted.pipe(targetStream); // encrypted.pipe(targetStream);
console.log('TypeScript definitions are correct'); console.log('TypeScript definitions are correct');