Simplify return value of generateKey, reformatKey and revokeKey and add support for binary output (#1345)

- `openpgp.generateKey`, `reformatKey` and `revokeKey` take a new `format`
option, whose possible values are: `'armor', 'binary', 'object'` (default is 
`'armor'`).
- `generateKey` and `reformatKey` now return an object of the form `{
publicKey, privateKey, revocationCertificate }`, where the type of `publicKey`
and `privateKey` depends on `options.format`:
    * if `format: 'armor'` then `privateKey, publicKey` are armored strings;
    * if `format: 'binary'` then `privateKey, publicKey` are `Uint8Array`;
    * if `format: 'object'` then `privateKey, publicKey` are `PrivateKey` and
`PublicKey` objects respectively;
- `revokeKey` now returns `{ publicKey, privateKey }`, where:
    * if a `PrivateKey` is passed as `key` input,  `privateKey, publicKey` are of the
requested format;
    * if a `PublicKey` is passed as `key` input, `publicKey` is of the requested format,
while `privateKey` is `null` (previously, in this case the `privateKey` field
was not defined).

Breaking changes:
- In `revokeKey`, if no `format` option is specified, the returned `publicKey,
privateKey` are armored strings (they used to be objects).
- In `generateKey` and `reformatKey`, the `key` value is no longer returned.
- For all three functions, the `publicKeyArmored` and `privateKeyArmored`
values are no longer returned.
This commit is contained in:
larabr 2021-06-24 17:14:39 +02:00 committed by GitHub
parent b862e139fc
commit 40542fd08a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 542 additions and 483 deletions

View File

@ -435,15 +435,15 @@ and a subkey for encryption using Curve25519.
```js ```js
(async () => { (async () => {
const { privateKeyArmored, publicKeyArmored, revocationCertificate } = await openpgp.generateKey({ const { privateKey, publicKey, revocationCertificate } = await openpgp.generateKey({
type: 'ecc', // Type of the key, defaults to ECC type: 'ecc', // Type of the key, defaults to ECC
curve: 'curve25519', // ECC curve name, defaults to curve25519 curve: 'curve25519', // ECC curve name, defaults to curve25519
userIDs: [{ name: 'Jon Smith', email: 'jon@example.com' }], // you can pass multiple user IDs userIDs: [{ name: 'Jon Smith', email: 'jon@example.com' }], // you can pass multiple user IDs
passphrase: 'super long and hard to guess secret' // protects the private key passphrase: 'super long and hard to guess secret', // protects the private key
}); format: 'armor' // output key format, defaults to 'armor' (other options: 'binary' or 'object')
console.log(privateKeyArmored); // '-----BEGIN PGP PRIVATE KEY BLOCK ... ' console.log(privateKey); // '-----BEGIN PGP PRIVATE KEY BLOCK ... '
console.log(publicKeyArmored); // '-----BEGIN PGP PUBLIC KEY BLOCK ... ' console.log(publicKey); // '-----BEGIN PGP PUBLIC KEY BLOCK ... '
console.log(revocationCertificate); // '-----BEGIN PGP PUBLIC KEY BLOCK ... ' console.log(revocationCertificate); // '-----BEGIN PGP PUBLIC KEY BLOCK ... '
})(); })();
``` ```
@ -452,7 +452,7 @@ RSA keys (increased compatibility):
```js ```js
(async () => { (async () => {
const key = await openpgp.generateKey({ const { privateKey, publicKey } = await openpgp.generateKey({
type: 'rsa', // Type of the key type: 'rsa', // Type of the key
rsaBits: 4096, // RSA key size (defaults to 4096 bits) rsaBits: 4096, // RSA key size (defaults to 4096 bits)
userIDs: [{ name: 'Jon Smith', email: 'jon@example.com' }], // you can pass multiple user IDs userIDs: [{ name: 'Jon Smith', email: 'jon@example.com' }], // you can pass multiple user IDs
@ -466,9 +466,10 @@ RSA keys (increased compatibility):
Using a revocation certificate: Using a revocation certificate:
```js ```js
(async () => { (async () => {
const { publicKeyArmored: revokedKeyArmored } = await openpgp.revokeKey({ const { publicKey: revokedKeyArmored } = await openpgp.revokeKey({
key: await openpgp.readKey({ armoredKey: publicKeyArmored }), key: await openpgp.readKey({ armoredKey: publicKeyArmored }),
revocationCertificate revocationCertificate,
format: 'armor' // output armored keys
}); });
console.log(revokedKeyArmored); // '-----BEGIN PGP PUBLIC KEY BLOCK ... ' console.log(revokedKeyArmored); // '-----BEGIN PGP PUBLIC KEY BLOCK ... '
})(); })();
@ -477,9 +478,11 @@ Using a revocation certificate:
Using the private key: Using the private key:
```js ```js
(async () => { (async () => {
const { publicKeyArmored, publicKey } = await openpgp.revokeKey({ const { publicKey: revokedKeyArmored } = await openpgp.revokeKey({
key: await openpgp.readKey({ armoredKey: privateKeyArmored }) key: await openpgp.readKey({ armoredKey: privateKeyArmored }),
format: 'armor' // output armored keys
}); });
console.log(revokedKeyArmored); // '-----BEGIN PGP PUBLIC KEY BLOCK ... '
})(); })();
``` ```

33
openpgp.d.ts vendored
View File

@ -17,11 +17,25 @@ export function readPrivateKey(options: { armoredKey: string, config?: PartialCo
export function readPrivateKey(options: { binaryKey: Uint8Array, config?: PartialConfig }): Promise<PrivateKey>; export function readPrivateKey(options: { binaryKey: Uint8Array, config?: PartialConfig }): Promise<PrivateKey>;
export function readPrivateKeys(options: { armoredKeys: string, config?: PartialConfig }): Promise<PrivateKey[]>; export function readPrivateKeys(options: { armoredKeys: string, config?: PartialConfig }): Promise<PrivateKey[]>;
export function readPrivateKeys(options: { binaryKeys: Uint8Array, config?: PartialConfig }): Promise<PrivateKey[]>; export function readPrivateKeys(options: { binaryKeys: Uint8Array, config?: PartialConfig }): Promise<PrivateKey[]>;
export function generateKey(options: KeyOptions): Promise<KeyPair>; export function generateKey(options: KeyOptions & { format?: 'armor' }): Promise<SerializedKeyPair<string> & { revocationCertificate: string }>;
export function generateKey(options: KeyOptions & { format: 'binary' }): Promise<SerializedKeyPair<Uint8Array> & { revocationCertificate: string }>;
export function generateKey(options: KeyOptions & { format: 'object' }): Promise<KeyPair & { revocationCertificate: string }>;
export function generateSessionKey(options: { encryptionKeys: PublicKey[], date?: Date, encryptionUserIDs?: UserID[], config?: PartialConfig }): Promise<SessionKey>; export function generateSessionKey(options: { encryptionKeys: PublicKey[], date?: Date, encryptionUserIDs?: UserID[], config?: PartialConfig }): Promise<SessionKey>;
export function decryptKey(options: { privateKey: PrivateKey; passphrase?: string | string[]; config?: PartialConfig }): Promise<PrivateKey>; export function decryptKey(options: { privateKey: PrivateKey; passphrase?: string | string[]; config?: PartialConfig }): Promise<PrivateKey>;
export function encryptKey(options: { privateKey: PrivateKey; passphrase?: string | string[]; config?: PartialConfig }): Promise<PrivateKey>; export function encryptKey(options: { privateKey: PrivateKey; passphrase?: string | string[]; config?: PartialConfig }): Promise<PrivateKey>;
export function reformatKey(options: { privateKey: PrivateKey; userIDs?: UserID|UserID[]; passphrase?: string; keyExpirationTime?: number; config?: PartialConfig }): Promise<KeyPair>; export function reformatKey(options: { privateKey: PrivateKey; userIDs?: UserID|UserID[]; passphrase?: string; keyExpirationTime?: number; date?: Date, format?: 'armor', config?: PartialConfig }): Promise<SerializedKeyPair<string> & { revocationCertificate: string }>;
export function reformatKey(options: { privateKey: PrivateKey; userIDs?: UserID|UserID[]; passphrase?: string; keyExpirationTime?: number; date?: Date, format: 'binary', config?: PartialConfig }): Promise<SerializedKeyPair<Uint8Array> & { revocationCertificate: string }>;
export function reformatKey(options: { privateKey: PrivateKey; userIDs?: UserID|UserID[]; passphrase?: string; keyExpirationTime?: number; date?: Date, format: 'object', config?: PartialConfig }): Promise<KeyPair & { revocationCertificate: string }>;
export function revokeKey(options: { key: PrivateKey, reasonForRevocation?: ReasonForRevocation, date?: Date, format?: 'armor', config?: PartialConfig }): Promise<SerializedKeyPair<string>>;
export function revokeKey(options: { key: PrivateKey, reasonForRevocation?: ReasonForRevocation, date?: Date, format: 'binary', config?: PartialConfig }): Promise<SerializedKeyPair<Uint8Array>>;
export function revokeKey(options: { key: PrivateKey, reasonForRevocation?: ReasonForRevocation, date?: Date, format: 'object', config?: PartialConfig }): Promise<KeyPair>;
export function revokeKey(options: { key: PrivateKey, revocationCertificate: string, date?: Date, format?: 'armor', config?: PartialConfig }): Promise<SerializedKeyPair<string>>;
export function revokeKey(options: { key: PrivateKey, revocationCertificate: string, date?: Date, format: 'binary', config?: PartialConfig }): Promise<SerializedKeyPair<Uint8Array>>;
export function revokeKey(options: { key: PrivateKey, revocationCertificate: string, date?: Date, format: 'object', config?: PartialConfig }): Promise<KeyPair>;
export function revokeKey(options: { key: PublicKey, revocationCertificate: string, date?: Date, format?: 'armor', config?: PartialConfig }): Promise<{ publicKey: string, privateKey: null }>;
export function revokeKey(options: { key: PublicKey, revocationCertificate: string, date?: Date, format: 'binary', config?: PartialConfig }): Promise<{ publicKey: Uint8Array, privateKey: null }>;
export function revokeKey(options: { key: PublicKey, revocationCertificate: string, date?: Date, format: 'object', config?: PartialConfig }): Promise<{ publicKey: PublicKey, privateKey: null }>;
export abstract class Key { export abstract class Key {
public readonly keyPacket: PublicKeyPacket | SecretKeyPacket; public readonly keyPacket: PublicKeyPacket | SecretKeyPacket;
@ -63,7 +77,7 @@ export class PublicKey extends Key {
export class PrivateKey extends PublicKey { export class PrivateKey extends PublicKey {
constructor(packetlist: PacketList<AnyKeyPacket>); constructor(packetlist: PacketList<AnyKeyPacket>);
public revoke(reason: { flag?: enums.reasonForRevocation; string?: string; }, date?: Date, config?: Config): Promise<PrivateKey>; public revoke(reason?: ReasonForRevocation, date?: Date, config?: Config): Promise<PrivateKey>;
public isDecrypted(): boolean; public isDecrypted(): boolean;
public addSubkey(options: SubkeyOptions): Promise<PrivateKey>; public addSubkey(options: SubkeyOptions): Promise<PrivateKey>;
public getDecryptionKeys(keyID?: KeyID, date?: Date | null, userID?: UserID, config?: Config): Promise<PrivateKey | Subkey> public getDecryptionKeys(keyID?: KeyID, date?: Date | null, userID?: UserID, config?: Config): Promise<PrivateKey | Subkey>
@ -537,6 +551,7 @@ export namespace stream {
export interface UserID { name?: string; email?: string; comment?: string; } export interface UserID { name?: string; email?: string; comment?: string; }
export interface SessionKey { data: Uint8Array; algorithm: string; } export interface SessionKey { data: Uint8Array; algorithm: string; }
export interface ReasonForRevocation { flag?: enums.reasonForRevocation, string?: string }
interface EncryptOptions { interface EncryptOptions {
/** message to be encrypted as created by createMessage */ /** message to be encrypted as created by createMessage */
@ -618,11 +633,14 @@ interface VerifyOptions {
config?: PartialConfig; config?: PartialConfig;
} }
interface SerializedKeyPair<T extends string|Uint8Array> {
privateKey: T;
publicKey: T;
}
interface KeyPair { interface KeyPair {
key: PrivateKey; privateKey: PrivateKey;
privateKeyArmored: string; publicKey: PublicKey;
publicKeyArmored: string;
revocationCertificate: string;
} }
export type EllipticCurveName = 'ed25519' | 'curve25519' | 'p256' | 'p384' | 'p521' | 'secp256k1' | 'brainpoolP256r1' | 'brainpoolP384r1' | 'brainpoolP512r1'; export type EllipticCurveName = 'ed25519' | 'curve25519' | 'p256' | 'p384' | 'p521' | 'secp256k1' | 'brainpoolP256r1' | 'brainpoolP384r1' | 'brainpoolP512r1';
@ -636,6 +654,7 @@ interface KeyOptions {
keyExpirationTime?: number; keyExpirationTime?: number;
date?: Date; date?: Date;
subkeys?: SubkeyOptions[]; subkeys?: SubkeyOptions[];
format?: 'armor' | 'object' | 'binary';
config?: PartialConfig; config?: PartialConfig;
} }

View File

@ -57,7 +57,7 @@ const allowedKeyPackets = /*#__PURE__*/ util.constructAllowedPackets([
* @param {Object} config - Full configuration * @param {Object} config - Full configuration
* @param {Array<Object>} options.subkeys (optional) options for each subkey, default to main key options. e.g. [{sign: true, passphrase: '123'}] * @param {Array<Object>} options.subkeys (optional) options for each subkey, default to main key options. e.g. [{sign: true, passphrase: '123'}]
* sign parameter defaults to false, and indicates whether the subkey should sign rather than encrypt * sign parameter defaults to false, and indicates whether the subkey should sign rather than encrypt
* @returns {Promise<PrivateKey>} * @returns {Promise<{{ key: PrivateKey, revocationCertificate: String }}>}
* @async * @async
* @static * @static
* @private * @private
@ -68,7 +68,12 @@ export async function generate(options, config) {
options.subkeys = options.subkeys.map((subkey, index) => helper.sanitizeKeyOptions(options.subkeys[index], options)); options.subkeys = options.subkeys.map((subkey, index) => helper.sanitizeKeyOptions(options.subkeys[index], options));
let promises = [helper.generateSecretKey(options, config)]; let promises = [helper.generateSecretKey(options, config)];
promises = promises.concat(options.subkeys.map(options => helper.generateSecretSubkey(options, config))); promises = promises.concat(options.subkeys.map(options => helper.generateSecretSubkey(options, config)));
return Promise.all(promises).then(packets => wrapKeyObject(packets[0], packets.slice(1), options, config)); const packets = await Promise.all(promises);
const key = await wrapKeyObject(packets[0], packets.slice(1), options, config);
const revocationCertificate = await key.getRevocationCertificate(options.date, config);
key.revocationSignatures = [];
return { key, revocationCertificate };
} }
/** /**
@ -81,7 +86,7 @@ export async function generate(options, config) {
* @param {Array<Object>} options.subkeys (optional) options for each subkey, default to main key options. e.g. [{sign: true, passphrase: '123'}] * @param {Array<Object>} options.subkeys (optional) options for each subkey, default to main key options. e.g. [{sign: true, passphrase: '123'}]
* @param {Object} config - Full configuration * @param {Object} config - Full configuration
* *
* @returns {Promise<PrivateKey>} * @returns {Promise<{{ key: PrivateKey, revocationCertificate: String }}>}
* @async * @async
* @static * @static
* @private * @private
@ -125,7 +130,10 @@ export async function reformat(options, config) {
options.subkeys = options.subkeys.map(subkeyOptions => sanitize(subkeyOptions, options)); options.subkeys = options.subkeys.map(subkeyOptions => sanitize(subkeyOptions, options));
return wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, config); const key = await wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, config);
const revocationCertificate = await key.getRevocationCertificate(options.date, config);
key.revocationSignatures = [];
return { key, revocationCertificate };
function sanitize(options, subkeyDefaults = {}) { function sanitize(options, subkeyDefaults = {}) {
options.keyExpirationTime = options.keyExpirationTime || subkeyDefaults.keyExpirationTime; options.keyExpirationTime = options.keyExpirationTime || subkeyDefaults.keyExpirationTime;
@ -136,7 +144,15 @@ export async function reformat(options, config) {
} }
} }
/**
* Construct PrivateKey object from the given key packets, add certification signatures and set passphrase protection
* The new key includes a revocation certificate that must be removed before returning the key, otherwise the key is considered revoked.
* @param {SecretKeyPacket} secretKeyPacket
* @param {SecretSubkeyPacket} secretSubkeyPackets
* @param {Object} options
* @param {Object} config - Full configuration
* @returns {PrivateKey}
*/
async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, config) { async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, config) {
// set passphrase protection // set passphrase protection
if (options.passphrase) { if (options.passphrase) {
@ -235,7 +251,6 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
reasonForRevocationString: '' reasonForRevocationString: ''
}, options.date, undefined, undefined, config)); }, options.date, undefined, undefined, config));
// set passphrase protection
if (options.passphrase) { if (options.passphrase) {
secretKeyPacket.clearPrivateParams(); secretKeyPacket.clearPrivateParams();
} }

View File

@ -44,13 +44,14 @@ import util from './util';
* @param {Number} [options.keyExpirationTime=0 (never expires)] - Number of seconds from the key creation time after which the key expires * @param {Number} [options.keyExpirationTime=0 (never expires)] - Number of seconds from the key creation time after which the key expires
* @param {Array<Object>} [options.subkeys=a single encryption subkey] - Options for each subkey e.g. `[{sign: true, passphrase: '123'}]` * @param {Array<Object>} [options.subkeys=a single encryption subkey] - Options for each subkey e.g. `[{sign: true, passphrase: '123'}]`
* default to main key options, except for `sign` parameter that defaults to false, and indicates whether the subkey should sign rather than encrypt * default to main key options, except for `sign` parameter that defaults to false, and indicates whether the subkey should sign rather than encrypt
* @param {'armor'|'binary'|'object'} [options.format='armor'] - format of the output keys
* @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<Object>} The generated key object in the form: * @returns {Promise<Object>} The generated key object in the form:
* { key:PrivateKey, privateKeyArmored:String, publicKeyArmored:String, revocationCertificate:String } * { privateKey:PrivateKey|Uint8Array|String, publicKey:PublicKey|Uint8Array|String, revocationCertificate:String }
* @async * @async
* @static * @static
*/ */
export async function generateKey({ userIDs = [], passphrase = "", type = "ecc", rsaBits = 4096, curve = "curve25519", keyExpirationTime = 0, date = new Date(), subkeys = [{}], config }) { export async function generateKey({ userIDs = [], passphrase = "", type = "ecc", rsaBits = 4096, curve = "curve25519", keyExpirationTime = 0, date = new Date(), subkeys = [{}], format = 'armor', config }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
userIDs = toArray(userIDs); userIDs = toArray(userIDs);
if (userIDs.length === 0) { if (userIDs.length === 0) {
@ -62,15 +63,12 @@ export async function generateKey({ userIDs = [], passphrase = "", type = "ecc",
const options = { userIDs, passphrase, type, rsaBits, curve, keyExpirationTime, date, subkeys }; const options = { userIDs, passphrase, type, rsaBits, curve, keyExpirationTime, date, subkeys };
try { try {
const key = await generate(options, config); const { key, revocationCertificate } = await generate(options, config);
const revocationCertificate = await key.getRevocationCertificate(date, config);
key.revocationSignatures = [];
return { return {
key, privateKey: formatKey(key, format, config),
privateKeyArmored: key.armor(config), publicKey: formatKey(key.toPublic(), format, config),
publicKeyArmored: key.toPublic().armor(config), revocationCertificate
revocationCertificate: revocationCertificate
}; };
} catch (err) { } catch (err) {
throw util.wrapError('Error generating keypair', err); throw util.wrapError('Error generating keypair', err);
@ -85,13 +83,14 @@ export async function generateKey({ userIDs = [], passphrase = "", type = "ecc",
* @param {String} [options.passphrase=(not protected)] - The passphrase used to encrypt the reformatted private key. If omitted, the key won't be encrypted. * @param {String} [options.passphrase=(not protected)] - The passphrase used to encrypt the reformatted private key. If omitted, the key won't be encrypted.
* @param {Number} [options.keyExpirationTime=0 (never expires)] - Number of seconds from the key creation time after which the key expires * @param {Number} [options.keyExpirationTime=0 (never expires)] - Number of seconds from the key creation time after which the key expires
* @param {Date} [options.date] - Override the creation date of the key signatures * @param {Date} [options.date] - Override the creation date of the key signatures
* @param {'armor'|'binary'|'object'} [options.format='armor'] - format of the output keys
* @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<Object>} The generated key object in the form: * @returns {Promise<Object>} The generated key object in the form:
* { key:PrivateKey, privateKeyArmored:String, publicKeyArmored:String, revocationCertificate:String } * { privateKey:PrivateKey|Uint8Array|String, publicKey:PublicKey|Uint8Array|String, revocationCertificate:String }
* @async * @async
* @static * @static
*/ */
export async function reformatKey({ privateKey, userIDs = [], passphrase = "", keyExpirationTime = 0, date, config }) { export async function reformatKey({ privateKey, userIDs = [], passphrase = "", keyExpirationTime = 0, date, format = 'armor', config }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
userIDs = toArray(userIDs); userIDs = toArray(userIDs);
if (userIDs.length === 0) { if (userIDs.length === 0) {
@ -100,15 +99,12 @@ export async function reformatKey({ privateKey, userIDs = [], passphrase = "", k
const options = { privateKey, userIDs, passphrase, keyExpirationTime, date }; const options = { privateKey, userIDs, passphrase, keyExpirationTime, date };
try { try {
const reformattedKey = await reformat(options, config); const { key: reformattedKey, revocationCertificate } = await reformat(options, config);
const revocationCertificate = await reformattedKey.getRevocationCertificate(date, config);
reformattedKey.revocationSignatures = [];
return { return {
key: reformattedKey, privateKey: formatKey(reformattedKey, format, config),
privateKeyArmored: reformattedKey.armor(config), publicKey: formatKey(reformattedKey.toPublic(), format, config),
publicKeyArmored: reformattedKey.toPublic().armor(config), revocationCertificate
revocationCertificate: revocationCertificate
}; };
} catch (err) { } catch (err) {
throw util.wrapError('Error reformatting keypair', err); throw util.wrapError('Error reformatting keypair', err);
@ -125,33 +121,27 @@ export async function reformatKey({ privateKey, userIDs = [], passphrase = "", k
* @param {module:enums.reasonForRevocation} [options.reasonForRevocation.flag=[noReason]{@link module:enums.reasonForRevocation}] - Flag indicating the reason for revocation * @param {module:enums.reasonForRevocation} [options.reasonForRevocation.flag=[noReason]{@link module:enums.reasonForRevocation}] - Flag indicating the reason for revocation
* @param {String} [options.reasonForRevocation.string=""] - String explaining the reason for revocation * @param {String} [options.reasonForRevocation.string=""] - String explaining the reason for revocation
* @param {Date} [options.date] - Use the given date instead of the current time to verify validity of revocation certificate (if provided), or as creation time of the revocation signature * @param {Date} [options.date] - Use the given date instead of the current time to verify validity of revocation certificate (if provided), or as creation time of the revocation signature
* @param {'armor'|'binary'|'object'} [options.format='armor'] - format of the output key(s)
* @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<Object>} The revoked key object in the form: * @returns {Promise<Object>} The revoked key in the form:
* `{ privateKey:PrivateKey, privateKeyArmored:String, publicKey:PublicKey, publicKeyArmored:String }` * { privateKey:PrivateKey|Uint8Array|String, publicKey:PublicKey|Uint8Array|String } if private key is passed, or
* (if private key is passed) or `{ publicKey:PublicKey, publicKeyArmored:String }` (otherwise) * { privateKey: null, publicKey:PublicKey|Uint8Array|String } otherwise
* @async * @async
* @static * @static
*/ */
export async function revokeKey({ key, revocationCertificate, reasonForRevocation, date = new Date(), config }) { export async function revokeKey({ key, revocationCertificate, reasonForRevocation, date = new Date(), format = 'armor', config }) {
config = { ...defaultConfig, ...config }; config = { ...defaultConfig, ...config };
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);
if (revokedKey.isPrivate()) { return revokedKey.isPrivate() ? {
const publicKey = revokedKey.toPublic(); privateKey: formatKey(revokedKey, format, config),
return { publicKey: formatKey(revokedKey.toPublic(), format, config)
privateKey: revokedKey, } : {
privateKeyArmored: revokedKey.armor(config), privateKey: null,
publicKey: publicKey, publicKey: formatKey(revokedKey, format, config)
publicKeyArmored: publicKey.armor(config)
};
}
return {
publicKey: revokedKey,
publicKeyArmored: revokedKey.armor(config)
}; };
} catch (err) { } catch (err) {
throw util.wrapError('Error revoking key', err); throw util.wrapError('Error revoking key', err);
@ -680,3 +670,23 @@ async function prepareSignatures(signatures) {
} }
})); }));
} }
/**
* Convert the key object to the given format
* @param {Key} key
* @param {'armor'|'binary'|'object'} format
* @param {Object} config - Full configuration
* @returns {String|Uint8Array|Object}
*/
function formatKey(key, format, config) {
switch (format) {
case 'object':
return key;
case 'armor':
return key.armor(config);
case 'binary':
return key.write();
default:
throw new Error(`Unsupported format ${format}`);
}
}

View File

@ -80,12 +80,17 @@ async function cloneKeyPacket(key) {
return keyPacket; return keyPacket;
} }
async function generatePrivateKeyObject(options) {
const { privateKey } = await openpgp.generateKey({ ...options, userIDs: [{ name: 'Test', email: 'test@test.com' }], format: 'object' });
return privateKey;
}
/* eslint-disable no-invalid-this */ /* eslint-disable no-invalid-this */
module.exports = () => { module.exports = () => {
describe('EdDSA parameter validation', function() { describe('EdDSA parameter validation', function() {
let eddsaKey; let eddsaKey;
before(async () => { before(async () => {
eddsaKey = (await openpgp.generateKey({ curve: 'ed25519', userIDs: [{ name: 'Test', email: 'test@test.com' }] })).key; eddsaKey = await generatePrivateKeyObject({ curve: 'ed25519' });
}); });
it('EdDSA params should be valid', async function() { it('EdDSA params should be valid', async function() {
@ -109,9 +114,9 @@ module.exports = () => {
let ecdhKey; let ecdhKey;
let ecdsaKey; let ecdsaKey;
before(async () => { before(async () => {
eddsaKey = (await openpgp.generateKey({ curve: 'ed25519', userIDs: [{ name: 'Test', email: 'test@test.com' }] })).key; eddsaKey = await generatePrivateKeyObject({ curve: 'ed25519' });
ecdhKey = eddsaKey.subkeys[0]; ecdhKey = eddsaKey.subkeys[0];
ecdsaKey = (await openpgp.generateKey({ curve: 'p256', userIDs: [{ name: 'Test', email: 'test@test.com' }] })).key; ecdsaKey = await generatePrivateKeyObject({ curve: 'p256' });
}); });
it('EdDSA params are not valid for ECDH', async function() { it('EdDSA params are not valid for ECDH', async function() {
@ -194,10 +199,10 @@ module.exports = () => {
let ecdhKey; let ecdhKey;
before(async () => { before(async () => {
if (curve !== 'curve25519') { if (curve !== 'curve25519') {
ecdsaKey = (await openpgp.generateKey({ curve, userIDs: [{ name: 'Test', email: 'test@test.com' }] })).key; ecdsaKey = await generatePrivateKeyObject({ curve });
ecdhKey = ecdsaKey.subkeys[0]; ecdhKey = ecdsaKey.subkeys[0];
} else { } else {
const eddsaKey = (await openpgp.generateKey({ curve: 'ed25519', userIDs: [{ name: 'Test', email: 'test@test.com' }] })).key; const eddsaKey = await generatePrivateKeyObject({ curve: 'ed25519' });
ecdhKey = eddsaKey.subkeys[0]; ecdhKey = eddsaKey.subkeys[0];
} }
}); });
@ -244,7 +249,7 @@ module.exports = () => {
describe('RSA parameter validation', function() { describe('RSA parameter validation', function() {
let rsaKey; let rsaKey;
before(async () => { before(async () => {
rsaKey = (await openpgp.generateKey({ type: 'rsa', rsaBits: 2048, userIDs: [{ name: 'Test', email: 'test@test.com' }] })).key; rsaKey = await generatePrivateKeyObject({ type: 'rsa', rsaBits: 2048 });
}); });
it('generated RSA params are valid', async function() { it('generated RSA params are valid', async function() {

View File

@ -285,12 +285,8 @@ function omnibus() {
const testData = input.createSomeMessage(); const testData = input.createSomeMessage();
const testData2 = input.createSomeMessage(); const testData2 = input.createSomeMessage();
const firstKey = await openpgp.generateKey({ userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "brainpoolP256r1" }); const { privateKey: hi, publicKey: pubHi } = await openpgp.generateKey({ userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "brainpoolP256r1", format: 'object' });
const hi = firstKey.key; const { privateKey: bye, publicKey: pubBye } = await openpgp.generateKey({ userIDs: { name: "Bye", email: "bye@good.bye" }, curve: "brainpoolP256r1", format: 'object' });
const pubHi = hi.toPublic();
const secondKey = await openpgp.generateKey({ userIDs: { name: "Bye", email: "bye@good.bye" }, curve: "brainpoolP256r1" });
const bye = secondKey.key;
const pubBye = bye.toPublic();
const cleartextMessage = await openpgp.sign({ message: await openpgp.createCleartextMessage({ text: testData }), signingKeys: hi }); const cleartextMessage = await openpgp.sign({ message: await openpgp.createCleartextMessage({ text: testData }), signingKeys: hi });
await openpgp.verify({ await openpgp.verify({

View File

@ -41,7 +41,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
}); });
it('openpgp.readKey', async function() { it('openpgp.readKey', async function() {
const { privateKeyArmored: armoredKey } = await openpgp.generateKey({ userIDs:[{ name:'test', email:'test@a.it' }] }); const { privateKey: armoredKey } = await openpgp.generateKey({ userIDs:[{ name:'test', email:'test@a.it' }] });
await expect( await expect(
openpgp.readKey({ armoredKey, config: { tolerant: false, maxUserIDLength: 2 } }) openpgp.readKey({ armoredKey, config: { tolerant: false, maxUserIDLength: 2 } })
).to.be.rejectedWith(/User ID string is too long/); ).to.be.rejectedWith(/User ID string is too long/);
@ -63,7 +63,8 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
const opt = { const opt = {
userIDs: { name: 'Test User', email: 'text@example.com' } userIDs: { name: 'Test User', email: 'text@example.com' }
}; };
const { key, privateKeyArmored } = await openpgp.generateKey(opt); const { privateKey: privateKeyArmored } = await openpgp.generateKey(opt);
const key = await openpgp.readKey({ armoredKey: privateKeyArmored });
expect(key.keyPacket.version).to.equal(4); expect(key.keyPacket.version).to.equal(4);
expect(privateKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false; expect(privateKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false;
expect(key.users[0].selfCertifications[0].preferredHashAlgorithms[0]).to.equal(openpgp.config.preferredHashAlgorithm); expect(key.users[0].selfCertifications[0].preferredHashAlgorithms[0]).to.equal(openpgp.config.preferredHashAlgorithm);
@ -77,7 +78,8 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
userIDs: { name: 'Test User', email: 'text@example.com' }, userIDs: { name: 'Test User', email: 'text@example.com' },
config config
}; };
const { key: key2, privateKeyArmored: privateKeyArmored2 } = await openpgp.generateKey(opt2); const { privateKey: privateKeyArmored2 } = await openpgp.generateKey(opt2);
const key2 = await openpgp.readKey({ armoredKey: privateKeyArmored2 });
expect(key2.keyPacket.version).to.equal(5); expect(key2.keyPacket.version).to.equal(5);
expect(privateKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true; expect(privateKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true;
expect(key2.users[0].selfCertifications[0].preferredHashAlgorithms[0]).to.equal(config.preferredHashAlgorithm); expect(key2.users[0].selfCertifications[0].preferredHashAlgorithms[0]).to.equal(config.preferredHashAlgorithm);
@ -98,14 +100,15 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
try { try {
const userIDs = { name: 'Test User', email: 'text2@example.com' }; const userIDs = { name: 'Test User', email: 'text2@example.com' };
const { key: origKey } = await openpgp.generateKey({ userIDs }); const { privateKey: origKey } = await openpgp.generateKey({ userIDs, format: 'object' });
const opt = { privateKey: origKey, userIDs }; const opt = { privateKey: origKey, userIDs };
const { key: refKey, privateKeyArmored: refKeyArmored } = await openpgp.reformatKey(opt); const { privateKey: refKeyArmored } = await openpgp.reformatKey(opt);
expect(refKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false;
const refKey = await openpgp.readKey({ armoredKey: refKeyArmored });
const prefs = refKey.users[0].selfCertifications[0]; const prefs = refKey.users[0].selfCertifications[0];
expect(prefs.preferredCompressionAlgorithms[0]).to.equal(openpgp.config.preferredCompressionAlgorithm); expect(prefs.preferredCompressionAlgorithms[0]).to.equal(openpgp.config.preferredCompressionAlgorithm);
expect(prefs.preferredHashAlgorithms[0]).to.equal(openpgp.config.preferredHashAlgorithm); expect(prefs.preferredHashAlgorithms[0]).to.equal(openpgp.config.preferredHashAlgorithm);
expect(refKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false;
const config = { const config = {
showComment: true, showComment: true,
@ -114,11 +117,12 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
rejectPublicKeyAlgorithms: new Set([openpgp.enums.publicKey.eddsa]) // should not matter in this context rejectPublicKeyAlgorithms: new Set([openpgp.enums.publicKey.eddsa]) // should not matter in this context
}; };
const opt2 = { privateKey: origKey, userIDs, config }; const opt2 = { privateKey: origKey, userIDs, config };
const { key: refKey2, privateKeyArmored: refKeyArmored2 } = await openpgp.reformatKey(opt2); const { privateKey: refKeyArmored2 } = await openpgp.reformatKey(opt2);
expect(refKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true;
const refKey2 = await openpgp.readKey({ armoredKey: refKeyArmored2 });
const prefs2 = refKey2.users[0].selfCertifications[0]; const prefs2 = refKey2.users[0].selfCertifications[0];
expect(prefs2.preferredCompressionAlgorithms[0]).to.equal(config.preferredCompressionAlgorithm); expect(prefs2.preferredCompressionAlgorithms[0]).to.equal(config.preferredCompressionAlgorithm);
expect(prefs2.preferredHashAlgorithms[0]).to.equal(config.preferredHashAlgorithm); expect(prefs2.preferredHashAlgorithms[0]).to.equal(config.preferredHashAlgorithm);
expect(refKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true;
} finally { } finally {
openpgp.config.preferredCompressionAlgorithm = preferredCompressionAlgorithmVal; openpgp.config.preferredCompressionAlgorithm = preferredCompressionAlgorithmVal;
openpgp.config.preferredHashAlgorithm = preferredHashAlgorithmVal; openpgp.config.preferredHashAlgorithm = preferredHashAlgorithmVal;
@ -133,14 +137,14 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
try { try {
const userIDs = { name: 'Test User', email: 'text2@example.com' }; const userIDs = { name: 'Test User', email: 'text2@example.com' };
const { key, revocationCertificate } = await openpgp.generateKey({ userIDs }); const { privateKey: key, revocationCertificate } = await openpgp.generateKey({ userIDs, format: 'object' });
const opt = { key }; const opt = { key };
const { privateKeyArmored: revKeyArmored } = await openpgp.revokeKey(opt); const { privateKey: revKeyArmored } = await openpgp.revokeKey(opt);
expect(revKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false; expect(revKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false;
const opt2 = { key, config: { showComment: true } }; const opt2 = { key, config: { showComment: true } };
const { privateKeyArmored: revKeyArmored2 } = await openpgp.revokeKey(opt2); const { privateKey: revKeyArmored2 } = await openpgp.revokeKey(opt2);
expect(revKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true; expect(revKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true;
const opt3 = { const opt3 = {
@ -158,7 +162,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
const userIDs = { name: 'Test User', email: 'text2@example.com' }; const userIDs = { name: 'Test User', email: 'text2@example.com' };
const passphrase = '12345678'; const passphrase = '12345678';
const { key } = await openpgp.generateKey({ userIDs, passphrase }); const { privateKey: key } = await openpgp.generateKey({ userIDs, passphrase, format: 'object' });
key.keyPacket.makeDummy(); key.keyPacket.makeDummy();
const opt = { const opt = {
@ -176,7 +180,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
try { try {
const passphrase = '12345678'; const passphrase = '12345678';
const userIDs = { name: 'Test User', email: 'text2@example.com' }; const userIDs = { name: 'Test User', email: 'text2@example.com' };
const { key: privateKey } = await openpgp.generateKey({ userIDs }); const { privateKey } = await openpgp.generateKey({ userIDs, format: 'object' });
const encKey = await openpgp.encryptKey({ privateKey, userIDs, passphrase }); const encKey = await openpgp.encryptKey({ privateKey, userIDs, passphrase });
expect(encKey.keyPacket.s2k.c).to.equal(openpgp.config.s2kIterationCountByte); expect(encKey.keyPacket.s2k.c).to.equal(openpgp.config.s2kIterationCountByte);
@ -222,7 +226,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
expect(compressed.algorithm).to.equal("zip"); expect(compressed.algorithm).to.equal("zip");
const userIDs = { name: 'Test User', email: 'text2@example.com' }; const userIDs = { name: 'Test User', email: 'text2@example.com' };
const { key } = await openpgp.generateKey({ userIDs }); const { privateKey: key } = await openpgp.generateKey({ userIDs, format: 'object' });
await expect(openpgp.encrypt({ await expect(openpgp.encrypt({
message, encryptionKeys: [key], config: { rejectPublicKeyAlgorithms: new Set([openpgp.enums.publicKey.ecdh]) } message, encryptionKeys: [key], config: { rejectPublicKeyAlgorithms: new Set([openpgp.enums.publicKey.ecdh]) }
})).to.be.eventually.rejectedWith(/ecdh keys are considered too weak/); })).to.be.eventually.rejectedWith(/ecdh keys are considered too weak/);
@ -236,7 +240,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
const plaintext = 'test'; const plaintext = 'test';
const message = await openpgp.createMessage({ text: plaintext }); const message = await openpgp.createMessage({ text: plaintext });
const userIDs = { name: 'Test User', email: 'text2@example.com' }; const userIDs = { name: 'Test User', email: 'text2@example.com' };
const { key } = await openpgp.generateKey({ userIDs, type: 'rsa', rsaBits: 2048 }); const { privateKey: key } = await openpgp.generateKey({ userIDs, type: 'rsa', rsaBits: 2048, format: 'object' });
const armoredMessage = await openpgp.encrypt({ message, encryptionKeys:[key], signingKeys: [key] }); const armoredMessage = await openpgp.encrypt({ message, encryptionKeys:[key], signingKeys: [key] });
const { data, signatures } = await openpgp.decrypt({ const { data, signatures } = await openpgp.decrypt({
@ -270,8 +274,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
it('openpgp.sign', async function() { it('openpgp.sign', async function() {
const userIDs = { name: 'Test User', email: 'text2@example.com' }; const userIDs = { name: 'Test User', email: 'text2@example.com' };
const { privateKeyArmored } = await openpgp.generateKey({ userIDs }); const { privateKey: key } = await openpgp.generateKey({ userIDs, format: 'object' });
const key = await openpgp.readKey({ armoredKey: privateKeyArmored });
const message = await openpgp.createMessage({ text: "test" }); const message = await openpgp.createMessage({ text: "test" });
const opt = { const opt = {
@ -298,8 +301,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
it('openpgp.verify', async function() { it('openpgp.verify', async function() {
const userIDs = { name: 'Test User', email: 'text2@example.com' }; const userIDs = { name: 'Test User', email: 'text2@example.com' };
const { privateKeyArmored } = await openpgp.generateKey({ userIDs }); const { privateKey: key } = await openpgp.generateKey({ userIDs, format: 'object' });
const key = await openpgp.readKey({ armoredKey: privateKeyArmored });
const config = { rejectMessageHashAlgorithms: new Set([openpgp.enums.hash.sha256, openpgp.enums.hash.sha512]) }; const config = { rejectMessageHashAlgorithms: new Set([openpgp.enums.hash.sha256, openpgp.enums.hash.sha512]) };

View File

@ -13,12 +13,8 @@ module.exports = () => describe('Elliptic Curve Cryptography for NIST P-256,P-38
const testData = input.createSomeMessage(); const testData = input.createSomeMessage();
const testData2 = input.createSomeMessage(); const testData2 = input.createSomeMessage();
const firstKey = await openpgp.generateKey({ userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "p256" }); const { privateKey: hi, publicKey: pubHi } = await openpgp.generateKey({ userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "p256", format: 'object' });
const hi = firstKey.key; const { privateKey: bye, publicKey: pubBye } = await openpgp.generateKey({ userIDs: { name: "Bye", email: "bye@good.bye" }, curve: "p256", format: 'object' });
const pubHi = hi.toPublic();
const secondKey = await openpgp.generateKey({ userIDs: { name: "Bye", email: "bye@good.bye" }, curve: "p256" });
const bye = secondKey.key;
const pubBye = bye.toPublic();
const cleartextMessage = await openpgp.sign({ message: await openpgp.createCleartextMessage({ text: testData }), signingKeys: hi }); const cleartextMessage = await openpgp.sign({ message: await openpgp.createCleartextMessage({ text: testData }), signingKeys: hi });
await openpgp.verify({ await openpgp.verify({
@ -54,31 +50,27 @@ module.exports = () => describe('Elliptic Curve Cryptography for NIST P-256,P-38
it('Sign message', async function () { it('Sign message', async function () {
const testData = input.createSomeMessage(); const testData = input.createSomeMessage();
const options = { userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "p256" }; const options = { userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "p256", format: 'object' };
const firstKey = await openpgp.generateKey(options); const { privateKey, publicKey } = await openpgp.generateKey(options);
const signature = await openpgp.sign({ message: await openpgp.createCleartextMessage({ text: testData }), signingKeys: firstKey.key }); const signature = await openpgp.sign({ message: await openpgp.createCleartextMessage({ text: testData }), signingKeys: privateKey });
const msg = await openpgp.readCleartextMessage({ cleartextMessage: signature }); const msg = await openpgp.readCleartextMessage({ cleartextMessage: signature });
const result = await openpgp.verify({ message: msg, verificationKeys: firstKey.key.toPublic() }); const result = await openpgp.verify({ message: msg, verificationKeys: publicKey });
expect(result.signatures[0].valid).to.be.true; expect(result.signatures[0].valid).to.be.true;
}); });
it('encrypt and sign message', async function () { it('Encrypt and sign message', async function () {
const testData = input.createSomeMessage(); const testData = input.createSomeMessage();
let options = { userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "p256" }; let options = { userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "p256", format: 'object' };
const firstKey = await openpgp.generateKey(options); const firstKey = await openpgp.generateKey(options);
options = { userIDs: { name: "Bye", email: "bye@good.bye" }, curve: "p256" }; options = { userIDs: { name: "Bye", email: "bye@good.bye" }, curve: "p256", format: 'object' };
const secondKey = await openpgp.generateKey(options); const secondKey = await openpgp.generateKey(options);
const encrypted = await openpgp.encrypt( const encrypted = await openpgp.encrypt({
{ message: await openpgp.createMessage({ text: testData }), message: await openpgp.createMessage({ text: testData }),
encryptionKeys: [secondKey.key.toPublic()], encryptionKeys: secondKey.publicKey,
signingKeys: [firstKey.key] } signingKeys: firstKey.privateKey
); });
const msg = await openpgp.readMessage({ armoredMessage: encrypted }); const message = await openpgp.readMessage({ armoredMessage: encrypted });
const result = await openpgp.decrypt( const result = await openpgp.decrypt({ message, decryptionKeys: secondKey.privateKey, verificationKeys: firstKey.publicKey });
{ message: msg,
decryptionKeys: secondKey.key,
verificationKeys: [firstKey.key.toPublic()] }
);
expect(result.signatures[0].valid).to.be.true; expect(result.signatures[0].valid).to.be.true;
}); });

View File

@ -226,14 +226,12 @@ module.exports = () => describe('Elliptic Curve Cryptography for secp256k1 curve
const options = { const options = {
userIDs: { name: "Hamlet (secp256k1)", email: "hamlet@example.net" }, userIDs: { name: "Hamlet (secp256k1)", email: "hamlet@example.net" },
curve: "secp256k1", curve: "secp256k1",
passphrase: "ophelia" passphrase: "ophelia",
format: 'object'
}; };
return openpgp.generateKey(options).then(function (key) { return openpgp.generateKey(options).then(function ({ privateKey, publicKey }) {
expect(key).to.exist; expect(privateKey.getAlgorithmInfo().curve).to.equal('secp256k1');
expect(key.key).to.exist; expect(publicKey.getAlgorithmInfo().curve).to.equal('secp256k1');
expect(key.key.keyPacket).to.exist;
expect(key.privateKeyArmored).to.exist;
expect(key.publicKeyArmored).to.exist;
}); });
}); });
}); });

View File

@ -2155,10 +2155,10 @@ function versionSpecificTests() {
} }
expect(key.users[0].selfCertifications[0].features).to.eql(expectedFeatures); expect(key.users[0].selfCertifications[0].features).to.eql(expectedFeatures);
}; };
const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: 'hello' }; const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: 'hello', format: 'object' };
return openpgp.generateKey(opt).then(async function(key) { return openpgp.generateKey(opt).then(async function({ privateKey, publicKey }) {
testPref(key.key); testPref(privateKey);
testPref(await openpgp.readKey({ armoredKey: key.publicKeyArmored })); testPref(publicKey);
}); });
}); });
@ -2200,11 +2200,11 @@ function versionSpecificTests() {
} }
expect(key.users[0].selfCertifications[0].features).to.eql(expectedFeatures); expect(key.users[0].selfCertifications[0].features).to.eql(expectedFeatures);
}; };
const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: 'hello' }; const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: 'hello', format: 'object' };
try { try {
const key = await openpgp.generateKey(opt); const { privateKey, publicKey } = await openpgp.generateKey(opt);
testPref(key.key); testPref(privateKey);
testPref(await openpgp.readKey({ armoredKey: key.publicKeyArmored })); testPref(publicKey);
} finally { } finally {
openpgp.config.preferredSymmetricAlgorithm = preferredSymmetricAlgorithmVal; openpgp.config.preferredSymmetricAlgorithm = preferredSymmetricAlgorithmVal;
openpgp.config.preferredHashAlgorithm = preferredHashAlgorithmVal; openpgp.config.preferredHashAlgorithm = preferredHashAlgorithmVal;
@ -2214,8 +2214,8 @@ function versionSpecificTests() {
}); });
it('Generated key is not unlocked by default', async function() { it('Generated key is not unlocked by default', async function() {
const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: '123' }; const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: '123', format: 'object' };
const { key } = await openpgp.generateKey(opt); const { privateKey: key } = await openpgp.generateKey(opt);
return openpgp.encrypt({ return openpgp.encrypt({
message: await openpgp.createMessage({ text: 'hello' }), message: await openpgp.createMessage({ text: 'hello' }),
encryptionKeys: key encryptionKeys: key
@ -2229,9 +2229,8 @@ function versionSpecificTests() {
it('Generate key - single userID', function() { it('Generate key - single userID', function() {
const userID = { name: 'test', email: 'a@b.com', comment: 'test comment' }; const userID = { name: 'test', email: 'a@b.com', comment: 'test comment' };
const opt = { userIDs: userID, passphrase: '123' }; const opt = { userIDs: userID, passphrase: '123', format: 'object' };
return openpgp.generateKey(opt).then(function(key) { return openpgp.generateKey(opt).then(function({ privateKey: key }) {
key = key.key;
expect(key.users.length).to.equal(1); expect(key.users.length).to.equal(1);
expect(key.users[0].userID.userID).to.equal('test (test comment) <a@b.com>'); expect(key.users[0].userID.userID).to.equal('test (test comment) <a@b.com>');
expect(key.users[0].userID.name).to.equal(userID.name); expect(key.users[0].userID.name).to.equal(userID.name);
@ -2240,11 +2239,10 @@ function versionSpecificTests() {
}); });
}); });
it('Generate key - single userID (all missing)', function() { it('Generate key - single userID (all empty)', function() {
const userID = { name: '', email: '', comment: '' }; const userID = { name: '', email: '', comment: '' };
const opt = { userIDs: userID, passphrase: '123' }; const opt = { userIDs: userID, passphrase: '123', format: 'object' };
return openpgp.generateKey(opt).then(function(key) { return openpgp.generateKey(opt).then(function({ privateKey: key }) {
key = key.key;
expect(key.users.length).to.equal(1); expect(key.users.length).to.equal(1);
expect(key.users[0].userID.userID).to.equal(''); expect(key.users[0].userID.userID).to.equal('');
expect(key.users[0].userID.name).to.equal(userID.name); expect(key.users[0].userID.name).to.equal(userID.name);
@ -2253,11 +2251,10 @@ function versionSpecificTests() {
}); });
}); });
it('Generate key - single userID (missing email)', function() { it('Generate key - single userID (empty email)', function() {
const userID = { name: 'test', email: '', comment: 'test comment' }; const userID = { name: 'test', email: '', comment: 'test comment' };
const opt = { userIDs: userID, passphrase: '123' }; const opt = { userIDs: userID, passphrase: '123', format: 'object' };
return openpgp.generateKey(opt).then(function(key) { return openpgp.generateKey(opt).then(function({ privateKey: key }) {
key = key.key;
expect(key.users.length).to.equal(1); expect(key.users.length).to.equal(1);
expect(key.users[0].userID.userID).to.equal('test (test comment)'); expect(key.users[0].userID.userID).to.equal('test (test comment)');
expect(key.users[0].userID.name).to.equal(userID.name); expect(key.users[0].userID.name).to.equal(userID.name);
@ -2266,11 +2263,10 @@ function versionSpecificTests() {
}); });
}); });
it('Generate key - single userID (missing comment)', function() { it('Generate key - single userID (empty comment)', function() {
const userID = { name: 'test', email: 'a@b.com', comment: '' }; const userID = { name: 'test', email: 'a@b.com', comment: '' };
const opt = { userIDs: userID, passphrase: '123' }; const opt = { userIDs: userID, passphrase: '123', format: 'object' };
return openpgp.generateKey(opt).then(function(key) { return openpgp.generateKey(opt).then(function({ privateKey: key }) {
key = key.key;
expect(key.users.length).to.equal(1); expect(key.users.length).to.equal(1);
expect(key.users[0].userID.userID).to.equal('test <a@b.com>'); expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
expect(key.users[0].userID.name).to.equal(userID.name); expect(key.users[0].userID.name).to.equal(userID.name);
@ -2284,14 +2280,15 @@ function versionSpecificTests() {
const opt = { const opt = {
userIDs: { name: 'Test User', email: 'text@example.com' }, userIDs: { name: 'Test User', email: 'text@example.com' },
passphrase: 'secret', passphrase: 'secret',
date: past date: past,
format: 'object'
}; };
return openpgp.generateKey(opt).then(function(newKey) { return openpgp.generateKey(opt).then(function({ privateKey }) {
expect(newKey.key).to.exist; expect(privateKey).to.exist;
expect(+newKey.key.getCreationTime()).to.equal(+past); expect(+privateKey.getCreationTime()).to.equal(+past);
expect(+newKey.key.subkeys[0].getCreationTime()).to.equal(+past); expect(+privateKey.subkeys[0].getCreationTime()).to.equal(+past);
expect(+newKey.key.subkeys[0].bindingSignatures[0].created).to.equal(+past); expect(+privateKey.subkeys[0].bindingSignatures[0].created).to.equal(+past);
}); });
}); });
@ -2300,23 +2297,23 @@ function versionSpecificTests() {
const opt = { const opt = {
userIDs: { name: 'Test User', email: 'text@example.com' }, userIDs: { name: 'Test User', email: 'text@example.com' },
passphrase: 'secret', passphrase: 'secret',
date: future date: future,
format: 'object'
}; };
return openpgp.generateKey(opt).then(function(newKey) { return openpgp.generateKey(opt).then(function({ privateKey }) {
expect(newKey.key).to.exist; expect(privateKey).to.exist;
expect(+newKey.key.getCreationTime()).to.equal(+future); expect(+privateKey.getCreationTime()).to.equal(+future);
expect(+newKey.key.subkeys[0].getCreationTime()).to.equal(+future); expect(+privateKey.subkeys[0].getCreationTime()).to.equal(+future);
expect(+newKey.key.subkeys[0].bindingSignatures[0].created).to.equal(+future); expect(+privateKey.subkeys[0].bindingSignatures[0].created).to.equal(+future);
}); });
}); });
it('Generate key - multi userID', function() { it('Generate key - multi userID', function() {
const userID1 = { name: 'test', email: 'a@b.com' }; const userID1 = { name: 'test', email: 'a@b.com' };
const userID2 = { name: 'test', email: 'b@c.com' }; const userID2 = { name: 'test', email: 'b@c.com' };
const opt = { userIDs: [userID1, userID2], passphrase: '123' }; const opt = { userIDs: [userID1, userID2], passphrase: '123', format: 'object' };
return openpgp.generateKey(opt).then(function(key) { return openpgp.generateKey(opt).then(function({ privateKey: key }) {
key = key.key;
expect(key.users.length).to.equal(2); expect(key.users.length).to.equal(2);
expect(key.users[0].userID.userID).to.equal('test <a@b.com>'); expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
@ -2327,8 +2324,8 @@ function versionSpecificTests() {
it('Generate key - default values', function() { it('Generate key - default values', function() {
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const opt = { userIDs: [userID] }; const opt = { userIDs: [userID], format: 'object' };
return openpgp.generateKey(opt).then(function({ key }) { return openpgp.generateKey(opt).then(function({ privateKey: key }) {
expect(key.isDecrypted()).to.be.true; expect(key.isDecrypted()).to.be.true;
expect(key.getAlgorithmInfo().algorithm).to.equal('eddsa'); expect(key.getAlgorithmInfo().algorithm).to.equal('eddsa');
expect(key.users.length).to.equal(1); expect(key.users.length).to.equal(1);
@ -2341,9 +2338,8 @@ function versionSpecificTests() {
it('Generate key - two subkeys with default values', function() { it('Generate key - two subkeys with default values', function() {
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const opt = { userIDs: [userID], passphrase: '123', subkeys:[{},{}] }; const opt = { userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{},{}] };
return openpgp.generateKey(opt).then(function(key) { return openpgp.generateKey(opt).then(function({ privateKey: key }) {
key = key.key;
expect(key.users.length).to.equal(1); expect(key.users.length).to.equal(1);
expect(key.users[0].userID.userID).to.equal('test <a@b.com>'); expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
@ -2359,9 +2355,9 @@ function versionSpecificTests() {
openpgp.config.minRSABits = rsaBits; openpgp.config.minRSABits = rsaBits;
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', subkeys:[{},{}] }; const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{},{}] };
try { try {
const { key } = await openpgp.generateKey(opt); const { privateKey: key } = await openpgp.generateKey(opt);
expect(key.users.length).to.equal(1); expect(key.users.length).to.equal(1);
expect(key.users[0].userID.userID).to.equal('test <a@b.com>'); expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
@ -2375,9 +2371,8 @@ function versionSpecificTests() {
it('Generate key - one signing subkey', function() { it('Generate key - one signing subkey', function() {
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const opt = { userIDs: [userID], passphrase: '123', subkeys:[{}, { sign: true }] }; const opt = { userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{}, { sign: true }] };
return openpgp.generateKey(opt).then(async function({ privateKeyArmored }) { return openpgp.generateKey(opt).then(async function({ privateKey: key }) {
const key = await openpgp.readKey({ armoredKey: privateKeyArmored });
expect(key.users.length).to.equal(1); expect(key.users.length).to.equal(1);
expect(key.users[0].userID.userID).to.equal('test <a@b.com>'); expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
@ -2389,13 +2384,13 @@ function versionSpecificTests() {
}); });
}); });
it('Reformat key - one signing subkey', function() { it('Reformat key - one signing subkey', async function() {
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const opt = { userIDs: [userID], subkeys:[{}, { sign: true }] }; const opt = { userIDs: [userID], format: 'object', subkeys:[{}, { sign: true }] };
return openpgp.generateKey(opt).then(async function({ key }) { const { privateKey } = await openpgp.generateKey(opt);
return openpgp.reformatKey({ privateKey: key, userIDs: [userID] });
}).then(async function({ privateKeyArmored }) { return openpgp.reformatKey({ privateKey, userIDs: [userID] }).then(async function({ privateKey: armoredKey }) {
const key = await openpgp.readKey({ armoredKey: privateKeyArmored }); const key = await openpgp.readKey({ armoredKey });
expect(key.users.length).to.equal(1); expect(key.users.length).to.equal(1);
expect(key.users[0].userID.userID).to.equal('test <a@b.com>'); expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
@ -2413,9 +2408,9 @@ function versionSpecificTests() {
openpgp.config.minRSABits = rsaBits; openpgp.config.minRSABits = rsaBits;
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', subkeys:[{ type: 'ecc', curve: 'curve25519' }] }; const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{ type: 'ecc', curve: 'curve25519' }] };
try { try {
const { key } = await openpgp.generateKey(opt); const { privateKey: key } = await openpgp.generateKey(opt);
expect(key.users.length).to.equal(1); expect(key.users.length).to.equal(1);
expect(key.users[0].userID.userID).to.equal('test <a@b.com>'); expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
@ -2427,39 +2422,11 @@ function versionSpecificTests() {
} }
}); });
it('Encrypt key with new passphrase', async function() {
const userID = { name: 'test', email: 'a@b.com' };
const passphrase = 'passphrase';
const newPassphrase = 'new_passphrase';
const privateKey = (await openpgp.generateKey({ userIDs: userID, passphrase })).key;
const armor1 = privateKey.armor();
const armor2 = privateKey.armor();
expect(armor1).to.equal(armor2);
const decryptedKey = await openpgp.decryptKey({ privateKey, passphrase });
expect(decryptedKey.isDecrypted()).to.be.true;
const newEncryptedKey = await openpgp.encryptKey({
privateKey: decryptedKey, passphrase: newPassphrase
});
expect(newEncryptedKey.isDecrypted()).to.be.false;
await expect(openpgp.decryptKey({
privateKey: newEncryptedKey, passphrase
})).to.be.rejectedWith('Incorrect key passphrase');
expect(newEncryptedKey.isDecrypted()).to.be.false;
const newDecryptedKey = await openpgp.decryptKey({ privateKey: newEncryptedKey, passphrase: newPassphrase });
expect(newDecryptedKey.isDecrypted()).to.be.true;
const armor3 = newDecryptedKey.armor();
expect(armor3).to.not.equal(armor1);
});
it('Generate key - ensure keyExpirationTime works', function() { it('Generate key - ensure keyExpirationTime works', function() {
const expect_delta = 365 * 24 * 60 * 60; const expect_delta = 365 * 24 * 60 * 60;
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const opt = { userIDs: userID, passphrase: '123', keyExpirationTime: expect_delta }; const opt = { userIDs: userID, passphrase: '123', format: 'object', keyExpirationTime: expect_delta };
return openpgp.generateKey(opt).then(async function(key) { return openpgp.generateKey(opt).then(async function({ privateKey: key }) {
key = key.key;
const expiration = await key.getExpirationTime(); const expiration = await key.getExpirationTime();
expect(expiration).to.exist; expect(expiration).to.exist;
@ -2588,72 +2555,45 @@ function versionSpecificTests() {
} }
}); });
it('Reformat key without passphrase', function() { it('Reformat and encrypt key with no subkey', async function() {
const userID1 = { name: 'test', email: 'a@b.com' };
const userID2 = { name: 'test', email: 'b@c.com' };
const opt = { userIDs: userID1 };
return openpgp.generateKey(opt).then(function(key) {
key = key.key;
expect(key.users.length).to.equal(1);
expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
expect(key.isDecrypted()).to.be.true;
opt.privateKey = key;
opt.userIDs = userID2;
return openpgp.reformatKey(opt).then(function(newKey) {
newKey = newKey.key;
expect(newKey.users.length).to.equal(1);
expect(newKey.users[0].userID.userID).to.equal('test <b@c.com>');
expect(newKey.isDecrypted()).to.be.true;
});
});
});
it('Reformat key with no subkey with passphrase', async function() {
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const key = await openpgp.readKey({ armoredKey: key_without_subkey }); const key = await openpgp.readKey({ armoredKey: key_without_subkey });
const opt = { privateKey: key, userIDs: [userID], passphrase: "test" }; const opt = { privateKey: key, userIDs: [userID], passphrase: "test", format: 'object' };
return openpgp.reformatKey(opt).then(function(newKey) { return openpgp.reformatKey(opt).then(function({ privateKey: newKey }) {
newKey = newKey.key;
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.false; expect(newKey.isDecrypted()).to.be.false;
}); });
}); });
it('Reformat key with two subkeys with passphrase', function() { it('Reformat key with one subkey', async function() {
const userID1 = { name: 'test', email: 'a@b.com' }; const original = await openpgp.readKey({ armoredKey: priv_key_rsa });
const userID2 = { name: 'test', email: 'b@c.com' }; const privateKey = await openpgp.decryptKey({ privateKey: original, passphrase: 'hello world' });
const now = util.normalizeDate(new Date());
const before = util.normalizeDate(new Date(0)); const userID = { name: 'test', email: 'b@c.com' };
const opt1 = { userIDs: [userID1], date: now }; const before = new Date(0);
return openpgp.generateKey(opt1).then(function(newKey) { expect(+privateKey.getCreationTime()).to.not.equal(+before);
newKey = newKey.key; expect(+privateKey.subkeys[0].getCreationTime()).to.not.equal(+before);
expect(newKey.users[0].userID.userID).to.equal('test <a@b.com>'); expect(+privateKey.subkeys[0].bindingSignatures[0].created).to.not.equal(+before);
expect(+newKey.getCreationTime()).to.equal(+now); const opt = { privateKey, userIDs: userID, date: before, format: 'object' };
expect(+newKey.subkeys[0].getCreationTime()).to.equal(+now); return openpgp.reformatKey(opt).then(function({ privateKey: refKey }) {
expect(+newKey.subkeys[0].bindingSignatures[0].created).to.equal(+now);
const opt2 = { privateKey: newKey, userIDs: [userID2], date: before };
return openpgp.reformatKey(opt2).then(function(refKey) {
refKey = refKey.key;
expect(refKey.users.length).to.equal(1); expect(refKey.users.length).to.equal(1);
expect(refKey.users[0].userID.userID).to.equal('test <b@c.com>'); expect(refKey.users[0].userID.userID).to.equal('test <b@c.com>');
expect(+refKey.subkeys[0].bindingSignatures[0].created).to.equal(+before); expect(+refKey.subkeys[0].bindingSignatures[0].created).to.equal(+before);
}); });
}); });
});
it('Reformat key with no subkey without passphrase', async function() { it('Reformat key with no subkey', async function() {
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const key = await openpgp.readKey({ armoredKey: key_without_subkey }); const key = await openpgp.readKey({ armoredKey: key_without_subkey });
const opt = { privateKey: key, userIDs: [userID] }; const opt = { privateKey: key, userIDs: [userID], format: 'object' };
return openpgp.reformatKey(opt).then(async function(newKey) { return openpgp.reformatKey(opt).then(async function({ privateKey: newKey, publicKey: newKeyPublic }) {
newKey = newKey.key;
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, armor: true }).then(async function(signed) {
return openpgp.verify( return openpgp.verify(
{ message: await openpgp.readCleartextMessage({ cleartextMessage: signed }), verificationKeys: newKey.toPublic() } { message: await openpgp.readCleartextMessage({ cleartextMessage: signed }), verificationKeys: newKeyPublic }
).then(async function(verified) { ).then(async function(verified) {
expect(verified.signatures[0].valid).to.be.true; expect(verified.signatures[0].valid).to.be.true;
const newSigningKey = await newKey.getSigningKey(); const newSigningKey = await newKey.getSigningKey();
@ -2664,15 +2604,15 @@ function versionSpecificTests() {
}); });
}); });
it('Reformat and encrypt key', function() { it('Reformat and encrypt key', async function() {
const userID1 = { name: 'test1', email: 'a@b.com' }; const original = await openpgp.readKey({ armoredKey: priv_key_rsa });
const userID2 = { name: 'test2', email: 'b@c.com' }; const privateKey = await openpgp.decryptKey({ privateKey: original, passphrase: 'hello world' });
const userID3 = { name: 'test3', email: 'c@d.com' };
const opt = { userIDs: userID1 }; const userID1 = { name: 'test2', email: 'b@c.com' };
return openpgp.generateKey(opt).then(function ({ key }) { const userID2 = { name: 'test3', email: 'c@d.com' };
const passphrase = '123'; const passphrase = '123';
const reformatOpt = { privateKey: key, userIDs: [userID2, userID3], passphrase }; const reformatOpt = { privateKey, userIDs: [userID1, userID2], passphrase, format: 'object' };
return openpgp.reformatKey(reformatOpt).then(async ({ key: refKey }) => { return openpgp.reformatKey(reformatOpt).then(async ({ privateKey: refKey }) => {
expect(refKey.users.length).to.equal(2); expect(refKey.users.length).to.equal(2);
expect(refKey.users[0].userID.userID).to.equal('test2 <b@c.com>'); expect(refKey.users[0].userID.userID).to.equal('test2 <b@c.com>');
expect(refKey.isDecrypted()).to.be.false; expect(refKey.isDecrypted()).to.be.false;
@ -2680,62 +2620,67 @@ function versionSpecificTests() {
expect(decryptedKey.isDecrypted()).to.be.true; expect(decryptedKey.isDecrypted()).to.be.true;
}); });
}); });
});
it('Sign and encrypt with reformatted key', function() { it('Sign and encrypt with reformatted key', async function() {
const userID1 = { name: 'test1', email: 'a@b.com' }; const userID1 = { name: 'test1', email: 'a@b.com' };
const userID2 = { name: 'test2', email: 'b@c.com' }; const userID2 = { name: 'test2', email: 'b@c.com' };
const opt = { userIDs: userID1 }; const { privateKey } = await openpgp.generateKey({ userIDs: userID1, format: 'object' });
return openpgp.generateKey(opt).then(function(key) {
key = key.key; const opt2 = { privateKey, userIDs: userID2, format: 'object' };
opt.privateKey = key; return openpgp.reformatKey(opt2).then(async function({ privateKey: newKey, publicKey: newKeyPublic }) {
opt.userIDs = userID2; const encrypted = await openpgp.encrypt({
return openpgp.reformatKey(opt).then(async function(newKey) { message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: newKey.toPublic(), signingKeys: newKey, armor: true, config: { minRSABits: 1024 }
newKey = newKey.key; });
return openpgp.encrypt({ message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: newKey.toPublic(), signingKeys: newKey, armor: true }).then(async function(encrypted) { const decrypted = await openpgp.decrypt({
return openpgp.decrypt({ message: await openpgp.readMessage({ armoredMessage: encrypted }), decryptionKeys: newKey, verificationKeys: newKey.toPublic() }).then(function(decrypted) { message: await openpgp.readMessage({ armoredMessage: encrypted }), decryptionKeys: newKey, verificationKeys: newKeyPublic, config: { minRSABits: 1024 }
});
expect(decrypted.data).to.equal('hello'); expect(decrypted.data).to.equal('hello');
expect(decrypted.signatures[0].valid).to.be.true; expect(decrypted.signatures[0].valid).to.be.true;
}); });
}); });
});
}); it('Reject with user-friendly error when reformatting encrypted key', async function() {
const privateKey = await openpgp.readKey({ armoredKey: priv_key_rsa });
await expect(
openpgp.reformatKey({ privateKey, userIDs: { name: 'test2', email: 'a@b.com' }, passphrase: '1234' })
).to.be.rejectedWith('Error reformatting keypair: Key is not decrypted');
}); });
it('Reject with user-friendly error when reformatting encrypted key', function() { it('Revoke generated key with revocation certificate', async function() {
const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: '1234' }; const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: '1234', format: 'object' };
return openpgp.generateKey(opt).then(function(original) { const { publicKey, revocationCertificate } = await openpgp.generateKey(opt);
return openpgp.reformatKey({ privateKey: original.key, userIDs: { name: 'test2', email: 'a@b.com' }, passphrase: '1234' }).then(function() { return openpgp.revokeKey({ key: publicKey, revocationCertificate, format: 'object' }).then(async function({ publicKey: revKey }) {
throw new Error('reformatKey should result in error when key not decrypted');
}).catch(function(error) {
expect(error.message).to.equal('Error reformatting keypair: Key is not decrypted');
});
});
});
it('Revoke generated key with revocation certificate', function() {
const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: '1234' };
return openpgp.generateKey(opt).then(function(original) {
return openpgp.revokeKey({ key: original.key.toPublic(), revocationCertificate: original.revocationCertificate }).then(async function(revKey) {
revKey = revKey.publicKey;
expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason); expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason);
expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal(''); expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal('');
await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked'); await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked');
}); });
}); });
});
it('Revoke generated key with private key', function() { it('Revoke generated key with private key', async function() {
const opt = { userIDs: { name: 'test', email: 'a@b.com' } }; const opt = { userIDs: { name: 'test', email: 'a@b.com' }, format: 'object' };
return openpgp.generateKey(opt).then(async function(original) { const { privateKey: key } = await openpgp.generateKey(opt);
return openpgp.revokeKey({ key: original.key, reasonForRevocation: { string: 'Testing key revocation' } }).then(async function(revKey) { return openpgp.revokeKey({ key, reasonForRevocation: { string: 'Testing key revocation' }, format: 'object' }).then(async function({ publicKey: revKey }) {
revKey = revKey.publicKey;
expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason); expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason);
expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal('Testing key revocation'); expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal('Testing key revocation');
await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked'); await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked');
}); });
}); });
it('Revoke reformatted key with revocation certificate', async function() {
const original = await openpgp.readKey({ armoredKey: priv_key_rsa });
const privateKey = await openpgp.decryptKey({ privateKey: original, passphrase: 'hello world' });
const opt = { privateKey, userIDs: { name: 'test', email: 'a@b.com' }, format: 'object' };
const { publicKey: refKey, revocationCertificate } = await openpgp.reformatKey(opt);
return openpgp.revokeKey({ key: refKey, revocationCertificate, format: 'object' }).then(async function({ publicKey: revKey }) {
expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason);
expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal('');
await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked');
await expect(privateKey.verifyPrimaryKey()).to.be.fulfilled;
}); });
});
it('Parses V5 sample key', async function() { it('Parses V5 sample key', async function() {
// sec ed25519 2019-03-20 [SC] // sec ed25519 2019-03-20 [SC]
@ -2990,7 +2935,7 @@ module.exports = () => describe('Key', function() {
}); });
it("validate() - don't throw if key parameters correspond", async function() { it("validate() - don't throw if key parameters correspond", async function() {
const { key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519' }); const { privateKey: key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519', format: 'object' });
await expect(key.validate()).to.not.be.rejected; await expect(key.validate()).to.not.be.rejected;
}); });
@ -3016,7 +2961,7 @@ module.exports = () => describe('Key', function() {
it("isDecrypted() - should reflect whether all (sub)keys are encrypted", async function() { it("isDecrypted() - should reflect whether all (sub)keys are encrypted", async function() {
const passphrase = '12345678'; const passphrase = '12345678';
const { key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519', passphrase }); const { privateKey: key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519', passphrase, format: 'object' });
expect(key.isDecrypted()).to.be.false; expect(key.isDecrypted()).to.be.false;
await key.subkeys[0].keyPacket.decrypt(passphrase); await key.subkeys[0].keyPacket.decrypt(passphrase);
expect(key.isDecrypted()).to.be.true; expect(key.isDecrypted()).to.be.true;
@ -3035,14 +2980,14 @@ module.exports = () => describe('Key', function() {
}); });
it('makeDummy() - the converted key can be parsed', async function() { it('makeDummy() - the converted key can be parsed', async function() {
const { key } = await openpgp.generateKey({ userIDs: { name: 'dummy', email: 'dummy@alice.com' } }); const { privateKey: key } = await openpgp.generateKey({ userIDs: { name: 'dummy', email: 'dummy@alice.com' }, format: 'object' });
key.keyPacket.makeDummy(); key.keyPacket.makeDummy();
const parsedKeys = await openpgp.readKey({ armoredKey: key.armor() }); const parsedKeys = await openpgp.readKey({ armoredKey: key.armor() });
expect(parsedKeys).to.not.be.empty; expect(parsedKeys).to.not.be.empty;
}); });
it('makeDummy() - the converted key can be encrypted and decrypted', async function() { it('makeDummy() - the converted key can be encrypted and decrypted', async function() {
const { key } = await openpgp.generateKey({ userIDs: { name: 'dummy', email: 'dummy@alice.com' } }); const { privateKey: key } = await openpgp.generateKey({ userIDs: { name: 'dummy', email: 'dummy@alice.com' }, format: 'object' });
const passphrase = 'passphrase'; const passphrase = 'passphrase';
key.keyPacket.makeDummy(); key.keyPacket.makeDummy();
expect(key.isDecrypted()).to.be.true; expect(key.isDecrypted()).to.be.true;
@ -3618,9 +3563,8 @@ VYGdb3eNlV8CfoEC
}); });
it("Should throw when trying to encrypt a key that's already encrypted", async function() { it("Should throw when trying to encrypt a key that's already encrypted", async function() {
const passphrase = 'pass'; const passphrase = 'hello world';
const { privateKeyArmored } = await openpgp.generateKey({ userIDs: [{ email: 'hello@user.com' }], passphrase }); const key = await openpgp.readKey({ armoredKey: priv_key_rsa });
const key = await openpgp.readKey({ armoredKey: privateKeyArmored });
const decryptedKey = await openpgp.decryptKey({ privateKey: key, passphrase }); const decryptedKey = await openpgp.decryptKey({ privateKey: key, passphrase });
const encryptedKey = await openpgp.encryptKey({ privateKey: decryptedKey, passphrase }); const encryptedKey = await openpgp.encryptKey({ privateKey: decryptedKey, passphrase });
await expect(openpgp.encryptKey({ privateKey: encryptedKey, passphrase })).to.be.eventually.rejectedWith(/Key packet is already encrypted/); await expect(openpgp.encryptKey({ privateKey: encryptedKey, passphrase })).to.be.eventually.rejectedWith(/Key packet is already encrypted/);
@ -3628,7 +3572,6 @@ VYGdb3eNlV8CfoEC
describe('addSubkey functionality testing', function() { describe('addSubkey functionality testing', function() {
const rsaBits = 1024; const rsaBits = 1024;
const rsaOpt = { type: 'rsa' };
let minRSABits; let minRSABits;
beforeEach(function() { beforeEach(function() {
minRSABits = openpgp.config.minRSABits; minRSABits = openpgp.config.minRSABits;
@ -3644,7 +3587,7 @@ VYGdb3eNlV8CfoEC
passphrase: 'hello world' passphrase: 'hello world'
}); });
const total = privateKey.subkeys.length; const total = privateKey.subkeys.length;
let newPrivateKey = await privateKey.addSubkey(rsaOpt); let newPrivateKey = await privateKey.addSubkey({ type: 'rsa' });
const armoredKey = newPrivateKey.armor(); const armoredKey = newPrivateKey.armor();
newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey });
const subkey = newPrivateKey.subkeys[total]; const subkey = newPrivateKey.subkeys[total];
@ -3660,18 +3603,18 @@ VYGdb3eNlV8CfoEC
it('Add a new default subkey to an rsaSign key', async function() { it('Add a new default subkey to an rsaSign key', async function() {
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const opt = { type: 'rsa', rsaBits, userIDs: [userID], subkeys: [] }; const opt = { type: 'rsa', rsaBits, userIDs: [userID], format: 'object', subkeys: [] };
const { key } = await openpgp.generateKey(opt); const { privateKey: key } = await openpgp.generateKey(opt);
expect(key.subkeys).to.have.length(0); expect(key.subkeys).to.have.length(0);
key.keyPacket.algorithm = "rsaSign"; key.getAlgorithmInfo().algorithm = "rsaSign";
const newKey = await key.addSubkey(); const newKey = await key.addSubkey();
expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign'); expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign');
}); });
it('Add a new default subkey to an ecc key', async function() { it('Add a new default subkey to an ecc key', async function() {
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const opt = { type: 'ecc', userIDs: [userID], subkeys: [] }; const opt = { type: 'ecc', userIDs: [userID], format: 'object', subkeys: [] };
const { key } = await openpgp.generateKey(opt); const { privateKey: key } = await openpgp.generateKey(opt);
expect(key.subkeys).to.have.length(0); expect(key.subkeys).to.have.length(0);
const newKey = await key.addSubkey(); const newKey = await key.addSubkey();
expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
@ -3703,7 +3646,7 @@ VYGdb3eNlV8CfoEC
const total = privateKey.subkeys.length; const total = privateKey.subkeys.length;
const passphrase = '12345678'; const passphrase = '12345678';
const newPrivateKey = await privateKey.addSubkey(rsaOpt); const newPrivateKey = await privateKey.addSubkey({ type: 'rsa' });
const encNewPrivateKey = await openpgp.encryptKey({ privateKey: newPrivateKey, passphrase }); const encNewPrivateKey = await openpgp.encryptKey({ privateKey: newPrivateKey, passphrase });
expect(encNewPrivateKey.subkeys.length).to.be.equal(total + 1); expect(encNewPrivateKey.subkeys.length).to.be.equal(total + 1);
@ -3718,14 +3661,13 @@ VYGdb3eNlV8CfoEC
await subkey.verify(); await subkey.verify();
}); });
it('create and add a new ec subkey to a ec key', async function() { it('create and add a new eddsa subkey to a eddsa key', async function() {
const passphrase = '12345678'; const passphrase = '12345678';
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const opt = { curve: 'curve25519', userIDs: [userID], subkeys:[] }; const { privateKey } = await openpgp.generateKey({ curve: 'curve25519', userIDs: [userID], format: 'object', subkeys:[] });
const privateKey = (await openpgp.generateKey(opt)).key;
const total = privateKey.subkeys.length; const total = privateKey.subkeys.length;
const opt2 = { curve: 'curve25519', userIDs: [userID], sign: true };
let newPrivateKey = await privateKey.addSubkey(opt2); let newPrivateKey = await privateKey.addSubkey({ curve: 'curve25519', userIDs: [userID], sign: true });
const subkey1 = newPrivateKey.subkeys[total]; const subkey1 = newPrivateKey.subkeys[total];
const encNewPrivateKey = await openpgp.encryptKey({ privateKey: newPrivateKey, passphrase }); const encNewPrivateKey = await openpgp.encryptKey({ privateKey: newPrivateKey, passphrase });
newPrivateKey = await openpgp.decryptKey({ newPrivateKey = await openpgp.decryptKey({
@ -3746,8 +3688,7 @@ VYGdb3eNlV8CfoEC
it('create and add a new ecdsa subkey to a eddsa key', async function() { it('create and add a new ecdsa subkey to a eddsa key', async function() {
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const opt = { curve: 'ed25519', userIDs: [userID], subkeys:[] }; const { privateKey } = await openpgp.generateKey({ curve: 'ed25519', userIDs: [userID], format: 'object', subkeys:[] });
const privateKey = (await openpgp.generateKey(opt)).key;
const total = privateKey.subkeys.length; const total = privateKey.subkeys.length;
let newPrivateKey = await privateKey.addSubkey({ curve: 'p256', sign: true }); let newPrivateKey = await privateKey.addSubkey({ curve: 'p256', sign: true });
newPrivateKey = await openpgp.readKey({ armoredKey: newPrivateKey.armor() }); newPrivateKey = await openpgp.readKey({ armoredKey: newPrivateKey.armor() });
@ -3782,12 +3723,12 @@ VYGdb3eNlV8CfoEC
it('create and add a new rsa subkey to a ecc key', async function() { it('create and add a new rsa subkey to a ecc key', async function() {
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const opt = { curve: 'ed25519', userIDs: [userID], subkeys:[] }; const opt = { curve: 'ed25519', userIDs: [userID], format: 'object', subkeys:[] };
const privateKey = (await openpgp.generateKey(opt)).key; const { privateKey } = await openpgp.generateKey(opt);
const total = privateKey.subkeys.length; const total = privateKey.subkeys.length;
let newPrivateKey = await privateKey.addSubkey({ type: 'rsa' }); let newPrivateKey = await privateKey.addSubkey({ type: 'rsa' });
const armoredKey = newPrivateKey.armor(); const armoredKey = newPrivateKey.armor();
newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); newPrivateKey = await openpgp.readKey({ armoredKey });
const subkey = newPrivateKey.subkeys[total]; const subkey = newPrivateKey.subkeys[total];
expect(subkey).to.exist; expect(subkey).to.exist;
expect(newPrivateKey.subkeys.length).to.be.equal(total + 1); expect(newPrivateKey.subkeys.length).to.be.equal(total + 1);
@ -3811,13 +3752,15 @@ VYGdb3eNlV8CfoEC
it('sign/verify data with the new subkey correctly using curve25519', async function() { it('sign/verify data with the new subkey correctly using curve25519', async function() {
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const opt = { curve: 'curve25519', userIDs: [userID], subkeys:[] }; const opt = { curve: 'curve25519', userIDs: [userID], format: 'object', subkeys:[] };
const privateKey = (await openpgp.generateKey(opt)).key; const { privateKey } = await openpgp.generateKey(opt);
const total = privateKey.subkeys.length; const total = privateKey.subkeys.length;
const opt2 = { sign: true }; const opt2 = { sign: true };
let newPrivateKey = await privateKey.addSubkey(opt2); let newPrivateKey = await privateKey.addSubkey(opt2);
const armoredKey = newPrivateKey.armor(); const armoredKey = newPrivateKey.armor();
newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey });
const subkey = newPrivateKey.subkeys[total]; const subkey = newPrivateKey.subkeys[total];
const subkeyOid = subkey.keyPacket.publicParams.oid; const subkeyOid = subkey.keyPacket.publicParams.oid;
const pkOid = newPrivateKey.keyPacket.publicParams.oid; const pkOid = newPrivateKey.keyPacket.publicParams.oid;
@ -3837,8 +3780,8 @@ VYGdb3eNlV8CfoEC
it('encrypt/decrypt data with the new subkey correctly using curve25519', async function() { it('encrypt/decrypt data with the new subkey correctly using curve25519', async function() {
const userID = { name: 'test', email: 'a@b.com' }; const userID = { name: 'test', email: 'a@b.com' };
const vData = 'the data to encrypted!'; const vData = 'the data to encrypted!';
const opt = { curve: 'curve25519', userIDs: [userID], subkeys:[] }; const opt = { curve: 'curve25519', userIDs: [userID], format: 'object', subkeys:[] };
const privateKey = (await openpgp.generateKey(opt)).key; const { privateKey } = await openpgp.generateKey(opt);
const total = privateKey.subkeys.length; const total = privateKey.subkeys.length;
let newPrivateKey = await privateKey.addSubkey(); let newPrivateKey = await privateKey.addSubkey();
const armoredKey = newPrivateKey.armor(); const armoredKey = newPrivateKey.armor();
@ -3869,6 +3812,7 @@ VYGdb3eNlV8CfoEC
let newPrivateKey = await privateKey.addSubkey(opt2); let newPrivateKey = await privateKey.addSubkey(opt2);
const armoredKey = newPrivateKey.armor(); const armoredKey = newPrivateKey.armor();
newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey });
const subkey = newPrivateKey.subkeys[total]; const subkey = newPrivateKey.subkeys[total];
expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('rsaEncryptSign'); expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('rsaEncryptSign');
await subkey.verify(); await subkey.verify();
@ -3888,9 +3832,10 @@ VYGdb3eNlV8CfoEC
passphrase: 'hello world' passphrase: 'hello world'
}); });
const total = privateKey.subkeys.length; const total = privateKey.subkeys.length;
let newPrivateKey = await privateKey.addSubkey(rsaOpt); let newPrivateKey = await privateKey.addSubkey({ type: 'rsa' });
const armoredKey = newPrivateKey.armor(); const armoredKey = newPrivateKey.armor();
newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey });
const subkey = newPrivateKey.subkeys[total]; const subkey = newPrivateKey.subkeys[total];
const publicKey = newPrivateKey.toPublic(); const publicKey = newPrivateKey.toPublic();
const vData = 'the data to encrypted!'; const vData = 'the data to encrypted!';
@ -3909,12 +3854,13 @@ VYGdb3eNlV8CfoEC
}); });
it('Subkey.verify returns the latest valid signature', async function () { it('Subkey.verify returns the latest valid signature', async function () {
const { key: encryptionKey } = await openpgp.generateKey({ userIDs: { name: "purple" } }); const { privateKey: encryptionKey } = await openpgp.generateKey({ userIDs: { name: "purple" }, format: 'object' });
const encryptionKeySignature = await encryptionKey.getSubkeys()[0].verify(); const encryptionKeySignature = await encryptionKey.getSubkeys()[0].verify();
expect(encryptionKeySignature instanceof openpgp.SignaturePacket).to.be.true; expect(encryptionKeySignature instanceof openpgp.SignaturePacket).to.be.true;
expect(encryptionKeySignature.keyFlags[0] & openpgp.enums.keyFlags.encryptCommunication).to.be.equals(openpgp.enums.keyFlags.encryptCommunication); expect(encryptionKeySignature.keyFlags[0] & openpgp.enums.keyFlags.encryptCommunication).to.be.equals(openpgp.enums.keyFlags.encryptCommunication);
expect(encryptionKeySignature.keyFlags[0] & openpgp.enums.keyFlags.encryptStorage).to.be.equals(openpgp.enums.keyFlags.encryptStorage); expect(encryptionKeySignature.keyFlags[0] & openpgp.enums.keyFlags.encryptStorage).to.be.equals(openpgp.enums.keyFlags.encryptStorage);
const { key: signingKey } = await openpgp.generateKey({ userIDs: { name: "purple" }, subkeys: [{ sign: true }] });
const { privateKey: signingKey } = await openpgp.generateKey({ userIDs: { name: "purple" }, format: 'object', subkeys: [{ sign: true }] });
const signingKeySignature = await signingKey.getSubkeys()[0].verify(); const signingKeySignature = await signingKey.getSubkeys()[0].verify();
expect(signingKeySignature instanceof openpgp.SignaturePacket).to.be.true; expect(signingKeySignature instanceof openpgp.SignaturePacket).to.be.true;
expect(signingKeySignature.keyFlags[0] & openpgp.enums.keyFlags.signData).to.be.equals(openpgp.enums.keyFlags.signData); expect(signingKeySignature.keyFlags[0] & openpgp.enums.keyFlags.signData).to.be.equals(openpgp.enums.keyFlags.signData);

View File

@ -6,6 +6,7 @@ const crypto = require('../../src/crypto');
const random = require('../../src/crypto/random'); const random = require('../../src/crypto/random');
const util = require('../../src/util'); const util = require('../../src/util');
const keyIDType = require('../../src/type/keyid'); const keyIDType = require('../../src/type/keyid');
const { isAEADSupported } = require('../../src/key');
const stream = require('@openpgp/web-stream-tools'); const stream = require('@openpgp/web-stream-tools');
@ -981,44 +982,92 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
const opt = { const opt = {
userIDs: { name: 'Test User', email: 'text@example.com' }, userIDs: { name: 'Test User', email: 'text@example.com' },
passphrase: 'secret', passphrase: 'secret',
date: now date: now,
format: 'object'
}; };
return openpgp.generateKey(opt).then(async function(newKey) { return openpgp.generateKey(opt).then(async function({ privateKey, publicKey }) {
expect(newKey.key).to.exist; for (const key of [publicKey, privateKey]) {
expect(newKey.key.users.length).to.equal(1); expect(key).to.exist;
expect(newKey.key.users[0].userID.name).to.equal('Test User'); expect(key.users.length).to.equal(1);
expect(newKey.key.users[0].userID.email).to.equal('text@example.com'); expect(key.users[0].userID.name).to.equal('Test User');
expect(newKey.key.getAlgorithmInfo().rsaBits).to.equal(undefined); expect(key.users[0].userID.email).to.equal('text@example.com');
expect(newKey.key.getAlgorithmInfo().curve).to.equal('ed25519'); expect(key.getAlgorithmInfo().rsaBits).to.equal(undefined);
expect(+newKey.key.getCreationTime()).to.equal(+now); expect(key.getAlgorithmInfo().curve).to.equal('ed25519');
expect(await newKey.key.getExpirationTime()).to.equal(Infinity); expect(+key.getCreationTime()).to.equal(+now);
expect(newKey.key.subkeys.length).to.equal(1); expect(await key.getExpirationTime()).to.equal(Infinity);
expect(newKey.key.subkeys[0].getAlgorithmInfo().rsaBits).to.equal(undefined); expect(key.subkeys.length).to.equal(1);
expect(newKey.key.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519'); expect(key.subkeys[0].getAlgorithmInfo().rsaBits).to.equal(undefined);
expect(+newKey.key.subkeys[0].getCreationTime()).to.equal(+now); expect(key.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519');
expect(await newKey.key.subkeys[0].getExpirationTime()).to.equal(Infinity); expect(+key.subkeys[0].getCreationTime()).to.equal(+now);
expect(newKey.privateKeyArmored).to.exist; expect(await key.subkeys[0].getExpirationTime()).to.equal(Infinity);
expect(newKey.publicKeyArmored).to.exist; }
}); });
}); });
it('should throw if missing userIDs', async function() { it('should output keypair with expected format', async function() {
await expect(openpgp.generateKey({})).to.be.rejectedWith(/UserIDs are required/);
});
});
describe('generateKey - integration tests', function() {
it('should work', function() {
const opt = { const opt = {
userIDs: [{ name: 'Test User', email: 'text@example.com' }] userIDs: { name: 'Test User', email: 'text@example.com' }
}; };
const armored = await openpgp.generateKey({ ...opt, format: 'armor' });
expect((await openpgp.readKey({ armoredKey: armored.privateKey })).isPrivate()).to.be.true;
expect((await openpgp.readKey({ armoredKey: armored.publicKey })).isPublic()).to.be.true;
return openpgp.generateKey(opt).then(function(newKey) { const binary = await openpgp.generateKey({ ...opt, format: 'binary' });
expect(newKey.key.getUserIDs()[0]).to.equal('Test User <text@example.com>'); expect((await openpgp.readKey({ binaryKey: binary.privateKey })).isPrivate()).to.be.true;
expect(newKey.publicKeyArmored).to.match(/^-----BEGIN PGP PUBLIC/); expect((await openpgp.readKey({ binaryKey: binary.publicKey })).isPublic()).to.be.true;
expect(newKey.privateKeyArmored).to.match(/^-----BEGIN PGP PRIVATE/);
const { privateKey, publicKey } = await openpgp.generateKey({ ...opt, format: 'object' });
expect(privateKey.isPrivate()).to.be.true;
expect(publicKey.isPublic()).to.be.true;
}); });
}); });
describe('reformatKey - unit tests', function() {
it('should output keypair with expected format', async function() {
const encryptedKey = await openpgp.readKey({ armoredKey: priv_key });
const original = await openpgp.decryptKey({
privateKey: encryptedKey,
passphrase: passphrase
});
const opt = {
privateKey: original,
userIDs: { name: 'Test User', email: 'text@example.com' }
};
const armored = await openpgp.reformatKey({ ...opt, format: 'armor' });
expect((await openpgp.readKey({ armoredKey: armored.privateKey })).isPrivate()).to.be.true;
expect((await openpgp.readKey({ armoredKey: armored.publicKey })).isPublic()).to.be.true;
const binary = await openpgp.reformatKey({ ...opt, format: 'binary' });
expect((await openpgp.readKey({ binaryKey: binary.privateKey })).isPrivate()).to.be.true;
expect((await openpgp.readKey({ binaryKey: binary.publicKey })).isPublic()).to.be.true;
const { privateKey, publicKey } = await openpgp.reformatKey({ ...opt, format: 'object' });
expect(privateKey.isPrivate()).to.be.true;
expect(publicKey.isPublic()).to.be.true;
});
});
describe('revokeKey - unit tests', function() {
it('should output key with expected format', async function() {
const encryptedKey = await openpgp.readKey({ armoredKey: priv_key });
const key = await openpgp.decryptKey({
privateKey: encryptedKey,
passphrase: passphrase
});
const armored = await openpgp.revokeKey({ key, format: 'armor' });
expect((await openpgp.readKey({ armoredKey: armored.privateKey })).isPrivate()).to.be.true;
expect((await openpgp.readKey({ armoredKey: armored.publicKey })).isPublic()).to.be.true;
const binary = await openpgp.revokeKey({ key, format: 'binary' });
expect((await openpgp.readKey({ binaryKey: binary.privateKey })).isPrivate()).to.be.true;
expect((await openpgp.readKey({ binaryKey: binary.publicKey })).isPublic()).to.be.true;
const { privateKey, publicKey } = await openpgp.revokeKey({ key, format: 'object' });
expect(privateKey.isPrivate()).to.be.true;
expect(publicKey.isPublic()).to.be.true;
});
}); });
describe('decryptKey - unit tests', function() { describe('decryptKey - unit tests', function() {
@ -1094,10 +1143,10 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
describe('encryptKey - unit tests', function() { describe('encryptKey - unit tests', function() {
it('should not change original key', async function() { it('should not change original key', async function() {
const { privateKeyArmored } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }] }); const { privateKey: armoredKey } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }] });
// read both keys from armored data to make sure all fields are exactly the same // read both keys from armored data to make sure all fields are exactly the same
const key = await openpgp.readKey({ armoredKey: privateKeyArmored }); const key = await openpgp.readKey({ armoredKey });
const originalKey = await openpgp.readKey({ armoredKey: privateKeyArmored }); const originalKey = await openpgp.readKey({ armoredKey });
return openpgp.encryptKey({ return openpgp.encryptKey({
privateKey: key, privateKey: key,
passphrase: passphrase passphrase: passphrase
@ -1114,9 +1163,9 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
}); });
it('encrypted key can be decrypted', async function() { it('encrypted key can be decrypted', async function() {
const { key } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }] }); const { privateKey } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }], format: 'object' });
const locked = await openpgp.encryptKey({ const locked = await openpgp.encryptKey({
privateKey: key, privateKey,
passphrase: passphrase passphrase: passphrase
}); });
expect(locked.isDecrypted()).to.be.false; expect(locked.isDecrypted()).to.be.false;
@ -1128,10 +1177,10 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
}); });
it('should support multiple passphrases', async function() { it('should support multiple passphrases', async function() {
const { key } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }] }); const { privateKey } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }], format: 'object' });
const passphrases = ['123', '456']; const passphrases = ['123', '456'];
const locked = await openpgp.encryptKey({ const locked = await openpgp.encryptKey({
privateKey: key, privateKey,
passphrase: passphrases passphrase: passphrases
}); });
expect(locked.isDecrypted()).to.be.false; expect(locked.isDecrypted()).to.be.false;
@ -2116,8 +2165,8 @@ aOU=
}; };
return openpgp.generateKey(genOpt).then(async function(newKey) { return openpgp.generateKey(genOpt).then(async function(newKey) {
const newPublicKey = await openpgp.readKey({ armoredKey: newKey.publicKeyArmored }); const newPublicKey = await openpgp.readKey({ armoredKey: newKey.publicKey });
const newPrivateKey = await openpgp.readKey({ armoredKey: newKey.privateKeyArmored }); const newPrivateKey = await openpgp.readKey({ armoredKey: newKey.privateKey });
const encOpt = { const encOpt = {
message: await openpgp.createMessage({ text: plaintext }), message: await openpgp.createMessage({ text: plaintext }),
@ -2146,8 +2195,8 @@ aOU=
const newKey = await openpgp.generateKey({ const newKey = await openpgp.generateKey({
userIDs: [{ name: 'Test User', email: 'text@example.com' }] userIDs: [{ name: 'Test User', email: 'text@example.com' }]
}); });
const newPublicKey = await openpgp.readKey({ armoredKey: newKey.publicKeyArmored }); const newPublicKey = await openpgp.readKey({ armoredKey: newKey.publicKey });
const newPrivateKey = await openpgp.readKey({ armoredKey: newKey.privateKeyArmored }); const newPrivateKey = await openpgp.readKey({ armoredKey: newKey.privateKey });
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message: await openpgp.createMessage({ text: plaintext }), message: await openpgp.createMessage({ text: plaintext }),
@ -2441,8 +2490,10 @@ aOU=
}); });
it('should fail to decrypt modified message', async function() { it('should fail to decrypt modified message', async function() {
const { privateKeyArmored } = await openpgp.generateKey({ curve: 'curve25519', userIDs: [{ email: 'test@email.com' }] }); const allowUnauthenticatedStream = openpgp.config.allowUnauthenticatedStream;
const key = await openpgp.readKey({ armoredKey: privateKeyArmored }); const { privateKey: key } = await openpgp.generateKey({ userIDs: [{ email: 'test@email.com' }], format: 'object' });
expect(await isAEADSupported([key])).to.equal(openpgp.config.aeadProtect);
const data = await openpgp.encrypt({ message: await openpgp.createMessage({ binary: new Uint8Array(500) }), encryptionKeys: [key.toPublic()] }); const data = await openpgp.encrypt({ message: await openpgp.createMessage({ binary: new Uint8Array(500) }), encryptionKeys: [key.toPublic()] });
let badSumEncrypted = data.replace(/\n=[a-zA-Z0-9/+]{4}/, '\n=aaaa'); let badSumEncrypted = data.replace(/\n=[a-zA-Z0-9/+]{4}/, '\n=aaaa');
if (badSumEncrypted === data) { // checksum was already =aaaa if (badSumEncrypted === data) { // checksum was already =aaaa
@ -2453,8 +2504,9 @@ aOU=
} }
const badBodyEncrypted = data.replace(/\n=([a-zA-Z0-9/+]{4})/, 'aaa\n=$1'); const badBodyEncrypted = data.replace(/\n=([a-zA-Z0-9/+]{4})/, 'aaa\n=$1');
await stream.loadStreamsPonyfill(); await stream.loadStreamsPonyfill();
for (let allow_streaming = 1; allow_streaming >= 0; allow_streaming--) { try {
openpgp.config.allowUnauthenticatedStream = !!allow_streaming; for (const allowStreaming of [true, false]) {
openpgp.config.allowUnauthenticatedStream = allowStreaming;
await Promise.all([badSumEncrypted, badBodyEncrypted].map(async (encrypted, i) => { await Promise.all([badSumEncrypted, badBodyEncrypted].map(async (encrypted, i) => {
await Promise.all([ await Promise.all([
encrypted, encrypted,
@ -2498,10 +2550,13 @@ aOU=
})); }));
})); }));
} }
} finally {
openpgp.config.allowUnauthenticatedStream = allowUnauthenticatedStream;
}
}); });
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 } = await openpgp.generateKey({ userIDs: {} }); 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, armor: false });
const encrypted = util.concat([message, new Uint8Array([11])]); const encrypted = util.concat([message, new Uint8Array([11])]);
await expect((async () => { await expect((async () => {
@ -3214,11 +3269,12 @@ aOU=
it('should fail to encrypt with revoked key', function() { it('should fail to encrypt with revoked key', function() {
return openpgp.revokeKey({ return openpgp.revokeKey({
key: privateKey key: privateKey,
}).then(async function(revKey) { format: 'object'
}).then(async function({ publicKey: revKey }) {
return openpgp.encrypt({ return openpgp.encrypt({
message: await openpgp.createMessage({ text: plaintext }), message: await openpgp.createMessage({ text: plaintext }),
encryptionKeys: revKey.publicKey encryptionKeys: revKey
}).then(function() { }).then(function() {
throw new Error('Should not encrypt with revoked key'); throw new Error('Should not encrypt with revoked key');
}).catch(function(error) { }).catch(function(error) {
@ -3414,7 +3470,7 @@ amnR6g==
curves.forEach(curve => { curves.forEach(curve => {
it(`sign/verify with ${curve}`, async function() { it(`sign/verify with ${curve}`, async function() {
const plaintext = 'short message'; const plaintext = 'short message';
const key = (await openpgp.generateKey({ curve, userIDs: { name: 'Alice', email: 'info@alice.com' } })).key; const { privateKey: key } = await openpgp.generateKey({ curve, userIDs: { name: 'Alice', email: 'info@alice.com' }, format: 'object' });
const signed = await openpgp.sign({ signingKeys:[key], message: await openpgp.createCleartextMessage({ text: plaintext }) }); const signed = await openpgp.sign({ signingKeys:[key], message: await openpgp.createCleartextMessage({ text: plaintext }) });
const verified = await openpgp.verify({ verificationKeys:[key], message: await openpgp.readCleartextMessage({ cleartextMessage: signed }) }); const verified = await openpgp.verify({ verificationKeys:[key], message: await openpgp.readCleartextMessage({ cleartextMessage: signed }) });
expect(verified.signatures[0].valid).to.be.true; expect(verified.signatures[0].valid).to.be.true;

View File

@ -694,23 +694,18 @@ hUhMKMuiM3pRwdIyDOItkUWQmjEEw7/XmhgInkXsCw==
`; `;
it("Retrieve the issuer Key ID of a signature", async function () { it("Retrieve the issuer Key ID of a signature", async function () {
const { privateKeyArmored, publicKeyArmored } = await openpgp.generateKey({ const publicKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
type: "ecc", // Type of the key, defaults to ECC
curve: "curve25519", // ECC curve name, defaults to curve25519
userIDs: [{ name: "name", email: "test@email.com" }], // you can pass multiple user IDs
passphrase: "password" // protects the private key
});
const publicKey = await openpgp.readKey({ armoredKey: publicKeyArmored });
const privateKey = await openpgp.decryptKey({ const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readKey({ armoredKey: privateKeyArmored }), privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
passphrase: "password" passphrase: 'hello world'
}); });
const message = await openpgp.createMessage({ text: "test" }); const message = await openpgp.createMessage({ text: "test" });
const armoredSignature = await openpgp.sign({ const armoredSignature = await openpgp.sign({
message, message,
signingKeys: privateKey, signingKeys: privateKey,
detached: true signingKeyIDs: [privateKey.getKeyID()],
detached: true,
config: { minRSABits: 1024 }
}); });
const signature = await openpgp.readSignature({ armoredSignature }); const signature = await openpgp.readSignature({ armoredSignature });
expect(signature.getSigningKeyIDs).to.exist; expect(signature.getSigningKeyIDs).to.exist;
@ -858,11 +853,12 @@ AkLaG/AkATpuH+DMkYDmKbDLGgD+N4yuxXBJmBfC2IBe4J1S2Gg=
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }), privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
passphrase: 'hello world' passphrase: 'hello world'
}); });
const { key: expiredKey } = await openpgp.reformatKey({ const { privateKey: expiredKey } = await openpgp.reformatKey({
privateKey: key, privateKey: key,
userIDs: key.users.map(user => user.userID), userIDs: key.users.map(user => user.userID),
keyExpirationTime: 1, keyExpirationTime: 1,
date: key.keyPacket.created date: key.keyPacket.created,
format: 'object'
}); });
await stream.loadStreamsPonyfill(); await stream.loadStreamsPonyfill();
const { signatures: [sigInfo] } = await openpgp.verify({ const { signatures: [sigInfo] } = await openpgp.verify({
@ -888,11 +884,12 @@ aMsUdQBgnPAcSGVsbG8gV29ybGQgOik=
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }), privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
passphrase: 'hello world' passphrase: 'hello world'
}); });
const { key: expiredKey } = await openpgp.reformatKey({ const { privateKey: expiredKey } = await openpgp.reformatKey({
privateKey: key, privateKey: key,
userIDs: key.users.map(user => user.userID), userIDs: key.users.map(user => user.userID),
keyExpirationTime: 1, keyExpirationTime: 1,
date: key.keyPacket.created date: key.keyPacket.created,
format: 'object'
}); });
await stream.loadStreamsPonyfill(); await stream.loadStreamsPonyfill();
const { signatures: [sigInfo] } = await openpgp.verify({ const { signatures: [sigInfo] } = await openpgp.verify({
@ -917,11 +914,12 @@ eSvSZutLuKKbidSYMLhWROPlwKc2GU2ws6PrLZAyCAel/lU=
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }), privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
passphrase: 'hello world' passphrase: 'hello world'
}); });
const { key: expiredKey } = await openpgp.reformatKey({ const { privateKey: expiredKey } = await openpgp.reformatKey({
privateKey: key, privateKey: key,
userIDs: key.users.map(user => user.userID), userIDs: key.users.map(user => user.userID),
keyExpirationTime: 1, keyExpirationTime: 1,
date: key.keyPacket.created date: key.keyPacket.created,
format: 'object'
}); });
await stream.loadStreamsPonyfill(); await stream.loadStreamsPonyfill();
const { signatures: [sigInfo] } = await openpgp.verify({ const { signatures: [sigInfo] } = await openpgp.verify({
@ -946,11 +944,12 @@ eSvSZutLuKKbidSYMLhWROPlwKc2GU2ws6PrLZAyCAel/lU=
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }), privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
passphrase: 'hello world' passphrase: 'hello world'
}); });
const { key: expiredKey } = await openpgp.reformatKey({ const { privateKey: expiredKey } = await openpgp.reformatKey({
privateKey: key, privateKey: key,
userIDs: key.users.map(user => user.userID), userIDs: key.users.map(user => user.userID),
keyExpirationTime: 1, keyExpirationTime: 1,
date: key.keyPacket.created date: key.keyPacket.created,
format: 'object'
}); });
const { signatures: [sigInfo] } = await openpgp.verify({ const { signatures: [sigInfo] } = await openpgp.verify({
verificationKeys: expiredKey, verificationKeys: expiredKey,
@ -1638,8 +1637,8 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
passphrase: 'hello world' passphrase: 'hello world'
}); });
const opt = { rsaBits: 2048, userIDs: { name:'test', email:'a@b.com' }, passphrase: null }; const opt = { userIDs: { name:'test', email:'a@b.com' }, format: 'object' };
const { key: generatedKey } = await openpgp.generateKey(opt); const { privateKey: generatedKey } = await openpgp.generateKey(opt);
const armoredSignature = await openpgp.sign({ signingKeys: [generatedKey, privKey], message, detached: true, config: { minRSABits: 1024 } }); const armoredSignature = await openpgp.sign({ signingKeys: [generatedKey, privKey], message, detached: true, config: { minRSABits: 1024 } });
const signature = await openpgp.readSignature({ armoredSignature }); const signature = await openpgp.readSignature({ armoredSignature });
const { data, signatures } = await openpgp.verify({ verificationKeys: [generatedKey.toPublic(), pubKey], message, signature, config: { minRSABits: 1024 } }); const { data, signatures } = await openpgp.verify({ verificationKeys: [generatedKey.toPublic(), pubKey], message, signature, config: { minRSABits: 1024 } });
@ -1649,9 +1648,8 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
}); });
it('Sign message with key without password', function() { it('Sign message with key without password', function() {
const opt = { userIDs: { name:'test', email:'a@b.com' }, passphrase: null }; const opt = { userIDs: { name:'test', email:'a@b.com' }, passphrase: null, format: 'object' };
return openpgp.generateKey(opt).then(async function(gen) { return openpgp.generateKey(opt).then(async function({ privateKey: key }) {
const key = gen.key;
const message = await openpgp.createMessage({ text: 'hello world' }); const message = await openpgp.createMessage({ text: 'hello world' });
return message.sign([key]); return message.sign([key]);
}); });

View File

@ -382,18 +382,17 @@ function omnibus() {
it('Omnibus Ed25519/Curve25519 Test', function() { it('Omnibus Ed25519/Curve25519 Test', function() {
const options = { const options = {
userIDs: { name: "Hi", email: "hi@hel.lo" }, userIDs: { name: "Hi", email: "hi@hel.lo" },
curve: "ed25519" curve: "ed25519",
format: 'object'
}; };
return openpgp.generateKey(options).then(async function(firstKey) { return openpgp.generateKey(options).then(async function({ privateKey, publicKey }) {
expect(firstKey).to.exist; expect(privateKey).to.exist;
expect(firstKey.privateKeyArmored).to.exist; expect(publicKey).to.exist;
expect(firstKey.publicKeyArmored).to.exist; expect(privateKey.keyPacket).to.exist;
expect(firstKey.key).to.exist; expect(privateKey.subkeys).to.have.length(1);
expect(firstKey.key.keyPacket).to.exist; expect(privateKey.subkeys[0].keyPacket).to.exist;
expect(firstKey.key.subkeys).to.have.length(1);
expect(firstKey.key.subkeys[0].keyPacket).to.exist;
const hi = firstKey.key; const hi = privateKey;
const primaryKey = hi.keyPacket; const primaryKey = hi.keyPacket;
const subkey = hi.subkeys[0]; const subkey = hi.subkeys[0];
expect(hi.getAlgorithmInfo().curve).to.equal('ed25519'); expect(hi.getAlgorithmInfo().curve).to.equal('ed25519');
@ -411,10 +410,11 @@ function omnibus() {
const options = { const options = {
userIDs: { name: "Bye", email: "bye@good.bye" }, userIDs: { name: "Bye", email: "bye@good.bye" },
curve: "curve25519" curve: "curve25519",
format: 'object'
}; };
return openpgp.generateKey(options).then(async function(secondKey) {
const bye = secondKey.key; return openpgp.generateKey(options).then(async function({ privateKey: bye }) {
expect(bye.getAlgorithmInfo().curve).to.equal('ed25519'); expect(bye.getAlgorithmInfo().curve).to.equal('ed25519');
expect(bye.getAlgorithmInfo().algorithm).to.equal('eddsa'); expect(bye.getAlgorithmInfo().algorithm).to.equal('eddsa');
expect(bye.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519'); expect(bye.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519');

View File

@ -8,24 +8,23 @@ chai.use(require('chai-as-promised'));
const expect = chai.expect; const expect = chai.expect;
async function generateTestData() { async function generateTestData() {
const victimPrivKey = (await openpgp.generateKey({ const { privateKey: victimPrivKey } = await openpgp.generateKey({
userIDs: [{ name: 'Victim', email: 'victim@example.com' }], userIDs: [{ name: 'Victim', email: 'victim@example.com' }],
type: 'rsa', type: 'rsa',
rsaBits: 2048, rsaBits: 2048,
subkeys: [{ subkeys: [{ sign: true }],
sign: true format: 'object'
}] });
})).key;
victimPrivKey.revocationSignatures = [];
const attackerPrivKey = (await openpgp.generateKey({ const { privateKey: attackerPrivKey } = await openpgp.generateKey({
userIDs: [{ name: 'Attacker', email: 'attacker@example.com' }], userIDs: [{ name: 'Attacker', email: 'attacker@example.com' }],
type: 'rsa', type: 'rsa',
rsaBits: 2048, rsaBits: 2048,
subkeys: [], subkeys: [],
sign: false sign: false,
})).key; format: 'object'
attackerPrivKey.revocationSignatures = []; });
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,

View File

@ -8,7 +8,7 @@
import { expect } from 'chai'; import { expect } from 'chai';
import { import {
generateKey, readKey, readKeys, readPrivateKey, PrivateKey, Key, generateKey, readKey, readKeys, readPrivateKey, PrivateKey, Key, PublicKey, revokeKey,
readMessage, createMessage, Message, createCleartextMessage, readMessage, createMessage, Message, createCleartextMessage,
encrypt, decrypt, sign, verify, config, enums, encrypt, decrypt, sign, verify, config, enums,
LiteralDataPacket, PacketList, CompressedDataPacket, PublicKeyPacket, PublicSubkeyPacket, SecretKeyPacket, SecretSubkeyPacket LiteralDataPacket, PacketList, CompressedDataPacket, PublicKeyPacket, PublicSubkeyPacket, SecretKeyPacket, SecretSubkeyPacket
@ -17,18 +17,38 @@ import {
(async () => { (async () => {
// Generate keys // Generate keys
const { publicKeyArmored, privateKeyArmored, key: privateKey } = await generateKey({ 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: privateKeyBinary } = await generateKey({ ...keyOptions, format: 'binary' });
const { privateKey, publicKey, revocationCertificate } = await generateKey({ ...keyOptions, format: 'object' });
expect(privateKey).to.be.instanceOf(PrivateKey); expect(privateKey).to.be.instanceOf(PrivateKey);
expect(publicKey).to.be.instanceOf(PublicKey);
expect(typeof revocationCertificate).to.equal('string');
const privateKeys = [privateKey]; const privateKeys = [privateKey];
const publicKeys = [privateKey.toPublic()]; const publicKeys = [privateKey.toPublic()];
expect(privateKey.toPublic().armor(config)).to.equal(publicKeyArmored);
// Parse keys // Parse keys
expect(await readKeys({ armoredKeys: publicKeyArmored })).to.have.lengthOf(1); expect(await readKeys({ armoredKeys: publicKeyArmored })).to.have.lengthOf(1);
const parsedKey: Key = await readKey({ armoredKey: publicKeyArmored }); const parsedKey: Key = await readKey({ armoredKey: publicKeyArmored });
parsedKey.armor(); expect(parsedKey.armor(config)).to.equal(publicKeyArmored);
expect(parsedKey.isPublic()).to.be.true;
const parsedPrivateKey: PrivateKey = await readPrivateKey({ armoredKey: privateKeyArmored }); const parsedPrivateKey: PrivateKey = await readPrivateKey({ armoredKey: privateKeyArmored });
expect(parsedPrivateKey.isPrivate()).to.be.true; expect(parsedPrivateKey.isPrivate()).to.be.true;
const parsedBinaryPrivateKey: PrivateKey = await readPrivateKey({ binaryKey: privateKeyBinary });
expect(parsedBinaryPrivateKey.isPrivate()).to.be.true;
// Revoke keys
await revokeKey({ key: privateKey });
// @ts-expect-error for missing revocation certificate
try { await revokeKey({ key: publicKey }); } catch (e) {}
const { privateKey: revokedPrivateKey, publicKey: revokedPublicKey } = await revokeKey({ key: privateKey, revocationCertificate, format: 'object' });
expect(revokedPrivateKey).to.be.instanceOf(PrivateKey);
expect(revokedPublicKey).to.be.instanceOf(PublicKey);
const revokedKeyPair = await revokeKey({ key: publicKey, revocationCertificate, format: 'object' });
// @ts-expect-error for null private key
try { revokedKeyPair.privateKey.armor(); } catch (e) {}
expect(revokedKeyPair.privateKey).to.be.null;
expect(revokedKeyPair.publicKey).to.be.instanceOf(PublicKey);
// Encrypt text message (armored) // Encrypt text message (armored)
const text = 'hello'; const text = 'hello';