mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-06-08 07:06:42 +00:00
Add config
parameter to top-level functions (#1241)
Refactor functions to take the configuration as a parameter. This allows setting a config option for a single function call, whereas setting `openpgp.config` could lead to concurrency-related issues when multiple async function calls are made at the same time. `openpgp.config` is used as default for unset config values in top-level functions. `openpgp.config` is used as default config object in low-level functions (i.e., when calling a low-level function, it may be required to pass `{ ...openpgp.config, modifiedConfig: modifiedValue }`). Also, - remove `config.rsaBlinding`: blinding is now always applied to RSA decryption - remove `config.debug`: debugging mode can be enabled by setting `process.env.NODE_ENV = 'development'` - remove `config.useNative`: native crypto is always used when available
This commit is contained in:
parent
15ee659c9c
commit
7f37a8aaca
@ -75,7 +75,7 @@ library to convert back and forth between them.
|
|||||||
|
|
||||||
* Version 2.x of the library has been built from the ground up with Uint8Arrays. This allows for much better performance and memory usage than strings.
|
* Version 2.x of the library has been built from the ground up with Uint8Arrays. This allows for much better performance and memory usage than strings.
|
||||||
|
|
||||||
* If the user's browser supports [native WebCrypto](https://caniuse.com/#feat=cryptography) via the `window.crypto.subtle` API, this will be used. Under Node.js the native [crypto module](https://nodejs.org/api/crypto.html#crypto_crypto) is used. This can be deactivated by setting `openpgp.config.useNative = false`.
|
* If the user's browser supports [native WebCrypto](https://caniuse.com/#feat=cryptography) via the `window.crypto.subtle` API, this will be used. Under Node.js the native [crypto module](https://nodejs.org/api/crypto.html#crypto_crypto) is used.
|
||||||
|
|
||||||
* The library implements the [IETF proposal](https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-07) for authenticated encryption using native AES-EAX, OCB, or GCM. This makes symmetric encryption up to 30x faster on supported platforms. Since the specification has not been finalized and other OpenPGP implementations haven't adopted it yet, the feature is currently behind a flag. **Note: activating this setting can break compatibility with other OpenPGP implementations, and also with future versions of OpenPGP.js. Don't use it with messages you want to store on disk or in a database.** You can enable it by setting `openpgp.config.aeadProtect = true`.
|
* The library implements the [IETF proposal](https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-07) for authenticated encryption using native AES-EAX, OCB, or GCM. This makes symmetric encryption up to 30x faster on supported platforms. Since the specification has not been finalized and other OpenPGP implementations haven't adopted it yet, the feature is currently behind a flag. **Note: activating this setting can break compatibility with other OpenPGP implementations, and also with future versions of OpenPGP.js. Don't use it with messages you want to store on disk or in a database.** You can enable it by setting `openpgp.config.aeadProtect = true`.
|
||||||
|
|
||||||
|
154
openpgp.d.ts
vendored
154
openpgp.d.ts
vendored
@ -9,15 +9,15 @@
|
|||||||
|
|
||||||
/* ############## v5 KEY #################### */
|
/* ############## v5 KEY #################### */
|
||||||
|
|
||||||
export function readKey(options: { armoredKey: string }): Promise<Key>;
|
export function readKey(options: { armoredKey: string, config?: PartialConfig }): Promise<Key>;
|
||||||
export function readKey(options: { binaryKey: Uint8Array }): Promise<Key>;
|
export function readKey(options: { binaryKey: Uint8Array, config?: PartialConfig }): Promise<Key>;
|
||||||
export function readKeys(options: { armoredKeys: string }): Promise<Key[]>;
|
export function readKeys(options: { armoredKeys: string, config?: PartialConfig }): Promise<Key[]>;
|
||||||
export function readKeys(options: { binaryKeys: Uint8Array }): Promise<Key[]>;
|
export function readKeys(options: { binaryKeys: Uint8Array, config?: PartialConfig }): Promise<Key[]>;
|
||||||
export function generateKey(options: KeyOptions): Promise<KeyPair>;
|
export function generateKey(options: KeyOptions): Promise<KeyPair>;
|
||||||
export function generateSessionKey(options: { publicKeys: Key[], date?: Date, toUserIds?: UserID[] }): Promise<SessionKey>;
|
export function generateSessionKey(options: { publicKeys: Key[], date?: Date, toUserIds?: UserID[], config?: PartialConfig }): Promise<SessionKey>;
|
||||||
export function decryptKey(options: { privateKey: Key; passphrase?: string | string[]; }): Promise<Key>;
|
export function decryptKey(options: { privateKey: Key; passphrase?: string | string[]; config?: PartialConfig }): Promise<Key>;
|
||||||
export function encryptKey(options: { privateKey: Key; passphrase?: string | string[]; }): Promise<Key>;
|
export function encryptKey(options: { privateKey: Key; passphrase?: string | string[]; config?: PartialConfig }): Promise<Key>;
|
||||||
export function reformatKey(options: { privateKey: Key; userIds?: UserID|UserID[]; passphrase?: string; keyExpirationTime?: number; }): Promise<KeyPair>;
|
export function reformatKey(options: { privateKey: Key; userIds?: UserID|UserID[]; passphrase?: string; keyExpirationTime?: number; config?: PartialConfig }): Promise<KeyPair>;
|
||||||
|
|
||||||
export class Key {
|
export class Key {
|
||||||
constructor(packetlist: PacketList<AnyPacket>);
|
constructor(packetlist: PacketList<AnyPacket>);
|
||||||
@ -26,23 +26,23 @@ export class Key {
|
|||||||
public users: User[];
|
public users: User[];
|
||||||
public revocationSignatures: SignaturePacket[];
|
public revocationSignatures: SignaturePacket[];
|
||||||
public keyPacket: PublicKeyPacket | SecretKeyPacket;
|
public keyPacket: PublicKeyPacket | SecretKeyPacket;
|
||||||
public armor(): string;
|
public armor(config?: Config): string;
|
||||||
public decrypt(passphrase: string | string[], keyId?: Keyid): Promise<void>; // throws on error
|
public decrypt(passphrase: string | string[], keyId?: Keyid, config?: Config): Promise<void>; // throws on error
|
||||||
public encrypt(passphrase: string | string[]): Promise<void>; // throws on error
|
public encrypt(passphrase: string | string[], keyId?: Keyid, config?: Config): Promise<void>; // throws on error
|
||||||
public getExpirationTime(capability?: 'encrypt' | 'encrypt_sign' | 'sign', keyId?: Keyid, userId?: UserID): Promise<Date | typeof Infinity | null>; // Returns null if `capabilities` is passed and the key does not have the specified capabilities or is revoked or invalid.
|
public getExpirationTime(capability?: 'encrypt' | 'encrypt_sign' | 'sign', keyId?: Keyid, userId?: UserID, config?: Config): Promise<Date | typeof Infinity | null>; // Returns null if `capabilities` is passed and the key does not have the specified capabilities or is revoked or invalid.
|
||||||
public getKeyIds(): Keyid[];
|
public getKeyIds(): Keyid[];
|
||||||
public getPrimaryUser(): Promise<PrimaryUser>; // throws on error
|
public getPrimaryUser(date?: Date, userId?: UserID, config?: Config): Promise<PrimaryUser>; // throws on error
|
||||||
public getUserIds(): string[];
|
public getUserIds(): string[];
|
||||||
public isPrivate(): boolean;
|
public isPrivate(): boolean;
|
||||||
public isPublic(): boolean;
|
public isPublic(): boolean;
|
||||||
public toPublic(): Key;
|
public toPublic(): Key;
|
||||||
public update(key: Key): void;
|
public update(key: Key, config?: Config): void;
|
||||||
public verifyPrimaryKey(): Promise<void>; // throws on error
|
public verifyPrimaryKey(date?: Date, userId?: UserID, config?: Config): Promise<void>; // throws on error
|
||||||
public isRevoked(): Promise<boolean>;
|
public isRevoked(signature: SignaturePacket, key?: AnyKeyPacket, date?: Date, config?: Config): Promise<boolean>;
|
||||||
public revoke(reason: { flag?: enums.reasonForRevocation; string?: string; }, date?: Date): Promise<Key>;
|
public revoke(reason: { flag?: enums.reasonForRevocation; string?: string; }, date?: Date, config?: Config): Promise<Key>;
|
||||||
public getRevocationCertificate(): Promise<Stream<string> | string | undefined>;
|
public getRevocationCertificate(date?: Date, config?: Config): Promise<Stream<string> | string | undefined>;
|
||||||
public getEncryptionKey(keyid?: Keyid, date?: Date | null, userId?: UserID): Promise<Key | SubKey>;
|
public getEncryptionKey(keyid?: Keyid, date?: Date | null, userId?: UserID, config?: Config): Promise<Key | SubKey>;
|
||||||
public getSigningKey(keyid?: Keyid, date?: Date | null, userId?: UserID): Promise<Key | SubKey>;
|
public getSigningKey(keyid?: Keyid, date?: Date | null, userId?: UserID, config?: Config): Promise<Key | SubKey>;
|
||||||
public getKeys(keyId?: Keyid): (Key | SubKey)[];
|
public getKeys(keyId?: Keyid): (Key | SubKey)[];
|
||||||
public getSubkeys(keyId?: Keyid): SubKey[];
|
public getSubkeys(keyId?: Keyid): SubKey[];
|
||||||
public isDecrypted(): boolean;
|
public isDecrypted(): boolean;
|
||||||
@ -50,6 +50,7 @@ export class Key {
|
|||||||
public getCreationTime(): Date;
|
public getCreationTime(): Date;
|
||||||
public getAlgorithmInfo(): AlgorithmInfo;
|
public getAlgorithmInfo(): AlgorithmInfo;
|
||||||
public getKeyId(): Keyid;
|
public getKeyId(): Keyid;
|
||||||
|
public addSubkey(options: SubKeyOptions): Promise<Key>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SubKey {
|
export class SubKey {
|
||||||
@ -57,7 +58,7 @@ export class SubKey {
|
|||||||
public keyPacket: SecretSubkeyPacket | PublicSubkeyPacket;
|
public keyPacket: SecretSubkeyPacket | PublicSubkeyPacket;
|
||||||
public bindingSignatures: SignaturePacket[];
|
public bindingSignatures: SignaturePacket[];
|
||||||
public revocationSignatures: SignaturePacket[];
|
public revocationSignatures: SignaturePacket[];
|
||||||
public verify(primaryKey: PublicKeyPacket | SecretKeyPacket): Promise<SignaturePacket>;
|
public verify(primaryKey: PublicKeyPacket | SecretKeyPacket, date?: Date, config?: Config): Promise<SignaturePacket>;
|
||||||
public isDecrypted(): boolean;
|
public isDecrypted(): boolean;
|
||||||
public getFingerprint(): string;
|
public getFingerprint(): string;
|
||||||
public getCreationTime(): Date;
|
public getCreationTime(): Date;
|
||||||
@ -86,13 +87,13 @@ type AlgorithmInfo = {
|
|||||||
|
|
||||||
/* ############## v5 SIG #################### */
|
/* ############## v5 SIG #################### */
|
||||||
|
|
||||||
export function readSignature(options: { armoredSignature: string }): Promise<Signature>;
|
export function readSignature(options: { armoredSignature: string, config?: PartialConfig }): Promise<Signature>;
|
||||||
export function readSignature(options: { binarySignature: Uint8Array }): Promise<Signature>;
|
export function readSignature(options: { binarySignature: Uint8Array, config?: PartialConfig }): Promise<Signature>;
|
||||||
|
|
||||||
export class Signature {
|
export class Signature {
|
||||||
public packets: PacketList<SignaturePacket>;
|
public packets: PacketList<SignaturePacket>;
|
||||||
constructor(packetlist: PacketList<SignaturePacket>);
|
constructor(packetlist: PacketList<SignaturePacket>);
|
||||||
public armor(): string;
|
public armor(config?: Config): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface VerificationResult {
|
interface VerificationResult {
|
||||||
@ -103,14 +104,14 @@ interface VerificationResult {
|
|||||||
|
|
||||||
/* ############## v5 CLEARTEXT #################### */
|
/* ############## v5 CLEARTEXT #################### */
|
||||||
|
|
||||||
export function readCleartextMessage(options: { cleartextMessage: string }): Promise<CleartextMessage>;
|
export function readCleartextMessage(options: { cleartextMessage: string, config?: PartialConfig }): Promise<CleartextMessage>;
|
||||||
|
|
||||||
/** Class that represents an OpenPGP cleartext signed message.
|
/** Class that represents an OpenPGP cleartext signed message.
|
||||||
*/
|
*/
|
||||||
export class CleartextMessage {
|
export class CleartextMessage {
|
||||||
/** Returns ASCII armored text of cleartext signed message
|
/** Returns ASCII armored text of cleartext signed message
|
||||||
*/
|
*/
|
||||||
armor(): string;
|
armor(config?: Config): string;
|
||||||
|
|
||||||
/** Returns the key IDs of the keys that signed the cleartext message
|
/** Returns the key IDs of the keys that signed the cleartext message
|
||||||
*/
|
*/
|
||||||
@ -124,20 +125,20 @@ export class CleartextMessage {
|
|||||||
*
|
*
|
||||||
* @param privateKeys private keys with decrypted secret key data for signing
|
* @param privateKeys private keys with decrypted secret key data for signing
|
||||||
*/
|
*/
|
||||||
sign(privateKeys: Key[]): void;
|
sign(privateKeys: Key[], signature?: Signature, signingKeyIds?: Keyid[], date?: Date, userIds?: UserID[], config?: Config): void;
|
||||||
|
|
||||||
/** Verify signatures of cleartext signed message
|
/** Verify signatures of cleartext signed message
|
||||||
* @param keys array of keys to verify signatures
|
* @param keys array of keys to verify signatures
|
||||||
*/
|
*/
|
||||||
verify(keys: Key[], date?: Date, streaming?: boolean): Promise<VerificationResult[]>;
|
verify(keys: Key[], date?: Date, config?: Config): Promise<VerificationResult[]>;
|
||||||
|
|
||||||
static fromText(text: string): CleartextMessage;
|
static fromText(text: string): CleartextMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ############## v5 MSG #################### */
|
/* ############## v5 MSG #################### */
|
||||||
|
|
||||||
export function readMessage<T extends MaybeStream<string>>(options: { armoredMessage: T }): Promise<Message<T>>;
|
export function readMessage<T extends MaybeStream<string>>(options: { armoredMessage: T, config?: PartialConfig }): Promise<Message<T>>;
|
||||||
export function readMessage<T extends MaybeStream<Uint8Array>>(options: { binaryMessage: T }): Promise<Message<T>>;
|
export function readMessage<T extends MaybeStream<Uint8Array>>(options: { binaryMessage: T, config?: PartialConfig }): Promise<Message<T>>;
|
||||||
|
|
||||||
export function encrypt<T extends 'web' | 'node' | false>(options: EncryptOptions & { streaming: T, armor: false }): Promise<
|
export function encrypt<T extends 'web' | 'node' | false>(options: EncryptOptions & { streaming: T, armor: false }): Promise<
|
||||||
T extends 'web' ? WebStream<Uint8Array> :
|
T extends 'web' ? WebStream<Uint8Array> :
|
||||||
@ -241,17 +242,17 @@ export class Message<T extends MaybeStream<Data>> {
|
|||||||
|
|
||||||
/** Returns ASCII armored text of message
|
/** Returns ASCII armored text of message
|
||||||
*/
|
*/
|
||||||
public armor(): string;
|
public armor(config?: Config): string;
|
||||||
|
|
||||||
/** Decrypt the message
|
/** Decrypt the message
|
||||||
@param privateKey private key with decrypted secret data
|
@param privateKey private key with decrypted secret data
|
||||||
*/
|
*/
|
||||||
public decrypt(privateKeys?: Key[] | null, passwords?: string[] | null, sessionKeys?: SessionKey[] | null, streaming?: boolean): Promise<Message<MaybeStream<Data>>>;
|
public decrypt(privateKeys?: Key[], passwords?: string[], sessionKeys?: SessionKey[], streaming?: boolean, config?: Config): Promise<Message<MaybeStream<Data>>>;
|
||||||
|
|
||||||
/** Encrypt the message
|
/** Encrypt the message
|
||||||
@param keys array of keys, used to encrypt the message
|
@param keys array of keys, used to encrypt the message
|
||||||
*/
|
*/
|
||||||
public encrypt(keys: Key[]): Promise<Message<MaybeStream<Data>>>;
|
public encrypt(keys?: Key[], passwords?: string[], sessionKeys?: SessionKey[], wildcard?: boolean, encryptionKeyIds?: Keyid[], date?: Date, userIds?: UserID[], streaming?: boolean, config?: Config): Promise<Message<MaybeStream<Data>>>;
|
||||||
|
|
||||||
/** Returns the key IDs of the keys to which the session key is encrypted
|
/** Returns the key IDs of the keys to which the session key is encrypted
|
||||||
*/
|
*/
|
||||||
@ -274,7 +275,7 @@ export class Message<T extends MaybeStream<Data>> {
|
|||||||
/** Sign the message (the literal data packet of the message)
|
/** Sign the message (the literal data packet of the message)
|
||||||
@param privateKey private keys with decrypted secret key data for signing
|
@param privateKey private keys with decrypted secret key data for signing
|
||||||
*/
|
*/
|
||||||
public sign(privateKey: Key[]): Promise<Message<T>>;
|
public sign(privateKey: Key[], signature?: Signature, signingKeyIds?: Keyid[], date?: Date, userIds?: UserID[], streaming?: boolean, config?: Config): Promise<Message<T>>;
|
||||||
|
|
||||||
/** Unwrap compressed message
|
/** Unwrap compressed message
|
||||||
*/
|
*/
|
||||||
@ -283,7 +284,7 @@ export class Message<T extends MaybeStream<Data>> {
|
|||||||
/** Verify message signatures
|
/** Verify message signatures
|
||||||
@param keys array of keys to verify signatures
|
@param keys array of keys to verify signatures
|
||||||
*/
|
*/
|
||||||
public verify(keys: Key[], date?: Date, streaming?: boolean): Promise<VerificationResult[]>;
|
public verify(keys: Key[], date?: Date, streaming?: boolean, config?: Config): Promise<VerificationResult[]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append signature to unencrypted message object
|
* Append signature to unencrypted message object
|
||||||
@ -298,31 +299,33 @@ export class Message<T extends MaybeStream<Data>> {
|
|||||||
|
|
||||||
/* ############## v5 CONFIG #################### */
|
/* ############## v5 CONFIG #################### */
|
||||||
|
|
||||||
export namespace config {
|
interface Config {
|
||||||
let preferHashAlgorithm: enums.hash;
|
preferHashAlgorithm: enums.hash;
|
||||||
let encryptionCipher: enums.symmetric;
|
encryptionCipher: enums.symmetric;
|
||||||
let compression: enums.compression;
|
compression: enums.compression;
|
||||||
let showVersion: boolean;
|
showVersion: boolean;
|
||||||
let showComment: boolean;
|
showComment: boolean;
|
||||||
let integrityProtect: boolean;
|
integrityProtect: boolean;
|
||||||
let debug: boolean;
|
deflateLevel: number;
|
||||||
let deflateLevel: number;
|
aeadProtect: boolean;
|
||||||
let aeadProtect: boolean;
|
ignoreMdcError: boolean;
|
||||||
let ignoreMdcError: boolean;
|
checksumRequired: boolean;
|
||||||
let checksumRequired: boolean;
|
minRsaBits: number;
|
||||||
let rsaBlinding: boolean;
|
passwordCollisionCheck: boolean;
|
||||||
let minRsaBits: number;
|
revocationsExpire: boolean;
|
||||||
let passwordCollisionCheck: boolean;
|
tolerant: boolean;
|
||||||
let revocationsExpire: boolean;
|
versionString: string;
|
||||||
let useNative: boolean;
|
commentString: string;
|
||||||
let zeroCopy: boolean;
|
keyserver: string;
|
||||||
let tolerant: boolean;
|
nodeStore: string;
|
||||||
let versionString: string;
|
allowInsecureDecryptionWithSigningKeys: boolean;
|
||||||
let commentString: string;
|
v5Keys: boolean;
|
||||||
let keyserver: string;
|
|
||||||
let nodeStore: string;
|
|
||||||
let allowInsecureDecryptionWithSigningKeys: boolean;
|
|
||||||
}
|
}
|
||||||
|
export var config: Config;
|
||||||
|
|
||||||
|
// PartialConfig has the same properties as Config, but declared as optional.
|
||||||
|
// This interface is relevant for top-level functions, which accept a subset of configuration options
|
||||||
|
interface PartialConfig extends Partial<Config> {}
|
||||||
|
|
||||||
/* ############## v5 PACKET #################### */
|
/* ############## v5 PACKET #################### */
|
||||||
|
|
||||||
@ -361,11 +364,11 @@ export class PublicSubkeyPacket extends BasePublicKeyPacket {
|
|||||||
|
|
||||||
declare abstract class BaseSecretKeyPacket extends BasePublicKeyPacket {
|
declare abstract class BaseSecretKeyPacket extends BasePublicKeyPacket {
|
||||||
public privateParams: object | null;
|
public privateParams: object | null;
|
||||||
public encrypt(passphrase: string): Promise<void>; // throws on error
|
public encrypt(passphrase: string, config?: Config): Promise<void>; // throws on error
|
||||||
public decrypt(passphrase: string): Promise<void>; // throws on error
|
public decrypt(passphrase: string): Promise<void>; // throws on error
|
||||||
public validate(): Promise<void>; // throws on error
|
public validate(): Promise<void>; // throws on error
|
||||||
public isDummy(): boolean;
|
public isDummy(): boolean;
|
||||||
public makeDummy(): void;
|
public makeDummy(config?: Config): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SecretKeyPacket extends BaseSecretKeyPacket {
|
export class SecretKeyPacket extends BaseSecretKeyPacket {
|
||||||
@ -472,7 +475,7 @@ export class SignaturePacket extends BasePacket {
|
|||||||
public verified: null | boolean;
|
public verified: null | boolean;
|
||||||
public revoked: null | boolean;
|
public revoked: null | boolean;
|
||||||
public sign(key: AnySecretKeyPacket, data: Uint8Array, detached?: boolean, streaming?: boolean): Promise<void>;
|
public sign(key: AnySecretKeyPacket, data: Uint8Array, detached?: boolean, streaming?: boolean): Promise<void>;
|
||||||
public verify(key: AnyKeyPacket, signatureType: enums.signature, data: Uint8Array, detached?: boolean, streaming?: boolean): Promise<void>; // throws on error
|
public verify(key: AnyKeyPacket, signatureType: enums.signature, data: Uint8Array, detached?: boolean, streaming?: boolean, config?: Config): Promise<void>; // throws on error
|
||||||
public isExpired(date?: Date): boolean;
|
public isExpired(date?: Date): boolean;
|
||||||
public getExpirationTime(): Date | typeof Infinity;
|
public getExpirationTime(): Date | typeof Infinity;
|
||||||
}
|
}
|
||||||
@ -491,7 +494,7 @@ type DataPacketType = 'utf8' | 'binary' | 'text' | 'mime';
|
|||||||
export class PacketList<PACKET_TYPE> extends Array<PACKET_TYPE> {
|
export class PacketList<PACKET_TYPE> extends Array<PACKET_TYPE> {
|
||||||
[index: number]: PACKET_TYPE;
|
[index: number]: PACKET_TYPE;
|
||||||
public length: number;
|
public length: number;
|
||||||
public read(bytes: Uint8Array): void;
|
public read(bytes: Uint8Array, allowedPackets?: object, streaming?: boolean, config?: Config): void;
|
||||||
public write(): Uint8Array;
|
public write(): Uint8Array;
|
||||||
public push(...packet: PACKET_TYPE[]): number;
|
public push(...packet: PACKET_TYPE[]): number;
|
||||||
public pop(): PACKET_TYPE;
|
public pop(): PACKET_TYPE;
|
||||||
@ -550,8 +553,6 @@ interface EncryptOptions {
|
|||||||
passwords?: string | string[];
|
passwords?: string | string[];
|
||||||
/** (optional) session key in the form: { data:Uint8Array, algorithm:String } */
|
/** (optional) session key in the form: { data:Uint8Array, algorithm:String } */
|
||||||
sessionKey?: SessionKey;
|
sessionKey?: SessionKey;
|
||||||
/** (optional) which compression algorithm to compress the message with, defaults to what is specified in config */
|
|
||||||
compression?: enums.compression;
|
|
||||||
/** if the return values should be ascii armored or the message/signature objects */
|
/** if the return values should be ascii armored or the message/signature objects */
|
||||||
armor?: boolean;
|
armor?: boolean;
|
||||||
/** (optional) whether to return data as a stream. Defaults to the type of stream `message` was created from, if any. */
|
/** (optional) whether to return data as a stream. Defaults to the type of stream `message` was created from, if any. */
|
||||||
@ -566,6 +567,7 @@ interface EncryptOptions {
|
|||||||
fromUserId?: UserID;
|
fromUserId?: UserID;
|
||||||
/** (optional) user ID to encrypt for, e.g. { name:'Robert Receiver', email:'robert@openpgp.org' } */
|
/** (optional) user ID to encrypt for, e.g. { name:'Robert Receiver', email:'robert@openpgp.org' } */
|
||||||
toUserId?: UserID;
|
toUserId?: UserID;
|
||||||
|
config?: PartialConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DecryptOptions {
|
interface DecryptOptions {
|
||||||
@ -587,6 +589,7 @@ interface DecryptOptions {
|
|||||||
signature?: Signature;
|
signature?: Signature;
|
||||||
/** (optional) use the given date for verification instead of the current time */
|
/** (optional) use the given date for verification instead of the current time */
|
||||||
date?: Date;
|
date?: Date;
|
||||||
|
config?: PartialConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SignOptions {
|
interface SignOptions {
|
||||||
@ -598,6 +601,7 @@ interface SignOptions {
|
|||||||
detached?: boolean;
|
detached?: boolean;
|
||||||
date?: Date;
|
date?: Date;
|
||||||
fromUserId?: UserID;
|
fromUserId?: UserID;
|
||||||
|
config?: PartialConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface VerifyOptions {
|
interface VerifyOptions {
|
||||||
@ -613,6 +617,7 @@ interface VerifyOptions {
|
|||||||
signature?: Signature;
|
signature?: Signature;
|
||||||
/** (optional) use the given date for verification instead of the current time */
|
/** (optional) use the given date for verification instead of the current time */
|
||||||
date?: Date;
|
date?: Date;
|
||||||
|
config?: PartialConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface KeyPair {
|
interface KeyPair {
|
||||||
@ -632,7 +637,18 @@ interface KeyOptions {
|
|||||||
rsaBits?: number;
|
rsaBits?: number;
|
||||||
keyExpirationTime?: number;
|
keyExpirationTime?: number;
|
||||||
date?: Date;
|
date?: Date;
|
||||||
subkeys?: KeyOptions[];
|
subkeys?: SubKeyOptions[];
|
||||||
|
config?: PartialConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SubKeyOptions {
|
||||||
|
type?: 'ecc' | 'rsa';
|
||||||
|
curve?: EllipticCurveName;
|
||||||
|
rsaBits?: number;
|
||||||
|
keyExpirationTime?: number;
|
||||||
|
date?: Date;
|
||||||
|
sign?: boolean;
|
||||||
|
config?: PartialConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare class Keyid {
|
declare class Keyid {
|
||||||
@ -657,15 +673,15 @@ interface VerifyMessageResult {
|
|||||||
/**
|
/**
|
||||||
* Armor an OpenPGP binary packet block
|
* Armor an OpenPGP binary packet block
|
||||||
*/
|
*/
|
||||||
export function armor(messagetype: enums.armor, body: object, partindex: number, parttotal: number): string;
|
export function armor(messagetype: enums.armor, body: object, partindex: number, parttotal: number, config?: Config): string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DeArmor an OpenPGP armored message; verify the checksum and return the encoded bytes
|
* DeArmor an OpenPGP armored message; verify the checksum and return the encoded bytes
|
||||||
*/
|
*/
|
||||||
export function unarmor(text: string): Promise<{ text: string, data: Stream<Uint8Array>, type: enums.armor }>;
|
export function unarmor(input: string, config?: Config): Promise<{ text: string, data: Stream<Uint8Array>, type: enums.armor }>;
|
||||||
|
|
||||||
export class HKP {
|
export class HKP {
|
||||||
constructor(keyServerBaseUrl?: string);
|
constructor(keyServerBaseUrl?: string, config?: Config);
|
||||||
public lookup(options: { keyid?: string, query?: string }): Promise<string | undefined>;
|
public lookup(options: { keyid?: string, query?: string }): Promise<string | undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ import util from './util';
|
|||||||
import { PacketList, LiteralDataPacket, SignaturePacket } from './packet';
|
import { PacketList, LiteralDataPacket, SignaturePacket } from './packet';
|
||||||
import { Signature } from './signature';
|
import { Signature } from './signature';
|
||||||
import { createVerificationObjects, createSignaturePackets } from './message';
|
import { createVerificationObjects, createSignaturePackets } from './message';
|
||||||
|
import defaultConfig from './config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that represents an OpenPGP cleartext signed message.
|
* Class that represents an OpenPGP cleartext signed message.
|
||||||
@ -69,11 +70,12 @@ export class CleartextMessage {
|
|||||||
* @param {Array<module:type/keyid>} signingKeyIds (optional) array of key IDs to use for signing. Each signingKeyIds[i] corresponds to privateKeys[i]
|
* @param {Array<module:type/keyid>} signingKeyIds (optional) array of key IDs to use for signing. Each signingKeyIds[i] corresponds to privateKeys[i]
|
||||||
* @param {Date} date (optional) The creation time of the signature that should be created
|
* @param {Date} date (optional) The creation time of the signature that should be created
|
||||||
* @param {Array} userIds (optional) user IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
|
* @param {Array} userIds (optional) user IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<module:cleartext.CleartextMessage>} new cleartext message with signed content
|
* @returns {Promise<module:cleartext.CleartextMessage>} new cleartext message with signed content
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async sign(privateKeys, signature = null, signingKeyIds = [], date = new Date(), userIds = []) {
|
async sign(privateKeys, signature = null, signingKeyIds = [], date = new Date(), userIds = [], config = defaultConfig) {
|
||||||
return new CleartextMessage(this.text, await this.signDetached(privateKeys, signature, signingKeyIds, date, userIds));
|
return new CleartextMessage(this.text, await this.signDetached(privateKeys, signature, signingKeyIds, date, userIds, config));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,40 +85,43 @@ export class CleartextMessage {
|
|||||||
* @param {Array<module:type/keyid>} signingKeyIds (optional) array of key IDs to use for signing. Each signingKeyIds[i] corresponds to privateKeys[i]
|
* @param {Array<module:type/keyid>} signingKeyIds (optional) array of key IDs to use for signing. Each signingKeyIds[i] corresponds to privateKeys[i]
|
||||||
* @param {Date} date (optional) The creation time of the signature that should be created
|
* @param {Date} date (optional) The creation time of the signature that should be created
|
||||||
* @param {Array} userIds (optional) user IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
|
* @param {Array} userIds (optional) user IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<module:signature.Signature>} new detached signature of message content
|
* @returns {Promise<module:signature.Signature>} new detached signature of message content
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async signDetached(privateKeys, signature = null, signingKeyIds = [], date = new Date(), userIds = []) {
|
async signDetached(privateKeys, signature = null, signingKeyIds = [], date = new Date(), userIds = [], config = defaultConfig) {
|
||||||
const literalDataPacket = new LiteralDataPacket();
|
const literalDataPacket = new LiteralDataPacket();
|
||||||
literalDataPacket.setText(this.text);
|
literalDataPacket.setText(this.text);
|
||||||
|
|
||||||
return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIds, date, userIds, true));
|
return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIds, date, userIds, true, undefined, config));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify signatures of cleartext signed message
|
* Verify signatures of cleartext signed message
|
||||||
* @param {Array<module:key.Key>} keys array of keys to verify signatures
|
* @param {Array<module:key.Key>} keys array of keys to verify signatures
|
||||||
* @param {Date} date (optional) Verify the signature against the given date, i.e. check signature creation time < date < expiration time
|
* @param {Date} date (optional) Verify the signature against the given date, i.e. check signature creation time < date < expiration time
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Array<{keyid: module:type/keyid, valid: Boolean}>>} list of signer's keyid and validity of signature
|
* @returns {Promise<Array<{keyid: module:type/keyid, valid: Boolean}>>} list of signer's keyid and validity of signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
verify(keys, date = new Date()) {
|
verify(keys, date = new Date(), config = defaultConfig) {
|
||||||
return this.verifyDetached(this.signature, keys, date);
|
return this.verifyDetached(this.signature, keys, date, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify signatures of cleartext signed message
|
* Verify signatures of cleartext signed message
|
||||||
* @param {Array<module:key.Key>} keys array of keys to verify signatures
|
* @param {Array<module:key.Key>} keys array of keys to verify signatures
|
||||||
* @param {Date} date (optional) Verify the signature against the given date, i.e. check signature creation time < date < expiration time
|
* @param {Date} date (optional) Verify the signature against the given date, i.e. check signature creation time < date < expiration time
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Array<{keyid: module:type/keyid, valid: Boolean}>>} list of signer's keyid and validity of signature
|
* @returns {Promise<Array<{keyid: module:type/keyid, valid: Boolean}>>} list of signer's keyid and validity of signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
verifyDetached(signature, keys, date = new Date()) {
|
verifyDetached(signature, keys, date = new Date(), config = defaultConfig) {
|
||||||
const signatureList = signature.packets;
|
const signatureList = signature.packets;
|
||||||
const literalDataPacket = new LiteralDataPacket();
|
const literalDataPacket = new LiteralDataPacket();
|
||||||
// we assume that cleartext signature is generated based on UTF8 cleartext
|
// we assume that cleartext signature is generated based on UTF8 cleartext
|
||||||
literalDataPacket.setText(this.text);
|
literalDataPacket.setText(this.text);
|
||||||
return createVerificationObjects(signatureList, [literalDataPacket], keys, date, true);
|
return createVerificationObjects(signatureList, [literalDataPacket], keys, date, true, undefined, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -130,9 +135,10 @@ export class CleartextMessage {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns ASCII armored text of cleartext signed message
|
* Returns ASCII armored text of cleartext signed message
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {String | ReadableStream<String>} ASCII armor
|
* @returns {String | ReadableStream<String>} ASCII armor
|
||||||
*/
|
*/
|
||||||
armor() {
|
armor(config = defaultConfig) {
|
||||||
let hashes = this.signature.packets.map(function(packet) {
|
let hashes = this.signature.packets.map(function(packet) {
|
||||||
return enums.read(enums.hash, packet.hashAlgorithm).toUpperCase();
|
return enums.read(enums.hash, packet.hashAlgorithm).toUpperCase();
|
||||||
});
|
});
|
||||||
@ -142,7 +148,7 @@ export class CleartextMessage {
|
|||||||
text: this.text,
|
text: this.text,
|
||||||
data: this.signature.packets.write()
|
data: this.signature.packets.write()
|
||||||
};
|
};
|
||||||
return armor(enums.armor.signed, body);
|
return armor(enums.armor.signed, body, undefined, undefined, undefined, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -159,11 +165,13 @@ export class CleartextMessage {
|
|||||||
/**
|
/**
|
||||||
* Reads an OpenPGP cleartext signed message and returns a CleartextMessage object
|
* Reads an OpenPGP cleartext signed message and returns a CleartextMessage object
|
||||||
* @param {String | ReadableStream<String>} cleartextMessage text to be parsed
|
* @param {String | ReadableStream<String>} cleartextMessage text to be parsed
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {module:cleartext.CleartextMessage} new cleartext message object
|
* @returns {module:cleartext.CleartextMessage} new cleartext message object
|
||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export async function readCleartextMessage({ cleartextMessage }) {
|
export async function readCleartextMessage({ cleartextMessage, config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
if (!cleartextMessage) {
|
if (!cleartextMessage) {
|
||||||
throw new Error('readCleartextMessage: must pass options object containing `cleartextMessage`');
|
throw new Error('readCleartextMessage: must pass options object containing `cleartextMessage`');
|
||||||
}
|
}
|
||||||
@ -172,7 +180,7 @@ export async function readCleartextMessage({ cleartextMessage }) {
|
|||||||
throw new Error('No cleartext signed message.');
|
throw new Error('No cleartext signed message.');
|
||||||
}
|
}
|
||||||
const packetlist = new PacketList();
|
const packetlist = new PacketList();
|
||||||
await packetlist.read(input.data, { SignaturePacket });
|
await packetlist.read(input.data, { SignaturePacket }, undefined, config);
|
||||||
verifyHeaders(input.headers, packetlist);
|
verifyHeaders(input.headers, packetlist);
|
||||||
const signature = new Signature(packetlist);
|
const signature = new Signature(packetlist);
|
||||||
return new CleartextMessage(input.text, signature);
|
return new CleartextMessage(input.text, signature);
|
||||||
|
@ -103,11 +103,6 @@ export default {
|
|||||||
* @property {Boolean} checksumRequired Do not throw error when armor is missing a checksum
|
* @property {Boolean} checksumRequired Do not throw error when armor is missing a checksum
|
||||||
*/
|
*/
|
||||||
checksumRequired: false,
|
checksumRequired: false,
|
||||||
/**
|
|
||||||
* @memberof module:config
|
|
||||||
* @property {Boolean} rsaBlinding
|
|
||||||
*/
|
|
||||||
rsaBlinding: true,
|
|
||||||
/**
|
/**
|
||||||
* @memberof module:config
|
* @memberof module:config
|
||||||
* @property {Number} minRsaBits Minimum RSA key size allowed for key generation
|
* @property {Number} minRsaBits Minimum RSA key size allowed for key generation
|
||||||
@ -134,21 +129,11 @@ export default {
|
|||||||
*/
|
*/
|
||||||
allowInsecureDecryptionWithSigningKeys: false,
|
allowInsecureDecryptionWithSigningKeys: false,
|
||||||
|
|
||||||
/**
|
|
||||||
* @memberof module:config
|
|
||||||
* @property {Boolean} useNative Use native Node.js crypto/zlib and WebCrypto APIs when available
|
|
||||||
*/
|
|
||||||
useNative: true,
|
|
||||||
/**
|
/**
|
||||||
* @memberof module:config
|
* @memberof module:config
|
||||||
* @property {Integer} minBytesForWebCrypto The minimum amount of bytes for which to use native WebCrypto APIs when available
|
* @property {Integer} minBytesForWebCrypto The minimum amount of bytes for which to use native WebCrypto APIs when available
|
||||||
*/
|
*/
|
||||||
minBytesForWebCrypto: 1000,
|
minBytesForWebCrypto: 1000,
|
||||||
/**
|
|
||||||
* @memberof module:config
|
|
||||||
* @property {Boolean} debug If enabled, debug messages will be printed
|
|
||||||
*/
|
|
||||||
debug: false,
|
|
||||||
/**
|
/**
|
||||||
* @memberof module:config
|
* @memberof module:config
|
||||||
* @property {Boolean} tolerant Ignore unsupported/unrecognizable packets instead of throwing an error
|
* @property {Boolean} tolerant Ignore unsupported/unrecognizable packets instead of throwing an error
|
||||||
|
@ -28,7 +28,6 @@ import { AES_CFB } from 'asmcrypto.js/dist_es8/aes/cfb';
|
|||||||
|
|
||||||
import stream from 'web-stream-tools';
|
import stream from 'web-stream-tools';
|
||||||
import * as cipher from './cipher';
|
import * as cipher from './cipher';
|
||||||
import config from '../config';
|
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
|
||||||
const webCrypto = util.getWebCrypto();
|
const webCrypto = util.getWebCrypto();
|
||||||
@ -47,12 +46,12 @@ const nodeAlgos = {
|
|||||||
/* twofish is not implemented in OpenSSL */
|
/* twofish is not implemented in OpenSSL */
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function encrypt(algo, key, plaintext, iv) {
|
export async function encrypt(algo, key, plaintext, iv, config) {
|
||||||
if (util.getNodeCrypto() && nodeAlgos[algo]) { // Node crypto library.
|
if (util.getNodeCrypto() && nodeAlgos[algo]) { // Node crypto library.
|
||||||
return nodeEncrypt(algo, key, plaintext, iv);
|
return nodeEncrypt(algo, key, plaintext, iv);
|
||||||
}
|
}
|
||||||
if (algo.substr(0, 3) === 'aes') {
|
if (algo.substr(0, 3) === 'aes') {
|
||||||
return aesEncrypt(algo, key, plaintext, iv);
|
return aesEncrypt(algo, key, plaintext, iv, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cipherfn = new cipher[algo](key);
|
const cipherfn = new cipher[algo](key);
|
||||||
@ -113,7 +112,7 @@ export async function decrypt(algo, key, ciphertext, iv) {
|
|||||||
return stream.transform(ciphertext, process, process);
|
return stream.transform(ciphertext, process, process);
|
||||||
}
|
}
|
||||||
|
|
||||||
function aesEncrypt(algo, key, pt, iv) {
|
function aesEncrypt(algo, key, pt, iv, config) {
|
||||||
if (
|
if (
|
||||||
util.getWebCrypto() &&
|
util.getWebCrypto() &&
|
||||||
key.length !== 24 && // Chrome doesn't support 192 bit keys, see https://www.chromium.org/blink/webcrypto#TOC-AES-support
|
key.length !== 24 && // Chrome doesn't support 192 bit keys, see https://www.chromium.org/blink/webcrypto#TOC-AES-support
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
* @requires hash.js
|
* @requires hash.js
|
||||||
* @requires web-stream-tools
|
* @requires web-stream-tools
|
||||||
* @requires crypto/hash/md5
|
* @requires crypto/hash/md5
|
||||||
* @requires config
|
|
||||||
* @requires util
|
* @requires util
|
||||||
* @module crypto/hash
|
* @module crypto/hash
|
||||||
*/
|
*/
|
||||||
@ -19,8 +18,8 @@ import sha512 from 'hash.js/lib/hash/sha/512';
|
|||||||
import { ripemd160 } from 'hash.js/lib/hash/ripemd';
|
import { ripemd160 } from 'hash.js/lib/hash/ripemd';
|
||||||
import stream from 'web-stream-tools';
|
import stream from 'web-stream-tools';
|
||||||
import md5 from './md5';
|
import md5 from './md5';
|
||||||
import config from '../../config';
|
|
||||||
import util from '../../util';
|
import util from '../../util';
|
||||||
|
import defaultConfig from '../../config';
|
||||||
|
|
||||||
const webCrypto = util.getWebCrypto();
|
const webCrypto = util.getWebCrypto();
|
||||||
const nodeCrypto = util.getNodeCrypto();
|
const nodeCrypto = util.getNodeCrypto();
|
||||||
@ -36,7 +35,7 @@ function node_hash(type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function hashjs_hash(hash, webCryptoHash) {
|
function hashjs_hash(hash, webCryptoHash) {
|
||||||
return async function(data) {
|
return async function(data, config = defaultConfig) {
|
||||||
if (!util.isStream(data) && webCrypto && webCryptoHash && data.length >= config.minBytesForWebCrypto) {
|
if (!util.isStream(data) && webCrypto && webCryptoHash && data.length >= config.minBytesForWebCrypto) {
|
||||||
return new Uint8Array(await webCrypto.digest(webCryptoHash, data));
|
return new Uint8Array(await webCrypto.digest(webCryptoHash, data));
|
||||||
}
|
}
|
||||||
@ -48,7 +47,7 @@ function hashjs_hash(hash, webCryptoHash) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function asmcrypto_hash(hash, webCryptoHash) {
|
function asmcrypto_hash(hash, webCryptoHash) {
|
||||||
return async function(data) {
|
return async function(data, config = defaultConfig) {
|
||||||
if (util.isStream(data)) {
|
if (util.isStream(data)) {
|
||||||
const hashInstance = new hash();
|
const hashInstance = new hash();
|
||||||
return stream.transform(data, value => {
|
return stream.transform(data, value => {
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
|
|
||||||
import { randomProbablePrime } from './prime';
|
import { randomProbablePrime } from './prime';
|
||||||
import { getRandomBigInteger } from '../random';
|
import { getRandomBigInteger } from '../random';
|
||||||
import config from '../../config';
|
|
||||||
import util from '../../util';
|
import util from '../../util';
|
||||||
import { uint8ArrayToB64, b64ToUint8Array } from '../../encoding/base64';
|
import { uint8ArrayToB64, b64ToUint8Array } from '../../encoding/base64';
|
||||||
import { emsaEncode, emeEncode, emeDecode } from '../pkcs1';
|
import { emsaEncode, emeEncode, emeDecode } from '../pkcs1';
|
||||||
@ -528,13 +527,10 @@ async function bnDecrypt(data, n, e, d, p, q, u) {
|
|||||||
const dq = d.mod(q.dec()); // d mod (q-1)
|
const dq = d.mod(q.dec()); // d mod (q-1)
|
||||||
const dp = d.mod(p.dec()); // d mod (p-1)
|
const dp = d.mod(p.dec()); // d mod (p-1)
|
||||||
|
|
||||||
let blinder;
|
const unblinder = (await getRandomBigInteger(new BigInteger(2), n)).mod(n);
|
||||||
let unblinder;
|
const blinder = unblinder.modInv(n).modExp(e, n);
|
||||||
if (config.rsaBlinding) {
|
data = data.mul(blinder).mod(n);
|
||||||
unblinder = (await getRandomBigInteger(new BigInteger(2), n)).mod(n);
|
|
||||||
blinder = unblinder.modInv(n).modExp(e, n);
|
|
||||||
data = data.mul(blinder).mod(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mp = data.modExp(dp, p); // data**{d mod (q-1)} mod p
|
const mp = data.modExp(dp, p); // data**{d mod (q-1)} mod p
|
||||||
const mq = data.modExp(dq, q); // data**{d mod (p-1)} mod q
|
const mq = data.modExp(dq, q); // data**{d mod (p-1)} mod q
|
||||||
@ -542,9 +538,8 @@ async function bnDecrypt(data, n, e, d, p, q, u) {
|
|||||||
|
|
||||||
let result = h.mul(p).add(mp); // result < n due to relations above
|
let result = h.mul(p).add(mp); // result < n due to relations above
|
||||||
|
|
||||||
if (config.rsaBlinding) {
|
result = result.mul(unblinder).mod(n);
|
||||||
result = result.mul(unblinder).mod(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
return emeDecode(result.toUint8Array('be', n.byteLength()));
|
return emeDecode(result.toUint8Array('be', n.byteLength()));
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
|
||||||
// Do not use util.getNodeCrypto because we need this regardless of useNative setting
|
const nodeCrypto = util.getNodeCrypto();
|
||||||
const nodeCrypto = util.detectNode() && require('crypto');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffer for secure random numbers
|
* Buffer for secure random numbers
|
||||||
|
@ -27,8 +27,8 @@
|
|||||||
import stream from 'web-stream-tools';
|
import stream from 'web-stream-tools';
|
||||||
import * as base64 from './base64.js';
|
import * as base64 from './base64.js';
|
||||||
import enums from '../enums.js';
|
import enums from '../enums.js';
|
||||||
import config from '../config';
|
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
import defaultConfig from '../config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds out which Ascii Armoring type is used. Throws error if unknown type.
|
* Finds out which Ascii Armoring type is used. Throws error if unknown type.
|
||||||
@ -100,7 +100,7 @@ function getType(text) {
|
|||||||
* @param {String} customComment (optional) additional comment to add to the armored string
|
* @param {String} customComment (optional) additional comment to add to the armored string
|
||||||
* @returns {String} The header information
|
* @returns {String} The header information
|
||||||
*/
|
*/
|
||||||
function addheader(customComment) {
|
function addheader(customComment, config) {
|
||||||
let result = "";
|
let result = "";
|
||||||
if (config.showVersion) {
|
if (config.showVersion) {
|
||||||
result += "Version: " + config.versionString + '\n';
|
result += "Version: " + config.versionString + '\n';
|
||||||
@ -233,7 +233,7 @@ function splitChecksum(text) {
|
|||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function unarmor(input) {
|
export function unarmor(input, config = defaultConfig) {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const reSplit = /^-----[^-]+-----$/m;
|
const reSplit = /^-----[^-]+-----$/m;
|
||||||
@ -359,7 +359,7 @@ export function unarmor(input) {
|
|||||||
* @returns {String | ReadableStream<String>} Armored text
|
* @returns {String | ReadableStream<String>} Armored text
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function armor(messagetype, body, partindex, parttotal, customComment) {
|
export function armor(messagetype, body, partindex, parttotal, customComment, config = defaultConfig) {
|
||||||
let text;
|
let text;
|
||||||
let hash;
|
let hash;
|
||||||
if (messagetype === enums.armor.signed) {
|
if (messagetype === enums.armor.signed) {
|
||||||
@ -372,14 +372,14 @@ export function armor(messagetype, body, partindex, parttotal, customComment) {
|
|||||||
switch (messagetype) {
|
switch (messagetype) {
|
||||||
case enums.armor.multipartSection:
|
case enums.armor.multipartSection:
|
||||||
result.push("-----BEGIN PGP MESSAGE, PART " + partindex + "/" + parttotal + "-----\n");
|
result.push("-----BEGIN PGP MESSAGE, PART " + partindex + "/" + parttotal + "-----\n");
|
||||||
result.push(addheader(customComment));
|
result.push(addheader(customComment, config));
|
||||||
result.push(base64.encode(body));
|
result.push(base64.encode(body));
|
||||||
result.push("=", getCheckSum(bodyClone));
|
result.push("=", getCheckSum(bodyClone));
|
||||||
result.push("-----END PGP MESSAGE, PART " + partindex + "/" + parttotal + "-----\n");
|
result.push("-----END PGP MESSAGE, PART " + partindex + "/" + parttotal + "-----\n");
|
||||||
break;
|
break;
|
||||||
case enums.armor.multipartLast:
|
case enums.armor.multipartLast:
|
||||||
result.push("-----BEGIN PGP MESSAGE, PART " + partindex + "-----\n");
|
result.push("-----BEGIN PGP MESSAGE, PART " + partindex + "-----\n");
|
||||||
result.push(addheader(customComment));
|
result.push(addheader(customComment, config));
|
||||||
result.push(base64.encode(body));
|
result.push(base64.encode(body));
|
||||||
result.push("=", getCheckSum(bodyClone));
|
result.push("=", getCheckSum(bodyClone));
|
||||||
result.push("-----END PGP MESSAGE, PART " + partindex + "-----\n");
|
result.push("-----END PGP MESSAGE, PART " + partindex + "-----\n");
|
||||||
@ -389,35 +389,35 @@ export function armor(messagetype, body, partindex, parttotal, customComment) {
|
|||||||
result.push("Hash: " + hash + "\n\n");
|
result.push("Hash: " + hash + "\n\n");
|
||||||
result.push(text.replace(/^-/mg, "- -"));
|
result.push(text.replace(/^-/mg, "- -"));
|
||||||
result.push("\n-----BEGIN PGP SIGNATURE-----\n");
|
result.push("\n-----BEGIN PGP SIGNATURE-----\n");
|
||||||
result.push(addheader(customComment));
|
result.push(addheader(customComment, config));
|
||||||
result.push(base64.encode(body));
|
result.push(base64.encode(body));
|
||||||
result.push("=", getCheckSum(bodyClone));
|
result.push("=", getCheckSum(bodyClone));
|
||||||
result.push("-----END PGP SIGNATURE-----\n");
|
result.push("-----END PGP SIGNATURE-----\n");
|
||||||
break;
|
break;
|
||||||
case enums.armor.message:
|
case enums.armor.message:
|
||||||
result.push("-----BEGIN PGP MESSAGE-----\n");
|
result.push("-----BEGIN PGP MESSAGE-----\n");
|
||||||
result.push(addheader(customComment));
|
result.push(addheader(customComment, config));
|
||||||
result.push(base64.encode(body));
|
result.push(base64.encode(body));
|
||||||
result.push("=", getCheckSum(bodyClone));
|
result.push("=", getCheckSum(bodyClone));
|
||||||
result.push("-----END PGP MESSAGE-----\n");
|
result.push("-----END PGP MESSAGE-----\n");
|
||||||
break;
|
break;
|
||||||
case enums.armor.publicKey:
|
case enums.armor.publicKey:
|
||||||
result.push("-----BEGIN PGP PUBLIC KEY BLOCK-----\n");
|
result.push("-----BEGIN PGP PUBLIC KEY BLOCK-----\n");
|
||||||
result.push(addheader(customComment));
|
result.push(addheader(customComment, config));
|
||||||
result.push(base64.encode(body));
|
result.push(base64.encode(body));
|
||||||
result.push("=", getCheckSum(bodyClone));
|
result.push("=", getCheckSum(bodyClone));
|
||||||
result.push("-----END PGP PUBLIC KEY BLOCK-----\n");
|
result.push("-----END PGP PUBLIC KEY BLOCK-----\n");
|
||||||
break;
|
break;
|
||||||
case enums.armor.privateKey:
|
case enums.armor.privateKey:
|
||||||
result.push("-----BEGIN PGP PRIVATE KEY BLOCK-----\n");
|
result.push("-----BEGIN PGP PRIVATE KEY BLOCK-----\n");
|
||||||
result.push(addheader(customComment));
|
result.push(addheader(customComment, config));
|
||||||
result.push(base64.encode(body));
|
result.push(base64.encode(body));
|
||||||
result.push("=", getCheckSum(bodyClone));
|
result.push("=", getCheckSum(bodyClone));
|
||||||
result.push("-----END PGP PRIVATE KEY BLOCK-----\n");
|
result.push("-----END PGP PRIVATE KEY BLOCK-----\n");
|
||||||
break;
|
break;
|
||||||
case enums.armor.signature:
|
case enums.armor.signature:
|
||||||
result.push("-----BEGIN PGP SIGNATURE-----\n");
|
result.push("-----BEGIN PGP SIGNATURE-----\n");
|
||||||
result.push(addheader(customComment));
|
result.push(addheader(customComment, config));
|
||||||
result.push(base64.encode(body));
|
result.push(base64.encode(body));
|
||||||
result.push("=", getCheckSum(bodyClone));
|
result.push("=", getCheckSum(bodyClone));
|
||||||
result.push("-----END PGP SIGNATURE-----\n");
|
result.push("-----END PGP SIGNATURE-----\n");
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
* @module hkp
|
* @module hkp
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import config from './config';
|
import defaultConfig from './config';
|
||||||
|
|
||||||
class HKP {
|
class HKP {
|
||||||
/**
|
/**
|
||||||
@ -29,8 +29,9 @@ class HKP {
|
|||||||
* @param {String} keyServerBaseUrl (optional) The HKP key server base url including
|
* @param {String} keyServerBaseUrl (optional) The HKP key server base url including
|
||||||
* the protocol to use, e.g. 'https://pgp.mit.edu'; defaults to
|
* the protocol to use, e.g. 'https://pgp.mit.edu'; defaults to
|
||||||
* openpgp.config.keyserver (https://keyserver.ubuntu.com)
|
* openpgp.config.keyserver (https://keyserver.ubuntu.com)
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
*/
|
*/
|
||||||
constructor(keyServerBaseUrl) {
|
constructor(keyServerBaseUrl, config = defaultConfig) {
|
||||||
this._baseUrl = keyServerBaseUrl || config.keyserver;
|
this._baseUrl = keyServerBaseUrl || config.keyserver;
|
||||||
this._fetch = typeof globalThis.fetch === 'function' ? globalThis.fetch : require('node-fetch');
|
this._fetch = typeof globalThis.fetch === 'function' ? globalThis.fetch : require('node-fetch');
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ import Key from './key';
|
|||||||
import * as helper from './helper';
|
import * as helper from './helper';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
import config from '../config';
|
import defaultConfig from '../config';
|
||||||
import { unarmor } from '../encoding/armor';
|
import { unarmor } from '../encoding/armor';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,20 +45,20 @@ import { unarmor } from '../encoding/armor';
|
|||||||
* @param {String} options.passphrase Passphrase used to encrypt the resulting private key
|
* @param {String} options.passphrase Passphrase used to encrypt the resulting private key
|
||||||
* @param {Number} options.keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires
|
* @param {Number} options.keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires
|
||||||
* @param {Date} options.date Creation date of the key and the key signatures
|
* @param {Date} options.date Creation date of the key and the key signatures
|
||||||
|
* @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<module:key.Key>}
|
* @returns {Promise<module:key.Key>}
|
||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export async function generate(options) {
|
export async function generate(options, config) {
|
||||||
options.sign = true; // primary key is always a signing key
|
options.sign = true; // primary key is always a signing key
|
||||||
options = helper.sanitizeKeyOptions(options);
|
options = helper.sanitizeKeyOptions(options);
|
||||||
options.subkeys = options.subkeys.map(function(subkey, index) { return 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)];
|
promises = promises.concat(options.subkeys.map(options => helper.generateSecretSubkey(options, config)));
|
||||||
promises = promises.concat(options.subkeys.map(helper.generateSecretSubkey));
|
return Promise.all(promises).then(packets => wrapKeyObject(packets[0], packets.slice(1), options, config));
|
||||||
return Promise.all(promises).then(packets => wrapKeyObject(packets[0], packets.slice(1), options));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,12 +69,13 @@ export async function generate(options) {
|
|||||||
* @param {Number} options.keyExpirationTime Number of seconds from the key creation time after which the key expires
|
* @param {Number} options.keyExpirationTime Number of seconds from the key creation time after which the key expires
|
||||||
* @param {Date} options.date Override the creation date of the key and the key signatures
|
* @param {Date} options.date Override the creation date of the key and the key signatures
|
||||||
* @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
|
||||||
*
|
*
|
||||||
* @returns {Promise<module:key.Key>}
|
* @returns {Promise<module:key.Key>}
|
||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export async function reformat(options) {
|
export async function reformat(options, config) {
|
||||||
options = sanitize(options);
|
options = sanitize(options);
|
||||||
|
|
||||||
if (options.privateKey.primaryKey.isDummy()) {
|
if (options.privateKey.primaryKey.isDummy()) {
|
||||||
@ -102,8 +103,8 @@ export async function reformat(options) {
|
|||||||
|
|
||||||
if (!options.subkeys) {
|
if (!options.subkeys) {
|
||||||
options.subkeys = await Promise.all(secretSubkeyPackets.map(async secretSubkeyPacket => ({
|
options.subkeys = await Promise.all(secretSubkeyPackets.map(async secretSubkeyPacket => ({
|
||||||
sign: await options.privateKey.getSigningKey(secretSubkeyPacket.getKeyId(), null).catch(() => {}) &&
|
sign: await options.privateKey.getSigningKey(secretSubkeyPacket.getKeyId(), null, undefined, config).catch(() => {}) &&
|
||||||
!await options.privateKey.getEncryptionKey(secretSubkeyPacket.getKeyId(), null).catch(() => {})
|
!await options.privateKey.getEncryptionKey(secretSubkeyPacket.getKeyId(), null, undefined, config).catch(() => {})
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +114,7 @@ export async function reformat(options) {
|
|||||||
|
|
||||||
options.subkeys = options.subkeys.map(function(subkey, index) { return sanitize(options.subkeys[index], options); });
|
options.subkeys = options.subkeys.map(function(subkey, index) { return sanitize(options.subkeys[index], options); });
|
||||||
|
|
||||||
return wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options);
|
return wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, config);
|
||||||
|
|
||||||
function sanitize(options, subkeyDefaults = {}) {
|
function sanitize(options, subkeyDefaults = {}) {
|
||||||
options.keyExpirationTime = options.keyExpirationTime || subkeyDefaults.keyExpirationTime;
|
options.keyExpirationTime = options.keyExpirationTime || subkeyDefaults.keyExpirationTime;
|
||||||
@ -125,16 +126,16 @@ export async function reformat(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options) {
|
async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, config) {
|
||||||
// set passphrase protection
|
// set passphrase protection
|
||||||
if (options.passphrase) {
|
if (options.passphrase) {
|
||||||
await secretKeyPacket.encrypt(options.passphrase);
|
await secretKeyPacket.encrypt(options.passphrase, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(secretSubkeyPackets.map(async function(secretSubkeyPacket, index) {
|
await Promise.all(secretSubkeyPackets.map(async function(secretSubkeyPacket, index) {
|
||||||
const subkeyPassphrase = options.subkeys[index].passphrase;
|
const subkeyPassphrase = options.subkeys[index].passphrase;
|
||||||
if (subkeyPassphrase) {
|
if (subkeyPassphrase) {
|
||||||
await secretSubkeyPacket.encrypt(subkeyPassphrase);
|
await secretSubkeyPacket.encrypt(subkeyPassphrase, config);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -163,7 +164,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options) {
|
|||||||
const signaturePacket = new SignaturePacket(options.date);
|
const signaturePacket = new SignaturePacket(options.date);
|
||||||
signaturePacket.signatureType = enums.signature.certGeneric;
|
signaturePacket.signatureType = enums.signature.certGeneric;
|
||||||
signaturePacket.publicKeyAlgorithm = secretKeyPacket.algorithm;
|
signaturePacket.publicKeyAlgorithm = secretKeyPacket.algorithm;
|
||||||
signaturePacket.hashAlgorithm = await helper.getPreferredHashAlgo(null, secretKeyPacket);
|
signaturePacket.hashAlgorithm = await helper.getPreferredHashAlgo(null, secretKeyPacket, undefined, undefined, config);
|
||||||
signaturePacket.keyFlags = [enums.keyFlags.certifyKeys | enums.keyFlags.signData];
|
signaturePacket.keyFlags = [enums.keyFlags.certifyKeys | enums.keyFlags.signData];
|
||||||
signaturePacket.preferredSymmetricAlgorithms = createdPreferredAlgos([
|
signaturePacket.preferredSymmetricAlgorithms = createdPreferredAlgos([
|
||||||
// prefer aes256, aes128, then aes192 (no WebCrypto support: https://www.chromium.org/blink/webcrypto#TOC-AES-support)
|
// prefer aes256, aes128, then aes192 (no WebCrypto support: https://www.chromium.org/blink/webcrypto#TOC-AES-support)
|
||||||
@ -218,7 +219,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options) {
|
|||||||
|
|
||||||
await Promise.all(secretSubkeyPackets.map(async function(secretSubkeyPacket, index) {
|
await Promise.all(secretSubkeyPackets.map(async function(secretSubkeyPacket, index) {
|
||||||
const subkeyOptions = options.subkeys[index];
|
const subkeyOptions = options.subkeys[index];
|
||||||
const subkeySignaturePacket = await helper.createBindingSignature(secretSubkeyPacket, secretKeyPacket, subkeyOptions);
|
const subkeySignaturePacket = await helper.createBindingSignature(secretSubkeyPacket, secretKeyPacket, subkeyOptions, config);
|
||||||
return { secretSubkeyPacket, subkeySignaturePacket };
|
return { secretSubkeyPacket, subkeySignaturePacket };
|
||||||
})).then(packets => {
|
})).then(packets => {
|
||||||
packets.forEach(({ secretSubkeyPacket, subkeySignaturePacket }) => {
|
packets.forEach(({ secretSubkeyPacket, subkeySignaturePacket }) => {
|
||||||
@ -234,7 +235,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options) {
|
|||||||
signatureType: enums.signature.keyRevocation,
|
signatureType: enums.signature.keyRevocation,
|
||||||
reasonForRevocationFlag: enums.reasonForRevocation.noReason,
|
reasonForRevocationFlag: enums.reasonForRevocation.noReason,
|
||||||
reasonForRevocationString: ''
|
reasonForRevocationString: ''
|
||||||
}, options.date));
|
}, options.date, undefined, undefined, undefined, config));
|
||||||
|
|
||||||
// set passphrase protection
|
// set passphrase protection
|
||||||
if (options.passphrase) {
|
if (options.passphrase) {
|
||||||
@ -255,17 +256,19 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options) {
|
|||||||
* Reads an (optionally armored) OpenPGP key and returns a key object
|
* Reads an (optionally armored) OpenPGP key and returns a key object
|
||||||
* @param {String} armoredKey armored key to be parsed
|
* @param {String} armoredKey armored key to be parsed
|
||||||
* @param {Uint8Array} binaryKey binary key to be parsed
|
* @param {Uint8Array} binaryKey binary key to be parsed
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Promise<Key>} key object
|
* @returns {Promise<Key>} key object
|
||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export async function readKey({ armoredKey, binaryKey }) {
|
export async function readKey({ armoredKey, binaryKey, config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
if (!armoredKey && !binaryKey) {
|
if (!armoredKey && !binaryKey) {
|
||||||
throw new Error('readKey: must pass options object containing `armoredKey` or `binaryKey`');
|
throw new Error('readKey: must pass options object containing `armoredKey` or `binaryKey`');
|
||||||
}
|
}
|
||||||
let input;
|
let input;
|
||||||
if (armoredKey) {
|
if (armoredKey) {
|
||||||
const { type, data } = await unarmor(armoredKey);
|
const { type, data } = await unarmor(armoredKey, config);
|
||||||
if (!(type === enums.armor.publicKey || type === enums.armor.privateKey)) {
|
if (!(type === enums.armor.publicKey || type === enums.armor.privateKey)) {
|
||||||
throw new Error('Armored text not of type key');
|
throw new Error('Armored text not of type key');
|
||||||
}
|
}
|
||||||
@ -274,7 +277,7 @@ export async function readKey({ armoredKey, binaryKey }) {
|
|||||||
input = binaryKey;
|
input = binaryKey;
|
||||||
}
|
}
|
||||||
const packetlist = new PacketList();
|
const packetlist = new PacketList();
|
||||||
await packetlist.read(input, helper.allowedKeyPackets);
|
await packetlist.read(input, helper.allowedKeyPackets, undefined, config);
|
||||||
return new Key(packetlist);
|
return new Key(packetlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,17 +285,19 @@ export async function readKey({ armoredKey, binaryKey }) {
|
|||||||
* Reads an (optionally armored) OpenPGP key block and returns a list of key objects
|
* Reads an (optionally armored) OpenPGP key block and returns a list of key objects
|
||||||
* @param {String | ReadableStream<String>} armoredKeys armored keys to be parsed
|
* @param {String | ReadableStream<String>} armoredKeys armored keys to be parsed
|
||||||
* @param {Uint8Array | ReadableStream<Uint8Array>} binaryKeys binary keys to be parsed
|
* @param {Uint8Array | ReadableStream<Uint8Array>} binaryKeys binary keys to be parsed
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Promise<Array<Key>>} key objects
|
* @returns {Promise<Array<Key>>} key objects
|
||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export async function readKeys({ armoredKeys, binaryKeys }) {
|
export async function readKeys({ armoredKeys, binaryKeys, config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
let input = armoredKeys || binaryKeys;
|
let input = armoredKeys || binaryKeys;
|
||||||
if (!input) {
|
if (!input) {
|
||||||
throw new Error('readKeys: must pass options object containing `armoredKeys` or `binaryKeys`');
|
throw new Error('readKeys: must pass options object containing `armoredKeys` or `binaryKeys`');
|
||||||
}
|
}
|
||||||
if (armoredKeys) {
|
if (armoredKeys) {
|
||||||
const { type, data } = await unarmor(armoredKeys);
|
const { type, data } = await unarmor(armoredKeys, config);
|
||||||
if (type !== enums.armor.publicKey && type !== enums.armor.privateKey) {
|
if (type !== enums.armor.publicKey && type !== enums.armor.privateKey) {
|
||||||
throw new Error('Armored text not of type key');
|
throw new Error('Armored text not of type key');
|
||||||
}
|
}
|
||||||
@ -300,7 +305,7 @@ export async function readKeys({ armoredKeys, binaryKeys }) {
|
|||||||
}
|
}
|
||||||
const keys = [];
|
const keys = [];
|
||||||
const packetlist = new PacketList();
|
const packetlist = new PacketList();
|
||||||
await packetlist.read(input, helper.allowedKeyPackets);
|
await packetlist.read(input, helper.allowedKeyPackets, undefined, config);
|
||||||
const keyIndex = packetlist.indexOfTag(enums.packet.publicKey, enums.packet.secretKey);
|
const keyIndex = packetlist.indexOfTag(enums.packet.publicKey, enums.packet.secretKey);
|
||||||
if (keyIndex.length === 0) {
|
if (keyIndex.length === 0) {
|
||||||
throw new Error('No key packet found');
|
throw new Error('No key packet found');
|
||||||
|
@ -17,9 +17,9 @@ import {
|
|||||||
SignaturePacket
|
SignaturePacket
|
||||||
} from '../packet';
|
} from '../packet';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import config from '../config';
|
|
||||||
import crypto from '../crypto';
|
import crypto from '../crypto';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
import defaultConfig from '../config';
|
||||||
|
|
||||||
export const allowedKeyPackets = {
|
export const allowedKeyPackets = {
|
||||||
PublicKeyPacket,
|
PublicKeyPacket,
|
||||||
@ -31,19 +31,19 @@ export const allowedKeyPackets = {
|
|||||||
SignaturePacket
|
SignaturePacket
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function generateSecretSubkey(options) {
|
export async function generateSecretSubkey(options, config) {
|
||||||
const secretSubkeyPacket = new SecretSubkeyPacket(options.date);
|
const secretSubkeyPacket = new SecretSubkeyPacket(options.date, config);
|
||||||
secretSubkeyPacket.packets = null;
|
secretSubkeyPacket.packets = null;
|
||||||
secretSubkeyPacket.algorithm = enums.read(enums.publicKey, options.algorithm);
|
secretSubkeyPacket.algorithm = enums.read(enums.publicKey, options.algorithm);
|
||||||
await secretSubkeyPacket.generate(options.rsaBits, options.curve);
|
await secretSubkeyPacket.generate(options.rsaBits, options.curve);
|
||||||
return secretSubkeyPacket;
|
return secretSubkeyPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateSecretKey(options) {
|
export async function generateSecretKey(options, config) {
|
||||||
const secretKeyPacket = new SecretKeyPacket(options.date);
|
const secretKeyPacket = new SecretKeyPacket(options.date, config);
|
||||||
secretKeyPacket.packets = null;
|
secretKeyPacket.packets = null;
|
||||||
secretKeyPacket.algorithm = enums.read(enums.publicKey, options.algorithm);
|
secretKeyPacket.algorithm = enums.read(enums.publicKey, options.algorithm);
|
||||||
await secretKeyPacket.generate(options.rsaBits, options.curve);
|
await secretKeyPacket.generate(options.rsaBits, options.curve, options.config);
|
||||||
return secretKeyPacket;
|
return secretKeyPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,10 +51,11 @@ export async function generateSecretKey(options) {
|
|||||||
* Returns the valid and non-expired signature that has the latest creation date, while ignoring signatures created in the future.
|
* Returns the valid and non-expired signature that has the latest creation date, while ignoring signatures created in the future.
|
||||||
* @param {Array<SignaturePacket>} signatures List of signatures
|
* @param {Array<SignaturePacket>} signatures List of signatures
|
||||||
* @param {Date} date Use the given date instead of the current time
|
* @param {Date} date Use the given date instead of the current time
|
||||||
|
* @param {Object} config full configuration
|
||||||
* @returns {Promise<SignaturePacket>} The latest valid signature
|
* @returns {Promise<SignaturePacket>} The latest valid signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function getLatestValidSignature(signatures, primaryKey, signatureType, dataToVerify, date = new Date()) {
|
export async function getLatestValidSignature(signatures, primaryKey, signatureType, dataToVerify, date = new Date(), config) {
|
||||||
let signature;
|
let signature;
|
||||||
let exception;
|
let exception;
|
||||||
for (let i = signatures.length - 1; i >= 0; i--) {
|
for (let i = signatures.length - 1; i >= 0; i--) {
|
||||||
@ -65,7 +66,7 @@ export async function getLatestValidSignature(signatures, primaryKey, signatureT
|
|||||||
!signatures[i].isExpired(date)
|
!signatures[i].isExpired(date)
|
||||||
) {
|
) {
|
||||||
// check binding signature is verified
|
// check binding signature is verified
|
||||||
signatures[i].verified || await signatures[i].verify(primaryKey, signatureType, dataToVerify);
|
signatures[i].verified || await signatures[i].verify(primaryKey, signatureType, dataToVerify, undefined, undefined, config);
|
||||||
signature = signatures[i];
|
signature = signatures[i];
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -97,20 +98,21 @@ export function isDataExpired(keyPacket, signature, date = new Date()) {
|
|||||||
* @param {SecretSubkeyPacket} subkey Subkey key packet
|
* @param {SecretSubkeyPacket} subkey Subkey key packet
|
||||||
* @param {SecretKeyPacket} primaryKey Primary key packet
|
* @param {SecretKeyPacket} primaryKey Primary key packet
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
|
* @param {Object} config full configuration
|
||||||
*/
|
*/
|
||||||
export async function createBindingSignature(subkey, primaryKey, options) {
|
export async function createBindingSignature(subkey, primaryKey, options, config) {
|
||||||
const dataToSign = {};
|
const dataToSign = {};
|
||||||
dataToSign.key = primaryKey;
|
dataToSign.key = primaryKey;
|
||||||
dataToSign.bind = subkey;
|
dataToSign.bind = subkey;
|
||||||
const subkeySignaturePacket = new SignaturePacket(options.date);
|
const subkeySignaturePacket = new SignaturePacket(options.date);
|
||||||
subkeySignaturePacket.signatureType = enums.signature.subkeyBinding;
|
subkeySignaturePacket.signatureType = enums.signature.subkeyBinding;
|
||||||
subkeySignaturePacket.publicKeyAlgorithm = primaryKey.algorithm;
|
subkeySignaturePacket.publicKeyAlgorithm = primaryKey.algorithm;
|
||||||
subkeySignaturePacket.hashAlgorithm = await getPreferredHashAlgo(null, subkey);
|
subkeySignaturePacket.hashAlgorithm = await getPreferredHashAlgo(null, subkey, undefined, undefined, config);
|
||||||
if (options.sign) {
|
if (options.sign) {
|
||||||
subkeySignaturePacket.keyFlags = [enums.keyFlags.signData];
|
subkeySignaturePacket.keyFlags = [enums.keyFlags.signData];
|
||||||
subkeySignaturePacket.embeddedSignature = await createSignaturePacket(dataToSign, null, subkey, {
|
subkeySignaturePacket.embeddedSignature = await createSignaturePacket(dataToSign, null, subkey, {
|
||||||
signatureType: enums.signature.keyBinding
|
signatureType: enums.signature.keyBinding
|
||||||
}, options.date);
|
}, options.date, undefined, undefined, undefined, config);
|
||||||
} else {
|
} else {
|
||||||
subkeySignaturePacket.keyFlags = [enums.keyFlags.encryptCommunication | enums.keyFlags.encryptStorage];
|
subkeySignaturePacket.keyFlags = [enums.keyFlags.encryptCommunication | enums.keyFlags.encryptStorage];
|
||||||
}
|
}
|
||||||
@ -128,14 +130,15 @@ export async function createBindingSignature(subkey, primaryKey, options) {
|
|||||||
* @param {SecretKeyPacket|SecretSubkeyPacket} keyPacket key packet used for signing
|
* @param {SecretKeyPacket|SecretSubkeyPacket} keyPacket key packet used for signing
|
||||||
* @param {Date} date (optional) use the given date for verification instead of the current time
|
* @param {Date} date (optional) use the given date for verification instead of the current time
|
||||||
* @param {Object} userId (optional) user ID
|
* @param {Object} userId (optional) user ID
|
||||||
|
* @param {Object} config full configuration
|
||||||
* @returns {Promise<String>}
|
* @returns {Promise<String>}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function getPreferredHashAlgo(key, keyPacket, date = new Date(), userId = {}) {
|
export async function getPreferredHashAlgo(key, keyPacket, date = new Date(), userId = {}, config) {
|
||||||
let hash_algo = config.preferHashAlgorithm;
|
let hash_algo = config.preferHashAlgorithm;
|
||||||
let pref_algo = hash_algo;
|
let pref_algo = hash_algo;
|
||||||
if (key) {
|
if (key) {
|
||||||
const primaryUser = await key.getPrimaryUser(date, userId);
|
const primaryUser = await key.getPrimaryUser(date, userId, config);
|
||||||
if (primaryUser.selfCertification.preferredHashAlgorithms) {
|
if (primaryUser.selfCertification.preferredHashAlgorithms) {
|
||||||
[pref_algo] = primaryUser.selfCertification.preferredHashAlgorithms;
|
[pref_algo] = primaryUser.selfCertification.preferredHashAlgorithms;
|
||||||
hash_algo = crypto.hash.getHashByteLength(hash_algo) <= crypto.hash.getHashByteLength(pref_algo) ?
|
hash_algo = crypto.hash.getHashByteLength(hash_algo) <= crypto.hash.getHashByteLength(pref_algo) ?
|
||||||
@ -164,15 +167,16 @@ export async function getPreferredHashAlgo(key, keyPacket, date = new Date(), us
|
|||||||
* @param {Array<module:key.Key>} keys Set of keys
|
* @param {Array<module:key.Key>} keys Set of keys
|
||||||
* @param {Date} date (optional) use the given date for verification instead of the current time
|
* @param {Date} date (optional) use the given date for verification instead of the current time
|
||||||
* @param {Array} userIds (optional) user IDs
|
* @param {Array} userIds (optional) user IDs
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<module:enums.symmetric>} Preferred symmetric algorithm
|
* @returns {Promise<module:enums.symmetric>} Preferred symmetric algorithm
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function getPreferredAlgo(type, keys, date = new Date(), userIds = []) {
|
export async function getPreferredAlgo(type, keys, date = new Date(), userIds = [], config = defaultConfig) {
|
||||||
const prefProperty = type === 'symmetric' ? 'preferredSymmetricAlgorithms' : 'preferredAeadAlgorithms';
|
const prefProperty = type === 'symmetric' ? 'preferredSymmetricAlgorithms' : 'preferredAeadAlgorithms';
|
||||||
const defaultAlgo = type === 'symmetric' ? enums.symmetric.aes128 : enums.aead.eax;
|
const defaultAlgo = type === 'symmetric' ? enums.symmetric.aes128 : enums.aead.eax;
|
||||||
const prioMap = {};
|
const prioMap = {};
|
||||||
await Promise.all(keys.map(async function(key, i) {
|
await Promise.all(keys.map(async function(key, i) {
|
||||||
const primaryUser = await key.getPrimaryUser(date, userIds[i]);
|
const primaryUser = await key.getPrimaryUser(date, userIds[i], config);
|
||||||
if (!primaryUser.selfCertification[prefProperty]) {
|
if (!primaryUser.selfCertification[prefProperty]) {
|
||||||
return defaultAlgo;
|
return defaultAlgo;
|
||||||
}
|
}
|
||||||
@ -207,9 +211,10 @@ export async function getPreferredAlgo(type, keys, date = new Date(), userIds =
|
|||||||
* @param {Object} userId (optional) user ID
|
* @param {Object} userId (optional) user ID
|
||||||
* @param {Object} detached (optional) whether to create a detached signature packet
|
* @param {Object} detached (optional) whether to create a detached signature packet
|
||||||
* @param {Boolean} streaming (optional) whether to process data as a stream
|
* @param {Boolean} streaming (optional) whether to process data as a stream
|
||||||
|
* @param {Object} config full configuration
|
||||||
* @returns {module:packet/signature} signature packet
|
* @returns {module:packet/signature} signature packet
|
||||||
*/
|
*/
|
||||||
export async function createSignaturePacket(dataToSign, privateKey, signingKeyPacket, signatureProperties, date, userId, detached = false, streaming = false) {
|
export async function createSignaturePacket(dataToSign, privateKey, signingKeyPacket, signatureProperties, date, userId, detached = false, streaming = false, config) {
|
||||||
if (signingKeyPacket.isDummy()) {
|
if (signingKeyPacket.isDummy()) {
|
||||||
throw new Error('Cannot sign with a gnu-dummy key.');
|
throw new Error('Cannot sign with a gnu-dummy key.');
|
||||||
}
|
}
|
||||||
@ -219,7 +224,7 @@ export async function createSignaturePacket(dataToSign, privateKey, signingKeyPa
|
|||||||
const signaturePacket = new SignaturePacket(date);
|
const signaturePacket = new SignaturePacket(date);
|
||||||
Object.assign(signaturePacket, signatureProperties);
|
Object.assign(signaturePacket, signatureProperties);
|
||||||
signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
|
signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
|
||||||
signaturePacket.hashAlgorithm = await getPreferredHashAlgo(privateKey, signingKeyPacket, date, userId);
|
signaturePacket.hashAlgorithm = await getPreferredHashAlgo(privateKey, signingKeyPacket, date, userId, config);
|
||||||
await signaturePacket.sign(signingKeyPacket, dataToSign, detached, streaming);
|
await signaturePacket.sign(signingKeyPacket, dataToSign, detached, streaming);
|
||||||
return signaturePacket;
|
return signaturePacket;
|
||||||
}
|
}
|
||||||
@ -262,10 +267,11 @@ export async function mergeSignatures(source, dest, attr, checkFn) {
|
|||||||
* PublicKeyPacket|
|
* PublicKeyPacket|
|
||||||
* SecretKeyPacket} key, optional The key packet to check the signature
|
* SecretKeyPacket} key, optional The key packet to check the signature
|
||||||
* @param {Date} date Use the given date instead of the current time
|
* @param {Date} date Use the given date instead of the current time
|
||||||
|
* @param {Object} config full configuration
|
||||||
* @returns {Promise<Boolean>} True if the signature revokes the data
|
* @returns {Promise<Boolean>} True if the signature revokes the data
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function isDataRevoked(primaryKey, signatureType, dataToVerify, revocations, signature, key, date = new Date()) {
|
export async function isDataRevoked(primaryKey, signatureType, dataToVerify, revocations, signature, key, date = new Date(), config) {
|
||||||
key = key || primaryKey;
|
key = key || primaryKey;
|
||||||
const normDate = util.normalizeDate(date);
|
const normDate = util.normalizeDate(date);
|
||||||
const revocationKeyIds = [];
|
const revocationKeyIds = [];
|
||||||
@ -283,7 +289,7 @@ export async function isDataRevoked(primaryKey, signatureType, dataToVerify, rev
|
|||||||
(!signature || revocationSignature.issuerKeyId.equals(signature.issuerKeyId)) &&
|
(!signature || revocationSignature.issuerKeyId.equals(signature.issuerKeyId)) &&
|
||||||
!(config.revocationsExpire && revocationSignature.isExpired(normDate))
|
!(config.revocationsExpire && revocationSignature.isExpired(normDate))
|
||||||
) {
|
) {
|
||||||
revocationSignature.verified || await revocationSignature.verify(key, signatureType, dataToVerify);
|
revocationSignature.verified || await revocationSignature.verify(key, signatureType, dataToVerify, undefined, undefined, config);
|
||||||
|
|
||||||
// TODO get an identifier of the revoked object instead
|
// TODO get an identifier of the revoked object instead
|
||||||
revocationKeyIds.push(revocationSignature.issuerKeyId);
|
revocationKeyIds.push(revocationSignature.issuerKeyId);
|
||||||
@ -313,14 +319,15 @@ export function getExpirationTime(keyPacket, signature) {
|
|||||||
* @param {Array<module:key.Key>} keys Set of keys
|
* @param {Array<module:key.Key>} keys Set of keys
|
||||||
* @param {Date} date (optional) use the given date for verification instead of the current time
|
* @param {Date} date (optional) use the given date for verification instead of the current time
|
||||||
* @param {Array} userIds (optional) user IDs
|
* @param {Array} userIds (optional) user IDs
|
||||||
|
* @param {Object} config full configuration
|
||||||
* @returns {Promise<Boolean>}
|
* @returns {Promise<Boolean>}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function isAeadSupported(keys, date = new Date(), userIds = []) {
|
export async function isAeadSupported(keys, date = new Date(), userIds = [], config = defaultConfig) {
|
||||||
let supported = true;
|
let supported = true;
|
||||||
// TODO replace when Promise.some or Promise.any are implemented
|
// TODO replace when Promise.some or Promise.any are implemented
|
||||||
await Promise.all(keys.map(async function(key, i) {
|
await Promise.all(keys.map(async function(key, i) {
|
||||||
const primaryUser = await key.getPrimaryUser(date, userIds[i]);
|
const primaryUser = await key.getPrimaryUser(date, userIds[i], config);
|
||||||
if (!primaryUser.selfCertification.features ||
|
if (!primaryUser.selfCertification.features ||
|
||||||
!(primaryUser.selfCertification.features[0] & enums.features.aead)) {
|
!(primaryUser.selfCertification.features[0] & enums.features.aead)) {
|
||||||
supported = false;
|
supported = false;
|
||||||
@ -388,7 +395,7 @@ export function isValidEncryptionKeyPacket(keyPacket, signature) {
|
|||||||
(signature.keyFlags[0] & enums.keyFlags.encryptStorage) !== 0);
|
(signature.keyFlags[0] & enums.keyFlags.encryptStorage) !== 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isValidDecryptionKeyPacket(signature) {
|
export function isValidDecryptionKeyPacket(signature, config) {
|
||||||
if (!signature.verified) { // Sanity check
|
if (!signature.verified) { // Sanity check
|
||||||
throw new Error('Signature not verified');
|
throw new Error('Signature not verified');
|
||||||
}
|
}
|
||||||
|
159
src/key/key.js
159
src/key/key.js
@ -32,7 +32,7 @@ import {
|
|||||||
PublicSubkeyPacket,
|
PublicSubkeyPacket,
|
||||||
SignaturePacket
|
SignaturePacket
|
||||||
} from '../packet';
|
} from '../packet';
|
||||||
import config from '../config';
|
import defaultConfig from '../config';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
import User from './user';
|
import User from './user';
|
||||||
@ -239,6 +239,7 @@ class Key {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns key as public key (shallow copy)
|
* Returns key as public key (shallow copy)
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {module:key.Key} new public Key
|
* @returns {module:key.Key} new public Key
|
||||||
*/
|
*/
|
||||||
toPublic() {
|
toPublic() {
|
||||||
@ -270,11 +271,12 @@ class Key {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns ASCII armored text of key
|
* Returns ASCII armored text of key
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {ReadableStream<String>} ASCII armor
|
* @returns {ReadableStream<String>} ASCII armor
|
||||||
*/
|
*/
|
||||||
armor() {
|
armor(config = defaultConfig) {
|
||||||
const type = this.isPublic() ? enums.armor.publicKey : enums.armor.privateKey;
|
const type = this.isPublic() ? enums.armor.publicKey : enums.armor.privateKey;
|
||||||
return armor(type, this.toPacketlist().write());
|
return armor(type, this.toPacketlist().write(), undefined, undefined, undefined, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -282,25 +284,26 @@ class Key {
|
|||||||
* @param {module:type/keyid} keyId, optional
|
* @param {module:type/keyid} keyId, optional
|
||||||
* @param {Date} date (optional) use the given date for verification instead of the current time
|
* @param {Date} date (optional) use the given date for verification instead of the current time
|
||||||
* @param {Object} userId, optional user ID
|
* @param {Object} userId, optional user ID
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<module:key.Key|module:key~SubKey|null>} key or null if no signing key has been found
|
* @returns {Promise<module:key.Key|module:key~SubKey|null>} key or null if no signing key has been found
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async getSigningKey(keyId = null, date = new Date(), userId = {}) {
|
async getSigningKey(keyId = null, date = new Date(), userId = {}, config = defaultConfig) {
|
||||||
await this.verifyPrimaryKey(date, userId);
|
await this.verifyPrimaryKey(date, userId, config);
|
||||||
const primaryKey = this.keyPacket;
|
const primaryKey = this.keyPacket;
|
||||||
const subKeys = this.subKeys.slice().sort((a, b) => b.keyPacket.created - a.keyPacket.created);
|
const subKeys = this.subKeys.slice().sort((a, b) => b.keyPacket.created - a.keyPacket.created);
|
||||||
let exception;
|
let exception;
|
||||||
for (let i = 0; i < subKeys.length; i++) {
|
for (let i = 0; i < subKeys.length; i++) {
|
||||||
if (!keyId || subKeys[i].getKeyId().equals(keyId)) {
|
if (!keyId || subKeys[i].getKeyId().equals(keyId)) {
|
||||||
try {
|
try {
|
||||||
await subKeys[i].verify(primaryKey, date);
|
await subKeys[i].verify(primaryKey, date, config);
|
||||||
const dataToVerify = { key: primaryKey, bind: subKeys[i].keyPacket };
|
const dataToVerify = { key: primaryKey, bind: subKeys[i].keyPacket };
|
||||||
const bindingSignature = await helper.getLatestValidSignature(subKeys[i].bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date);
|
const bindingSignature = await helper.getLatestValidSignature(subKeys[i].bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config);
|
||||||
if (
|
if (
|
||||||
bindingSignature &&
|
bindingSignature &&
|
||||||
bindingSignature.embeddedSignature &&
|
bindingSignature.embeddedSignature &&
|
||||||
helper.isValidSigningKeyPacket(subKeys[i].keyPacket, bindingSignature) &&
|
helper.isValidSigningKeyPacket(subKeys[i].keyPacket, bindingSignature) &&
|
||||||
await helper.getLatestValidSignature([bindingSignature.embeddedSignature], subKeys[i].keyPacket, enums.signature.keyBinding, dataToVerify, date)
|
await helper.getLatestValidSignature([bindingSignature.embeddedSignature], subKeys[i].keyPacket, enums.signature.keyBinding, dataToVerify, date, config)
|
||||||
) {
|
) {
|
||||||
return subKeys[i];
|
return subKeys[i];
|
||||||
}
|
}
|
||||||
@ -309,7 +312,7 @@ class Key {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const primaryUser = await this.getPrimaryUser(date, userId);
|
const primaryUser = await this.getPrimaryUser(date, userId, config);
|
||||||
if ((!keyId || primaryKey.getKeyId().equals(keyId)) &&
|
if ((!keyId || primaryKey.getKeyId().equals(keyId)) &&
|
||||||
helper.isValidSigningKeyPacket(primaryKey, primaryUser.selfCertification)) {
|
helper.isValidSigningKeyPacket(primaryKey, primaryUser.selfCertification)) {
|
||||||
return this;
|
return this;
|
||||||
@ -322,11 +325,12 @@ class Key {
|
|||||||
* @param {module:type/keyid} keyId, optional
|
* @param {module:type/keyid} keyId, optional
|
||||||
* @param {Date} date, optional
|
* @param {Date} date, optional
|
||||||
* @param {String} userId, optional
|
* @param {String} userId, optional
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<module:key.Key|module:key~SubKey|null>} key or null if no encryption key has been found
|
* @returns {Promise<module:key.Key|module:key~SubKey|null>} key or null if no encryption key has been found
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async getEncryptionKey(keyId, date = new Date(), userId = {}) {
|
async getEncryptionKey(keyId, date = new Date(), userId = {}, config = defaultConfig) {
|
||||||
await this.verifyPrimaryKey(date, userId);
|
await this.verifyPrimaryKey(date, userId, config);
|
||||||
const primaryKey = this.keyPacket;
|
const primaryKey = this.keyPacket;
|
||||||
// V4: by convention subkeys are preferred for encryption service
|
// V4: by convention subkeys are preferred for encryption service
|
||||||
const subKeys = this.subKeys.slice().sort((a, b) => b.keyPacket.created - a.keyPacket.created);
|
const subKeys = this.subKeys.slice().sort((a, b) => b.keyPacket.created - a.keyPacket.created);
|
||||||
@ -334,9 +338,9 @@ class Key {
|
|||||||
for (let i = 0; i < subKeys.length; i++) {
|
for (let i = 0; i < subKeys.length; i++) {
|
||||||
if (!keyId || subKeys[i].getKeyId().equals(keyId)) {
|
if (!keyId || subKeys[i].getKeyId().equals(keyId)) {
|
||||||
try {
|
try {
|
||||||
await subKeys[i].verify(primaryKey, date);
|
await subKeys[i].verify(primaryKey, date, config);
|
||||||
const dataToVerify = { key: primaryKey, bind: subKeys[i].keyPacket };
|
const dataToVerify = { key: primaryKey, bind: subKeys[i].keyPacket };
|
||||||
const bindingSignature = await helper.getLatestValidSignature(subKeys[i].bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date);
|
const bindingSignature = await helper.getLatestValidSignature(subKeys[i].bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config);
|
||||||
if (bindingSignature && helper.isValidEncryptionKeyPacket(subKeys[i].keyPacket, bindingSignature)) {
|
if (bindingSignature && helper.isValidEncryptionKeyPacket(subKeys[i].keyPacket, bindingSignature)) {
|
||||||
return subKeys[i];
|
return subKeys[i];
|
||||||
}
|
}
|
||||||
@ -346,7 +350,7 @@ class Key {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if no valid subkey for encryption, evaluate primary key
|
// if no valid subkey for encryption, evaluate primary key
|
||||||
const primaryUser = await this.getPrimaryUser(date, userId);
|
const primaryUser = await this.getPrimaryUser(date, userId, config);
|
||||||
if ((!keyId || primaryKey.getKeyId().equals(keyId)) &&
|
if ((!keyId || primaryKey.getKeyId().equals(keyId)) &&
|
||||||
helper.isValidEncryptionKeyPacket(primaryKey, primaryUser.selfCertification)) {
|
helper.isValidEncryptionKeyPacket(primaryKey, primaryUser.selfCertification)) {
|
||||||
return this;
|
return this;
|
||||||
@ -360,18 +364,19 @@ class Key {
|
|||||||
* @param {module:type/keyid} keyId, optional
|
* @param {module:type/keyid} keyId, optional
|
||||||
* @param {Date} date, optional
|
* @param {Date} date, optional
|
||||||
* @param {String} userId, optional
|
* @param {String} userId, optional
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Array<module:key.Key|module:key~SubKey>>} array of decryption keys
|
* @returns {Promise<Array<module:key.Key|module:key~SubKey>>} array of decryption keys
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async getDecryptionKeys(keyId, date = new Date(), userId = {}) {
|
async getDecryptionKeys(keyId, date = new Date(), userId = {}, config = defaultConfig) {
|
||||||
const primaryKey = this.keyPacket;
|
const primaryKey = this.keyPacket;
|
||||||
const keys = [];
|
const keys = [];
|
||||||
for (let i = 0; i < this.subKeys.length; i++) {
|
for (let i = 0; i < this.subKeys.length; i++) {
|
||||||
if (!keyId || this.subKeys[i].getKeyId().equals(keyId, true)) {
|
if (!keyId || this.subKeys[i].getKeyId().equals(keyId, true)) {
|
||||||
try {
|
try {
|
||||||
const dataToVerify = { key: primaryKey, bind: this.subKeys[i].keyPacket };
|
const dataToVerify = { key: primaryKey, bind: this.subKeys[i].keyPacket };
|
||||||
const bindingSignature = await helper.getLatestValidSignature(this.subKeys[i].bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date);
|
const bindingSignature = await helper.getLatestValidSignature(this.subKeys[i].bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config);
|
||||||
if (bindingSignature && helper.isValidDecryptionKeyPacket(bindingSignature)) {
|
if (bindingSignature && helper.isValidDecryptionKeyPacket(bindingSignature, config)) {
|
||||||
keys.push(this.subKeys[i]);
|
keys.push(this.subKeys[i]);
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
@ -379,9 +384,9 @@ class Key {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// evaluate primary key
|
// evaluate primary key
|
||||||
const primaryUser = await this.getPrimaryUser(date, userId);
|
const primaryUser = await this.getPrimaryUser(date, userId, config);
|
||||||
if ((!keyId || primaryKey.getKeyId().equals(keyId, true)) &&
|
if ((!keyId || primaryKey.getKeyId().equals(keyId, true)) &&
|
||||||
helper.isValidDecryptionKeyPacket(primaryUser.selfCertification)) {
|
helper.isValidDecryptionKeyPacket(primaryUser.selfCertification, config)) {
|
||||||
keys.push(this);
|
keys.push(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,10 +397,11 @@ class Key {
|
|||||||
* Encrypts all secret key and subkey packets matching keyId
|
* Encrypts all secret key and subkey packets matching keyId
|
||||||
* @param {String|Array<String>} passphrases - if multiple passphrases, then should be in same order as packets each should encrypt
|
* @param {String|Array<String>} passphrases - if multiple passphrases, then should be in same order as packets each should encrypt
|
||||||
* @param {module:type/keyid} keyId
|
* @param {module:type/keyid} keyId
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @throws {Error} if encryption failed for any key or subkey
|
* @throws {Error} if encryption failed for any key or subkey
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async encrypt(passphrases, keyId = null) {
|
async encrypt(passphrases, keyId = null, config = defaultConfig) {
|
||||||
if (!this.isPrivate()) {
|
if (!this.isPrivate()) {
|
||||||
throw new Error("Nothing to encrypt in a public key");
|
throw new Error("Nothing to encrypt in a public key");
|
||||||
}
|
}
|
||||||
@ -408,7 +414,7 @@ class Key {
|
|||||||
|
|
||||||
await Promise.all(keys.map(async function(key, i) {
|
await Promise.all(keys.map(async function(key, i) {
|
||||||
const { keyPacket } = key;
|
const { keyPacket } = key;
|
||||||
await keyPacket.encrypt(passphrases[i]);
|
await keyPacket.encrypt(passphrases[i], config);
|
||||||
keyPacket.clearPrivateParams();
|
keyPacket.clearPrivateParams();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -417,10 +423,11 @@ class Key {
|
|||||||
* Decrypts all secret key and subkey packets matching keyId
|
* Decrypts all secret key and subkey packets matching keyId
|
||||||
* @param {String|Array<String>} passphrases
|
* @param {String|Array<String>} passphrases
|
||||||
* @param {module:type/keyid} keyId
|
* @param {module:type/keyid} keyId
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @throws {Error} if any matching key or subkey packets did not decrypt successfully
|
* @throws {Error} if any matching key or subkey packets did not decrypt successfully
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async decrypt(passphrases, keyId = null) {
|
async decrypt(passphrases, keyId = null, config = defaultConfig) {
|
||||||
if (!this.isPrivate()) {
|
if (!this.isPrivate()) {
|
||||||
throw new Error("Nothing to decrypt in a public key");
|
throw new Error("Nothing to decrypt in a public key");
|
||||||
}
|
}
|
||||||
@ -446,7 +453,7 @@ class Key {
|
|||||||
|
|
||||||
if (!keyId) {
|
if (!keyId) {
|
||||||
// The full key should be decrypted and we can validate it all
|
// The full key should be decrypted and we can validate it all
|
||||||
await this.validate();
|
await this.validate(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,10 +471,11 @@ class Key {
|
|||||||
* In case of gnu-dummy primary key, it is enough to validate any signing subkeys
|
* In case of gnu-dummy primary key, it is enough to validate any signing subkeys
|
||||||
* otherwise all encryption subkeys are validated
|
* otherwise all encryption subkeys are validated
|
||||||
* If only gnu-dummy keys are found, we cannot properly validate so we throw an error
|
* If only gnu-dummy keys are found, we cannot properly validate so we throw an error
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @throws {Error} if validation was not successful and the key cannot be trusted
|
* @throws {Error} if validation was not successful and the key cannot be trusted
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async validate() {
|
async validate(config = defaultConfig) {
|
||||||
if (!this.isPrivate()) {
|
if (!this.isPrivate()) {
|
||||||
throw new Error("Cannot validate a public key");
|
throw new Error("Cannot validate a public key");
|
||||||
}
|
}
|
||||||
@ -480,7 +488,7 @@ class Key {
|
|||||||
* It is enough to validate any signing keys
|
* It is enough to validate any signing keys
|
||||||
* since its binding signatures are also checked
|
* since its binding signatures are also checked
|
||||||
*/
|
*/
|
||||||
const signingKey = await this.getSigningKey(null, null);
|
const signingKey = await this.getSigningKey(null, null, undefined, config);
|
||||||
// This could again be a dummy key
|
// This could again be a dummy key
|
||||||
if (signingKey && !signingKey.keyPacket.isDummy()) {
|
if (signingKey && !signingKey.keyPacket.isDummy()) {
|
||||||
signingKeyPacket = signingKey.keyPacket;
|
signingKeyPacket = signingKey.keyPacket;
|
||||||
@ -522,31 +530,33 @@ class Key {
|
|||||||
* PublicKeyPacket|
|
* PublicKeyPacket|
|
||||||
* SecretKeyPacket} key, optional The key to verify the signature
|
* SecretKeyPacket} key, optional The key to verify the signature
|
||||||
* @param {Date} date Use the given date instead of the current time
|
* @param {Date} date Use the given date instead of the current time
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Boolean>} True if the certificate is revoked
|
* @returns {Promise<Boolean>} True if the certificate is revoked
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async isRevoked(signature, key, date = new Date()) {
|
async isRevoked(signature, key, date = new Date(), config = defaultConfig) {
|
||||||
return helper.isDataRevoked(
|
return helper.isDataRevoked(
|
||||||
this.keyPacket, enums.signature.keyRevocation, { key: this.keyPacket }, this.revocationSignatures, signature, key, date
|
this.keyPacket, enums.signature.keyRevocation, { key: this.keyPacket }, this.revocationSignatures, signature, key, date, config
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify primary key. Checks for revocation signatures, expiration time
|
* Verify primary key. Checks for revocation signatures, expiration time
|
||||||
* and valid self signature. Throws if the primary key is invalid.
|
* and valid self signature. Throws if the primary key is invalid.
|
||||||
* @param {Date} date (optional) use the given date for verification instead of the current time
|
* @param {Date} date (optional) use the given date for verification instead of the current time
|
||||||
* @param {Object} userId (optional) user ID
|
* @param {Object} userId (optional) user ID
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @throws {Error} If key verification failed
|
* @throws {Error} If key verification failed
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async verifyPrimaryKey(date = new Date(), userId = {}) {
|
async verifyPrimaryKey(date = new Date(), userId = {}, config = defaultConfig) {
|
||||||
const primaryKey = this.keyPacket;
|
const primaryKey = this.keyPacket;
|
||||||
// check for key revocation signatures
|
// check for key revocation signatures
|
||||||
if (await this.isRevoked(null, null, date)) {
|
if (await this.isRevoked(null, null, date, config)) {
|
||||||
throw new Error('Primary key is revoked');
|
throw new Error('Primary key is revoked');
|
||||||
}
|
}
|
||||||
// check for valid, unrevoked, unexpired self signature
|
// check for valid, unrevoked, unexpired self signature
|
||||||
const { selfCertification } = await this.getPrimaryUser(date, userId);
|
const { selfCertification } = await this.getPrimaryUser(date, userId, config);
|
||||||
// check for expiration time
|
// check for expiration time
|
||||||
if (helper.isDataExpired(primaryKey, selfCertification, date)) {
|
if (helper.isDataExpired(primaryKey, selfCertification, date)) {
|
||||||
throw new Error('Primary key is expired');
|
throw new Error('Primary key is expired');
|
||||||
@ -561,29 +571,30 @@ class Key {
|
|||||||
* @param {encrypt|sign|encrypt_sign} capabilities, optional
|
* @param {encrypt|sign|encrypt_sign} capabilities, optional
|
||||||
* @param {module:type/keyid} keyId, optional
|
* @param {module:type/keyid} keyId, optional
|
||||||
* @param {Object} userId, optional user ID
|
* @param {Object} userId, optional user ID
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Date | Infinity | null>}
|
* @returns {Promise<Date | Infinity | null>}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async getExpirationTime(capabilities, keyId, userId) {
|
async getExpirationTime(capabilities, keyId, userId, config = defaultConfig) {
|
||||||
const primaryUser = await this.getPrimaryUser(null, userId);
|
const primaryUser = await this.getPrimaryUser(null, userId, config);
|
||||||
const selfCert = primaryUser.selfCertification;
|
const selfCert = primaryUser.selfCertification;
|
||||||
const keyExpiry = helper.getExpirationTime(this.keyPacket, selfCert);
|
const keyExpiry = helper.getExpirationTime(this.keyPacket, selfCert);
|
||||||
const sigExpiry = selfCert.getExpirationTime();
|
const sigExpiry = selfCert.getExpirationTime();
|
||||||
let expiry = keyExpiry < sigExpiry ? keyExpiry : sigExpiry;
|
let expiry = keyExpiry < sigExpiry ? keyExpiry : sigExpiry;
|
||||||
if (capabilities === 'encrypt' || capabilities === 'encrypt_sign') {
|
if (capabilities === 'encrypt' || capabilities === 'encrypt_sign') {
|
||||||
const encryptKey =
|
const encryptKey =
|
||||||
await this.getEncryptionKey(keyId, expiry, userId).catch(() => {}) ||
|
await this.getEncryptionKey(keyId, expiry, userId, config).catch(() => {}) ||
|
||||||
await this.getEncryptionKey(keyId, null, userId).catch(() => {});
|
await this.getEncryptionKey(keyId, null, userId, config).catch(() => {});
|
||||||
if (!encryptKey) return null;
|
if (!encryptKey) return null;
|
||||||
const encryptExpiry = await encryptKey.getExpirationTime(this.keyPacket);
|
const encryptExpiry = await encryptKey.getExpirationTime(this.keyPacket, undefined, config);
|
||||||
if (encryptExpiry < expiry) expiry = encryptExpiry;
|
if (encryptExpiry < expiry) expiry = encryptExpiry;
|
||||||
}
|
}
|
||||||
if (capabilities === 'sign' || capabilities === 'encrypt_sign') {
|
if (capabilities === 'sign' || capabilities === 'encrypt_sign') {
|
||||||
const signKey =
|
const signKey =
|
||||||
await this.getSigningKey(keyId, expiry, userId).catch(() => {}) ||
|
await this.getSigningKey(keyId, expiry, userId, config).catch(() => {}) ||
|
||||||
await this.getSigningKey(keyId, null, userId).catch(() => {});
|
await this.getSigningKey(keyId, null, userId, config).catch(() => {});
|
||||||
if (!signKey) return null;
|
if (!signKey) return null;
|
||||||
const signExpiry = await signKey.getExpirationTime(this.keyPacket);
|
const signExpiry = await signKey.getExpirationTime(this.keyPacket, undefined, config);
|
||||||
if (signExpiry < expiry) expiry = signExpiry;
|
if (signExpiry < expiry) expiry = signExpiry;
|
||||||
}
|
}
|
||||||
return expiry;
|
return expiry;
|
||||||
@ -595,11 +606,12 @@ class Key {
|
|||||||
* - otherwise, returns the user with the latest self signature
|
* - otherwise, returns the user with the latest self signature
|
||||||
* @param {Date} date (optional) use the given date for verification instead of the current time
|
* @param {Date} date (optional) use the given date for verification instead of the current time
|
||||||
* @param {Object} userId (optional) user ID to get instead of the primary user, if it exists
|
* @param {Object} userId (optional) user ID to get instead of the primary user, if it exists
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<{user: module:key.User,
|
* @returns {Promise<{user: module:key.User,
|
||||||
* selfCertification: SignaturePacket}>} The primary user and the self signature
|
* selfCertification: SignaturePacket}>} The primary user and the self signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async getPrimaryUser(date = new Date(), userId = {}) {
|
async getPrimaryUser(date = new Date(), userId = {}, config = defaultConfig) {
|
||||||
const primaryKey = this.keyPacket;
|
const primaryKey = this.keyPacket;
|
||||||
const users = [];
|
const users = [];
|
||||||
let exception;
|
let exception;
|
||||||
@ -617,7 +629,7 @@ class Key {
|
|||||||
throw new Error('Could not find user that matches that user ID');
|
throw new Error('Could not find user that matches that user ID');
|
||||||
}
|
}
|
||||||
const dataToVerify = { userId: user.userId, key: primaryKey };
|
const dataToVerify = { userId: user.userId, key: primaryKey };
|
||||||
const selfCertification = await helper.getLatestValidSignature(user.selfCertifications, primaryKey, enums.signature.certGeneric, dataToVerify, date);
|
const selfCertification = await helper.getLatestValidSignature(user.selfCertifications, primaryKey, enums.signature.certGeneric, dataToVerify, date, config);
|
||||||
users.push({ index: i, user, selfCertification });
|
users.push({ index: i, user, selfCertification });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
exception = e;
|
exception = e;
|
||||||
@ -627,7 +639,7 @@ class Key {
|
|||||||
throw exception || new Error('Could not find primary user');
|
throw exception || new Error('Could not find primary user');
|
||||||
}
|
}
|
||||||
await Promise.all(users.map(async function (a) {
|
await Promise.all(users.map(async function (a) {
|
||||||
return a.user.revoked || a.user.isRevoked(primaryKey, a.selfCertification, null, date);
|
return a.user.revoked || a.user.isRevoked(primaryKey, a.selfCertification, null, date, config);
|
||||||
}));
|
}));
|
||||||
// sort by primary user flag and signature creation time
|
// sort by primary user flag and signature creation time
|
||||||
const primaryUser = users.sort(function(a, b) {
|
const primaryUser = users.sort(function(a, b) {
|
||||||
@ -636,7 +648,7 @@ class Key {
|
|||||||
return B.revoked - A.revoked || A.isPrimaryUserID - B.isPrimaryUserID || A.created - B.created;
|
return B.revoked - A.revoked || A.isPrimaryUserID - B.isPrimaryUserID || A.created - B.created;
|
||||||
}).pop();
|
}).pop();
|
||||||
const { user, selfCertification: cert } = primaryUser;
|
const { user, selfCertification: cert } = primaryUser;
|
||||||
if (cert.revoked || await user.isRevoked(primaryKey, cert, null, date)) {
|
if (cert.revoked || await user.isRevoked(primaryKey, cert, null, date, config)) {
|
||||||
throw new Error('Primary user is revoked');
|
throw new Error('Primary user is revoked');
|
||||||
}
|
}
|
||||||
return primaryUser;
|
return primaryUser;
|
||||||
@ -650,10 +662,11 @@ class Key {
|
|||||||
* If the specified key is a private key and the destination key is public,
|
* If the specified key is a private key and the destination key is public,
|
||||||
* the destination key is transformed to a private key.
|
* the destination key is transformed to a private key.
|
||||||
* @param {module:key.Key} key Source key to merge
|
* @param {module:key.Key} key Source key to merge
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<undefined>}
|
* @returns {Promise<undefined>}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async update(key) {
|
async update(key, config = defaultConfig) {
|
||||||
if (!this.hasSameFingerprintAs(key)) {
|
if (!this.hasSameFingerprintAs(key)) {
|
||||||
throw new Error('Key update method: fingerprints of keys not equal');
|
throw new Error('Key update method: fingerprints of keys not equal');
|
||||||
}
|
}
|
||||||
@ -672,7 +685,7 @@ class Key {
|
|||||||
}
|
}
|
||||||
// revocation signatures
|
// revocation signatures
|
||||||
await helper.mergeSignatures(key, this, 'revocationSignatures', srcRevSig => {
|
await helper.mergeSignatures(key, this, 'revocationSignatures', srcRevSig => {
|
||||||
return helper.isDataRevoked(this.keyPacket, enums.signature.keyRevocation, this, [srcRevSig], null, key.keyPacket);
|
return helper.isDataRevoked(this.keyPacket, enums.signature.keyRevocation, this, [srcRevSig], null, key.keyPacket, undefined, config);
|
||||||
});
|
});
|
||||||
// direct signatures
|
// direct signatures
|
||||||
await helper.mergeSignatures(key, this, 'directSignatures');
|
await helper.mergeSignatures(key, this, 'directSignatures');
|
||||||
@ -684,7 +697,7 @@ class Key {
|
|||||||
if ((srcUser.userId && dstUser.userId &&
|
if ((srcUser.userId && dstUser.userId &&
|
||||||
(srcUser.userId.userid === dstUser.userId.userid)) ||
|
(srcUser.userId.userid === dstUser.userId.userid)) ||
|
||||||
(srcUser.userAttribute && (srcUser.userAttribute.equals(dstUser.userAttribute)))) {
|
(srcUser.userAttribute && (srcUser.userAttribute.equals(dstUser.userAttribute)))) {
|
||||||
await dstUser.update(srcUser, this.keyPacket);
|
await dstUser.update(srcUser, this.keyPacket, config);
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@ -698,7 +711,7 @@ class Key {
|
|||||||
let found = false;
|
let found = false;
|
||||||
await Promise.all(this.subKeys.map(async dstSubKey => {
|
await Promise.all(this.subKeys.map(async dstSubKey => {
|
||||||
if (dstSubKey.hasSameFingerprintAs(srcSubKey)) {
|
if (dstSubKey.hasSameFingerprintAs(srcSubKey)) {
|
||||||
await dstSubKey.update(srcSubKey, this.keyPacket);
|
await dstSubKey.update(srcSubKey, this.keyPacket, config);
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@ -714,6 +727,7 @@ class Key {
|
|||||||
* @param {module:enums.reasonForRevocation} reasonForRevocation.flag optional, flag indicating the reason for revocation
|
* @param {module:enums.reasonForRevocation} reasonForRevocation.flag optional, flag indicating the reason for revocation
|
||||||
* @param {String} reasonForRevocation.string optional, string explaining the reason for revocation
|
* @param {String} reasonForRevocation.string optional, string explaining the reason for revocation
|
||||||
* @param {Date} date optional, override the creationtime of the revocation signature
|
* @param {Date} date optional, override the creationtime of the revocation signature
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<module:key.Key>} new key with revocation signature
|
* @returns {Promise<module:key.Key>} new key with revocation signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
@ -722,7 +736,8 @@ class Key {
|
|||||||
flag: reasonForRevocationFlag = enums.reasonForRevocation.noReason,
|
flag: reasonForRevocationFlag = enums.reasonForRevocation.noReason,
|
||||||
string: reasonForRevocationString = ''
|
string: reasonForRevocationString = ''
|
||||||
} = {},
|
} = {},
|
||||||
date = new Date()
|
date = new Date(),
|
||||||
|
config = defaultConfig
|
||||||
) {
|
) {
|
||||||
if (this.isPublic()) {
|
if (this.isPublic()) {
|
||||||
throw new Error('Need private key for revoking');
|
throw new Error('Need private key for revoking');
|
||||||
@ -733,7 +748,7 @@ class Key {
|
|||||||
signatureType: enums.signature.keyRevocation,
|
signatureType: enums.signature.keyRevocation,
|
||||||
reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag),
|
reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag),
|
||||||
reasonForRevocationString
|
reasonForRevocationString
|
||||||
}, date));
|
}, date, undefined, undefined, undefined, config));
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -741,12 +756,13 @@ class Key {
|
|||||||
* Get revocation certificate from a revoked key.
|
* Get revocation certificate from a revoked key.
|
||||||
* (To get a revocation certificate for an unrevoked key, call revoke() first.)
|
* (To get a revocation certificate for an unrevoked key, call revoke() first.)
|
||||||
* @param {Date} date Use the given date instead of the current time
|
* @param {Date} date Use the given date instead of the current time
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<String>} armored revocation certificate
|
* @returns {Promise<String>} armored revocation certificate
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async getRevocationCertificate(date = new Date()) {
|
async getRevocationCertificate(date = new Date(), config = defaultConfig) {
|
||||||
const dataToVerify = { key: this.keyPacket };
|
const dataToVerify = { key: this.keyPacket };
|
||||||
const revocationSignature = await helper.getLatestValidSignature(this.revocationSignatures, this.keyPacket, enums.signature.keyRevocation, dataToVerify, date);
|
const revocationSignature = await helper.getLatestValidSignature(this.revocationSignatures, this.keyPacket, enums.signature.keyRevocation, dataToVerify, date, config);
|
||||||
const packetlist = new PacketList();
|
const packetlist = new PacketList();
|
||||||
packetlist.push(revocationSignature);
|
packetlist.push(revocationSignature);
|
||||||
return armor(enums.armor.publicKey, packetlist.write(), null, null, 'This is a revocation certificate');
|
return armor(enums.armor.publicKey, packetlist.write(), null, null, 'This is a revocation certificate');
|
||||||
@ -757,13 +773,14 @@ class Key {
|
|||||||
* This adds the first signature packet in the armored text to the key,
|
* This adds the first signature packet in the armored text to the key,
|
||||||
* if it is a valid revocation signature.
|
* if it is a valid revocation signature.
|
||||||
* @param {String} revocationCertificate armored revocation certificate
|
* @param {String} revocationCertificate armored revocation certificate
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<module:key.Key>} new revoked key
|
* @returns {Promise<module:key.Key>} new revoked key
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async applyRevocationCertificate(revocationCertificate) {
|
async applyRevocationCertificate(revocationCertificate, config = defaultConfig) {
|
||||||
const input = await unarmor(revocationCertificate);
|
const input = await unarmor(revocationCertificate, config);
|
||||||
const packetlist = new PacketList();
|
const packetlist = new PacketList();
|
||||||
await packetlist.read(input.data, { SignaturePacket });
|
await packetlist.read(input.data, { SignaturePacket }, undefined, config);
|
||||||
const revocationSignature = packetlist.findPacket(enums.packet.signature);
|
const revocationSignature = packetlist.findPacket(enums.packet.signature);
|
||||||
if (!revocationSignature || revocationSignature.signatureType !== enums.signature.keyRevocation) {
|
if (!revocationSignature || revocationSignature.signatureType !== enums.signature.keyRevocation) {
|
||||||
throw new Error('Could not find revocation signature packet');
|
throw new Error('Could not find revocation signature packet');
|
||||||
@ -775,7 +792,7 @@ class Key {
|
|||||||
throw new Error('Revocation signature is expired');
|
throw new Error('Revocation signature is expired');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await revocationSignature.verify(this.keyPacket, enums.signature.keyRevocation, { key: this.keyPacket });
|
await revocationSignature.verify(this.keyPacket, enums.signature.keyRevocation, { key: this.keyPacket }, undefined, undefined, config);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw util.wrapError('Could not verify revocation signature', e);
|
throw util.wrapError('Could not verify revocation signature', e);
|
||||||
}
|
}
|
||||||
@ -789,12 +806,13 @@ class Key {
|
|||||||
* @param {Array<module:key.Key>} privateKeys decrypted private keys for signing
|
* @param {Array<module:key.Key>} privateKeys decrypted private keys for signing
|
||||||
* @param {Date} date (optional) use the given date for verification instead of the current time
|
* @param {Date} date (optional) use the given date for verification instead of the current time
|
||||||
* @param {Object} userId (optional) user ID to get instead of the primary user, if it exists
|
* @param {Object} userId (optional) user ID to get instead of the primary user, if it exists
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<module:key.Key>} new public key with new certificate signature
|
* @returns {Promise<module:key.Key>} new public key with new certificate signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async signPrimaryUser(privateKeys, date, userId) {
|
async signPrimaryUser(privateKeys, date, userId, config = defaultConfig) {
|
||||||
const { index, user } = await this.getPrimaryUser(date, userId);
|
const { index, user } = await this.getPrimaryUser(date, userId, config);
|
||||||
const userSign = await user.sign(this.keyPacket, privateKeys);
|
const userSign = await user.sign(this.keyPacket, privateKeys, config);
|
||||||
const key = await this.clone();
|
const key = await this.clone();
|
||||||
key.users[index] = userSign;
|
key.users[index] = userSign;
|
||||||
return key;
|
return key;
|
||||||
@ -803,14 +821,15 @@ class Key {
|
|||||||
/**
|
/**
|
||||||
* Signs all users of key
|
* Signs all users of key
|
||||||
* @param {Array<module:key.Key>} privateKeys decrypted private keys for signing
|
* @param {Array<module:key.Key>} privateKeys decrypted private keys for signing
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<module:key.Key>} new public key with new certificate signature
|
* @returns {Promise<module:key.Key>} new public key with new certificate signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async signAllUsers(privateKeys) {
|
async signAllUsers(privateKeys, config = defaultConfig) {
|
||||||
const that = this;
|
const that = this;
|
||||||
const key = await this.clone();
|
const key = await this.clone();
|
||||||
key.users = await Promise.all(this.users.map(function(user) {
|
key.users = await Promise.all(this.users.map(function(user) {
|
||||||
return user.sign(that.keyPacket, privateKeys);
|
return user.sign(that.keyPacket, privateKeys, config);
|
||||||
}));
|
}));
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
@ -822,15 +841,16 @@ class Key {
|
|||||||
* @param {Array<module:key.Key>} keys array of keys to verify certificate signatures
|
* @param {Array<module:key.Key>} keys array of keys to verify certificate signatures
|
||||||
* @param {Date} date (optional) use the given date for verification instead of the current time
|
* @param {Date} date (optional) use the given date for verification instead of the current time
|
||||||
* @param {Object} userId (optional) user ID to get instead of the primary user, if it exists
|
* @param {Object} userId (optional) user ID to get instead of the primary user, if it exists
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Array<{keyid: module:type/keyid,
|
* @returns {Promise<Array<{keyid: module:type/keyid,
|
||||||
* valid: Boolean}>>} List of signer's keyid and validity of signature
|
* valid: Boolean}>>} List of signer's keyid and validity of signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async verifyPrimaryUser(keys, date, userId) {
|
async verifyPrimaryUser(keys, date, userId, config = defaultConfig) {
|
||||||
const primaryKey = this.keyPacket;
|
const primaryKey = this.keyPacket;
|
||||||
const { user } = await this.getPrimaryUser(date, userId);
|
const { user } = await this.getPrimaryUser(date, userId, config);
|
||||||
const results = keys ? await user.verifyAllCertifications(primaryKey, keys) :
|
const results = keys ? await user.verifyAllCertifications(primaryKey, keys, undefined, config) :
|
||||||
[{ keyid: primaryKey.keyid, valid: await user.verify(primaryKey).catch(() => false) }];
|
[{ keyid: primaryKey.keyid, valid: await user.verify(primaryKey, undefined, config).catch(() => false) }];
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -839,17 +859,18 @@ class Key {
|
|||||||
* - if no arguments are given, verifies the self certificates;
|
* - if no arguments are given, verifies the self certificates;
|
||||||
* - otherwise, verifies all certificates signed with given keys.
|
* - otherwise, verifies all certificates signed with given keys.
|
||||||
* @param {Array<module:key.Key>} keys array of keys to verify certificate signatures
|
* @param {Array<module:key.Key>} keys array of keys to verify certificate signatures
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Array<{userid: String,
|
* @returns {Promise<Array<{userid: String,
|
||||||
* keyid: module:type/keyid,
|
* keyid: module:type/keyid,
|
||||||
* valid: Boolean}>>} list of userid, signer's keyid and validity of signature
|
* valid: Boolean}>>} list of userid, signer's keyid and validity of signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async verifyAllUsers(keys) {
|
async verifyAllUsers(keys, config = defaultConfig) {
|
||||||
const results = [];
|
const results = [];
|
||||||
const primaryKey = this.keyPacket;
|
const primaryKey = this.keyPacket;
|
||||||
await Promise.all(this.users.map(async function(user) {
|
await Promise.all(this.users.map(async function(user) {
|
||||||
const signatures = keys ? await user.verifyAllCertifications(primaryKey, keys) :
|
const signatures = keys ? await user.verifyAllCertifications(primaryKey, keys, undefined, config) :
|
||||||
[{ keyid: primaryKey.keyid, valid: await user.verify(primaryKey).catch(() => false) }];
|
[{ keyid: primaryKey.keyid, valid: await user.verify(primaryKey, undefined, config).catch(() => false) }];
|
||||||
signatures.forEach(signature => {
|
signatures.forEach(signature => {
|
||||||
results.push({
|
results.push({
|
||||||
userid: user.userId.userid,
|
userid: user.userId.userid,
|
||||||
@ -870,10 +891,12 @@ class Key {
|
|||||||
* @param {Number} options.keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires
|
* @param {Number} options.keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires
|
||||||
* @param {Date} options.date (optional) Override the creation date of the key and the key signatures
|
* @param {Date} options.date (optional) Override the creation date of the key and the key signatures
|
||||||
* @param {Boolean} options.sign (optional) Indicates whether the subkey should sign rather than encrypt. Defaults to false
|
* @param {Boolean} options.sign (optional) Indicates whether the subkey should sign rather than encrypt. Defaults to false
|
||||||
|
* @param {Object} options.config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Promise<module:key.Key>}
|
* @returns {Promise<module:key.Key>}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async addSubkey(options = {}) {
|
async addSubkey(options = {}) {
|
||||||
|
const config = { ...defaultConfig, ...options.config };
|
||||||
if (!this.isPrivate()) {
|
if (!this.isPrivate()) {
|
||||||
throw new Error("Cannot add a subkey to a public key");
|
throw new Error("Cannot add a subkey to a public key");
|
||||||
}
|
}
|
||||||
@ -896,7 +919,7 @@ class Key {
|
|||||||
defaultOptions.curve = defaultOptions.curve || 'curve25519';
|
defaultOptions.curve = defaultOptions.curve || 'curve25519';
|
||||||
options = helper.sanitizeKeyOptions(options, defaultOptions);
|
options = helper.sanitizeKeyOptions(options, defaultOptions);
|
||||||
const keyPacket = await helper.generateSecretSubkey(options);
|
const keyPacket = await helper.generateSecretSubkey(options);
|
||||||
const bindingSignature = await helper.createBindingSignature(keyPacket, secretKeyPacket, options);
|
const bindingSignature = await helper.createBindingSignature(keyPacket, secretKeyPacket, options, config);
|
||||||
const packetList = this.toPacketlist();
|
const packetList = this.toPacketlist();
|
||||||
packetList.push(keyPacket);
|
packetList.push(keyPacket);
|
||||||
packetList.push(bindingSignature);
|
packetList.push(bindingSignature);
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import * as helper from './helper';
|
import * as helper from './helper';
|
||||||
import { PacketList } from '../packet';
|
import { PacketList } from '../packet';
|
||||||
|
import defaultConfig from '../config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that represents a subkey packet and the relevant signatures.
|
* Class that represents a subkey packet and the relevant signatures.
|
||||||
@ -50,15 +51,16 @@ class SubKey {
|
|||||||
* PublicKeyPacket|
|
* PublicKeyPacket|
|
||||||
* SecretKeyPacket} key, optional The key to verify the signature
|
* SecretKeyPacket} key, optional The key to verify the signature
|
||||||
* @param {Date} date Use the given date instead of the current time
|
* @param {Date} date Use the given date instead of the current time
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Boolean>} True if the binding signature is revoked
|
* @returns {Promise<Boolean>} True if the binding signature is revoked
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async isRevoked(primaryKey, signature, key, date = new Date()) {
|
async isRevoked(primaryKey, signature, key, date = new Date(), config = defaultConfig) {
|
||||||
return helper.isDataRevoked(
|
return helper.isDataRevoked(
|
||||||
primaryKey, enums.signature.subkeyRevocation, {
|
primaryKey, enums.signature.subkeyRevocation, {
|
||||||
key: primaryKey,
|
key: primaryKey,
|
||||||
bind: this.keyPacket
|
bind: this.keyPacket
|
||||||
}, this.revocationSignatures, signature, key, date
|
}, this.revocationSignatures, signature, key, date, config
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,16 +70,17 @@ class SubKey {
|
|||||||
* @param {SecretKeyPacket|
|
* @param {SecretKeyPacket|
|
||||||
* PublicKeyPacket} primaryKey The primary key packet
|
* PublicKeyPacket} primaryKey The primary key packet
|
||||||
* @param {Date} date Use the given date instead of the current time
|
* @param {Date} date Use the given date instead of the current time
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<SignaturePacket>}
|
* @returns {Promise<SignaturePacket>}
|
||||||
* @throws {Error} if the subkey is invalid.
|
* @throws {Error} if the subkey is invalid.
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async verify(primaryKey, date = new Date()) {
|
async verify(primaryKey, date = new Date(), config = defaultConfig) {
|
||||||
const dataToVerify = { key: primaryKey, bind: this.keyPacket };
|
const dataToVerify = { key: primaryKey, bind: this.keyPacket };
|
||||||
// check subkey binding signatures
|
// check subkey binding signatures
|
||||||
const bindingSignature = await helper.getLatestValidSignature(this.bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date);
|
const bindingSignature = await helper.getLatestValidSignature(this.bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config);
|
||||||
// check binding signature is not revoked
|
// check binding signature is not revoked
|
||||||
if (bindingSignature.revoked || await this.isRevoked(primaryKey, bindingSignature, null, date)) {
|
if (bindingSignature.revoked || await this.isRevoked(primaryKey, bindingSignature, null, date, config)) {
|
||||||
throw new Error('Subkey is revoked');
|
throw new Error('Subkey is revoked');
|
||||||
}
|
}
|
||||||
// check for expiration time
|
// check for expiration time
|
||||||
@ -93,14 +96,15 @@ class SubKey {
|
|||||||
* @param {SecretKeyPacket|
|
* @param {SecretKeyPacket|
|
||||||
* PublicKeyPacket} primaryKey The primary key packet
|
* PublicKeyPacket} primaryKey The primary key packet
|
||||||
* @param {Date} date Use the given date instead of the current time
|
* @param {Date} date Use the given date instead of the current time
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Date | Infinity | null>}
|
* @returns {Promise<Date | Infinity | null>}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async getExpirationTime(primaryKey, date = new Date()) {
|
async getExpirationTime(primaryKey, date = new Date(), config = defaultConfig) {
|
||||||
const dataToVerify = { key: primaryKey, bind: this.keyPacket };
|
const dataToVerify = { key: primaryKey, bind: this.keyPacket };
|
||||||
let bindingSignature;
|
let bindingSignature;
|
||||||
try {
|
try {
|
||||||
bindingSignature = await helper.getLatestValidSignature(this.bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date);
|
bindingSignature = await helper.getLatestValidSignature(this.bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -114,10 +118,11 @@ class SubKey {
|
|||||||
* @param {module:key~SubKey} subKey Source subkey to merge
|
* @param {module:key~SubKey} subKey Source subkey to merge
|
||||||
* @param {SecretKeyPacket|
|
* @param {SecretKeyPacket|
|
||||||
SecretSubkeyPacket} primaryKey primary key used for validation
|
SecretSubkeyPacket} primaryKey primary key used for validation
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @throws {Error} if update failed
|
* @throws {Error} if update failed
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async update(subKey, primaryKey) {
|
async update(subKey, primaryKey, config = defaultConfig) {
|
||||||
if (!this.hasSameFingerprintAs(subKey)) {
|
if (!this.hasSameFingerprintAs(subKey)) {
|
||||||
throw new Error('SubKey update method: fingerprints of subkeys not equal');
|
throw new Error('SubKey update method: fingerprints of subkeys not equal');
|
||||||
}
|
}
|
||||||
@ -139,7 +144,7 @@ class SubKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
srcBindSig.verified || await srcBindSig.verify(primaryKey, enums.signature.subkeyBinding, dataToVerify);
|
srcBindSig.verified || await srcBindSig.verify(primaryKey, enums.signature.subkeyBinding, dataToVerify, undefined, undefined, config);
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
@ -147,7 +152,7 @@ class SubKey {
|
|||||||
});
|
});
|
||||||
// revocation signatures
|
// revocation signatures
|
||||||
await helper.mergeSignatures(subKey, this, 'revocationSignatures', function(srcRevSig) {
|
await helper.mergeSignatures(subKey, this, 'revocationSignatures', function(srcRevSig) {
|
||||||
return helper.isDataRevoked(primaryKey, enums.signature.subkeyRevocation, dataToVerify, [srcRevSig]);
|
return helper.isDataRevoked(primaryKey, enums.signature.subkeyRevocation, dataToVerify, [srcRevSig], undefined, undefined, undefined, config);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,6 +163,7 @@ class SubKey {
|
|||||||
* @param {module:enums.reasonForRevocation} reasonForRevocation.flag optional, flag indicating the reason for revocation
|
* @param {module:enums.reasonForRevocation} reasonForRevocation.flag optional, flag indicating the reason for revocation
|
||||||
* @param {String} reasonForRevocation.string optional, string explaining the reason for revocation
|
* @param {String} reasonForRevocation.string optional, string explaining the reason for revocation
|
||||||
* @param {Date} date optional, override the creationtime of the revocation signature
|
* @param {Date} date optional, override the creationtime of the revocation signature
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<module:key~SubKey>} new subkey with revocation signature
|
* @returns {Promise<module:key~SubKey>} new subkey with revocation signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
@ -167,7 +173,8 @@ class SubKey {
|
|||||||
flag: reasonForRevocationFlag = enums.reasonForRevocation.noReason,
|
flag: reasonForRevocationFlag = enums.reasonForRevocation.noReason,
|
||||||
string: reasonForRevocationString = ''
|
string: reasonForRevocationString = ''
|
||||||
} = {},
|
} = {},
|
||||||
date = new Date()
|
date = new Date(),
|
||||||
|
config = defaultConfig
|
||||||
) {
|
) {
|
||||||
const dataToSign = { key: primaryKey, bind: this.keyPacket };
|
const dataToSign = { key: primaryKey, bind: this.keyPacket };
|
||||||
const subKey = new SubKey(this.keyPacket);
|
const subKey = new SubKey(this.keyPacket);
|
||||||
@ -175,7 +182,7 @@ class SubKey {
|
|||||||
signatureType: enums.signature.subkeyRevocation,
|
signatureType: enums.signature.subkeyRevocation,
|
||||||
reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag),
|
reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag),
|
||||||
reasonForRevocationString
|
reasonForRevocationString
|
||||||
}, date));
|
}, date, undefined, undefined, undefined, config));
|
||||||
await subKey.update(this, primaryKey);
|
await subKey.update(this, primaryKey);
|
||||||
return subKey;
|
return subKey;
|
||||||
}
|
}
|
||||||
|
@ -44,10 +44,11 @@ class User {
|
|||||||
* @param {SecretKeyPacket|
|
* @param {SecretKeyPacket|
|
||||||
* PublicKeyPacket} primaryKey The primary key packet
|
* PublicKeyPacket} primaryKey The primary key packet
|
||||||
* @param {Array<module:key.Key>} privateKeys Decrypted private keys for signing
|
* @param {Array<module:key.Key>} privateKeys Decrypted private keys for signing
|
||||||
|
* @param {Object} config Full configuration
|
||||||
* @returns {Promise<module:key.Key>} New user with new certificate signatures
|
* @returns {Promise<module:key.Key>} New user with new certificate signatures
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async sign(primaryKey, privateKeys) {
|
async sign(primaryKey, privateKeys, config) {
|
||||||
const dataToSign = {
|
const dataToSign = {
|
||||||
userId: this.userId,
|
userId: this.userId,
|
||||||
userAttribute: this.userAttribute,
|
userAttribute: this.userAttribute,
|
||||||
@ -61,12 +62,12 @@ class User {
|
|||||||
if (privateKey.hasSameFingerprintAs(primaryKey)) {
|
if (privateKey.hasSameFingerprintAs(primaryKey)) {
|
||||||
throw new Error('Not implemented for self signing');
|
throw new Error('Not implemented for self signing');
|
||||||
}
|
}
|
||||||
const signingKey = await privateKey.getSigningKey();
|
const signingKey = await privateKey.getSigningKey(undefined, undefined, undefined, config);
|
||||||
return createSignaturePacket(dataToSign, privateKey, signingKey.keyPacket, {
|
return createSignaturePacket(dataToSign, privateKey, signingKey.keyPacket, {
|
||||||
// Most OpenPGP implementations use generic certification (0x10)
|
// Most OpenPGP implementations use generic certification (0x10)
|
||||||
signatureType: enums.signature.certGeneric,
|
signatureType: enums.signature.certGeneric,
|
||||||
keyFlags: [enums.keyFlags.certifyKeys | enums.keyFlags.signData]
|
keyFlags: [enums.keyFlags.certifyKeys | enums.keyFlags.signData]
|
||||||
});
|
}, undefined, undefined, undefined, undefined, config);
|
||||||
}));
|
}));
|
||||||
await user.update(this, primaryKey);
|
await user.update(this, primaryKey);
|
||||||
return user;
|
return user;
|
||||||
@ -82,16 +83,17 @@ class User {
|
|||||||
* PublicKeyPacket|
|
* PublicKeyPacket|
|
||||||
* SecretKeyPacket} key, optional The key to verify the signature
|
* SecretKeyPacket} key, optional The key to verify the signature
|
||||||
* @param {Date} date Use the given date instead of the current time
|
* @param {Date} date Use the given date instead of the current time
|
||||||
|
* @param {Object} config Full configuration
|
||||||
* @returns {Promise<Boolean>} True if the certificate is revoked
|
* @returns {Promise<Boolean>} True if the certificate is revoked
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async isRevoked(primaryKey, certificate, key, date = new Date()) {
|
async isRevoked(primaryKey, certificate, key, date = new Date(), config) {
|
||||||
return isDataRevoked(
|
return isDataRevoked(
|
||||||
primaryKey, enums.signature.certRevocation, {
|
primaryKey, enums.signature.certRevocation, {
|
||||||
key: primaryKey,
|
key: primaryKey,
|
||||||
userId: this.userId,
|
userId: this.userId,
|
||||||
userAttribute: this.userAttribute
|
userAttribute: this.userAttribute
|
||||||
}, this.revocationSignatures, certificate, key, date
|
}, this.revocationSignatures, certificate, key, date, config
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,10 +104,11 @@ class User {
|
|||||||
* @param {SignaturePacket} certificate A certificate of this user
|
* @param {SignaturePacket} certificate A certificate of this user
|
||||||
* @param {Array<module:key.Key>} keys Array of keys to verify certificate signatures
|
* @param {Array<module:key.Key>} keys Array of keys to verify certificate signatures
|
||||||
* @param {Date} date Use the given date instead of the current time
|
* @param {Date} date Use the given date instead of the current time
|
||||||
|
* @param {Object} config Full configuration
|
||||||
* @returns {Promise<true|null>} status of the certificate
|
* @returns {Promise<true|null>} status of the certificate
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async verifyCertificate(primaryKey, certificate, keys, date = new Date()) {
|
async verifyCertificate(primaryKey, certificate, keys, date = new Date(), config) {
|
||||||
const that = this;
|
const that = this;
|
||||||
const keyid = certificate.issuerKeyId;
|
const keyid = certificate.issuerKeyId;
|
||||||
const dataToVerify = {
|
const dataToVerify = {
|
||||||
@ -117,12 +120,12 @@ class User {
|
|||||||
if (!key.getKeyIds().some(id => id.equals(keyid))) {
|
if (!key.getKeyIds().some(id => id.equals(keyid))) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const signingKey = await key.getSigningKey(keyid, date);
|
const signingKey = await key.getSigningKey(keyid, date, undefined, config);
|
||||||
if (certificate.revoked || await that.isRevoked(primaryKey, certificate, signingKey.keyPacket, date)) {
|
if (certificate.revoked || await that.isRevoked(primaryKey, certificate, signingKey.keyPacket, date, config)) {
|
||||||
throw new Error('User certificate is revoked');
|
throw new Error('User certificate is revoked');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
certificate.verified || await certificate.verify(signingKey.keyPacket, enums.signature.certGeneric, dataToVerify);
|
certificate.verified || await certificate.verify(signingKey.keyPacket, enums.signature.certGeneric, dataToVerify, undefined, undefined, config);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw util.wrapError('User certificate is invalid', e);
|
throw util.wrapError('User certificate is invalid', e);
|
||||||
}
|
}
|
||||||
@ -139,18 +142,19 @@ class User {
|
|||||||
* @param {SecretKeyPacket|
|
* @param {SecretKeyPacket|
|
||||||
* PublicKeyPacket} primaryKey The primary key packet
|
* PublicKeyPacket} primaryKey The primary key packet
|
||||||
* @param {Array<module:key.Key>} keys Array of keys to verify certificate signatures
|
* @param {Array<module:key.Key>} keys Array of keys to verify certificate signatures
|
||||||
* @param {Date} date Use the given date instead of the current time
|
* @param {Date} date Use the given date instead of the current time
|
||||||
|
* @param {Object} config Full configuration
|
||||||
* @returns {Promise<Array<{keyid: module:type/keyid,
|
* @returns {Promise<Array<{keyid: module:type/keyid,
|
||||||
* valid: Boolean}>>} List of signer's keyid and validity of signature
|
* valid: Boolean}>>} List of signer's keyid and validity of signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async verifyAllCertifications(primaryKey, keys, date = new Date()) {
|
async verifyAllCertifications(primaryKey, keys, date = new Date(), config) {
|
||||||
const that = this;
|
const that = this;
|
||||||
const certifications = this.selfCertifications.concat(this.otherCertifications);
|
const certifications = this.selfCertifications.concat(this.otherCertifications);
|
||||||
return Promise.all(certifications.map(async function(certification) {
|
return Promise.all(certifications.map(async function(certification) {
|
||||||
return {
|
return {
|
||||||
keyid: certification.issuerKeyId,
|
keyid: certification.issuerKeyId,
|
||||||
valid: await that.verifyCertificate(primaryKey, certification, keys, date).catch(() => false)
|
valid: await that.verifyCertificate(primaryKey, certification, keys, date, config).catch(() => false)
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -161,11 +165,12 @@ class User {
|
|||||||
* @param {SecretKeyPacket|
|
* @param {SecretKeyPacket|
|
||||||
* PublicKeyPacket} primaryKey The primary key packet
|
* PublicKeyPacket} primaryKey The primary key packet
|
||||||
* @param {Date} date Use the given date instead of the current time
|
* @param {Date} date Use the given date instead of the current time
|
||||||
|
* @param {Object} config Full configuration
|
||||||
* @returns {Promise<true>} Status of user
|
* @returns {Promise<true>} Status of user
|
||||||
* @throws {Error} if there are no valid self signatures.
|
* @throws {Error} if there are no valid self signatures.
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async verify(primaryKey, date = new Date()) {
|
async verify(primaryKey, date = new Date(), config) {
|
||||||
if (!this.selfCertifications.length) {
|
if (!this.selfCertifications.length) {
|
||||||
throw new Error('No self-certifications');
|
throw new Error('No self-certifications');
|
||||||
}
|
}
|
||||||
@ -180,11 +185,11 @@ class User {
|
|||||||
for (let i = this.selfCertifications.length - 1; i >= 0; i--) {
|
for (let i = this.selfCertifications.length - 1; i >= 0; i--) {
|
||||||
try {
|
try {
|
||||||
const selfCertification = this.selfCertifications[i];
|
const selfCertification = this.selfCertifications[i];
|
||||||
if (selfCertification.revoked || await that.isRevoked(primaryKey, selfCertification, undefined, date)) {
|
if (selfCertification.revoked || await that.isRevoked(primaryKey, selfCertification, undefined, date, config)) {
|
||||||
throw new Error('Self-certification is revoked');
|
throw new Error('Self-certification is revoked');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
selfCertification.verified || await selfCertification.verify(primaryKey, enums.signature.certGeneric, dataToVerify);
|
selfCertification.verified || await selfCertification.verify(primaryKey, enums.signature.certGeneric, dataToVerify, undefined, undefined, config);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw util.wrapError('Self-certification is invalid', e);
|
throw util.wrapError('Self-certification is invalid', e);
|
||||||
}
|
}
|
||||||
@ -204,10 +209,11 @@ class User {
|
|||||||
* @param {module:key.User} user Source user to merge
|
* @param {module:key.User} user Source user to merge
|
||||||
* @param {SecretKeyPacket|
|
* @param {SecretKeyPacket|
|
||||||
* SecretSubkeyPacket} primaryKey primary key used for validation
|
* SecretSubkeyPacket} primaryKey primary key used for validation
|
||||||
|
* @param {Object} config Full configuration
|
||||||
* @returns {Promise<undefined>}
|
* @returns {Promise<undefined>}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async update(user, primaryKey) {
|
async update(user, primaryKey, config) {
|
||||||
const dataToVerify = {
|
const dataToVerify = {
|
||||||
userId: this.userId,
|
userId: this.userId,
|
||||||
userAttribute: this.userAttribute,
|
userAttribute: this.userAttribute,
|
||||||
@ -216,7 +222,7 @@ class User {
|
|||||||
// self signatures
|
// self signatures
|
||||||
await mergeSignatures(user, this, 'selfCertifications', async function(srcSelfSig) {
|
await mergeSignatures(user, this, 'selfCertifications', async function(srcSelfSig) {
|
||||||
try {
|
try {
|
||||||
srcSelfSig.verified || await srcSelfSig.verify(primaryKey, enums.signature.certGeneric, dataToVerify);
|
srcSelfSig.verified || await srcSelfSig.verify(primaryKey, enums.signature.certGeneric, dataToVerify, undefined, undefined, config);
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
@ -226,7 +232,7 @@ class User {
|
|||||||
await mergeSignatures(user, this, 'otherCertifications');
|
await mergeSignatures(user, this, 'otherCertifications');
|
||||||
// revocation signatures
|
// revocation signatures
|
||||||
await mergeSignatures(user, this, 'revocationSignatures', function(srcRevSig) {
|
await mergeSignatures(user, this, 'revocationSignatures', function(srcRevSig) {
|
||||||
return isDataRevoked(primaryKey, enums.signature.certRevocation, dataToVerify, [srcRevSig]);
|
return isDataRevoked(primaryKey, enums.signature.certRevocation, dataToVerify, [srcRevSig], undefined, undefined, undefined, config);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { readKeys } from '../key';
|
import { readKeys } from '../key';
|
||||||
|
import defaultConfig from '../config';
|
||||||
import LocalStore from './localstore';
|
import LocalStore from './localstore';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,10 +78,11 @@ class KeyArray {
|
|||||||
/**
|
/**
|
||||||
* Imports a key from an ascii armored message
|
* Imports a key from an ascii armored message
|
||||||
* @param {String} armored message to read the keys/key from
|
* @param {String} armored message to read the keys/key from
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async importKey(armored) {
|
async importKey(armored, config = defaultConfig) {
|
||||||
const imported = await readKeys({ armoredKeys: armored });
|
const imported = await readKeys({ armoredKeys: armored, config });
|
||||||
for (let i = 0; i < imported.length; i++) {
|
for (let i = 0; i < imported.length; i++) {
|
||||||
const key = imported[i];
|
const key = imported[i];
|
||||||
// check if key already in key array
|
// check if key already in key array
|
||||||
@ -123,9 +125,10 @@ class Keyring {
|
|||||||
/**
|
/**
|
||||||
* Initialization routine for the keyring.
|
* Initialization routine for the keyring.
|
||||||
* @param {keyring/localstore} [storeHandler] class implementing loadPublic(), loadPrivate(), storePublic(), and storePrivate() methods
|
* @param {keyring/localstore} [storeHandler] class implementing loadPublic(), loadPrivate(), storePublic(), and storePrivate() methods
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
*/
|
*/
|
||||||
constructor(storeHandler) {
|
constructor(storeHandler, config = defaultConfig) {
|
||||||
this.storeHandler = storeHandler || new LocalStore();
|
this.storeHandler = storeHandler || new LocalStore(undefined, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,8 +24,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import stream from 'web-stream-tools';
|
import stream from 'web-stream-tools';
|
||||||
import config from '../config';
|
|
||||||
import { readKey } from '../key';
|
import { readKey } from '../key';
|
||||||
|
import defaultConfig from '../config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class that deals with storage of the keyring.
|
* The class that deals with storage of the keyring.
|
||||||
@ -34,8 +34,9 @@ import { readKey } from '../key';
|
|||||||
class LocalStore {
|
class LocalStore {
|
||||||
/**
|
/**
|
||||||
* @param {String} prefix prefix for itemnames in localstore
|
* @param {String} prefix prefix for itemnames in localstore
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
*/
|
*/
|
||||||
constructor(prefix) {
|
constructor(prefix, config = defaultConfig) {
|
||||||
prefix = prefix || 'openpgp-';
|
prefix = prefix || 'openpgp-';
|
||||||
this.publicKeysItem = prefix + this.publicKeysItem;
|
this.publicKeysItem = prefix + this.publicKeysItem;
|
||||||
this.privateKeysItem = prefix + this.privateKeysItem;
|
this.privateKeysItem = prefix + this.privateKeysItem;
|
||||||
@ -51,37 +52,40 @@ class LocalStore {
|
|||||||
* @returns {Array<module:key.Key>} array of keys retrieved from localstore
|
* @returns {Array<module:key.Key>} array of keys retrieved from localstore
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async loadPublic() {
|
async loadPublic(config = defaultConfig) {
|
||||||
return loadKeys(this.storage, this.publicKeysItem);
|
return loadKeys(this.storage, this.publicKeysItem, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the private keys from HTML5 local storage.
|
* Load the private keys from HTML5 local storage.
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Array<module:key.Key>} array of keys retrieved from localstore
|
* @returns {Array<module:key.Key>} array of keys retrieved from localstore
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async loadPrivate() {
|
async loadPrivate(config = defaultConfig) {
|
||||||
return loadKeys(this.storage, this.privateKeysItem);
|
return loadKeys(this.storage, this.privateKeysItem, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the current state of the public keys to HTML5 local storage.
|
* Saves the current state of the public keys to HTML5 local storage.
|
||||||
* The key array gets stringified using JSON
|
* The key array gets stringified using JSON
|
||||||
* @param {Array<module:key.Key>} keys array of keys to save in localstore
|
* @param {Array<module:key.Key>} keys array of keys to save in localstore
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async storePublic(keys) {
|
async storePublic(keys, config = defaultConfig) {
|
||||||
await storeKeys(this.storage, this.publicKeysItem, keys);
|
await storeKeys(this.storage, this.publicKeysItem, keys, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the current state of the private keys to HTML5 local storage.
|
* Saves the current state of the private keys to HTML5 local storage.
|
||||||
* The key array gets stringified using JSON
|
* The key array gets stringified using JSON
|
||||||
* @param {Array<module:key.Key>} keys array of keys to save in localstore
|
* @param {Array<module:key.Key>} keys array of keys to save in localstore
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async storePrivate(keys) {
|
async storePrivate(keys, config = defaultConfig) {
|
||||||
await storeKeys(this.storage, this.privateKeysItem, keys);
|
await storeKeys(this.storage, this.privateKeysItem, keys, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,22 +95,22 @@ class LocalStore {
|
|||||||
LocalStore.prototype.publicKeysItem = 'public-keys';
|
LocalStore.prototype.publicKeysItem = 'public-keys';
|
||||||
LocalStore.prototype.privateKeysItem = 'private-keys';
|
LocalStore.prototype.privateKeysItem = 'private-keys';
|
||||||
|
|
||||||
async function loadKeys(storage, itemname) {
|
async function loadKeys(storage, itemname, config) {
|
||||||
const armoredKeys = JSON.parse(storage.getItem(itemname));
|
const armoredKeys = JSON.parse(storage.getItem(itemname));
|
||||||
const keys = [];
|
const keys = [];
|
||||||
if (armoredKeys !== null && armoredKeys.length !== 0) {
|
if (armoredKeys !== null && armoredKeys.length !== 0) {
|
||||||
let key;
|
let key;
|
||||||
for (let i = 0; i < armoredKeys.length; i++) {
|
for (let i = 0; i < armoredKeys.length; i++) {
|
||||||
key = await readKey({ armoredKey: armoredKeys[i] });
|
key = await readKey({ armoredKey: armoredKeys[i], config });
|
||||||
keys.push(key);
|
keys.push(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function storeKeys(storage, itemname, keys) {
|
async function storeKeys(storage, itemname, keys, config) {
|
||||||
if (keys.length) {
|
if (keys.length) {
|
||||||
const armoredKeys = await Promise.all(keys.map(key => stream.readToEnd(key.armor())));
|
const armoredKeys = await Promise.all(keys.map(key => stream.readToEnd(key.armor(config))));
|
||||||
storage.setItem(itemname, JSON.stringify(armoredKeys));
|
storage.setItem(itemname, JSON.stringify(armoredKeys));
|
||||||
} else {
|
} else {
|
||||||
storage.removeItem(itemname);
|
storage.removeItem(itemname);
|
||||||
|
116
src/message.js
116
src/message.js
@ -32,7 +32,7 @@
|
|||||||
import stream from 'web-stream-tools';
|
import stream from 'web-stream-tools';
|
||||||
import { armor, unarmor } from './encoding/armor';
|
import { armor, unarmor } from './encoding/armor';
|
||||||
import type_keyid from './type/keyid';
|
import type_keyid from './type/keyid';
|
||||||
import config from './config';
|
import defaultConfig from './config';
|
||||||
import crypto from './crypto';
|
import crypto from './crypto';
|
||||||
import enums from './enums';
|
import enums from './enums';
|
||||||
import util from './util';
|
import util from './util';
|
||||||
@ -106,11 +106,12 @@ export class Message {
|
|||||||
* @param {Array<String>} passwords (optional) passwords used to decrypt
|
* @param {Array<String>} passwords (optional) passwords used to decrypt
|
||||||
* @param {Array<Object>} sessionKeys (optional) session keys in the form: { data:Uint8Array, algorithm:String, [aeadAlgorithm:String] }
|
* @param {Array<Object>} sessionKeys (optional) session keys in the form: { data:Uint8Array, algorithm:String, [aeadAlgorithm:String] }
|
||||||
* @param {Boolean} streaming (optional) whether to process data as a stream
|
* @param {Boolean} streaming (optional) whether to process data as a stream
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Message>} new message with decrypted content
|
* @returns {Promise<Message>} new message with decrypted content
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async decrypt(privateKeys, passwords, sessionKeys, streaming) {
|
async decrypt(privateKeys, passwords, sessionKeys, streaming, config = defaultConfig) {
|
||||||
const keyObjs = sessionKeys || await this.decryptSessionKeys(privateKeys, passwords);
|
const keyObjs = sessionKeys || await this.decryptSessionKeys(privateKeys, passwords, config);
|
||||||
|
|
||||||
const symEncryptedPacketlist = this.packets.filterByTag(
|
const symEncryptedPacketlist = this.packets.filterByTag(
|
||||||
enums.packet.symmetricallyEncryptedData,
|
enums.packet.symmetricallyEncryptedData,
|
||||||
@ -130,7 +131,7 @@ export class Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await symEncryptedPacket.decrypt(keyObj.algorithm, keyObj.data, streaming);
|
await symEncryptedPacket.decrypt(keyObj.algorithm, keyObj.data, streaming, config);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
util.printDebugError(e);
|
util.printDebugError(e);
|
||||||
exception = e;
|
exception = e;
|
||||||
@ -155,11 +156,12 @@ export class Message {
|
|||||||
* Decrypt encrypted session keys either with private keys or passwords.
|
* Decrypt encrypted session keys either with private keys or passwords.
|
||||||
* @param {Array<Key>} privateKeys (optional) private keys with decrypted secret data
|
* @param {Array<Key>} privateKeys (optional) private keys with decrypted secret data
|
||||||
* @param {Array<String>} passwords (optional) passwords used to decrypt
|
* @param {Array<String>} passwords (optional) passwords used to decrypt
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Array<{ data: Uint8Array,
|
* @returns {Promise<Array<{ data: Uint8Array,
|
||||||
algorithm: String }>>} array of object with potential sessionKey, algorithm pairs
|
algorithm: String }>>} array of object with potential sessionKey, algorithm pairs
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async decryptSessionKeys(privateKeys, passwords) {
|
async decryptSessionKeys(privateKeys, passwords, config = defaultConfig) {
|
||||||
let keyPackets = [];
|
let keyPackets = [];
|
||||||
|
|
||||||
let exception;
|
let exception;
|
||||||
@ -199,14 +201,14 @@ export class Message {
|
|||||||
enums.symmetric.cast5 // Golang OpenPGP fallback
|
enums.symmetric.cast5 // Golang OpenPGP fallback
|
||||||
];
|
];
|
||||||
try {
|
try {
|
||||||
const primaryUser = await privateKey.getPrimaryUser(); // TODO: Pass userId from somewhere.
|
const primaryUser = await privateKey.getPrimaryUser(undefined, undefined, config); // TODO: Pass userId from somewhere.
|
||||||
if (primaryUser.selfCertification.preferredSymmetricAlgorithms) {
|
if (primaryUser.selfCertification.preferredSymmetricAlgorithms) {
|
||||||
algos = algos.concat(primaryUser.selfCertification.preferredSymmetricAlgorithms);
|
algos = algos.concat(primaryUser.selfCertification.preferredSymmetricAlgorithms);
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
// do not check key expiration to allow decryption of old messages
|
// do not check key expiration to allow decryption of old messages
|
||||||
const privateKeyPackets = (await privateKey.getDecryptionKeys(keyPacket.publicKeyId, null)).map(key => key.keyPacket);
|
const privateKeyPackets = (await privateKey.getDecryptionKeys(keyPacket.publicKeyId, null, undefined, config)).map(key => key.keyPacket);
|
||||||
await Promise.all(privateKeyPackets.map(async function(privateKeyPacket) {
|
await Promise.all(privateKeyPackets.map(async function(privateKeyPacket) {
|
||||||
if (!privateKeyPacket || privateKeyPacket.isDummy()) {
|
if (!privateKeyPacket || privateKeyPacket.isDummy()) {
|
||||||
return;
|
return;
|
||||||
@ -290,13 +292,14 @@ export class Message {
|
|||||||
* @param {Array<Key>} keys (optional) public key(s) to select algorithm preferences for
|
* @param {Array<Key>} keys (optional) public key(s) to select algorithm preferences for
|
||||||
* @param {Date} date (optional) date to select algorithm preferences at
|
* @param {Date} date (optional) date to select algorithm preferences at
|
||||||
* @param {Array<Object>} userIds (optional) user IDs to select algorithm preferences for
|
* @param {Array<Object>} userIds (optional) user IDs to select algorithm preferences for
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<{ data: Uint8Array, algorithm: String }>} object with session key data and algorithm
|
* @returns {Promise<{ data: Uint8Array, algorithm: String }>} object with session key data and algorithm
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
static async generateSessionKey(keys = [], date = new Date(), userIds = []) {
|
static async generateSessionKey(keys = [], date = new Date(), userIds = [], config = defaultConfig) {
|
||||||
const algorithm = enums.read(enums.symmetric, await getPreferredAlgo('symmetric', keys, date, userIds));
|
const algorithm = enums.read(enums.symmetric, await getPreferredAlgo('symmetric', keys, date, userIds, config));
|
||||||
const aeadAlgorithm = config.aeadProtect && await isAeadSupported(keys, date, userIds) ?
|
const aeadAlgorithm = config.aeadProtect && await isAeadSupported(keys, date, userIds, config) ?
|
||||||
enums.read(enums.aead, await getPreferredAlgo('aead', keys, date, userIds)) :
|
enums.read(enums.aead, await getPreferredAlgo('aead', keys, date, userIds, config)) :
|
||||||
undefined;
|
undefined;
|
||||||
const sessionKeyData = await crypto.generateSessionKey(algorithm);
|
const sessionKeyData = await crypto.generateSessionKey(algorithm);
|
||||||
return { data: sessionKeyData, algorithm, aeadAlgorithm };
|
return { data: sessionKeyData, algorithm, aeadAlgorithm };
|
||||||
@ -312,25 +315,26 @@ export class Message {
|
|||||||
* @param {Date} date (optional) override the creation date of the literal package
|
* @param {Date} date (optional) override the creation date of the literal package
|
||||||
* @param {Array<Object>} userIds (optional) user IDs to encrypt for, e.g. [{ name:'Robert Receiver', email:'robert@openpgp.org' }]
|
* @param {Array<Object>} userIds (optional) user IDs to encrypt for, e.g. [{ name:'Robert Receiver', email:'robert@openpgp.org' }]
|
||||||
* @param {Boolean} streaming (optional) whether to process data as a stream
|
* @param {Boolean} streaming (optional) whether to process data as a stream
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Message>} new message with encrypted content
|
* @returns {Promise<Message>} new message with encrypted content
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async encrypt(keys, passwords, sessionKey, wildcard = false, encryptionKeyIds = [], date = new Date(), userIds = [], streaming) {
|
async encrypt(keys, passwords, sessionKey, wildcard = false, encryptionKeyIds = [], date = new Date(), userIds = [], streaming, config = defaultConfig) {
|
||||||
if (sessionKey) {
|
if (sessionKey) {
|
||||||
if (!util.isUint8Array(sessionKey.data) || !util.isString(sessionKey.algorithm)) {
|
if (!util.isUint8Array(sessionKey.data) || !util.isString(sessionKey.algorithm)) {
|
||||||
throw new Error('Invalid session key for encryption.');
|
throw new Error('Invalid session key for encryption.');
|
||||||
}
|
}
|
||||||
} else if (keys && keys.length) {
|
} else if (keys && keys.length) {
|
||||||
sessionKey = await Message.generateSessionKey(keys, date, userIds);
|
sessionKey = await Message.generateSessionKey(keys, date, userIds, config);
|
||||||
} else if (passwords && passwords.length) {
|
} else if (passwords && passwords.length) {
|
||||||
sessionKey = await Message.generateSessionKey();
|
sessionKey = await Message.generateSessionKey(undefined, undefined, undefined, config);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('No keys, passwords, or session key provided.');
|
throw new Error('No keys, passwords, or session key provided.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data: sessionKeyData, algorithm, aeadAlgorithm } = sessionKey;
|
const { data: sessionKeyData, algorithm, aeadAlgorithm } = sessionKey;
|
||||||
|
|
||||||
const msg = await Message.encryptSessionKey(sessionKeyData, algorithm, aeadAlgorithm, keys, passwords, wildcard, encryptionKeyIds, date, userIds);
|
const msg = await Message.encryptSessionKey(sessionKeyData, algorithm, aeadAlgorithm, keys, passwords, wildcard, encryptionKeyIds, date, userIds, config);
|
||||||
|
|
||||||
let symEncryptedPacket;
|
let symEncryptedPacket;
|
||||||
if (aeadAlgorithm) {
|
if (aeadAlgorithm) {
|
||||||
@ -343,7 +347,7 @@ export class Message {
|
|||||||
}
|
}
|
||||||
symEncryptedPacket.packets = this.packets;
|
symEncryptedPacket.packets = this.packets;
|
||||||
|
|
||||||
await symEncryptedPacket.encrypt(algorithm, sessionKeyData, streaming);
|
await symEncryptedPacket.encrypt(algorithm, sessionKeyData, streaming, config);
|
||||||
|
|
||||||
msg.packets.push(symEncryptedPacket);
|
msg.packets.push(symEncryptedPacket);
|
||||||
symEncryptedPacket.packets = new PacketList(); // remove packets after encryption
|
symEncryptedPacket.packets = new PacketList(); // remove packets after encryption
|
||||||
@ -361,15 +365,16 @@ export class Message {
|
|||||||
* @param {Array<module:type/keyid>} encryptionKeyIds (optional) array of key IDs to use for encryption. Each encryptionKeyIds[i] corresponds to publicKeys[i]
|
* @param {Array<module:type/keyid>} encryptionKeyIds (optional) array of key IDs to use for encryption. Each encryptionKeyIds[i] corresponds to publicKeys[i]
|
||||||
* @param {Date} date (optional) override the date
|
* @param {Date} date (optional) override the date
|
||||||
* @param {Array} userIds (optional) user IDs to encrypt for, e.g. [{ name:'Robert Receiver', email:'robert@openpgp.org' }]
|
* @param {Array} userIds (optional) user IDs to encrypt for, e.g. [{ name:'Robert Receiver', email:'robert@openpgp.org' }]
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Message>} new message with encrypted content
|
* @returns {Promise<Message>} new message with encrypted content
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
static async encryptSessionKey(sessionKey, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard = false, encryptionKeyIds = [], date = new Date(), userIds = []) {
|
static async encryptSessionKey(sessionKey, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard = false, encryptionKeyIds = [], date = new Date(), userIds = [], config = defaultConfig) {
|
||||||
const packetlist = new PacketList();
|
const packetlist = new PacketList();
|
||||||
|
|
||||||
if (publicKeys) {
|
if (publicKeys) {
|
||||||
const results = await Promise.all(publicKeys.map(async function(publicKey, i) {
|
const results = await Promise.all(publicKeys.map(async function(publicKey, i) {
|
||||||
const encryptionKey = await publicKey.getEncryptionKey(encryptionKeyIds[i], date, userIds);
|
const encryptionKey = await publicKey.getEncryptionKey(encryptionKeyIds[i], date, userIds, config);
|
||||||
const pkESKeyPacket = new PublicKeyEncryptedSessionKeyPacket();
|
const pkESKeyPacket = new PublicKeyEncryptedSessionKeyPacket();
|
||||||
pkESKeyPacket.publicKeyId = wildcard ? type_keyid.wildcard() : encryptionKey.getKeyId();
|
pkESKeyPacket.publicKeyId = wildcard ? type_keyid.wildcard() : encryptionKey.getKeyId();
|
||||||
pkESKeyPacket.publicKeyAlgorithm = encryptionKey.keyPacket.algorithm;
|
pkESKeyPacket.publicKeyAlgorithm = encryptionKey.keyPacket.algorithm;
|
||||||
@ -394,13 +399,13 @@ export class Message {
|
|||||||
const sum = (accumulator, currentValue) => accumulator + currentValue;
|
const sum = (accumulator, currentValue) => accumulator + currentValue;
|
||||||
|
|
||||||
const encryptPassword = async function(sessionKey, algorithm, aeadAlgorithm, password) {
|
const encryptPassword = async function(sessionKey, algorithm, aeadAlgorithm, password) {
|
||||||
const symEncryptedSessionKeyPacket = new SymEncryptedSessionKeyPacket();
|
const symEncryptedSessionKeyPacket = new SymEncryptedSessionKeyPacket(config);
|
||||||
symEncryptedSessionKeyPacket.sessionKey = sessionKey;
|
symEncryptedSessionKeyPacket.sessionKey = sessionKey;
|
||||||
symEncryptedSessionKeyPacket.sessionKeyAlgorithm = algorithm;
|
symEncryptedSessionKeyPacket.sessionKeyAlgorithm = algorithm;
|
||||||
if (aeadAlgorithm) {
|
if (aeadAlgorithm) {
|
||||||
symEncryptedSessionKeyPacket.aeadAlgorithm = aeadAlgorithm;
|
symEncryptedSessionKeyPacket.aeadAlgorithm = aeadAlgorithm;
|
||||||
}
|
}
|
||||||
await symEncryptedSessionKeyPacket.encrypt(password);
|
await symEncryptedSessionKeyPacket.encrypt(password, config);
|
||||||
|
|
||||||
if (config.passwordCollisionCheck) {
|
if (config.passwordCollisionCheck) {
|
||||||
const results = await Promise.all(passwords.map(pwd => testDecrypt(symEncryptedSessionKeyPacket, pwd)));
|
const results = await Promise.all(passwords.map(pwd => testDecrypt(symEncryptedSessionKeyPacket, pwd)));
|
||||||
@ -428,10 +433,11 @@ export class Message {
|
|||||||
* @param {Date} date (optional) override the creation time of the signature
|
* @param {Date} date (optional) override the creation time of the signature
|
||||||
* @param {Array} userIds (optional) user IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
|
* @param {Array} userIds (optional) user IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
|
||||||
* @param {Boolean} streaming (optional) whether to process data as a stream
|
* @param {Boolean} streaming (optional) whether to process data as a stream
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Message>} new message with signed content
|
* @returns {Promise<Message>} new message with signed content
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async sign(privateKeys = [], signature = null, signingKeyIds = [], date = new Date(), userIds = [], streaming = false) {
|
async sign(privateKeys = [], signature = null, signingKeyIds = [], date = new Date(), userIds = [], streaming = false, config = defaultConfig) {
|
||||||
const packetlist = new PacketList();
|
const packetlist = new PacketList();
|
||||||
|
|
||||||
const literalDataPacket = this.packets.findPacket(enums.packet.literalData);
|
const literalDataPacket = this.packets.findPacket(enums.packet.literalData);
|
||||||
@ -466,10 +472,10 @@ export class Message {
|
|||||||
throw new Error('Need private key for signing');
|
throw new Error('Need private key for signing');
|
||||||
}
|
}
|
||||||
const signingKeyId = signingKeyIds[privateKeys.length - 1 - i];
|
const signingKeyId = signingKeyIds[privateKeys.length - 1 - i];
|
||||||
const signingKey = await privateKey.getSigningKey(signingKeyId, date, userIds);
|
const signingKey = await privateKey.getSigningKey(signingKeyId, date, userIds, config);
|
||||||
const onePassSig = new OnePassSignaturePacket();
|
const onePassSig = new OnePassSignaturePacket();
|
||||||
onePassSig.signatureType = signatureType;
|
onePassSig.signatureType = signatureType;
|
||||||
onePassSig.hashAlgorithm = await getPreferredHashAlgo(privateKey, signingKey.keyPacket, date, userIds);
|
onePassSig.hashAlgorithm = await getPreferredHashAlgo(privateKey, signingKey.keyPacket, date, userIds, config);
|
||||||
onePassSig.publicKeyAlgorithm = signingKey.keyPacket.algorithm;
|
onePassSig.publicKeyAlgorithm = signingKey.keyPacket.algorithm;
|
||||||
onePassSig.issuerKeyId = signingKey.getKeyId();
|
onePassSig.issuerKeyId = signingKey.getKeyId();
|
||||||
if (i === privateKeys.length - 1) {
|
if (i === privateKeys.length - 1) {
|
||||||
@ -481,24 +487,23 @@ export class Message {
|
|||||||
});
|
});
|
||||||
|
|
||||||
packetlist.push(literalDataPacket);
|
packetlist.push(literalDataPacket);
|
||||||
packetlist.concat(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIds, date, userIds, false, streaming));
|
packetlist.concat(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIds, date, userIds, false, streaming, config));
|
||||||
|
|
||||||
return new Message(packetlist);
|
return new Message(packetlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compresses the message (the literal and -if signed- signature data packets of the message)
|
* Compresses the message (the literal and -if signed- signature data packets of the message)
|
||||||
* @param {module:enums.compression} compression compression algorithm to be used
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {module:message.Message} new message with compressed content
|
* @returns {module:message.Message} new message with compressed content
|
||||||
*/
|
*/
|
||||||
compress(compression) {
|
compress(config = defaultConfig) {
|
||||||
if (compression === enums.compression.uncompressed) {
|
if (config.compression === enums.compression.uncompressed) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
const compressed = new CompressedDataPacket();
|
const compressed = new CompressedDataPacket(config);
|
||||||
compressed.packets = this.packets;
|
compressed.packets = this.packets;
|
||||||
compressed.algorithm = enums.read(enums.compression, compression);
|
|
||||||
|
|
||||||
const packetList = new PacketList();
|
const packetList = new PacketList();
|
||||||
packetList.push(compressed);
|
packetList.push(compressed);
|
||||||
@ -514,15 +519,16 @@ export class Message {
|
|||||||
* @param {Date} date (optional) override the creation time of the signature
|
* @param {Date} date (optional) override the creation time of the signature
|
||||||
* @param {Array} userIds (optional) user IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
|
* @param {Array} userIds (optional) user IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
|
||||||
* @param {Boolean} streaming (optional) whether to process data as a stream
|
* @param {Boolean} streaming (optional) whether to process data as a stream
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<module:signature.Signature>} new detached signature of message content
|
* @returns {Promise<module:signature.Signature>} new detached signature of message content
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async signDetached(privateKeys = [], signature = null, signingKeyIds = [], date = new Date(), userIds = [], streaming = false) {
|
async signDetached(privateKeys = [], signature = null, signingKeyIds = [], date = new Date(), userIds = [], streaming = false, config = defaultConfig) {
|
||||||
const literalDataPacket = this.packets.findPacket(enums.packet.literalData);
|
const literalDataPacket = this.packets.findPacket(enums.packet.literalData);
|
||||||
if (!literalDataPacket) {
|
if (!literalDataPacket) {
|
||||||
throw new Error('No literal data packet to sign.');
|
throw new Error('No literal data packet to sign.');
|
||||||
}
|
}
|
||||||
return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIds, date, userIds, true, streaming));
|
return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIds, date, userIds, true, streaming, config));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -530,10 +536,11 @@ export class Message {
|
|||||||
* @param {Array<module:key.Key>} keys array of keys to verify signatures
|
* @param {Array<module:key.Key>} keys array of keys to verify signatures
|
||||||
* @param {Date} date (optional) Verify the signature against the given date, i.e. check signature creation time < date < expiration time
|
* @param {Date} date (optional) Verify the signature against the given date, i.e. check signature creation time < date < expiration time
|
||||||
* @param {Boolean} streaming (optional) whether to process data as a stream
|
* @param {Boolean} streaming (optional) whether to process data as a stream
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Array<({keyid: module:type/keyid, valid: Boolean})>>} list of signer's keyid and validity of signature
|
* @returns {Promise<Array<({keyid: module:type/keyid, valid: Boolean})>>} list of signer's keyid and validity of signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async verify(keys, date = new Date(), streaming) {
|
async verify(keys, date = new Date(), streaming, config = defaultConfig) {
|
||||||
const msg = this.unwrapCompressed();
|
const msg = this.unwrapCompressed();
|
||||||
const literalDataList = msg.packets.filterByTag(enums.packet.literalData);
|
const literalDataList = msg.packets.filterByTag(enums.packet.literalData);
|
||||||
if (literalDataList.length !== 1) {
|
if (literalDataList.length !== 1) {
|
||||||
@ -572,9 +579,9 @@ export class Message {
|
|||||||
await writer.abort(e);
|
await writer.abort(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return createVerificationObjects(onePassSigList, literalDataList, keys, date, false, streaming);
|
return createVerificationObjects(onePassSigList, literalDataList, keys, date, false, streaming, config);
|
||||||
}
|
}
|
||||||
return createVerificationObjects(signatureList, literalDataList, keys, date, false, streaming);
|
return createVerificationObjects(signatureList, literalDataList, keys, date, false, streaming, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -582,17 +589,18 @@ export class Message {
|
|||||||
* @param {Array<module:key.Key>} keys array of keys to verify signatures
|
* @param {Array<module:key.Key>} keys array of keys to verify signatures
|
||||||
* @param {Signature} signature
|
* @param {Signature} signature
|
||||||
* @param {Date} date Verify the signature against the given date, i.e. check signature creation time < date < expiration time
|
* @param {Date} date Verify the signature against the given date, i.e. check signature creation time < date < expiration time
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Array<({keyid: module:type/keyid, valid: Boolean})>>} list of signer's keyid and validity of signature
|
* @returns {Promise<Array<({keyid: module:type/keyid, valid: Boolean})>>} list of signer's keyid and validity of signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
verifyDetached(signature, keys, date = new Date()) {
|
verifyDetached(signature, keys, date = new Date(), streaming, config = defaultConfig) {
|
||||||
const msg = this.unwrapCompressed();
|
const msg = this.unwrapCompressed();
|
||||||
const literalDataList = msg.packets.filterByTag(enums.packet.literalData);
|
const literalDataList = msg.packets.filterByTag(enums.packet.literalData);
|
||||||
if (literalDataList.length !== 1) {
|
if (literalDataList.length !== 1) {
|
||||||
throw new Error('Can only verify message with one literal data packet.');
|
throw new Error('Can only verify message with one literal data packet.');
|
||||||
}
|
}
|
||||||
const signatureList = signature.packets;
|
const signatureList = signature.packets;
|
||||||
return createVerificationObjects(signatureList, literalDataList, keys, date, true);
|
return createVerificationObjects(signatureList, literalDataList, keys, date, true, undefined, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -625,10 +633,11 @@ export class Message {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns ASCII armored text of message
|
* Returns ASCII armored text of message
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {ReadableStream<String>} ASCII armor
|
* @returns {ReadableStream<String>} ASCII armor
|
||||||
*/
|
*/
|
||||||
armor() {
|
armor(config = defaultConfig) {
|
||||||
return armor(enums.armor.message, this.write());
|
return armor(enums.armor.message, this.write(), null, null, null, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -699,10 +708,11 @@ export class Message {
|
|||||||
* @param {Array} userIds (optional) user IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
|
* @param {Array} userIds (optional) user IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
|
||||||
* @param {Boolean} detached (optional) whether to create detached signature packets
|
* @param {Boolean} detached (optional) whether to create detached signature packets
|
||||||
* @param {Boolean} streaming (optional) whether to process data as a stream
|
* @param {Boolean} streaming (optional) whether to process data as a stream
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<module:PacketList>} list of signature packets
|
* @returns {Promise<module:PacketList>} list of signature packets
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function createSignaturePackets(literalDataPacket, privateKeys, signature = null, signingKeyIds = [], date = new Date(), userIds = [], detached = false, streaming = false) {
|
export async function createSignaturePackets(literalDataPacket, privateKeys, signature = null, signingKeyIds = [], date = new Date(), userIds = [], detached = false, streaming = false, config = defaultConfig) {
|
||||||
const packetlist = new PacketList();
|
const packetlist = new PacketList();
|
||||||
|
|
||||||
// If data packet was created from Uint8Array, use binary, otherwise use text
|
// If data packet was created from Uint8Array, use binary, otherwise use text
|
||||||
@ -714,8 +724,8 @@ export async function createSignaturePackets(literalDataPacket, privateKeys, sig
|
|||||||
if (privateKey.isPublic()) {
|
if (privateKey.isPublic()) {
|
||||||
throw new Error('Need private key for signing');
|
throw new Error('Need private key for signing');
|
||||||
}
|
}
|
||||||
const signingKey = await privateKey.getSigningKey(signingKeyIds[i], date, userId);
|
const signingKey = await privateKey.getSigningKey(signingKeyIds[i], date, userId, config);
|
||||||
return createSignaturePacket(literalDataPacket, privateKey, signingKey.keyPacket, { signatureType }, date, userId, detached, streaming);
|
return createSignaturePacket(literalDataPacket, privateKey, signingKey.keyPacket, { signatureType }, date, userId, detached, streaming, config);
|
||||||
})).then(signatureList => {
|
})).then(signatureList => {
|
||||||
signatureList.forEach(signaturePacket => packetlist.push(signaturePacket));
|
signatureList.forEach(signaturePacket => packetlist.push(signaturePacket));
|
||||||
});
|
});
|
||||||
@ -735,17 +745,18 @@ export async function createSignaturePackets(literalDataPacket, privateKeys, sig
|
|||||||
* @param {Date} date Verify the signature against the given date,
|
* @param {Date} date Verify the signature against the given date,
|
||||||
* i.e. check signature creation time < date < expiration time
|
* i.e. check signature creation time < date < expiration time
|
||||||
* @param {Boolean} detached (optional) whether to verify detached signature packets
|
* @param {Boolean} detached (optional) whether to verify detached signature packets
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Array<{keyid: module:type/keyid,
|
* @returns {Promise<Array<{keyid: module:type/keyid,
|
||||||
* valid: Boolean|null}>>} list of signer's keyid and validity of signature
|
* valid: Boolean|null}>>} list of signer's keyid and validity of signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async function createVerificationObject(signature, literalDataList, keys, date = new Date(), detached = false, streaming = false) {
|
async function createVerificationObject(signature, literalDataList, keys, date = new Date(), detached = false, streaming = false, config = defaultConfig) {
|
||||||
let primaryKey = null;
|
let primaryKey = null;
|
||||||
let signingKey = null;
|
let signingKey = null;
|
||||||
await Promise.all(keys.map(async function(key) {
|
await Promise.all(keys.map(async function(key) {
|
||||||
// Look for the unique key that matches issuerKeyId of signature
|
// Look for the unique key that matches issuerKeyId of signature
|
||||||
try {
|
try {
|
||||||
signingKey = await key.getSigningKey(signature.issuerKeyId, null);
|
signingKey = await key.getSigningKey(signature.issuerKeyId, null, undefined, config);
|
||||||
primaryKey = key;
|
primaryKey = key;
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}));
|
}));
|
||||||
@ -757,13 +768,13 @@ async function createVerificationObject(signature, literalDataList, keys, date =
|
|||||||
if (!signingKey) {
|
if (!signingKey) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
await signature.verify(signingKey.keyPacket, signature.signatureType, literalDataList[0], detached, streaming);
|
await signature.verify(signingKey.keyPacket, signature.signatureType, literalDataList[0], detached, streaming, config);
|
||||||
const sig = await signaturePacket;
|
const sig = await signaturePacket;
|
||||||
if (sig.isExpired(date) || !(
|
if (sig.isExpired(date) || !(
|
||||||
sig.created >= signingKey.getCreationTime() &&
|
sig.created >= signingKey.getCreationTime() &&
|
||||||
sig.created < await (signingKey === primaryKey ?
|
sig.created < await (signingKey === primaryKey ?
|
||||||
signingKey.getExpirationTime() :
|
signingKey.getExpirationTime(undefined, undefined, undefined, config) :
|
||||||
signingKey.getExpirationTime(primaryKey, date)
|
signingKey.getExpirationTime(primaryKey, date, undefined, config)
|
||||||
)
|
)
|
||||||
)) {
|
)) {
|
||||||
throw new Error('Signature is expired');
|
throw new Error('Signature is expired');
|
||||||
@ -796,15 +807,16 @@ async function createVerificationObject(signature, literalDataList, keys, date =
|
|||||||
* @param {Date} date Verify the signature against the given date,
|
* @param {Date} date Verify the signature against the given date,
|
||||||
* i.e. check signature creation time < date < expiration time
|
* i.e. check signature creation time < date < expiration time
|
||||||
* @param {Boolean} detached (optional) whether to verify detached signature packets
|
* @param {Boolean} detached (optional) whether to verify detached signature packets
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Array<{keyid: module:type/keyid,
|
* @returns {Promise<Array<{keyid: module:type/keyid,
|
||||||
* valid: Boolean}>>} list of signer's keyid and validity of signature
|
* valid: Boolean}>>} list of signer's keyid and validity of signature
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function createVerificationObjects(signatureList, literalDataList, keys, date = new Date(), detached = false, streaming = false) {
|
export async function createVerificationObjects(signatureList, literalDataList, keys, date = new Date(), detached = false, streaming = false, config = defaultConfig) {
|
||||||
return Promise.all(signatureList.filter(function(signature) {
|
return Promise.all(signatureList.filter(function(signature) {
|
||||||
return ['text', 'binary'].includes(enums.read(enums.signature, signature.signatureType));
|
return ['text', 'binary'].includes(enums.read(enums.signature, signature.signatureType));
|
||||||
}).map(async function(signature) {
|
}).map(async function(signature) {
|
||||||
return createVerificationObject(signature, literalDataList, keys, date, detached, streaming);
|
return createVerificationObject(signature, literalDataList, keys, date, detached, streaming, config);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -812,11 +824,13 @@ export async function createVerificationObjects(signatureList, literalDataList,
|
|||||||
* Reads an (optionally armored) OpenPGP message and returns a Message object
|
* Reads an (optionally armored) OpenPGP message and returns a Message object
|
||||||
* @param {String | ReadableStream<String>} armoredMessage armored message to be parsed
|
* @param {String | ReadableStream<String>} armoredMessage armored message to be parsed
|
||||||
* @param {Uint8Array | ReadableStream<Uint8Array>} binaryMessage binary to be parsed
|
* @param {Uint8Array | ReadableStream<Uint8Array>} binaryMessage binary to be parsed
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Promise<Message>} new message object
|
* @returns {Promise<Message>} new message object
|
||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export async function readMessage({ armoredMessage, binaryMessage }) {
|
export async function readMessage({ armoredMessage, binaryMessage, config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
let input = armoredMessage || binaryMessage;
|
let input = armoredMessage || binaryMessage;
|
||||||
if (!input) {
|
if (!input) {
|
||||||
throw new Error('readMessage: must pass options object containing `armoredMessage` or `binaryMessage`');
|
throw new Error('readMessage: must pass options object containing `armoredMessage` or `binaryMessage`');
|
||||||
@ -826,7 +840,7 @@ export async function readMessage({ armoredMessage, binaryMessage }) {
|
|||||||
input = stream.nodeToWeb(input);
|
input = stream.nodeToWeb(input);
|
||||||
}
|
}
|
||||||
if (armoredMessage) {
|
if (armoredMessage) {
|
||||||
const { type, data } = await unarmor(input);
|
const { type, data } = await unarmor(input, config);
|
||||||
if (type !== enums.armor.message) {
|
if (type !== enums.armor.message) {
|
||||||
throw new Error('Armored text not of type message');
|
throw new Error('Armored text not of type message');
|
||||||
}
|
}
|
||||||
@ -843,7 +857,7 @@ export async function readMessage({ armoredMessage, binaryMessage }) {
|
|||||||
SymEncryptedSessionKeyPacket,
|
SymEncryptedSessionKeyPacket,
|
||||||
OnePassSignaturePacket,
|
OnePassSignaturePacket,
|
||||||
SignaturePacket
|
SignaturePacket
|
||||||
}, streamType);
|
}, streamType, config);
|
||||||
const message = new Message(packetlist);
|
const message = new Message(packetlist);
|
||||||
message.fromStream = streamType;
|
message.fromStream = streamType;
|
||||||
return message;
|
return message;
|
||||||
|
128
src/openpgp.js
128
src/openpgp.js
@ -43,7 +43,7 @@ import { createReadableStreamWrapper } from '@mattiasbuelens/web-streams-adapter
|
|||||||
import { Message } from './message';
|
import { Message } from './message';
|
||||||
import { CleartextMessage } from './cleartext';
|
import { CleartextMessage } from './cleartext';
|
||||||
import { generate, reformat } from './key';
|
import { generate, reformat } from './key';
|
||||||
import config from './config/config';
|
import defaultConfig from './config';
|
||||||
import './polyfills';
|
import './polyfills';
|
||||||
import util from './util';
|
import util from './util';
|
||||||
|
|
||||||
@ -74,27 +74,29 @@ if (globalThis.ReadableStream) {
|
|||||||
* @param {Number} keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires
|
* @param {Number} keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires
|
||||||
* @param {Array<Object>} subkeys (optional) Options for each subkey, default to main key options. e.g. [{sign: true, passphrase: '123'}]
|
* @param {Array<Object>} 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
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Promise<Object>} The generated key object in the form:
|
* @returns {Promise<Object>} The generated key object in the form:
|
||||||
* { key:Key, privateKeyArmored:String, publicKeyArmored:String, revocationCertificate:String }
|
* { key:Key, privateKeyArmored:String, publicKeyArmored:String, revocationCertificate:String }
|
||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function generateKey({ userIds = [], passphrase = "", type = "ecc", rsaBits = 4096, curve = "curve25519", keyExpirationTime = 0, date = new Date(), subkeys = [{}] }) {
|
export function generateKey({ userIds = [], passphrase = "", type = "ecc", rsaBits = 4096, curve = "curve25519", keyExpirationTime = 0, date = new Date(), subkeys = [{}], config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
userIds = toArray(userIds);
|
userIds = toArray(userIds);
|
||||||
const options = { userIds, passphrase, type, rsaBits, curve, keyExpirationTime, date, subkeys };
|
const options = { userIds, passphrase, type, rsaBits, curve, keyExpirationTime, date, subkeys };
|
||||||
if (type === "rsa" && rsaBits < config.minRsaBits) {
|
if (type === "rsa" && rsaBits < config.minRsaBits) {
|
||||||
throw new Error(`rsaBits should be at least ${config.minRsaBits}, got: ${rsaBits}`);
|
throw new Error(`rsaBits should be at least ${config.minRsaBits}, got: ${rsaBits}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return generate(options).then(async key => {
|
return generate(options, config).then(async key => {
|
||||||
const revocationCertificate = await key.getRevocationCertificate(date);
|
const revocationCertificate = await key.getRevocationCertificate(date, config);
|
||||||
key.revocationSignatures = [];
|
key.revocationSignatures = [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
||||||
key: key,
|
key: key,
|
||||||
privateKeyArmored: key.armor(),
|
privateKeyArmored: key.armor(config),
|
||||||
publicKeyArmored: key.toPublic().armor(),
|
publicKeyArmored: key.toPublic().armor(config),
|
||||||
revocationCertificate: revocationCertificate
|
revocationCertificate: revocationCertificate
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -107,24 +109,26 @@ export function generateKey({ userIds = [], passphrase = "", type = "ecc", rsaBi
|
|||||||
* @param {Object|Array<Object>} userIds User IDs as objects: { name:'Jo Doe', email:'info@jo.com' }
|
* @param {Object|Array<Object>} userIds User IDs as objects: { name:'Jo Doe', email:'info@jo.com' }
|
||||||
* @param {String} passphrase (optional) The passphrase used to encrypt the resulting private key
|
* @param {String} passphrase (optional) The passphrase used to encrypt the resulting private key
|
||||||
* @param {Number} keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires
|
* @param {Number} keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Promise<Object>} The generated key object in the form:
|
* @returns {Promise<Object>} The generated key object in the form:
|
||||||
* { key:Key, privateKeyArmored:String, publicKeyArmored:String, revocationCertificate:String }
|
* { key:Key, privateKeyArmored:String, publicKeyArmored:String, revocationCertificate:String }
|
||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function reformatKey({ privateKey, userIds = [], passphrase = "", keyExpirationTime = 0, date }) {
|
export function reformatKey({ privateKey, userIds = [], passphrase = "", keyExpirationTime = 0, date, config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
userIds = toArray(userIds);
|
userIds = toArray(userIds);
|
||||||
const options = { privateKey, userIds, passphrase, keyExpirationTime, date };
|
const options = { privateKey, userIds, passphrase, keyExpirationTime, date };
|
||||||
|
|
||||||
return reformat(options).then(async key => {
|
return reformat(options, config).then(async key => {
|
||||||
const revocationCertificate = await key.getRevocationCertificate(date);
|
const revocationCertificate = await key.getRevocationCertificate(date, config);
|
||||||
key.revocationSignatures = [];
|
key.revocationSignatures = [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
||||||
key: key,
|
key: key,
|
||||||
privateKeyArmored: key.armor(),
|
privateKeyArmored: key.armor(config),
|
||||||
publicKeyArmored: key.toPublic().armor(),
|
publicKeyArmored: key.toPublic().armor(config),
|
||||||
revocationCertificate: revocationCertificate
|
revocationCertificate: revocationCertificate
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -139,33 +143,34 @@ export function reformatKey({ privateKey, userIds = [], passphrase = "", keyExpi
|
|||||||
* @param {Object} reasonForRevocation (optional) object indicating the reason for revocation
|
* @param {Object} reasonForRevocation (optional) object indicating the reason for revocation
|
||||||
* @param {module:enums.reasonForRevocation} reasonForRevocation.flag (optional) flag indicating the reason for revocation
|
* @param {module:enums.reasonForRevocation} reasonForRevocation.flag (optional) flag indicating the reason for revocation
|
||||||
* @param {String} reasonForRevocation.string (optional) string explaining the reason for revocation
|
* @param {String} reasonForRevocation.string (optional) string explaining the reason for revocation
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Promise<Object>} The revoked key object in the form:
|
* @returns {Promise<Object>} The revoked key object in the form:
|
||||||
* { privateKey:Key, privateKeyArmored:String, publicKey:Key, publicKeyArmored:String }
|
* { privateKey:Key, privateKeyArmored:String, publicKey:Key, publicKeyArmored:String }
|
||||||
* (if private key is passed) or { publicKey:Key, publicKeyArmored:String } (otherwise)
|
* (if private key is passed) or { publicKey:Key, publicKeyArmored:String } (otherwise)
|
||||||
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function revokeKey({
|
export function revokeKey({ key, revocationCertificate, reasonForRevocation, config }) {
|
||||||
key, revocationCertificate, reasonForRevocation
|
config = { ...defaultConfig, ...config };
|
||||||
} = {}) {
|
|
||||||
return Promise.resolve().then(() => {
|
return Promise.resolve().then(() => {
|
||||||
if (revocationCertificate) {
|
if (revocationCertificate) {
|
||||||
return key.applyRevocationCertificate(revocationCertificate);
|
return key.applyRevocationCertificate(revocationCertificate, config);
|
||||||
} else {
|
} else {
|
||||||
return key.revoke(reasonForRevocation);
|
return key.revoke(reasonForRevocation, undefined, config);
|
||||||
}
|
}
|
||||||
}).then(async key => {
|
}).then(async key => {
|
||||||
if (key.isPrivate()) {
|
if (key.isPrivate()) {
|
||||||
const publicKey = key.toPublic();
|
const publicKey = key.toPublic();
|
||||||
return {
|
return {
|
||||||
privateKey: key,
|
privateKey: key,
|
||||||
privateKeyArmored: key.armor(),
|
privateKeyArmored: key.armor(config),
|
||||||
publicKey: publicKey,
|
publicKey: publicKey,
|
||||||
publicKeyArmored: publicKey.armor()
|
publicKeyArmored: publicKey.armor(config)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
publicKey: key,
|
publicKey: key,
|
||||||
publicKeyArmored: key.armor()
|
publicKeyArmored: key.armor(config)
|
||||||
};
|
};
|
||||||
}).catch(onError.bind(null, 'Error revoking key'));
|
}).catch(onError.bind(null, 'Error revoking key'));
|
||||||
}
|
}
|
||||||
@ -175,10 +180,12 @@ export function revokeKey({
|
|||||||
* This method does not change the original key.
|
* This method does not change the original key.
|
||||||
* @param {Key} privateKey the private key to decrypt
|
* @param {Key} privateKey the private key to decrypt
|
||||||
* @param {String|Array<String>} passphrase the user's passphrase(s)
|
* @param {String|Array<String>} passphrase the user's passphrase(s)
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Promise<Key>} the unlocked key object
|
* @returns {Promise<Key>} the unlocked key object
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function decryptKey({ privateKey, passphrase }) {
|
export async function decryptKey({ privateKey, passphrase, config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
const key = await privateKey.clone();
|
const key = await privateKey.clone();
|
||||||
// shallow clone is enough since the encrypted material is not changed in place by decryption
|
// shallow clone is enough since the encrypted material is not changed in place by decryption
|
||||||
key.getKeys().forEach(k => {
|
key.getKeys().forEach(k => {
|
||||||
@ -188,7 +195,7 @@ export async function decryptKey({ privateKey, passphrase }) {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await key.decrypt(passphrase);
|
await key.decrypt(passphrase, undefined, config);
|
||||||
return key;
|
return key;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
key.clearPrivateParams();
|
key.clearPrivateParams();
|
||||||
@ -201,10 +208,12 @@ export async function decryptKey({ privateKey, passphrase }) {
|
|||||||
* This method does not change the original key.
|
* This method does not change the original key.
|
||||||
* @param {Key} privateKey the private key to encrypt
|
* @param {Key} privateKey the private key to encrypt
|
||||||
* @param {String|Array<String>} passphrase if multiple passphrases, they should be in the same order as the packets each should encrypt
|
* @param {String|Array<String>} passphrase if multiple passphrases, they should be in the same order as the packets each should encrypt
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Promise<Key>} the locked key object
|
* @returns {Promise<Key>} the locked key object
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function encryptKey({ privateKey, passphrase }) {
|
export async function encryptKey({ privateKey, passphrase, config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
const key = await privateKey.clone();
|
const key = await privateKey.clone();
|
||||||
key.getKeys().forEach(k => {
|
key.getKeys().forEach(k => {
|
||||||
// shallow clone the key packets
|
// shallow clone the key packets
|
||||||
@ -221,7 +230,7 @@ export async function encryptKey({ privateKey, passphrase }) {
|
|||||||
k.keyPacket.privateParams = privateParams;
|
k.keyPacket.privateParams = privateParams;
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await key.encrypt(passphrase);
|
await key.encrypt(passphrase, undefined, config);
|
||||||
return key;
|
return key;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
key.clearPrivateParams();
|
key.clearPrivateParams();
|
||||||
@ -245,7 +254,6 @@ export async function encryptKey({ privateKey, passphrase }) {
|
|||||||
* @param {Key|Array<Key>} privateKeys (optional) private keys for signing. If omitted message will not be signed
|
* @param {Key|Array<Key>} privateKeys (optional) private keys for signing. If omitted message will not be signed
|
||||||
* @param {String|Array<String>} passwords (optional) array of passwords or a single password to encrypt the message
|
* @param {String|Array<String>} passwords (optional) array of passwords or a single password to encrypt the message
|
||||||
* @param {Object} sessionKey (optional) session key in the form: { data:Uint8Array, algorithm:String }
|
* @param {Object} sessionKey (optional) session key in the form: { data:Uint8Array, algorithm:String }
|
||||||
* @param {module:enums.compression} compression (optional) which compression algorithm to compress the message with, defaults to what is specified in config
|
|
||||||
* @param {Boolean} armor (optional) whether the return values should be ascii armored (true, the default) or binary (false)
|
* @param {Boolean} armor (optional) whether the return values should be ascii armored (true, the default) or binary (false)
|
||||||
* @param {'web'|'ponyfill'|'node'|false} streaming (optional) whether to return data as a stream. Defaults to the type of stream `message` was created from, if any.
|
* @param {'web'|'ponyfill'|'node'|false} streaming (optional) whether to return data as a stream. Defaults to the type of stream `message` was created from, if any.
|
||||||
* @param {Signature} signature (optional) a detached signature to add to the encrypted message
|
* @param {Signature} signature (optional) a detached signature to add to the encrypted message
|
||||||
@ -255,11 +263,13 @@ export async function encryptKey({ privateKey, passphrase }) {
|
|||||||
* @param {Date} date (optional) override the creation date of the message signature
|
* @param {Date} date (optional) override the creation date of the message signature
|
||||||
* @param {Array<Object>} fromUserIds (optional) array of user IDs to sign with, one per key in `privateKeys`, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
|
* @param {Array<Object>} fromUserIds (optional) array of user IDs to sign with, one per key in `privateKeys`, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
|
||||||
* @param {Array<Object>} toUserIds (optional) array of user IDs to encrypt for, one per key in `publicKeys`, e.g. [{ name:'Robert Receiver', email:'robert@openpgp.org' }]
|
* @param {Array<Object>} toUserIds (optional) array of user IDs to encrypt for, one per key in `publicKeys`, e.g. [{ name:'Robert Receiver', email:'robert@openpgp.org' }]
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Promise<String|ReadableStream<String>|NodeStream<String>|Uint8Array|ReadableStream<Uint8Array>|NodeStream<Uint8Array>>} (String if `armor` was true, the default; Uint8Array if `armor` was false)
|
* @returns {Promise<String|ReadableStream<String>|NodeStream<String>|Uint8Array|ReadableStream<Uint8Array>|NodeStream<Uint8Array>>} (String if `armor` was true, the default; Uint8Array if `armor` was false)
|
||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function encrypt({ message, publicKeys, privateKeys, passwords, sessionKey, compression = config.compression, armor = true, streaming = message && message.fromStream, detached = false, signature = null, wildcard = false, signingKeyIds = [], encryptionKeyIds = [], date = new Date(), fromUserIds = [], toUserIds = [] }) {
|
export function encrypt({ message, publicKeys, privateKeys, passwords, sessionKey, armor = true, streaming = message && message.fromStream, detached = false, signature = null, wildcard = false, signingKeyIds = [], encryptionKeyIds = [], date = new Date(), fromUserIds = [], toUserIds = [], config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
checkMessage(message); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords); fromUserIds = toArray(fromUserIds); toUserIds = toArray(toUserIds);
|
checkMessage(message); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords); fromUserIds = toArray(fromUserIds); toUserIds = toArray(toUserIds);
|
||||||
if (detached) {
|
if (detached) {
|
||||||
throw new Error("detached option has been removed from openpgp.encrypt. Separately call openpgp.sign instead. Don't forget to remove privateKeys option as well.");
|
throw new Error("detached option has been removed from openpgp.encrypt. Separately call openpgp.sign instead. Don't forget to remove privateKeys option as well.");
|
||||||
@ -270,11 +280,11 @@ export function encrypt({ message, publicKeys, privateKeys, passwords, sessionKe
|
|||||||
privateKeys = [];
|
privateKeys = [];
|
||||||
}
|
}
|
||||||
if (privateKeys.length || signature) { // sign the message only if private keys or signature is specified
|
if (privateKeys.length || signature) { // sign the message only if private keys or signature is specified
|
||||||
message = await message.sign(privateKeys, signature, signingKeyIds, date, fromUserIds, message.fromStream);
|
message = await message.sign(privateKeys, signature, signingKeyIds, date, fromUserIds, message.fromStream, config);
|
||||||
}
|
}
|
||||||
message = message.compress(compression);
|
message = message.compress(config);
|
||||||
message = await message.encrypt(publicKeys, passwords, sessionKey, wildcard, encryptionKeyIds, date, toUserIds, streaming);
|
message = await message.encrypt(publicKeys, passwords, sessionKey, wildcard, encryptionKeyIds, date, toUserIds, streaming, config);
|
||||||
const data = armor ? message.armor() : message.write();
|
const data = armor ? message.armor(config) : message.write();
|
||||||
return convertStream(data, streaming, armor ? 'utf8' : 'binary');
|
return convertStream(data, streaming, armor ? 'utf8' : 'binary');
|
||||||
}).catch(onError.bind(null, 'Error encrypting message'));
|
}).catch(onError.bind(null, 'Error encrypting message'));
|
||||||
}
|
}
|
||||||
@ -291,6 +301,7 @@ export function encrypt({ message, publicKeys, privateKeys, passwords, sessionKe
|
|||||||
* @param {'web'|'ponyfill'|'node'|false} streaming (optional) whether to return data as a stream. Defaults to the type of stream `message` was created from, if any.
|
* @param {'web'|'ponyfill'|'node'|false} streaming (optional) whether to return data as a stream. Defaults to the type of stream `message` was created from, if any.
|
||||||
* @param {Signature} signature (optional) detached signature for verification
|
* @param {Signature} signature (optional) detached signature for verification
|
||||||
* @param {Date} date (optional) use the given date for verification instead of the current time
|
* @param {Date} date (optional) use the given date for verification instead of the current time
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Promise<Object>} Object containing decrypted and verified message in the form:
|
* @returns {Promise<Object>} Object containing decrypted and verified message in the form:
|
||||||
*
|
*
|
||||||
* {
|
* {
|
||||||
@ -308,16 +319,17 @@ export function encrypt({ message, publicKeys, privateKeys, passwords, sessionKe
|
|||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKeys, format = 'utf8', streaming = message && message.fromStream, signature = null, date = new Date() }) {
|
export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKeys, format = 'utf8', streaming = message && message.fromStream, signature = null, date = new Date(), config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
checkMessage(message); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords); sessionKeys = toArray(sessionKeys);
|
checkMessage(message); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords); sessionKeys = toArray(sessionKeys);
|
||||||
|
|
||||||
return message.decrypt(privateKeys, passwords, sessionKeys, streaming).then(async function(decrypted) {
|
return message.decrypt(privateKeys, passwords, sessionKeys, streaming, config).then(async function(decrypted) {
|
||||||
if (!publicKeys) {
|
if (!publicKeys) {
|
||||||
publicKeys = [];
|
publicKeys = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = {};
|
const result = {};
|
||||||
result.signatures = signature ? await decrypted.verifyDetached(signature, publicKeys, date, streaming) : await decrypted.verify(publicKeys, date, streaming);
|
result.signatures = signature ? await decrypted.verifyDetached(signature, publicKeys, date, streaming, config) : await decrypted.verify(publicKeys, date, streaming, config);
|
||||||
result.data = format === 'binary' ? decrypted.getLiteralData() : decrypted.getText();
|
result.data = format === 'binary' ? decrypted.getLiteralData() : decrypted.getText();
|
||||||
result.filename = decrypted.getFilename();
|
result.filename = decrypted.getFilename();
|
||||||
linkStreams(result, message);
|
linkStreams(result, message);
|
||||||
@ -345,11 +357,13 @@ export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKe
|
|||||||
* @param {Array<module:type/keyid>} signingKeyIds (optional) array of key IDs to use for signing. Each signingKeyIds[i] corresponds to privateKeys[i]
|
* @param {Array<module:type/keyid>} signingKeyIds (optional) array of key IDs to use for signing. Each signingKeyIds[i] corresponds to privateKeys[i]
|
||||||
* @param {Date} date (optional) override the creation date of the signature
|
* @param {Date} date (optional) override the creation date of the signature
|
||||||
* @param {Array<Object>} fromUserIds (optional) array of user IDs to sign with, one per key in `privateKeys`, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
|
* @param {Array<Object>} fromUserIds (optional) array of user IDs to sign with, one per key in `privateKeys`, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Promise<String|ReadableStream<String>|NodeStream<String>|Uint8Array|ReadableStream<Uint8Array>|NodeStream<Uint8Array>>} (String if `armor` was true, the default; Uint8Array if `armor` was false)
|
* @returns {Promise<String|ReadableStream<String>|NodeStream<String>|Uint8Array|ReadableStream<Uint8Array>|NodeStream<Uint8Array>>} (String if `armor` was true, the default; Uint8Array if `armor` was false)
|
||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function sign({ message, privateKeys, armor = true, streaming = message && message.fromStream, detached = false, signingKeyIds = [], date = new Date(), fromUserIds = [] }) {
|
export function sign({ message, privateKeys, armor = true, streaming = message && message.fromStream, detached = false, signingKeyIds = [], date = new Date(), fromUserIds = [], config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
checkCleartextOrMessage(message);
|
checkCleartextOrMessage(message);
|
||||||
if (message instanceof CleartextMessage && !armor) throw new Error("Can't sign non-armored cleartext message");
|
if (message instanceof CleartextMessage && !armor) throw new Error("Can't sign non-armored cleartext message");
|
||||||
if (message instanceof CleartextMessage && detached) throw new Error("Can't sign detached cleartext message");
|
if (message instanceof CleartextMessage && detached) throw new Error("Can't sign detached cleartext message");
|
||||||
@ -357,12 +371,14 @@ export function sign({ message, privateKeys, armor = true, streaming = message &
|
|||||||
|
|
||||||
return Promise.resolve().then(async function() {
|
return Promise.resolve().then(async function() {
|
||||||
let signature;
|
let signature;
|
||||||
if (detached) {
|
if (message instanceof CleartextMessage) {
|
||||||
signature = await message.signDetached(privateKeys, undefined, signingKeyIds, date, fromUserIds, message.fromStream);
|
signature = await message.sign(privateKeys, undefined, signingKeyIds, date, fromUserIds, config);
|
||||||
|
} else if (detached) {
|
||||||
|
signature = await message.signDetached(privateKeys, undefined, signingKeyIds, date, fromUserIds, message.fromStream, config);
|
||||||
} else {
|
} else {
|
||||||
signature = await message.sign(privateKeys, undefined, signingKeyIds, date, fromUserIds, message.fromStream);
|
signature = await message.sign(privateKeys, undefined, signingKeyIds, date, fromUserIds, message.fromStream, config);
|
||||||
}
|
}
|
||||||
signature = armor ? signature.armor() : signature.write();
|
signature = armor ? signature.armor(config) : signature.write();
|
||||||
if (detached) {
|
if (detached) {
|
||||||
signature = stream.transformPair(message.packets.write(), async (readable, writable) => {
|
signature = stream.transformPair(message.packets.write(), async (readable, writable) => {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
@ -383,6 +399,7 @@ export function sign({ message, privateKeys, armor = true, streaming = message &
|
|||||||
* @param {'web'|'ponyfill'|'node'|false} streaming (optional) whether to return data as a stream. Defaults to the type of stream `message` was created from, if any.
|
* @param {'web'|'ponyfill'|'node'|false} streaming (optional) whether to return data as a stream. Defaults to the type of stream `message` was created from, if any.
|
||||||
* @param {Signature} signature (optional) detached signature for verification
|
* @param {Signature} signature (optional) detached signature for verification
|
||||||
* @param {Date} date (optional) use the given date for verification instead of the current time
|
* @param {Date} date (optional) use the given date for verification instead of the current time
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Promise<Object>} Object containing verified message in the form:
|
* @returns {Promise<Object>} Object containing verified message in the form:
|
||||||
*
|
*
|
||||||
* {
|
* {
|
||||||
@ -399,14 +416,19 @@ export function sign({ message, privateKeys, armor = true, streaming = message &
|
|||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function verify({ message, publicKeys, format = 'utf8', streaming = message && message.fromStream, signature = null, date = new Date() }) {
|
export function verify({ message, publicKeys, format = 'utf8', streaming = message && message.fromStream, signature = null, date = new Date(), config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
checkCleartextOrMessage(message);
|
checkCleartextOrMessage(message);
|
||||||
if (message instanceof CleartextMessage && format === 'binary') throw new Error("Can't return cleartext message data as binary");
|
if (message instanceof CleartextMessage && format === 'binary') throw new Error("Can't return cleartext message data as binary");
|
||||||
publicKeys = toArray(publicKeys);
|
publicKeys = toArray(publicKeys);
|
||||||
|
|
||||||
return Promise.resolve().then(async function() {
|
return Promise.resolve().then(async function() {
|
||||||
const result = {};
|
const result = {};
|
||||||
result.signatures = signature ? await message.verifyDetached(signature, publicKeys, date, streaming) : await message.verify(publicKeys, date, streaming);
|
if (message instanceof CleartextMessage) {
|
||||||
|
result.signatures = signature ? await message.verifyDetached(signature, publicKeys, date, config) : await message.verify(publicKeys, date, config);
|
||||||
|
} else {
|
||||||
|
result.signatures = signature ? await message.verifyDetached(signature, publicKeys, date, streaming, config) : await message.verify(publicKeys, date, streaming, config);
|
||||||
|
}
|
||||||
result.data = format === 'binary' ? message.getLiteralData() : message.getText();
|
result.data = format === 'binary' ? message.getLiteralData() : message.getText();
|
||||||
if (streaming) linkStreams(result, message);
|
if (streaming) linkStreams(result, message);
|
||||||
result.data = await convertStream(result.data, streaming, format);
|
result.data = await convertStream(result.data, streaming, format);
|
||||||
@ -427,16 +449,18 @@ export function verify({ message, publicKeys, format = 'utf8', streaming = messa
|
|||||||
* @param {Key|Array<Key>} publicKeys array of public keys or single key used to select algorithm preferences for
|
* @param {Key|Array<Key>} publicKeys array of public keys or single key used to select algorithm preferences for
|
||||||
* @param {Date} date (optional) date to select algorithm preferences at
|
* @param {Date} date (optional) date to select algorithm preferences at
|
||||||
* @param {Array} toUserIds (optional) user IDs to select algorithm preferences for
|
* @param {Array} toUserIds (optional) user IDs to select algorithm preferences for
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Promise<{ data: Uint8Array, algorithm: String }>} object with session key data and algorithm
|
* @returns {Promise<{ data: Uint8Array, algorithm: String }>} object with session key data and algorithm
|
||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function generateSessionKey({ publicKeys, date = new Date(), toUserIds = [] }) {
|
export function generateSessionKey({ publicKeys, date = new Date(), toUserIds = [], config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
publicKeys = toArray(publicKeys); toUserIds = toArray(toUserIds);
|
publicKeys = toArray(publicKeys); toUserIds = toArray(toUserIds);
|
||||||
|
|
||||||
return Promise.resolve().then(async function() {
|
return Promise.resolve().then(async function() {
|
||||||
|
|
||||||
return Message.generateSessionKey(publicKeys, date, toUserIds);
|
return Message.generateSessionKey(publicKeys, date, toUserIds, config);
|
||||||
|
|
||||||
}).catch(onError.bind(null, 'Error generating session key'));
|
}).catch(onError.bind(null, 'Error generating session key'));
|
||||||
}
|
}
|
||||||
@ -454,17 +478,19 @@ export function generateSessionKey({ publicKeys, date = new Date(), toUserIds =
|
|||||||
* @param {Array<module:type/keyid>} encryptionKeyIds (optional) array of key IDs to use for encryption. Each encryptionKeyIds[i] corresponds to publicKeys[i]
|
* @param {Array<module:type/keyid>} encryptionKeyIds (optional) array of key IDs to use for encryption. Each encryptionKeyIds[i] corresponds to publicKeys[i]
|
||||||
* @param {Date} date (optional) override the date
|
* @param {Date} date (optional) override the date
|
||||||
* @param {Array} toUserIds (optional) array of user IDs to encrypt for, one per key in `publicKeys`, e.g. [{ name:'Phil Zimmermann', email:'phil@openpgp.org' }]
|
* @param {Array} toUserIds (optional) array of user IDs to encrypt for, one per key in `publicKeys`, e.g. [{ name:'Phil Zimmermann', email:'phil@openpgp.org' }]
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Promise<String|Uint8Array>} (String if `armor` was true, the default; Uint8Array if `armor` was false)
|
* @returns {Promise<String|Uint8Array>} (String if `armor` was true, the default; Uint8Array if `armor` was false)
|
||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function encryptSessionKey({ data, algorithm, aeadAlgorithm, publicKeys, passwords, armor = true, wildcard = false, encryptionKeyIds = [], date = new Date(), toUserIds = [] }) {
|
export function encryptSessionKey({ data, algorithm, aeadAlgorithm, publicKeys, passwords, armor = true, wildcard = false, encryptionKeyIds = [], date = new Date(), toUserIds = [], config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
checkBinary(data); checkString(algorithm, 'algorithm'); publicKeys = toArray(publicKeys); passwords = toArray(passwords); toUserIds = toArray(toUserIds);
|
checkBinary(data); checkString(algorithm, 'algorithm'); publicKeys = toArray(publicKeys); passwords = toArray(passwords); toUserIds = toArray(toUserIds);
|
||||||
|
|
||||||
return Promise.resolve().then(async function() {
|
return Promise.resolve().then(async function() {
|
||||||
|
|
||||||
const message = await Message.encryptSessionKey(data, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard, encryptionKeyIds, date, toUserIds);
|
const message = await Message.encryptSessionKey(data, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard, encryptionKeyIds, date, toUserIds, config);
|
||||||
return armor ? message.armor() : message.write();
|
return armor ? message.armor(config) : message.write();
|
||||||
|
|
||||||
}).catch(onError.bind(null, 'Error encrypting session key'));
|
}).catch(onError.bind(null, 'Error encrypting session key'));
|
||||||
}
|
}
|
||||||
@ -472,21 +498,23 @@ export function encryptSessionKey({ data, algorithm, aeadAlgorithm, publicKeys,
|
|||||||
/**
|
/**
|
||||||
* Decrypt symmetric session keys with a private key or password. Either a private key or
|
* Decrypt symmetric session keys with a private key or password. Either a private key or
|
||||||
* a password must be specified.
|
* a password must be specified.
|
||||||
* @param {Message} message a message object containing the encrypted session key packets
|
* @param {Message} message a message object containing the encrypted session key packets
|
||||||
* @param {Key|Array<Key>} privateKeys (optional) private keys with decrypted secret key data
|
* @param {Key|Array<Key>} privateKeys (optional) private keys with decrypted secret key data
|
||||||
* @param {String|Array<String>} passwords (optional) passwords to decrypt the session key
|
* @param {String|Array<String>} passwords (optional) passwords to decrypt the session key
|
||||||
* @returns {Promise<Object|undefined>} Array of decrypted session key, algorithm pairs in form:
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* { data:Uint8Array, algorithm:String }
|
* @returns {Promise<Object|undefined>} Array of decrypted session key, algorithm pairs in form:
|
||||||
* or 'undefined' if no key packets found
|
* { data:Uint8Array, algorithm:String }
|
||||||
|
* or 'undefined' if no key packets found
|
||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function decryptSessionKeys({ message, privateKeys, passwords }) {
|
export function decryptSessionKeys({ message, privateKeys, passwords, config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
checkMessage(message); privateKeys = toArray(privateKeys); passwords = toArray(passwords);
|
checkMessage(message); privateKeys = toArray(privateKeys); passwords = toArray(passwords);
|
||||||
|
|
||||||
return Promise.resolve().then(async function() {
|
return Promise.resolve().then(async function() {
|
||||||
|
|
||||||
return message.decryptSessionKeys(privateKeys, passwords);
|
return message.decryptSessionKeys(privateKeys, passwords, config);
|
||||||
|
|
||||||
}).catch(onError.bind(null, 'Error decrypting session keys'));
|
}).catch(onError.bind(null, 'Error decrypting session keys'));
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import stream from 'web-stream-tools';
|
import stream from 'web-stream-tools';
|
||||||
import config from '../config';
|
|
||||||
import crypto from '../crypto';
|
import crypto from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
@ -35,6 +34,7 @@ import {
|
|||||||
OnePassSignaturePacket,
|
OnePassSignaturePacket,
|
||||||
SignaturePacket
|
SignaturePacket
|
||||||
} from '../packet';
|
} from '../packet';
|
||||||
|
import defaultConfig from '../config';
|
||||||
|
|
||||||
const VERSION = 1; // A one-octet version number of the data packet.
|
const VERSION = 1; // A one-octet version number of the data packet.
|
||||||
|
|
||||||
@ -107,10 +107,11 @@ class AEADEncryptedDataPacket {
|
|||||||
* @param {String} sessionKeyAlgorithm The session key's cipher algorithm e.g. 'aes128'
|
* @param {String} sessionKeyAlgorithm The session key's cipher algorithm e.g. 'aes128'
|
||||||
* @param {Uint8Array} key The session key used to encrypt the payload
|
* @param {Uint8Array} key The session key used to encrypt the payload
|
||||||
* @param {Boolean} streaming Whether the top-level function will return a stream
|
* @param {Boolean} streaming Whether the top-level function will return a stream
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @throws {Error} if encryption was not successful
|
* @throws {Error} if encryption was not successful
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async encrypt(sessionKeyAlgorithm, key, streaming) {
|
async encrypt(sessionKeyAlgorithm, key, streaming, config = defaultConfig) {
|
||||||
this.cipherAlgo = enums.write(enums.symmetric, sessionKeyAlgorithm);
|
this.cipherAlgo = enums.write(enums.symmetric, sessionKeyAlgorithm);
|
||||||
this.aeadAlgo = enums.write(enums.aead, this.aeadAlgorithm);
|
this.aeadAlgo = enums.write(enums.aead, this.aeadAlgorithm);
|
||||||
const mode = crypto[enums.read(enums.aead, this.aeadAlgo)];
|
const mode = crypto[enums.read(enums.aead, this.aeadAlgo)];
|
||||||
|
@ -30,9 +30,9 @@ import { Inflate } from 'pako/lib/inflate';
|
|||||||
import { Z_SYNC_FLUSH, Z_FINISH } from 'pako/lib/zlib/constants';
|
import { Z_SYNC_FLUSH, Z_FINISH } from 'pako/lib/zlib/constants';
|
||||||
import { decode as BunzipDecode } from 'seek-bzip';
|
import { decode as BunzipDecode } from 'seek-bzip';
|
||||||
import stream from 'web-stream-tools';
|
import stream from 'web-stream-tools';
|
||||||
import config from '../config';
|
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
import defaultConfig from '../config';
|
||||||
import {
|
import {
|
||||||
LiteralDataPacket,
|
LiteralDataPacket,
|
||||||
OnePassSignaturePacket,
|
OnePassSignaturePacket,
|
||||||
@ -49,7 +49,10 @@ import {
|
|||||||
* @memberof module:packet
|
* @memberof module:packet
|
||||||
*/
|
*/
|
||||||
class CompressedDataPacket {
|
class CompressedDataPacket {
|
||||||
constructor() {
|
/**
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
|
*/
|
||||||
|
constructor(config = defaultConfig) {
|
||||||
/**
|
/**
|
||||||
* Packet type
|
* Packet type
|
||||||
* @type {module:enums.packet}
|
* @type {module:enums.packet}
|
||||||
@ -64,20 +67,25 @@ class CompressedDataPacket {
|
|||||||
* Compression algorithm
|
* Compression algorithm
|
||||||
* @type {compression}
|
* @type {compression}
|
||||||
*/
|
*/
|
||||||
this.algorithm = 'zip';
|
this.algorithm = enums.read(enums.compression, config.compression);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compressed packet data
|
* Compressed packet data
|
||||||
* @type {Uint8Array | ReadableStream<Uint8Array>}
|
* @type {Uint8Array | ReadableStream<Uint8Array>}
|
||||||
*/
|
*/
|
||||||
this.compressed = null;
|
this.compressed = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zip/zlib compression level, between 1 and 9
|
||||||
|
*/
|
||||||
|
this.deflateLevel = config.deflateLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parsing function for the packet.
|
* Parsing function for the packet.
|
||||||
* @param {Uint8Array | ReadableStream<Uint8Array>} bytes Payload of a tag 8 packet
|
* @param {Uint8Array | ReadableStream<Uint8Array>} bytes Payload of a tag 8 packet
|
||||||
*/
|
*/
|
||||||
async read(bytes, streaming) {
|
async read(bytes, config, streaming) {
|
||||||
await stream.parse(bytes, async reader => {
|
await stream.parse(bytes, async reader => {
|
||||||
|
|
||||||
// One octet that gives the algorithm used to compress the packet.
|
// One octet that gives the algorithm used to compress the packet.
|
||||||
@ -125,12 +133,11 @@ class CompressedDataPacket {
|
|||||||
* Compress the packet data (member decompressedData)
|
* Compress the packet data (member decompressedData)
|
||||||
*/
|
*/
|
||||||
compress() {
|
compress() {
|
||||||
|
|
||||||
if (!compress_fns[this.algorithm]) {
|
if (!compress_fns[this.algorithm]) {
|
||||||
throw new Error(this.algorithm + ' compression not supported');
|
throw new Error(this.algorithm + ' compression not supported');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.compressed = compress_fns[this.algorithm](this.packets.write());
|
this.compressed = compress_fns[this.algorithm](this.packets.write(), this.deflateLevel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,11 +186,11 @@ function bzip2(func) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const compress_fns = nodeZlib ? {
|
const compress_fns = nodeZlib ? {
|
||||||
zip: /*#__PURE__*/ node_zlib(nodeZlib.createDeflateRaw, { level: config.deflateLevel }),
|
zip: /*#__PURE__*/ (compressed, level) => node_zlib(nodeZlib.createDeflateRaw, { level })(compressed),
|
||||||
zlib: /*#__PURE__*/ node_zlib(nodeZlib.createDeflate, { level: config.deflateLevel })
|
zlib: /*#__PURE__*/ (compressed, level) => node_zlib(nodeZlib.createDeflate, { level })(compressed)
|
||||||
} : {
|
} : {
|
||||||
zip: /*#__PURE__*/ pako_zlib(Deflate, { raw: true, level: config.deflateLevel }),
|
zip: /*#__PURE__*/ (compressed, level) => pako_zlib(Deflate, { raw: true, level })(compressed),
|
||||||
zlib: /*#__PURE__*/ pako_zlib(Deflate, { level: config.deflateLevel })
|
zlib: /*#__PURE__*/ (compressed, level) => pako_zlib(Deflate, { level })(compressed)
|
||||||
};
|
};
|
||||||
|
|
||||||
const decompress_fns = nodeZlib ? {
|
const decompress_fns = nodeZlib ? {
|
||||||
|
@ -14,9 +14,9 @@ import {
|
|||||||
writeTag, writeHeader,
|
writeTag, writeHeader,
|
||||||
writePartialLength, writeSimpleLength
|
writePartialLength, writeSimpleLength
|
||||||
} from './packet';
|
} from './packet';
|
||||||
import config from '../config';
|
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
import defaultConfig from '../config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents a list of openpgp packets.
|
* This class represents a list of openpgp packets.
|
||||||
@ -30,7 +30,7 @@ class PacketList extends Array {
|
|||||||
* Reads a stream of binary data and interprets it as a list of packets.
|
* Reads a stream of binary data and interprets it as a list of packets.
|
||||||
* @param {Uint8Array | ReadableStream<Uint8Array>} bytes A Uint8Array of bytes.
|
* @param {Uint8Array | ReadableStream<Uint8Array>} bytes A Uint8Array of bytes.
|
||||||
*/
|
*/
|
||||||
async read(bytes, allowedPackets, streaming) {
|
async read(bytes, allowedPackets, streaming, config = defaultConfig) {
|
||||||
this.stream = stream.transformPair(bytes, async (readable, writable) => {
|
this.stream = stream.transformPair(bytes, async (readable, writable) => {
|
||||||
const writer = stream.getWriter(writable);
|
const writer = stream.getWriter(writable);
|
||||||
try {
|
try {
|
||||||
@ -42,7 +42,7 @@ class PacketList extends Array {
|
|||||||
const packet = packets.newPacketFromTag(tag, allowedPackets);
|
const packet = packets.newPacketFromTag(tag, allowedPackets);
|
||||||
packet.packets = new PacketList();
|
packet.packets = new PacketList();
|
||||||
packet.fromStream = util.isStream(parsed.packet);
|
packet.fromStream = util.isStream(parsed.packet);
|
||||||
await packet.read(parsed.packet, streaming);
|
await packet.read(parsed.packet, config, streaming);
|
||||||
await writer.write(packet);
|
await writer.write(packet);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!config.tolerant || supportsStreaming(parsed.tag)) {
|
if (!config.tolerant || supportsStreaming(parsed.tag)) {
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
import { Sha1 } from 'asmcrypto.js/dist_es8/hash/sha1/sha1';
|
import { Sha1 } from 'asmcrypto.js/dist_es8/hash/sha1/sha1';
|
||||||
import { Sha256 } from 'asmcrypto.js/dist_es8/hash/sha256/sha256';
|
import { Sha256 } from 'asmcrypto.js/dist_es8/hash/sha256/sha256';
|
||||||
import type_keyid from '../type/keyid';
|
import type_keyid from '../type/keyid';
|
||||||
import config from '../config';
|
import defaultConfig from '../config';
|
||||||
import crypto from '../crypto';
|
import crypto from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
@ -46,7 +46,11 @@ import util from '../util';
|
|||||||
* @memberof module:packet
|
* @memberof module:packet
|
||||||
*/
|
*/
|
||||||
class PublicKeyPacket {
|
class PublicKeyPacket {
|
||||||
constructor(date = new Date()) {
|
/**
|
||||||
|
* @param {Date} date (optional) creation date
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
|
*/
|
||||||
|
constructor(date = new Date(), config = defaultConfig) {
|
||||||
/**
|
/**
|
||||||
* Packet type
|
* Packet type
|
||||||
* @type {module:enums.packet}
|
* @type {module:enums.packet}
|
||||||
|
@ -33,8 +33,12 @@ import enums from '../enums';
|
|||||||
* @extends PublicKeyPacket
|
* @extends PublicKeyPacket
|
||||||
*/
|
*/
|
||||||
class PublicSubkeyPacket extends PublicKeyPacket {
|
class PublicSubkeyPacket extends PublicKeyPacket {
|
||||||
constructor() {
|
/**
|
||||||
super();
|
* @param {Date} date (optional) creation date
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
|
*/
|
||||||
|
constructor(date, config) {
|
||||||
|
super(date, config);
|
||||||
this.tag = enums.packet.publicSubkey;
|
this.tag = enums.packet.publicSubkey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import type_s2k from '../type/s2k';
|
|||||||
import crypto from '../crypto';
|
import crypto from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
import defaultConfig from '../config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Secret-Key packet contains all the information that is found in a
|
* A Secret-Key packet contains all the information that is found in a
|
||||||
@ -38,8 +39,12 @@ import util from '../util';
|
|||||||
* @extends PublicKeyPacket
|
* @extends PublicKeyPacket
|
||||||
*/
|
*/
|
||||||
class SecretKeyPacket extends PublicKeyPacket {
|
class SecretKeyPacket extends PublicKeyPacket {
|
||||||
constructor(date = new Date()) {
|
/**
|
||||||
super(date);
|
* @param {Date} date (optional) creation date
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
|
*/
|
||||||
|
constructor(date = new Date(), config = defaultConfig) {
|
||||||
|
super(date, config);
|
||||||
/**
|
/**
|
||||||
* Packet type
|
* Packet type
|
||||||
* @type {module:enums.packet}
|
* @type {module:enums.packet}
|
||||||
@ -247,8 +252,9 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
/**
|
/**
|
||||||
* Remove private key material, converting the key to a dummy one.
|
* Remove private key material, converting the key to a dummy one.
|
||||||
* The resulting key cannot be used for signing/decrypting but can still verify signatures.
|
* The resulting key cannot be used for signing/decrypting but can still verify signatures.
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
*/
|
*/
|
||||||
makeDummy() {
|
makeDummy(config = defaultConfig) {
|
||||||
if (this.isDummy()) {
|
if (this.isDummy()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -257,7 +263,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
}
|
}
|
||||||
this.isEncrypted = null;
|
this.isEncrypted = null;
|
||||||
this.keyMaterial = null;
|
this.keyMaterial = null;
|
||||||
this.s2k = new type_s2k();
|
this.s2k = new type_s2k(config);
|
||||||
this.s2k.algorithm = 0;
|
this.s2k.algorithm = 0;
|
||||||
this.s2k.c = 0;
|
this.s2k.c = 0;
|
||||||
this.s2k.type = 'gnu-dummy';
|
this.s2k.type = 'gnu-dummy';
|
||||||
@ -271,10 +277,11 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
* and the passphrase is empty or undefined, the key will be set as not encrypted.
|
* and the passphrase is empty or undefined, the key will be set as not encrypted.
|
||||||
* This can be used to remove passphrase protection after calling decrypt().
|
* This can be used to remove passphrase protection after calling decrypt().
|
||||||
* @param {String} passphrase
|
* @param {String} passphrase
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @throws {Error} if encryption was not successful
|
* @throws {Error} if encryption was not successful
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async encrypt(passphrase) {
|
async encrypt(passphrase, config = defaultConfig) {
|
||||||
if (this.isDummy()) {
|
if (this.isDummy()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -290,7 +297,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
throw new Error('The key must be decrypted before removing passphrase protection.');
|
throw new Error('The key must be decrypted before removing passphrase protection.');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.s2k = new type_s2k();
|
this.s2k = new type_s2k(config);
|
||||||
this.s2k.salt = await crypto.random.getRandomBytes(8);
|
this.s2k.salt = await crypto.random.getRandomBytes(8);
|
||||||
const algo = enums.write(enums.publicKey, this.algorithm);
|
const algo = enums.write(enums.publicKey, this.algorithm);
|
||||||
const cleartext = crypto.serializeParams(algo, this.privateParams);
|
const cleartext = crypto.serializeParams(algo, this.privateParams);
|
||||||
@ -309,8 +316,8 @@ class SecretKeyPacket extends PublicKeyPacket {
|
|||||||
this.s2k_usage = 254;
|
this.s2k_usage = 254;
|
||||||
this.keyMaterial = await crypto.cfb.encrypt(this.symmetric, key, util.concatUint8Array([
|
this.keyMaterial = await crypto.cfb.encrypt(this.symmetric, key, util.concatUint8Array([
|
||||||
cleartext,
|
cleartext,
|
||||||
await crypto.hash.sha1(cleartext)
|
await crypto.hash.sha1(cleartext, config)
|
||||||
]), this.iv);
|
]), this.iv, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
import SecretKeyPacket from './secret_key';
|
import SecretKeyPacket from './secret_key';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
|
import defaultConfig from '../config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Secret-Subkey packet (tag 7) is the subkey analog of the Secret
|
* A Secret-Subkey packet (tag 7) is the subkey analog of the Secret
|
||||||
@ -30,8 +31,12 @@ import enums from '../enums';
|
|||||||
* @extends SecretKeyPacket
|
* @extends SecretKeyPacket
|
||||||
*/
|
*/
|
||||||
class SecretSubkeyPacket extends SecretKeyPacket {
|
class SecretSubkeyPacket extends SecretKeyPacket {
|
||||||
constructor(date = new Date()) {
|
/**
|
||||||
super(date);
|
* @param {Date} date (optional) creation date
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
|
*/
|
||||||
|
constructor(date = new Date(), config = defaultConfig) {
|
||||||
|
super(date, config);
|
||||||
this.tag = enums.packet.secretSubkey;
|
this.tag = enums.packet.secretSubkey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ import type_keyid from '../type/keyid.js';
|
|||||||
import crypto from '../crypto';
|
import crypto from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
import config from '../config';
|
import defaultConfig from '../config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the Signature Packet (Tag 2)
|
* Implementation of the Signature Packet (Tag 2)
|
||||||
@ -99,9 +99,10 @@ class SignaturePacket {
|
|||||||
/**
|
/**
|
||||||
* parsing function for a signature packet (tag 2).
|
* parsing function for a signature packet (tag 2).
|
||||||
* @param {String} bytes payload of a tag 2 packet
|
* @param {String} bytes payload of a tag 2 packet
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {SignaturePacket} object representation
|
* @returns {SignaturePacket} object representation
|
||||||
*/
|
*/
|
||||||
read(bytes) {
|
read(bytes, config = defaultConfig) {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
this.version = bytes[i++];
|
this.version = bytes[i++];
|
||||||
|
|
||||||
@ -114,7 +115,7 @@ class SignaturePacket {
|
|||||||
this.hashAlgorithm = bytes[i++];
|
this.hashAlgorithm = bytes[i++];
|
||||||
|
|
||||||
// hashed subpackets
|
// hashed subpackets
|
||||||
i += this.read_sub_packets(bytes.subarray(i, bytes.length), true);
|
i += this.read_sub_packets(bytes.subarray(i, bytes.length), true, config);
|
||||||
|
|
||||||
// A V4 signature hashes the packet body
|
// A V4 signature hashes the packet body
|
||||||
// starting from its first field, the version number, through the end
|
// starting from its first field, the version number, through the end
|
||||||
@ -125,7 +126,7 @@ class SignaturePacket {
|
|||||||
this.signatureData = bytes.subarray(0, i);
|
this.signatureData = bytes.subarray(0, i);
|
||||||
|
|
||||||
// unhashed subpackets
|
// unhashed subpackets
|
||||||
i += this.read_sub_packets(bytes.subarray(i, bytes.length), false);
|
i += this.read_sub_packets(bytes.subarray(i, bytes.length), false, config);
|
||||||
|
|
||||||
// Two-octet field holding left 16 bits of signed hash value.
|
// Two-octet field holding left 16 bits of signed hash value.
|
||||||
this.signedHashValue = bytes.subarray(i, i + 2);
|
this.signedHashValue = bytes.subarray(i, i + 2);
|
||||||
@ -340,7 +341,7 @@ class SignaturePacket {
|
|||||||
|
|
||||||
// V4 signature sub packets
|
// V4 signature sub packets
|
||||||
|
|
||||||
read_sub_packet(bytes, trusted = true) {
|
read_sub_packet(bytes, trusted = true, config) {
|
||||||
let mypos = 0;
|
let mypos = 0;
|
||||||
|
|
||||||
const read_array = (prop, bytes) => {
|
const read_array = (prop, bytes) => {
|
||||||
@ -536,7 +537,7 @@ class SignaturePacket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
read_sub_packets(bytes, trusted = true) {
|
read_sub_packets(bytes, trusted = true, config) {
|
||||||
// Two-octet scalar octet count for following subpacket data.
|
// Two-octet scalar octet count for following subpacket data.
|
||||||
const subpacket_length = util.readNumber(bytes.subarray(0, 2));
|
const subpacket_length = util.readNumber(bytes.subarray(0, 2));
|
||||||
|
|
||||||
@ -547,7 +548,7 @@ class SignaturePacket {
|
|||||||
const len = readSimpleLength(bytes.subarray(i, bytes.length));
|
const len = readSimpleLength(bytes.subarray(i, bytes.length));
|
||||||
i += len.offset;
|
i += len.offset;
|
||||||
|
|
||||||
this.read_sub_packet(bytes.subarray(i, i + len.len), trusted);
|
this.read_sub_packet(bytes.subarray(i, i + len.len), trusted, config);
|
||||||
|
|
||||||
i += len.len;
|
i += len.len;
|
||||||
}
|
}
|
||||||
@ -671,10 +672,11 @@ class SignaturePacket {
|
|||||||
* @param {String|Object} data data which on the signature applies
|
* @param {String|Object} data data which on the signature applies
|
||||||
* @param {Boolean} detached (optional) whether to verify a detached signature
|
* @param {Boolean} detached (optional) whether to verify a detached signature
|
||||||
* @param {Boolean} streaming (optional) whether to process data as a stream
|
* @param {Boolean} streaming (optional) whether to process data as a stream
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @throws {Error} if signature validation failed
|
* @throws {Error} if signature validation failed
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async verify(key, signatureType, data, detached = false, streaming = false) {
|
async verify(key, signatureType, data, detached = false, streaming = false, config = defaultConfig) {
|
||||||
const publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm);
|
const publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm);
|
||||||
const hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm);
|
const hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm);
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import stream from 'web-stream-tools';
|
import stream from 'web-stream-tools';
|
||||||
import config from '../config';
|
|
||||||
import crypto from '../crypto';
|
import crypto from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
@ -36,6 +35,7 @@ import {
|
|||||||
OnePassSignaturePacket,
|
OnePassSignaturePacket,
|
||||||
SignaturePacket
|
SignaturePacket
|
||||||
} from '../packet';
|
} from '../packet';
|
||||||
|
import defaultConfig from '../config';
|
||||||
|
|
||||||
const VERSION = 1; // A one-octet version number of the data packet.
|
const VERSION = 1; // A one-octet version number of the data packet.
|
||||||
|
|
||||||
@ -90,10 +90,11 @@ class SymEncryptedIntegrityProtectedDataPacket {
|
|||||||
* @param {String} sessionKeyAlgorithm The selected symmetric encryption algorithm to be used e.g. 'aes128'
|
* @param {String} sessionKeyAlgorithm The selected symmetric encryption algorithm to be used e.g. 'aes128'
|
||||||
* @param {Uint8Array} key The key of cipher blocksize length to be used
|
* @param {Uint8Array} key The key of cipher blocksize length to be used
|
||||||
* @param {Boolean} streaming Whether to set this.encrypted to a stream
|
* @param {Boolean} streaming Whether to set this.encrypted to a stream
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Boolean>}
|
* @returns {Promise<Boolean>}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async encrypt(sessionKeyAlgorithm, key, streaming) {
|
async encrypt(sessionKeyAlgorithm, key, streaming, config = defaultConfig) {
|
||||||
let bytes = this.packets.write();
|
let bytes = this.packets.write();
|
||||||
if (!streaming) bytes = await stream.readToEnd(bytes);
|
if (!streaming) bytes = await stream.readToEnd(bytes);
|
||||||
const prefix = await crypto.getPrefixRandom(sessionKeyAlgorithm);
|
const prefix = await crypto.getPrefixRandom(sessionKeyAlgorithm);
|
||||||
@ -103,7 +104,7 @@ class SymEncryptedIntegrityProtectedDataPacket {
|
|||||||
const hash = await crypto.hash.sha1(stream.passiveClone(tohash));
|
const hash = await crypto.hash.sha1(stream.passiveClone(tohash));
|
||||||
const plaintext = util.concat([tohash, hash]);
|
const plaintext = util.concat([tohash, hash]);
|
||||||
|
|
||||||
this.encrypted = await crypto.cfb.encrypt(sessionKeyAlgorithm, key, plaintext, new Uint8Array(crypto.cipher[sessionKeyAlgorithm].blockSize));
|
this.encrypted = await crypto.cfb.encrypt(sessionKeyAlgorithm, key, plaintext, new Uint8Array(crypto.cipher[sessionKeyAlgorithm].blockSize), config);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,10 +113,11 @@ class SymEncryptedIntegrityProtectedDataPacket {
|
|||||||
* @param {String} sessionKeyAlgorithm The selected symmetric encryption algorithm to be used e.g. 'aes128'
|
* @param {String} sessionKeyAlgorithm The selected symmetric encryption algorithm to be used e.g. 'aes128'
|
||||||
* @param {Uint8Array} key The key of cipher blocksize length to be used
|
* @param {Uint8Array} key The key of cipher blocksize length to be used
|
||||||
* @param {Boolean} streaming Whether to read this.encrypted as a stream
|
* @param {Boolean} streaming Whether to read this.encrypted as a stream
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {Promise<Boolean>}
|
* @returns {Promise<Boolean>}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async decrypt(sessionKeyAlgorithm, key, streaming) {
|
async decrypt(sessionKeyAlgorithm, key, streaming, config = defaultConfig) {
|
||||||
let encrypted = stream.clone(this.encrypted);
|
let encrypted = stream.clone(this.encrypted);
|
||||||
if (!streaming) encrypted = await stream.readToEnd(encrypted);
|
if (!streaming) encrypted = await stream.readToEnd(encrypted);
|
||||||
const decrypted = await crypto.cfb.decrypt(sessionKeyAlgorithm, key, encrypted, new Uint8Array(crypto.cipher[sessionKeyAlgorithm].blockSize));
|
const decrypted = await crypto.cfb.decrypt(sessionKeyAlgorithm, key, encrypted, new Uint8Array(crypto.cipher[sessionKeyAlgorithm].blockSize));
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type_s2k from '../type/s2k';
|
import type_s2k from '../type/s2k';
|
||||||
import config from '../config';
|
import defaultConfig from '../config';
|
||||||
import crypto from '../crypto';
|
import crypto from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
@ -44,7 +44,10 @@ import util from '../util';
|
|||||||
* @memberof module:packet
|
* @memberof module:packet
|
||||||
*/
|
*/
|
||||||
class SymEncryptedSessionKeyPacket {
|
class SymEncryptedSessionKeyPacket {
|
||||||
constructor() {
|
/**
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
|
*/
|
||||||
|
constructor(config = defaultConfig) {
|
||||||
this.tag = enums.packet.symEncryptedSessionKey;
|
this.tag = enums.packet.symEncryptedSessionKey;
|
||||||
this.version = config.aeadProtect ? 5 : 4;
|
this.version = config.aeadProtect ? 5 : 4;
|
||||||
this.sessionKey = null;
|
this.sessionKey = null;
|
||||||
@ -154,17 +157,18 @@ class SymEncryptedSessionKeyPacket {
|
|||||||
/**
|
/**
|
||||||
* Encrypts the session key
|
* Encrypts the session key
|
||||||
* @param {String} passphrase The passphrase in string form
|
* @param {String} passphrase The passphrase in string form
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @throws {Error} if encryption was not successful
|
* @throws {Error} if encryption was not successful
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async encrypt(passphrase) {
|
async encrypt(passphrase, config = defaultConfig) {
|
||||||
const algo = this.sessionKeyEncryptionAlgorithm !== null ?
|
const algo = this.sessionKeyEncryptionAlgorithm !== null ?
|
||||||
this.sessionKeyEncryptionAlgorithm :
|
this.sessionKeyEncryptionAlgorithm :
|
||||||
this.sessionKeyAlgorithm;
|
this.sessionKeyAlgorithm;
|
||||||
|
|
||||||
this.sessionKeyEncryptionAlgorithm = algo;
|
this.sessionKeyEncryptionAlgorithm = algo;
|
||||||
|
|
||||||
this.s2k = new type_s2k();
|
this.s2k = new type_s2k(config);
|
||||||
this.s2k.salt = await crypto.random.getRandomBytes(8);
|
this.s2k.salt = await crypto.random.getRandomBytes(8);
|
||||||
|
|
||||||
const length = crypto.cipher[algo].keySize;
|
const length = crypto.cipher[algo].keySize;
|
||||||
@ -183,7 +187,7 @@ class SymEncryptedSessionKeyPacket {
|
|||||||
} else {
|
} else {
|
||||||
const algo_enum = new Uint8Array([enums.write(enums.symmetric, this.sessionKeyAlgorithm)]);
|
const algo_enum = new Uint8Array([enums.write(enums.symmetric, this.sessionKeyAlgorithm)]);
|
||||||
const private_key = util.concatUint8Array([algo_enum, this.sessionKey]);
|
const private_key = util.concatUint8Array([algo_enum, this.sessionKey]);
|
||||||
this.encrypted = await crypto.cfb.encrypt(algo, key, private_key, new Uint8Array(crypto.cipher[algo].blockSize));
|
this.encrypted = await crypto.cfb.encrypt(algo, key, private_key, new Uint8Array(crypto.cipher[algo].blockSize), config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import stream from 'web-stream-tools';
|
import stream from 'web-stream-tools';
|
||||||
import config from '../config';
|
|
||||||
import crypto from '../crypto';
|
import crypto from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
@ -35,6 +34,7 @@ import {
|
|||||||
OnePassSignaturePacket,
|
OnePassSignaturePacket,
|
||||||
SignaturePacket
|
SignaturePacket
|
||||||
} from '../packet';
|
} from '../packet';
|
||||||
|
import defaultConfig from '../config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the Symmetrically Encrypted Data Packet (Tag 9)
|
* Implementation of the Symmetrically Encrypted Data Packet (Tag 9)
|
||||||
@ -63,11 +63,6 @@ class SymmetricallyEncryptedDataPacket {
|
|||||||
* @type {PacketList}
|
* @type {PacketList}
|
||||||
*/
|
*/
|
||||||
this.packets = null;
|
this.packets = null;
|
||||||
/**
|
|
||||||
* When true, decrypt fails if message is not integrity protected
|
|
||||||
* @see module:config.ignoreMdcError
|
|
||||||
*/
|
|
||||||
this.ignoreMdcError = config.ignoreMdcError;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
read(bytes) {
|
read(bytes) {
|
||||||
@ -83,12 +78,14 @@ class SymmetricallyEncryptedDataPacket {
|
|||||||
* See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms.
|
* See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms.
|
||||||
* @param {module:enums.symmetric} sessionKeyAlgorithm Symmetric key algorithm to use
|
* @param {module:enums.symmetric} sessionKeyAlgorithm Symmetric key algorithm to use
|
||||||
* @param {Uint8Array} key The key of cipher blocksize length to be used
|
* @param {Uint8Array} key The key of cipher blocksize length to be used
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
|
|
||||||
* @throws {Error} if decryption was not successful
|
* @throws {Error} if decryption was not successful
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async decrypt(sessionKeyAlgorithm, key, streaming) {
|
async decrypt(sessionKeyAlgorithm, key, streaming, config = defaultConfig) {
|
||||||
// If MDC errors are not being ignored, all missing MDC packets in symmetrically encrypted data should throw an error
|
// If MDC errors are not being ignored, all missing MDC packets in symmetrically encrypted data should throw an error
|
||||||
if (!this.ignoreMdcError) {
|
if (!config.ignoreMdcError) {
|
||||||
throw new Error('Decryption failed due to missing MDC.');
|
throw new Error('Decryption failed due to missing MDC.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,15 +108,16 @@ class SymmetricallyEncryptedDataPacket {
|
|||||||
* See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms.
|
* See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms.
|
||||||
* @param {module:enums.symmetric} sessionKeyAlgorithm Symmetric key algorithm to use
|
* @param {module:enums.symmetric} sessionKeyAlgorithm Symmetric key algorithm to use
|
||||||
* @param {Uint8Array} key The key of cipher blocksize length to be used
|
* @param {Uint8Array} key The key of cipher blocksize length to be used
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @throws {Error} if encryption was not successful
|
* @throws {Error} if encryption was not successful
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async encrypt(algo, key) {
|
async encrypt(algo, key, streaming, config = defaultConfig) {
|
||||||
const data = this.packets.write();
|
const data = this.packets.write();
|
||||||
|
|
||||||
const prefix = await crypto.getPrefixRandom(algo);
|
const prefix = await crypto.getPrefixRandom(algo);
|
||||||
const FRE = await crypto.cfb.encrypt(algo, key, prefix, new Uint8Array(crypto.cipher[algo].blockSize));
|
const FRE = await crypto.cfb.encrypt(algo, key, prefix, new Uint8Array(crypto.cipher[algo].blockSize), config);
|
||||||
const ciphertext = await crypto.cfb.encrypt(algo, key, data, FRE.subarray(2));
|
const ciphertext = await crypto.cfb.encrypt(algo, key, data, FRE.subarray(2), config);
|
||||||
this.encrypted = util.concat([FRE, ciphertext]);
|
this.encrypted = util.concat([FRE, ciphertext]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ import emailAddresses from 'email-addresses';
|
|||||||
|
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
import config from '../config';
|
import defaultConfig from '../config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the User ID Packet (Tag 13)
|
* Implementation of the User ID Packet (Tag 13)
|
||||||
@ -76,7 +76,7 @@ class UserIDPacket {
|
|||||||
* Parsing function for a user id packet (tag 13).
|
* Parsing function for a user id packet (tag 13).
|
||||||
* @param {Uint8Array} input payload of a tag 13 packet
|
* @param {Uint8Array} input payload of a tag 13 packet
|
||||||
*/
|
*/
|
||||||
read(bytes) {
|
read(bytes, config = defaultConfig) {
|
||||||
const userid = util.decodeUtf8(bytes);
|
const userid = util.decodeUtf8(bytes);
|
||||||
if (userid.length > config.maxUseridLength) {
|
if (userid.length > config.maxUseridLength) {
|
||||||
throw new Error('User ID string is too long');
|
throw new Error('User ID string is too long');
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
import { armor, unarmor } from './encoding/armor';
|
import { armor, unarmor } from './encoding/armor';
|
||||||
import { PacketList, SignaturePacket } from './packet';
|
import { PacketList, SignaturePacket } from './packet';
|
||||||
import enums from './enums';
|
import enums from './enums';
|
||||||
|
import defaultConfig from './config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that represents an OpenPGP signature.
|
* Class that represents an OpenPGP signature.
|
||||||
@ -47,10 +48,11 @@ export class Signature {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns ASCII armored text of signature
|
* Returns ASCII armored text of signature
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
* @returns {ReadableStream<String>} ASCII armor
|
* @returns {ReadableStream<String>} ASCII armor
|
||||||
*/
|
*/
|
||||||
armor() {
|
armor(config = defaultConfig) {
|
||||||
return armor(enums.armor.signature, this.write());
|
return armor(enums.armor.signature, this.write(), undefined, undefined, undefined, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,23 +60,25 @@ export class Signature {
|
|||||||
* reads an (optionally armored) OpenPGP signature and returns a signature object
|
* reads an (optionally armored) OpenPGP signature and returns a signature object
|
||||||
* @param {String | ReadableStream<String>} armoredSignature armored signature to be parsed
|
* @param {String | ReadableStream<String>} armoredSignature armored signature to be parsed
|
||||||
* @param {Uint8Array | ReadableStream<Uint8Array>} binarySignature binary signature to be parsed
|
* @param {Uint8Array | ReadableStream<Uint8Array>} binarySignature binary signature to be parsed
|
||||||
|
* @param {Object} config (optional) custom configuration settings to overwrite those in openpgp.config
|
||||||
* @returns {Signature} new signature object
|
* @returns {Signature} new signature object
|
||||||
* @async
|
* @async
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export async function readSignature({ armoredSignature, binarySignature }) {
|
export async function readSignature({ armoredSignature, binarySignature, config }) {
|
||||||
|
config = { ...defaultConfig, ...config };
|
||||||
let input = armoredSignature || binarySignature;
|
let input = armoredSignature || binarySignature;
|
||||||
if (!input) {
|
if (!input) {
|
||||||
throw new Error('readSignature: must pass options object containing `armoredSignature` or `binarySignature`');
|
throw new Error('readSignature: must pass options object containing `armoredSignature` or `binarySignature`');
|
||||||
}
|
}
|
||||||
if (armoredSignature) {
|
if (armoredSignature) {
|
||||||
const { type, data } = await unarmor(input);
|
const { type, data } = await unarmor(input, config);
|
||||||
if (type !== enums.armor.signature) {
|
if (type !== enums.armor.signature) {
|
||||||
throw new Error('Armored text not of type signature');
|
throw new Error('Armored text not of type signature');
|
||||||
}
|
}
|
||||||
input = data;
|
input = data;
|
||||||
}
|
}
|
||||||
const packetlist = new PacketList();
|
const packetlist = new PacketList();
|
||||||
await packetlist.read(input, { SignaturePacket });
|
await packetlist.read(input, { SignaturePacket }, undefined, config);
|
||||||
return new Signature(packetlist);
|
return new Signature(packetlist);
|
||||||
}
|
}
|
||||||
|
@ -31,13 +31,16 @@
|
|||||||
* @module type/s2k
|
* @module type/s2k
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import config from '../config';
|
import defaultConfig from '../config';
|
||||||
import crypto from '../crypto';
|
import crypto from '../crypto';
|
||||||
import enums from '../enums.js';
|
import enums from '../enums.js';
|
||||||
import util from '../util.js';
|
import util from '../util.js';
|
||||||
|
|
||||||
class S2K {
|
class S2K {
|
||||||
constructor() {
|
/**
|
||||||
|
* @param {Object} config (optional) full configuration, defaults to openpgp.config
|
||||||
|
*/
|
||||||
|
constructor(config = defaultConfig) {
|
||||||
/** @type {module:enums.hash} */
|
/** @type {module:enums.hash} */
|
||||||
this.algorithm = 'sha256';
|
this.algorithm = 'sha256';
|
||||||
/** @type {module:enums.s2k} */
|
/** @type {module:enums.s2k} */
|
||||||
|
60
src/util.js
60
src/util.js
@ -21,17 +21,16 @@
|
|||||||
* This object contains utility functions
|
* This object contains utility functions
|
||||||
* @requires email-addresses
|
* @requires email-addresses
|
||||||
* @requires web-stream-tools
|
* @requires web-stream-tools
|
||||||
* @requires config
|
|
||||||
* @requires encoding/base64
|
* @requires encoding/base64
|
||||||
* @module util
|
* @module util
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import stream from 'web-stream-tools';
|
import stream from 'web-stream-tools';
|
||||||
import config from './config';
|
|
||||||
import util from './util'; // re-import module to access util functions
|
|
||||||
import { getBigInteger } from './biginteger';
|
import { getBigInteger } from './biginteger';
|
||||||
|
|
||||||
export default {
|
const debugMode = globalThis.process && globalThis.process.env.NODE_ENV === 'development';
|
||||||
|
|
||||||
|
const util = {
|
||||||
isString: function(data) {
|
isString: function(data) {
|
||||||
return typeof data === 'string' || String.prototype.isPrototypeOf(data);
|
return typeof data === 'string' || String.prototype.isPrototypeOf(data);
|
||||||
},
|
},
|
||||||
@ -358,11 +357,10 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* Helper function to print a debug message. Debug
|
* Helper function to print a debug message. Debug
|
||||||
* messages are only printed if
|
* messages are only printed if
|
||||||
* @link module:config/config.debug is set to true.
|
|
||||||
* @param {String} str String of the debug message
|
* @param {String} str String of the debug message
|
||||||
*/
|
*/
|
||||||
printDebug: function (str) {
|
printDebug: function (str) {
|
||||||
if (config.debug) {
|
if (debugMode) {
|
||||||
console.log(str);
|
console.log(str);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -370,12 +368,11 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* Helper function to print a debug message. Debug
|
* Helper function to print a debug message. Debug
|
||||||
* messages are only printed if
|
* messages are only printed if
|
||||||
* @link module:config/config.debug is set to true.
|
|
||||||
* Different than print_debug because will call Uint8ArrayToHex iff necessary.
|
* Different than print_debug because will call Uint8ArrayToHex iff necessary.
|
||||||
* @param {String} str String of the debug message
|
* @param {String} str String of the debug message
|
||||||
*/
|
*/
|
||||||
printDebugHexArrayDump: function (str, arrToHex) {
|
printDebugHexArrayDump: function (str, arrToHex) {
|
||||||
if (config.debug) {
|
if (debugMode) {
|
||||||
str += ': ' + util.uint8ArrayToHex(arrToHex);
|
str += ': ' + util.uint8ArrayToHex(arrToHex);
|
||||||
console.log(str);
|
console.log(str);
|
||||||
}
|
}
|
||||||
@ -384,12 +381,11 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* Helper function to print a debug message. Debug
|
* Helper function to print a debug message. Debug
|
||||||
* messages are only printed if
|
* messages are only printed if
|
||||||
* @link module:config/config.debug is set to true.
|
|
||||||
* Different than print_debug because will call strToHex iff necessary.
|
* Different than print_debug because will call strToHex iff necessary.
|
||||||
* @param {String} str String of the debug message
|
* @param {String} str String of the debug message
|
||||||
*/
|
*/
|
||||||
printDebugHexStrDump: function (str, strToHex) {
|
printDebugHexStrDump: function (str, strToHex) {
|
||||||
if (config.debug) {
|
if (debugMode) {
|
||||||
str += util.strToHex(strToHex);
|
str += util.strToHex(strToHex);
|
||||||
console.log(str);
|
console.log(str);
|
||||||
}
|
}
|
||||||
@ -398,11 +394,10 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* Helper function to print a debug error. Debug
|
* Helper function to print a debug error. Debug
|
||||||
* messages are only printed if
|
* messages are only printed if
|
||||||
* @link module:config/config.debug is set to true.
|
|
||||||
* @param {String} str String of the debug message
|
* @param {String} str String of the debug message
|
||||||
*/
|
*/
|
||||||
printDebugError: function (error) {
|
printDebugError: function (error) {
|
||||||
if (config.debug) {
|
if (debugMode) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -490,40 +485,12 @@ export default {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get native Web Cryptography api, only the current version of the spec.
|
* Get native Web Cryptography api, only the current version of the spec.
|
||||||
* The default configuration is to use the api when available. But it can
|
|
||||||
* be deactivated with config.useNative
|
|
||||||
* @returns {Object} The SubtleCrypto api or 'undefined'
|
* @returns {Object} The SubtleCrypto api or 'undefined'
|
||||||
*/
|
*/
|
||||||
getWebCrypto: function() {
|
getWebCrypto: function() {
|
||||||
if (!config.useNative) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return typeof globalThis !== 'undefined' && globalThis.crypto && globalThis.crypto.subtle;
|
return typeof globalThis !== 'undefined' && globalThis.crypto && globalThis.crypto.subtle;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Get native Web Cryptography api for all browsers, including legacy
|
|
||||||
* implementations of the spec e.g IE11 and Safari 8/9. The default
|
|
||||||
* configuration is to use the api when available. But it can be deactivated
|
|
||||||
* with config.useNative
|
|
||||||
* @returns {Object} The SubtleCrypto api or 'undefined'
|
|
||||||
*/
|
|
||||||
getWebCryptoAll: function() {
|
|
||||||
if (!config.useNative) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof globalThis !== 'undefined') {
|
|
||||||
if (globalThis.crypto) {
|
|
||||||
return globalThis.crypto.subtle || globalThis.crypto.webkitSubtle;
|
|
||||||
}
|
|
||||||
if (globalThis.msCrypto) {
|
|
||||||
return globalThis.msCrypto.subtle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect Node.js runtime.
|
* Detect Node.js runtime.
|
||||||
*/
|
*/
|
||||||
@ -547,23 +514,14 @@ export default {
|
|||||||
getBigInteger,
|
getBigInteger,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get native Node.js crypto api. The default configuration is to use
|
* Get native Node.js crypto api.
|
||||||
* the api when available. But it can also be deactivated with config.useNative
|
|
||||||
* @returns {Object} The crypto module or 'undefined'
|
* @returns {Object} The crypto module or 'undefined'
|
||||||
*/
|
*/
|
||||||
getNodeCrypto: function() {
|
getNodeCrypto: function() {
|
||||||
if (!config.useNative) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return require('crypto');
|
return require('crypto');
|
||||||
},
|
},
|
||||||
|
|
||||||
getNodeZlib: function() {
|
getNodeZlib: function() {
|
||||||
if (!config.useNative) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return require('zlib');
|
return require('zlib');
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -743,3 +701,5 @@ export default {
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default util;
|
||||||
|
@ -242,33 +242,11 @@ module.exports = () => describe('API functional testing', function() {
|
|||||||
await Promise.all(symmAlgos.map(async function(algo) {
|
await Promise.all(symmAlgos.map(async function(algo) {
|
||||||
const symmKey = await crypto.generateSessionKey(algo);
|
const symmKey = await crypto.generateSessionKey(algo);
|
||||||
const IV = new Uint8Array(crypto.cipher[algo].blockSize);
|
const IV = new Uint8Array(crypto.cipher[algo].blockSize);
|
||||||
const symmencData = await crypto.cfb.encrypt(algo, symmKey, util.strToUint8Array(plaintext), IV);
|
const symmencData = await crypto.cfb.encrypt(algo, symmKey, util.strToUint8Array(plaintext), IV, openpgp.config);
|
||||||
const text = util.uint8ArrayToStr(await crypto.cfb.decrypt(algo, symmKey, symmencData, new Uint8Array(crypto.cipher[algo].blockSize)));
|
const text = util.uint8ArrayToStr(await crypto.cfb.decrypt(algo, symmKey, symmencData, new Uint8Array(crypto.cipher[algo].blockSize)));
|
||||||
expect(text).to.equal(plaintext);
|
expect(text).to.equal(plaintext);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function testAESGCM(plaintext, nativeDecrypt) {
|
|
||||||
symmAlgos.forEach(function(algo) {
|
|
||||||
if (algo.substr(0,3) === 'aes') {
|
|
||||||
it(algo, async function() {
|
|
||||||
const key = await crypto.generateSessionKey(algo);
|
|
||||||
const iv = await crypto.random.getRandomBytes(crypto.gcm.ivLength);
|
|
||||||
let modeInstance = await crypto.gcm(algo, key);
|
|
||||||
|
|
||||||
const ciphertext = await modeInstance.encrypt(util.strToUint8Array(plaintext), iv);
|
|
||||||
|
|
||||||
openpgp.config.useNative = nativeDecrypt;
|
|
||||||
modeInstance = await crypto.gcm(algo, key);
|
|
||||||
|
|
||||||
const decrypted = await modeInstance.decrypt(util.strToUint8Array(util.uint8ArrayToStr(ciphertext)), iv);
|
|
||||||
const decryptedStr = util.uint8ArrayToStr(decrypted);
|
|
||||||
expect(decryptedStr).to.equal(plaintext);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
it("Symmetric with OpenPGP CFB", async function () {
|
it("Symmetric with OpenPGP CFB", async function () {
|
||||||
await testCFB("hello");
|
await testCFB("hello");
|
||||||
await testCFB("1234567");
|
await testCFB("1234567");
|
||||||
@ -276,45 +254,6 @@ module.exports = () => describe('API functional testing', function() {
|
|||||||
await testCFB("12345678901234567890123456789012345678901234567890");
|
await testCFB("12345678901234567890123456789012345678901234567890");
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Symmetric AES-GCM (native)', function() {
|
|
||||||
let useNativeVal;
|
|
||||||
beforeEach(function() {
|
|
||||||
useNativeVal = openpgp.config.useNative;
|
|
||||||
openpgp.config.useNative = true;
|
|
||||||
});
|
|
||||||
afterEach(function() {
|
|
||||||
openpgp.config.useNative = useNativeVal;
|
|
||||||
});
|
|
||||||
|
|
||||||
testAESGCM("12345678901234567890123456789012345678901234567890", true);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Symmetric AES-GCM (asm.js fallback)', function() {
|
|
||||||
let useNativeVal;
|
|
||||||
beforeEach(function() {
|
|
||||||
useNativeVal = openpgp.config.useNative;
|
|
||||||
openpgp.config.useNative = false;
|
|
||||||
});
|
|
||||||
afterEach(function() {
|
|
||||||
openpgp.config.useNative = useNativeVal;
|
|
||||||
});
|
|
||||||
|
|
||||||
testAESGCM("12345678901234567890123456789012345678901234567890", false);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Symmetric AES-GCM (native encrypt, asm.js decrypt)', function() {
|
|
||||||
let useNativeVal;
|
|
||||||
beforeEach(function() {
|
|
||||||
useNativeVal = openpgp.config.useNative;
|
|
||||||
openpgp.config.useNative = true;
|
|
||||||
});
|
|
||||||
afterEach(function() {
|
|
||||||
openpgp.config.useNative = useNativeVal;
|
|
||||||
});
|
|
||||||
|
|
||||||
testAESGCM("12345678901234567890123456789012345678901234567890", false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Asymmetric using RSA with eme_pkcs1 padding', async function () {
|
it('Asymmetric using RSA with eme_pkcs1 padding', async function () {
|
||||||
const symmKey = await crypto.generateSessionKey('aes256');
|
const symmKey = await crypto.generateSessionKey('aes256');
|
||||||
return crypto.publicKeyEncrypt(algoRSA, RSAPublicParams, symmKey).then(RSAEncryptedData => {
|
return crypto.publicKeyEncrypt(algoRSA, RSAPublicParams, symmKey).then(RSAEncryptedData => {
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
// Adapted from https://github.com/artjomb/cryptojs-extension/blob/8c61d159/test/eax.js
|
// Adapted from https://github.com/artjomb/cryptojs-extension/blob/8c61d159/test/eax.js
|
||||||
|
|
||||||
const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
|
|
||||||
const EAX = require('../../src/crypto/eax');
|
const EAX = require('../../src/crypto/eax');
|
||||||
const util = require('../../src/util');
|
const util = require('../../src/util');
|
||||||
|
|
||||||
|
const sandbox = require('sinon/lib/sinon/sandbox');
|
||||||
const chai = require('chai');
|
const chai = require('chai');
|
||||||
chai.use(require('chai-as-promised'));
|
chai.use(require('chai-as-promised'));
|
||||||
|
|
||||||
@ -125,30 +125,45 @@ function testAESEAX() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = () => {
|
module.exports = () => describe('Symmetric AES-EAX', function() {
|
||||||
|
let sinonSandbox;
|
||||||
|
let getWebCryptoStub;
|
||||||
|
let getNodeCryptoStub;
|
||||||
|
|
||||||
|
const disableNative = () => {
|
||||||
|
enableNative();
|
||||||
|
// stubbed functions return undefined
|
||||||
|
getWebCryptoStub = sinonSandbox.stub(util, "getWebCrypto");
|
||||||
|
getNodeCryptoStub = sinonSandbox.stub(util, "getNodeCrypto");
|
||||||
|
};
|
||||||
|
const enableNative = () => {
|
||||||
|
getWebCryptoStub && getWebCryptoStub.restore();
|
||||||
|
getNodeCryptoStub && getNodeCryptoStub.restore();
|
||||||
|
};
|
||||||
|
|
||||||
describe('Symmetric AES-EAX (native)', function() {
|
describe('Symmetric AES-EAX (native)', function() {
|
||||||
let useNativeVal;
|
beforeEach(function () {
|
||||||
beforeEach(function() {
|
sinonSandbox = sandbox.create();
|
||||||
useNativeVal = openpgp.config.useNative;
|
enableNative();
|
||||||
openpgp.config.useNative = true;
|
|
||||||
});
|
});
|
||||||
afterEach(function() {
|
|
||||||
openpgp.config.useNative = useNativeVal;
|
afterEach(function () {
|
||||||
|
sinonSandbox.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
testAESEAX();
|
testAESEAX();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Symmetric AES-EAX (asm.js fallback)', function() {
|
describe('Symmetric AES-EAX (asm.js fallback)', function() {
|
||||||
let useNativeVal;
|
beforeEach(function () {
|
||||||
beforeEach(function() {
|
sinonSandbox = sandbox.create();
|
||||||
useNativeVal = openpgp.config.useNative;
|
disableNative();
|
||||||
openpgp.config.useNative = false;
|
|
||||||
});
|
});
|
||||||
afterEach(function() {
|
|
||||||
openpgp.config.useNative = useNativeVal;
|
afterEach(function () {
|
||||||
|
sinonSandbox.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
testAESEAX();
|
testAESEAX();
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
|
@ -4,6 +4,7 @@ const KDFParams = require('../../src/type/kdf_params');
|
|||||||
const elliptic_curves = require('../../src/crypto/public_key/elliptic');
|
const elliptic_curves = require('../../src/crypto/public_key/elliptic');
|
||||||
const util = require('../../src/util');
|
const util = require('../../src/util');
|
||||||
|
|
||||||
|
const sandbox = require('sinon/lib/sinon/sandbox');
|
||||||
const chai = require('chai');
|
const chai = require('chai');
|
||||||
const elliptic_data = require('./elliptic_data');
|
const elliptic_data = require('./elliptic_data');
|
||||||
|
|
||||||
@ -133,133 +134,111 @@ module.exports = () => describe('ECDH key exchange @lightweight', function () {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
describe('ECDHE key generation', function () {
|
describe('ECDHE key generation', function () {
|
||||||
|
const ecdh = elliptic_curves.ecdh;
|
||||||
|
|
||||||
it('Invalid curve', async function () {
|
it('Invalid curve', async function () {
|
||||||
if (!openpgp.config.useIndutnyElliptic && !util.getNodeCrypto()) {
|
if (!openpgp.config.useIndutnyElliptic && !util.getNodeCrypto()) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
const { key: publicKey } = await openpgp.generateKey({ curve: "secp256k1", userIds: [{ name: 'Test' }] });
|
const curve = new elliptic_curves.Curve('secp256k1');
|
||||||
publicKey.subKeys[0].keyPacket.publicParams.Q = Q1;
|
const oid = new OID(curve.oid);
|
||||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
|
||||||
await expect(
|
const data = util.strToUint8Array('test');
|
||||||
openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') })
|
expect(
|
||||||
|
ecdh.encrypt(oid, kdfParams, data, Q1, fingerprint1)
|
||||||
).to.be.rejectedWith(Error, /Public key is not valid for specified curve|Failed to translate Buffer to a EC_POINT|Unknown point format/);
|
).to.be.rejectedWith(Error, /Public key is not valid for specified curve|Failed to translate Buffer to a EC_POINT|Unknown point format/);
|
||||||
});
|
});
|
||||||
it('Invalid public part of ephemeral key and private key', async function () {
|
it('Different keys', async function () {
|
||||||
const { key: publicKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
const curve = new elliptic_curves.Curve('curve25519');
|
||||||
publicKey.subKeys[0].keyPacket.publicParams.Q = Q1;
|
const oid = new OID(curve.oid);
|
||||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
|
||||||
const { key: privateKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
const data = util.strToUint8Array('test');
|
||||||
privateKey.subKeys[0].keyPacket.publicParams.Q = Q2;
|
const { publicKey: V, wrappedKey: C } = await ecdh.encrypt(oid, kdfParams, data, Q1, fingerprint1);
|
||||||
privateKey.subKeys[0].keyPacket.privateParams.d = d2;
|
|
||||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
|
||||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
|
||||||
await expect(
|
await expect(
|
||||||
openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
ecdh.decrypt(oid, kdfParams, V, C, Q2, d2, fingerprint1)
|
||||||
).to.be.rejectedWith('Error decrypting message: Key Data Integrity failed');
|
).to.be.rejectedWith(/Key Data Integrity failed/);
|
||||||
});
|
});
|
||||||
it('Invalid fingerprint', async function () {
|
it('Invalid fingerprint', async function () {
|
||||||
const { key: publicKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
const curve = new elliptic_curves.Curve('curve25519');
|
||||||
publicKey.subKeys[0].keyPacket.publicParams.Q = Q1;
|
const oid = new OID(curve.oid);
|
||||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
|
||||||
const { key: privateKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
const data = util.strToUint8Array('test');
|
||||||
privateKey.subKeys[0].keyPacket.publicParams.Q = Q2;
|
const { publicKey: V, wrappedKey: C } = await ecdh.encrypt(oid, kdfParams, data, Q2, fingerprint1);
|
||||||
privateKey.subKeys[0].keyPacket.privateParams.d = d2;
|
|
||||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint2;
|
|
||||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
|
||||||
await expect(
|
await expect(
|
||||||
openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
ecdh.decrypt(oid, kdfParams, V, C, Q2, d2, fingerprint2)
|
||||||
).to.be.rejectedWith('Error decrypting message: Session key decryption failed');
|
).to.be.rejectedWith(/Key Data Integrity failed/);
|
||||||
});
|
|
||||||
it('Different keys', async function () {
|
|
||||||
const { key: publicKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
|
||||||
publicKey.subKeys[0].keyPacket.publicParams.Q = Q2;
|
|
||||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
|
||||||
const { key: privateKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
|
||||||
privateKey.subKeys[0].keyPacket.publicParams.Q = Q1;
|
|
||||||
privateKey.subKeys[0].keyPacket.privateParams.d = d1;
|
|
||||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
|
||||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
|
||||||
await expect(
|
|
||||||
openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
|
||||||
).to.be.rejectedWith('Error decrypting message: Key Data Integrity failed');
|
|
||||||
});
|
});
|
||||||
it('Successful exchange curve25519', async function () {
|
it('Successful exchange curve25519', async function () {
|
||||||
const { key: publicKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
const curve = new elliptic_curves.Curve('curve25519');
|
||||||
publicKey.subKeys[0].keyPacket.publicParams.Q = Q1;
|
const oid = new OID(curve.oid);
|
||||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
|
||||||
const { key: privateKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
const data = util.strToUint8Array('test');
|
||||||
privateKey.subKeys[0].keyPacket.publicParams.Q = Q1;
|
const { publicKey: V, wrappedKey: C } = await ecdh.encrypt(oid, kdfParams, data, Q1, fingerprint1);
|
||||||
privateKey.subKeys[0].keyPacket.privateParams.d = d1;
|
expect(await ecdh.decrypt(oid, kdfParams, V, C, Q1, d1, fingerprint1)).to.deep.equal(data);
|
||||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
|
||||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
|
||||||
expect((
|
|
||||||
await openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
|
||||||
).data).to.equal('test');
|
|
||||||
});
|
|
||||||
it('Successful exchange NIST P256', async function () {
|
|
||||||
const { key: publicKey } = await openpgp.generateKey({ curve: "p256", userIds: [{ name: 'Test' }] });
|
|
||||||
publicKey.subKeys[0].keyPacket.publicParams.Q = key_data.p256.pub;
|
|
||||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
|
||||||
const { key: privateKey } = await openpgp.generateKey({ curve: "p256", userIds: [{ name: 'Test' }] });
|
|
||||||
privateKey.subKeys[0].keyPacket.publicParams.Q = key_data.p256.pub;
|
|
||||||
privateKey.subKeys[0].keyPacket.privateParams.d = key_data.p256.priv;
|
|
||||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
|
||||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
|
||||||
expect((
|
|
||||||
await openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
|
||||||
).data).to.equal('test');
|
|
||||||
});
|
|
||||||
it('Successful exchange NIST P384', async function () {
|
|
||||||
const { key: publicKey } = await openpgp.generateKey({ curve: "p384", userIds: [{ name: 'Test' }] });
|
|
||||||
publicKey.subKeys[0].keyPacket.publicParams.Q = key_data.p384.pub;
|
|
||||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
|
||||||
const { key: privateKey } = await openpgp.generateKey({ curve: "p384", userIds: [{ name: 'Test' }] });
|
|
||||||
privateKey.subKeys[0].keyPacket.publicParams.Q = key_data.p384.pub;
|
|
||||||
privateKey.subKeys[0].keyPacket.privateParams.d = key_data.p384.priv;
|
|
||||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
|
||||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
|
||||||
expect((
|
|
||||||
await openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
|
||||||
).data).to.equal('test');
|
|
||||||
});
|
|
||||||
it('Successful exchange NIST P521', async function () {
|
|
||||||
const { key: publicKey } = await openpgp.generateKey({ curve: "p521", userIds: [{ name: 'Test' }] });
|
|
||||||
publicKey.subKeys[0].keyPacket.publicParams.Q = key_data.p521.pub;
|
|
||||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
|
||||||
const { key: privateKey } = await openpgp.generateKey({ curve: "p521", userIds: [{ name: 'Test' }] });
|
|
||||||
privateKey.subKeys[0].keyPacket.publicParams.Q = key_data.p521.pub;
|
|
||||||
privateKey.subKeys[0].keyPacket.privateParams.d = key_data.p521.priv;
|
|
||||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
|
||||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
|
||||||
expect((
|
|
||||||
await openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
|
||||||
).data).to.equal('test');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Comparing decrypting with useNative = true and false', async function () {
|
['p256', 'p384', 'p521'].forEach(curveName => {
|
||||||
const names = ["p256", "p384", "p521"];
|
it(`NIST ${curveName} - Successful exchange`, async function () {
|
||||||
return Promise.all(names.map(async function (name) {
|
const curve = new elliptic_curves.Curve(curveName);
|
||||||
const { key: publicKey } = await openpgp.generateKey({ curve: name, userIds: [{ name: 'Test' }] });
|
const oid = new OID(curve.oid);
|
||||||
publicKey.subKeys[0].keyPacket.publicParams.Q = key_data[name].pub;
|
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
|
||||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
const data = util.strToUint8Array('test');
|
||||||
const { key: privateKey } = await openpgp.generateKey({ curve: name, userIds: [{ name: 'Test' }] });
|
const Q = key_data[curveName].pub;
|
||||||
privateKey.subKeys[0].keyPacket.publicParams.Q = key_data[name].pub;
|
const d = key_data[curveName].priv;
|
||||||
privateKey.subKeys[0].keyPacket.privateParams.d = key_data[name].priv;
|
const { publicKey: V, wrappedKey: C } = await ecdh.encrypt(oid, kdfParams, data, Q, fingerprint1);
|
||||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
expect(await ecdh.decrypt(oid, kdfParams, V, C, Q, d, fingerprint1)).to.deep.equal(data);
|
||||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
});
|
||||||
expect((
|
});
|
||||||
await openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
|
||||||
).data).to.equal('test');
|
describe('Comparing decrypting with and without native crypto', () => {
|
||||||
const useNative = openpgp.config.useNative;
|
let sinonSandbox;
|
||||||
openpgp.config.useNative = !useNative;
|
let getWebCryptoStub;
|
||||||
try {
|
let getNodeCryptoStub;
|
||||||
expect((
|
|
||||||
await openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
beforeEach(function () {
|
||||||
).data).to.equal('test');
|
sinonSandbox = sandbox.create();
|
||||||
} finally {
|
});
|
||||||
openpgp.config.useNative = useNative;
|
|
||||||
}
|
afterEach(function () {
|
||||||
}));
|
sinonSandbox.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
const disableNative = () => {
|
||||||
|
enableNative();
|
||||||
|
// stubbed functions return undefined
|
||||||
|
getWebCryptoStub = sinonSandbox.stub(util, "getWebCrypto");
|
||||||
|
getNodeCryptoStub = sinonSandbox.stub(util, "getNodeCrypto");
|
||||||
|
};
|
||||||
|
const enableNative = () => {
|
||||||
|
getWebCryptoStub && getWebCryptoStub.restore();
|
||||||
|
getNodeCryptoStub && getNodeCryptoStub.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
['p256', 'p384', 'p521'].forEach(curveName => {
|
||||||
|
it(`NIST ${curveName}`, async function () {
|
||||||
|
const nodeCrypto = util.getNodeCrypto();
|
||||||
|
const webCrypto = util.getWebCrypto();
|
||||||
|
if (!nodeCrypto && !webCrypto) {
|
||||||
|
this.skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
const curve = new elliptic_curves.Curve(curveName);
|
||||||
|
const oid = new OID(curve.oid);
|
||||||
|
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
|
||||||
|
const data = util.strToUint8Array('test');
|
||||||
|
const Q = key_data[curveName].pub;
|
||||||
|
const d = key_data[curveName].priv;
|
||||||
|
const { publicKey: V, wrappedKey: C } = await ecdh.encrypt(oid, kdfParams, data, Q, fingerprint1);
|
||||||
|
|
||||||
|
const nativeDecryptSpy = webCrypto ? sinonSandbox.spy(webCrypto, 'deriveBits') : sinonSandbox.spy(nodeCrypto, 'createECDH');
|
||||||
|
expect(await ecdh.decrypt(oid, kdfParams, V, C, Q, d, fingerprint1)).to.deep.equal(data);
|
||||||
|
disableNative();
|
||||||
|
expect(await ecdh.decrypt(oid, kdfParams, V, C, Q, d, fingerprint1)).to.deep.equal(data);
|
||||||
|
if (curveName !== 'p521') { // safari does not implement p521 in webcrypto
|
||||||
|
expect(nativeDecryptSpy.calledOnce).to.be.true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -4,6 +4,7 @@ const hashMod = require('../../src/crypto/hash');
|
|||||||
const config = require('../../src/config');
|
const config = require('../../src/config');
|
||||||
const util = require('../../src/util');
|
const util = require('../../src/util');
|
||||||
|
|
||||||
|
const sandbox = require('sinon/lib/sinon/sandbox');
|
||||||
const chai = require('chai');
|
const chai = require('chai');
|
||||||
|
|
||||||
const elliptic_data = require('./elliptic_data');
|
const elliptic_data = require('./elliptic_data');
|
||||||
@ -99,6 +100,29 @@ module.exports = () => describe('Elliptic Curve Cryptography @lightweight', func
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('ECDSA signature', function () {
|
describe('ECDSA signature', function () {
|
||||||
|
let sinonSandbox;
|
||||||
|
let getWebCryptoStub;
|
||||||
|
let getNodeCryptoStub;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
sinonSandbox = sandbox.create();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
sinonSandbox.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
const disableNative = () => {
|
||||||
|
enableNative();
|
||||||
|
// stubbed functions return undefined
|
||||||
|
getWebCryptoStub = sinonSandbox.stub(util, "getWebCrypto");
|
||||||
|
getNodeCryptoStub = sinonSandbox.stub(util, "getNodeCrypto");
|
||||||
|
};
|
||||||
|
const enableNative = () => {
|
||||||
|
getWebCryptoStub && getWebCryptoStub.restore();
|
||||||
|
getNodeCryptoStub && getNodeCryptoStub.restore();
|
||||||
|
};
|
||||||
|
|
||||||
const verify_signature = async function (oid, hash, r, s, message, pub) {
|
const verify_signature = async function (oid, hash, r, s, message, pub) {
|
||||||
if (util.isString(message)) {
|
if (util.isString(message)) {
|
||||||
message = util.strToUint8Array(message);
|
message = util.strToUint8Array(message);
|
||||||
@ -151,7 +175,7 @@ module.exports = () => describe('Elliptic Curve Cryptography @lightweight', func
|
|||||||
});
|
});
|
||||||
it('Invalid public key', async function () {
|
it('Invalid public key', async function () {
|
||||||
if (!config.useIndutnyElliptic && !util.getNodeCrypto()) {
|
if (!config.useIndutnyElliptic && !util.getNodeCrypto()) {
|
||||||
this.skip();
|
this.skip(); // webcrypto does not implement secp256k1
|
||||||
}
|
}
|
||||||
if (util.getNodeCrypto()) {
|
if (util.getNodeCrypto()) {
|
||||||
await expect(verify_signature(
|
await expect(verify_signature(
|
||||||
@ -162,20 +186,13 @@ module.exports = () => describe('Elliptic Curve Cryptography @lightweight', func
|
|||||||
)).to.eventually.be.false;
|
)).to.eventually.be.false;
|
||||||
}
|
}
|
||||||
if (config.useIndutnyElliptic) {
|
if (config.useIndutnyElliptic) {
|
||||||
const useNative = config.useNative;
|
disableNative();
|
||||||
config.useNative = false;
|
await expect(verify_signature(
|
||||||
try {
|
'secp256k1', 8, [], [], [], []
|
||||||
await Promise.all([
|
)).to.be.rejectedWith(Error, /Unknown point format/);
|
||||||
expect(verify_signature(
|
await expect(verify_signature(
|
||||||
'secp256k1', 8, [], [], [], []
|
'secp256k1', 8, [], [], [], secp256k1_invalid_point_format
|
||||||
)).to.be.rejectedWith(Error, /Unknown point format/),
|
)).to.be.rejectedWith(Error, /Unknown point format/);
|
||||||
expect(verify_signature(
|
|
||||||
'secp256k1', 8, [], [], [], secp256k1_invalid_point_format
|
|
||||||
)).to.be.rejectedWith(Error, /Unknown point format/)
|
|
||||||
]);
|
|
||||||
} finally {
|
|
||||||
config.useNative = useNative;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
it('Invalid point', async function () {
|
it('Invalid point', async function () {
|
||||||
@ -188,15 +205,10 @@ module.exports = () => describe('Elliptic Curve Cryptography @lightweight', func
|
|||||||
)).to.eventually.be.false;
|
)).to.eventually.be.false;
|
||||||
}
|
}
|
||||||
if (config.useIndutnyElliptic) {
|
if (config.useIndutnyElliptic) {
|
||||||
const useNative = config.useNative;
|
disableNative();
|
||||||
config.useNative = false;
|
await expect(verify_signature(
|
||||||
try {
|
'secp256k1', 8, [], [], [], secp256k1_invalid_point
|
||||||
await expect(verify_signature(
|
)).to.be.rejectedWith(Error, /Invalid elliptic public key/);
|
||||||
'secp256k1', 8, [], [], [], secp256k1_invalid_point
|
|
||||||
)).to.be.rejectedWith(Error, /Invalid elliptic public key/);
|
|
||||||
} finally {
|
|
||||||
config.useNative = useNative;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
it('Invalid signature', function (done) {
|
it('Invalid signature', function (done) {
|
||||||
|
86
test/crypto/gcm.js
Normal file
86
test/crypto/gcm.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
|
||||||
|
const crypto = require('../../src/crypto');
|
||||||
|
const util = require('../../src/util');
|
||||||
|
|
||||||
|
const sandbox = require('sinon/lib/sinon/sandbox');
|
||||||
|
const chai = require('chai');
|
||||||
|
chai.use(require('chai-as-promised'));
|
||||||
|
|
||||||
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
module.exports = () => describe('Symmetric AES-GCM (experimental)', function() {
|
||||||
|
let sinonSandbox;
|
||||||
|
let getWebCryptoStub;
|
||||||
|
let getNodeCryptoStub;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
sinonSandbox = sandbox.create();
|
||||||
|
enableNative();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
sinonSandbox.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
const disableNative = () => {
|
||||||
|
enableNative();
|
||||||
|
// stubbed functions return undefined
|
||||||
|
getWebCryptoStub = sinonSandbox.stub(util, "getWebCrypto");
|
||||||
|
getNodeCryptoStub = sinonSandbox.stub(util, "getNodeCrypto");
|
||||||
|
};
|
||||||
|
const enableNative = () => {
|
||||||
|
getWebCryptoStub && getWebCryptoStub.restore();
|
||||||
|
getNodeCryptoStub && getNodeCryptoStub.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
function testAESGCM(plaintext, nativeEncrypt, nativeDecrypt) {
|
||||||
|
const aesAlgos = Object.keys(openpgp.enums.symmetric).filter(
|
||||||
|
algo => algo.substr(0,3) === 'aes'
|
||||||
|
);
|
||||||
|
aesAlgos.forEach(function(algo) {
|
||||||
|
it(algo, async function() {
|
||||||
|
const nodeCrypto = util.getNodeCrypto();
|
||||||
|
const webCrypto = util.getWebCrypto();
|
||||||
|
if (!nodeCrypto && !webCrypto) {
|
||||||
|
this.skip(); // eslint-disable-line no-invalid-this
|
||||||
|
}
|
||||||
|
const key = await crypto.generateSessionKey(algo);
|
||||||
|
const iv = await crypto.random.getRandomBytes(crypto.gcm.ivLength);
|
||||||
|
|
||||||
|
const nativeEncryptSpy = webCrypto ? sinonSandbox.spy(webCrypto, 'encrypt') : sinonSandbox.spy(nodeCrypto, 'createCipheriv');
|
||||||
|
const nativeDecryptSpy = webCrypto ? sinonSandbox.spy(webCrypto, 'decrypt') : sinonSandbox.spy(nodeCrypto, 'createDecipheriv');
|
||||||
|
|
||||||
|
nativeEncrypt || disableNative();
|
||||||
|
let modeInstance = await crypto.gcm(algo, key);
|
||||||
|
const ciphertext = await modeInstance.encrypt(util.strToUint8Array(plaintext), iv);
|
||||||
|
enableNative();
|
||||||
|
|
||||||
|
nativeDecrypt || disableNative();
|
||||||
|
modeInstance = await crypto.gcm(algo, key);
|
||||||
|
const decrypted = await modeInstance.decrypt(util.strToUint8Array(util.uint8ArrayToStr(ciphertext)), iv);
|
||||||
|
enableNative();
|
||||||
|
|
||||||
|
const decryptedStr = util.uint8ArrayToStr(decrypted);
|
||||||
|
expect(decryptedStr).to.equal(plaintext);
|
||||||
|
|
||||||
|
if (algo !== 'aes192') { // not implemented by webcrypto
|
||||||
|
// sanity check: native crypto was indeed on/off
|
||||||
|
expect(nativeEncryptSpy.called).to.equal(nativeEncrypt);
|
||||||
|
expect(nativeDecryptSpy.called).to.equal(nativeDecrypt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Symmetric AES-GCM (native)', function() {
|
||||||
|
testAESGCM("12345678901234567890123456789012345678901234567890", true, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Symmetric AES-GCM (asm.js fallback)', function() {
|
||||||
|
testAESGCM("12345678901234567890123456789012345678901234567890", false, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Symmetric AES-GCM (native encrypt, asm.js decrypt)', function() {
|
||||||
|
testAESGCM("12345678901234567890123456789012345678901234567890", true, false);
|
||||||
|
});
|
||||||
|
});
|
@ -7,6 +7,7 @@ module.exports = () => describe('Crypto', function () {
|
|||||||
require('./ecdh.js')();
|
require('./ecdh.js')();
|
||||||
require('./pkcs5.js')();
|
require('./pkcs5.js')();
|
||||||
require('./aes_kw.js')();
|
require('./aes_kw.js')();
|
||||||
|
require('./gcm.js')();
|
||||||
require('./eax.js')();
|
require('./eax.js')();
|
||||||
require('./ocb.js')();
|
require('./ocb.js')();
|
||||||
require('./rsa.js')();
|
require('./rsa.js')();
|
||||||
|
@ -3,6 +3,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 sandbox = require('sinon/lib/sinon/sandbox');
|
||||||
const chai = require('chai');
|
const chai = require('chai');
|
||||||
|
|
||||||
chai.use(require('chai-as-promised'));
|
chai.use(require('chai-as-promised'));
|
||||||
@ -13,6 +14,30 @@ const expect = chai.expect;
|
|||||||
/* eslint-disable no-invalid-this */
|
/* eslint-disable no-invalid-this */
|
||||||
const native = util.getWebCrypto() || util.getNodeCrypto();
|
const native = util.getWebCrypto() || util.getNodeCrypto();
|
||||||
module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptography with native crypto', function () {
|
module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptography with native crypto', function () {
|
||||||
|
let sinonSandbox;
|
||||||
|
let getWebCryptoStub;
|
||||||
|
let getNodeCryptoStub;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
sinonSandbox = sandbox.create();
|
||||||
|
enableNative();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
sinonSandbox.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
const disableNative = () => {
|
||||||
|
enableNative();
|
||||||
|
// stubbed functions return undefined
|
||||||
|
getWebCryptoStub = sinonSandbox.stub(util, "getWebCrypto");
|
||||||
|
getNodeCryptoStub = sinonSandbox.stub(util, "getNodeCrypto");
|
||||||
|
};
|
||||||
|
const enableNative = () => {
|
||||||
|
getWebCryptoStub && getWebCryptoStub.restore();
|
||||||
|
getNodeCryptoStub && getNodeCryptoStub.restore();
|
||||||
|
};
|
||||||
|
|
||||||
it('generate rsa key', async function() {
|
it('generate rsa key', async function() {
|
||||||
const bits = 1024;
|
const bits = 1024;
|
||||||
const keyObject = await crypto.publicKey.rsa.generate(bits, 65537);
|
const keyObject = await crypto.publicKey.rsa.generate(bits, 65537);
|
||||||
@ -49,29 +74,24 @@ module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptogra
|
|||||||
|
|
||||||
it('decrypt nodeCrypto by bnCrypto and vice versa', async function() {
|
it('decrypt nodeCrypto by bnCrypto and vice versa', async function() {
|
||||||
if (!util.getNodeCrypto()) {
|
if (!util.getNodeCrypto()) {
|
||||||
this.skip();
|
this.skip(); // webcrypto does not implement RSA PKCS#1 v.15 decryption
|
||||||
}
|
}
|
||||||
const bits = 1024;
|
const bits = 1024;
|
||||||
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
|
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
|
||||||
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
|
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
|
||||||
const message = await crypto.generateSessionKey('aes256');
|
const message = await crypto.generateSessionKey('aes256');
|
||||||
const useNative = openpgp.config.useNative;
|
disableNative();
|
||||||
try {
|
const encryptedBn = await crypto.publicKey.rsa.encrypt(message, n, e);
|
||||||
openpgp.config.useNative = false;
|
enableNative();
|
||||||
const encryptedBn = await crypto.publicKey.rsa.encrypt(message, n, e);
|
const decrypted1 = await crypto.publicKey.rsa.decrypt(encryptedBn, n, e, d, p, q, u);
|
||||||
openpgp.config.useNative = true;
|
expect(decrypted1).to.deep.equal(message);
|
||||||
const decrypted1 = await crypto.publicKey.rsa.decrypt(encryptedBn, n, e, d, p, q, u);
|
const encryptedNode = await crypto.publicKey.rsa.encrypt(message, n, e);
|
||||||
expect(decrypted1).to.deep.equal(message);
|
disableNative();
|
||||||
const encryptedNode = await crypto.publicKey.rsa.encrypt(message, n, e);
|
const decrypted2 = await crypto.publicKey.rsa.decrypt(encryptedNode, n, e, d, p, q, u);
|
||||||
openpgp.config.useNative = false;
|
expect(decrypted2).to.deep.equal(message);
|
||||||
const decrypted2 = await crypto.publicKey.rsa.decrypt(encryptedNode, n, e, d, p, q, u);
|
|
||||||
expect(decrypted2).to.deep.equal(message);
|
|
||||||
} finally {
|
|
||||||
openpgp.config.useNative = useNative;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('compare native crypto and bn math sign', async function() {
|
it('compare native crypto and bnSign', async function() {
|
||||||
const bits = 1024;
|
const bits = 1024;
|
||||||
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
|
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
|
||||||
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
|
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
|
||||||
@ -79,25 +99,14 @@ module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptogra
|
|||||||
const hashName = 'sha256';
|
const hashName = 'sha256';
|
||||||
const hash_algo = openpgp.enums.write(openpgp.enums.hash, hashName);
|
const hash_algo = openpgp.enums.write(openpgp.enums.hash, hashName);
|
||||||
const hashed = await crypto.hash.digest(hash_algo, message);
|
const hashed = await crypto.hash.digest(hash_algo, message);
|
||||||
const useNative = openpgp.config.useNative;
|
enableNative();
|
||||||
try {
|
const signatureNative = await crypto.publicKey.rsa.sign(hash_algo, message, n, e, d, p, q, u, hashed);
|
||||||
openpgp.config.useNative = true;
|
disableNative();
|
||||||
let signatureWeb;
|
const signatureBN = await crypto.publicKey.rsa.sign(hash_algo, message, n, e, d, p, q, u, hashed);
|
||||||
try {
|
expect(util.uint8ArrayToHex(signatureNative)).to.be.equal(util.uint8ArrayToHex(signatureBN));
|
||||||
signatureWeb = await crypto.publicKey.rsa.sign(hash_algo, message, n, e, d, p, q, u, hashed);
|
|
||||||
} catch (error) {
|
|
||||||
util.printDebugError('web crypto error');
|
|
||||||
this.skip();
|
|
||||||
}
|
|
||||||
openpgp.config.useNative = false;
|
|
||||||
const signatureBN = await crypto.publicKey.rsa.sign(hash_algo, message, n, e, d, p, q, u, hashed);
|
|
||||||
expect(util.uint8ArrayToHex(signatureWeb)).to.be.equal(util.uint8ArrayToHex(signatureBN));
|
|
||||||
} finally {
|
|
||||||
openpgp.config.useNative = useNative;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('compare native crypto and bn math verify', async function() {
|
it('compare native crypto and bnVerify', async function() {
|
||||||
const bits = 1024;
|
const bits = 1024;
|
||||||
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
|
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
|
||||||
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
|
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
|
||||||
@ -105,24 +114,12 @@ module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptogra
|
|||||||
const hashName = 'sha256';
|
const hashName = 'sha256';
|
||||||
const hash_algo = openpgp.enums.write(openpgp.enums.hash, hashName);
|
const hash_algo = openpgp.enums.write(openpgp.enums.hash, hashName);
|
||||||
const hashed = await crypto.hash.digest(hash_algo, message);
|
const hashed = await crypto.hash.digest(hash_algo, message);
|
||||||
let verifyWeb;
|
enableNative();
|
||||||
let signature;
|
const signatureNative = await crypto.publicKey.rsa.sign(hash_algo, message, n, e, d, p, q, u, hashed);
|
||||||
const useNative = openpgp.config.useNative;
|
const verifyNative = await crypto.publicKey.rsa.verify(hash_algo, message, signatureNative, n, e);
|
||||||
try {
|
disableNative();
|
||||||
openpgp.config.useNative = true;
|
const verifyBN = await crypto.publicKey.rsa.verify(hash_algo, message, signatureNative, n, e, hashed);
|
||||||
try {
|
expect(verifyNative).to.be.true;
|
||||||
signature = await crypto.publicKey.rsa.sign(hash_algo, message, n, e, d, p, q, u, hashed);
|
expect(verifyBN).to.be.true;
|
||||||
verifyWeb = await crypto.publicKey.rsa.verify(hash_algo, message, signature, n, e);
|
|
||||||
} catch (error) {
|
|
||||||
util.printDebugError('web crypto error');
|
|
||||||
this.skip();
|
|
||||||
}
|
|
||||||
openpgp.config.useNative = false;
|
|
||||||
const verifyBN = await crypto.publicKey.rsa.verify(hash_algo, message, signature, n, e, hashed);
|
|
||||||
expect(verifyWeb).to.be.true;
|
|
||||||
expect(verifyBN).to.be.true;
|
|
||||||
} finally {
|
|
||||||
openpgp.config.useNative = useNative;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -244,13 +244,13 @@ EJ4QcD/oQ6x1M/8X/iKQCtxZP8RnlrbH7ExkNON5s5g=
|
|||||||
});
|
});
|
||||||
it('Decrypt and verify message with leading zero in hash signed with old elliptic algorithm', async function () {
|
it('Decrypt and verify message with leading zero in hash signed with old elliptic algorithm', async function () {
|
||||||
//this test would not work with nodeCrypto, since message is signed with leading zero stripped from the hash
|
//this test would not work with nodeCrypto, since message is signed with leading zero stripped from the hash
|
||||||
const useNative = openpgp.config.useNative;
|
if (util.getNodeCrypto()) {
|
||||||
openpgp.config.useNative = false;
|
this.skip(); // eslint-disable-line no-invalid-this
|
||||||
|
}
|
||||||
const juliet = await load_priv_key('juliet');
|
const juliet = await load_priv_key('juliet');
|
||||||
const romeo = await load_pub_key('romeo');
|
const romeo = await load_pub_key('romeo');
|
||||||
const msg = await openpgp.readMessage({ armoredMessage: data.romeo.message_encrypted_with_leading_zero_in_hash_signed_by_elliptic_with_old_implementation });
|
const msg = await openpgp.readMessage({ armoredMessage: data.romeo.message_encrypted_with_leading_zero_in_hash_signed_by_elliptic_with_old_implementation });
|
||||||
const result = await openpgp.decrypt({ privateKeys: juliet, publicKeys: [romeo], message: msg });
|
const result = await openpgp.decrypt({ privateKeys: juliet, publicKeys: [romeo], message: msg });
|
||||||
openpgp.config.useNative = useNative;
|
|
||||||
expect(result).to.exist;
|
expect(result).to.exist;
|
||||||
expect(result.data).to.equal(data.romeo.message_with_leading_zero_in_hash_old_elliptic_implementation);
|
expect(result.data).to.equal(data.romeo.message_with_leading_zero_in_hash_old_elliptic_implementation);
|
||||||
expect(result.signatures).to.have.length(1);
|
expect(result.signatures).to.have.length(1);
|
||||||
|
242
test/general/config.js
Normal file
242
test/general/config.js
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
const { expect } = require('chai');
|
||||||
|
|
||||||
|
const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
|
||||||
|
|
||||||
|
module.exports = () => describe('Custom configuration', function() {
|
||||||
|
it('openpgp.generateKey', async function() {
|
||||||
|
const v5KeysVal = openpgp.config.v5Keys;
|
||||||
|
const preferHashAlgorithmVal = openpgp.config.preferHashAlgorithm;
|
||||||
|
const showCommentVal = openpgp.config.showComment;
|
||||||
|
openpgp.config.v5Keys = false;
|
||||||
|
openpgp.config.preferHashAlgorithm = openpgp.enums.hash.sha256;
|
||||||
|
openpgp.config.showComment = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const opt = {
|
||||||
|
userIds: { name: 'Test User', email: 'text@example.com' }
|
||||||
|
};
|
||||||
|
const { key, privateKeyArmored } = await openpgp.generateKey(opt);
|
||||||
|
expect(key.keyPacket.version).to.equal(4);
|
||||||
|
expect(privateKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false;
|
||||||
|
expect(key.users[0].selfCertifications[0].preferredHashAlgorithms[0]).to.equal(openpgp.config.preferHashAlgorithm);
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
v5Keys: true,
|
||||||
|
showComment: true,
|
||||||
|
preferHashAlgorithm: openpgp.enums.hash.sha512
|
||||||
|
};
|
||||||
|
const opt2 = {
|
||||||
|
userIds: { name: 'Test User', email: 'text@example.com' },
|
||||||
|
config
|
||||||
|
};
|
||||||
|
const { key: key2, privateKeyArmored: privateKeyArmored2 } = await openpgp.generateKey(opt2);
|
||||||
|
expect(key2.keyPacket.version).to.equal(5);
|
||||||
|
expect(privateKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true;
|
||||||
|
expect(key2.users[0].selfCertifications[0].preferredHashAlgorithms[0]).to.equal(config.preferHashAlgorithm);
|
||||||
|
} finally {
|
||||||
|
openpgp.config.v5Keys = v5KeysVal;
|
||||||
|
openpgp.config.preferHashAlgorithm = preferHashAlgorithmVal;
|
||||||
|
openpgp.config.showComment = showCommentVal;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('openpgp.reformatKey', async function() {
|
||||||
|
const compressionVal = openpgp.config.compression;
|
||||||
|
const preferHashAlgorithmVal = openpgp.config.preferHashAlgorithm;
|
||||||
|
const showCommentVal = openpgp.config.showComment;
|
||||||
|
openpgp.config.compression = openpgp.enums.compression.bzip2;
|
||||||
|
openpgp.config.preferHashAlgorithm = openpgp.enums.hash.sha256;
|
||||||
|
openpgp.config.showComment = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const userIds = { name: 'Test User', email: 'text2@example.com' };
|
||||||
|
const { key: origKey } = await openpgp.generateKey({ userIds });
|
||||||
|
|
||||||
|
const opt = { privateKey: origKey, userIds };
|
||||||
|
const { key: refKey, privateKeyArmored: refKeyArmored } = await openpgp.reformatKey(opt);
|
||||||
|
const prefs = refKey.users[0].selfCertifications[0];
|
||||||
|
expect(prefs.preferredCompressionAlgorithms[0]).to.equal(openpgp.config.compression);
|
||||||
|
expect(prefs.preferredHashAlgorithms[0]).to.equal(openpgp.config.preferHashAlgorithm);
|
||||||
|
expect(refKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false;
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
showComment: true,
|
||||||
|
compression: openpgp.enums.compression.zip,
|
||||||
|
preferHashAlgorithm: openpgp.enums.hash.sha512
|
||||||
|
};
|
||||||
|
const opt2 = { privateKey: origKey, userIds, config };
|
||||||
|
const { key: refKey2, privateKeyArmored: refKeyArmored2 } = await openpgp.reformatKey(opt2);
|
||||||
|
const prefs2 = refKey2.users[0].selfCertifications[0];
|
||||||
|
expect(prefs2.preferredCompressionAlgorithms[0]).to.equal(config.compression);
|
||||||
|
expect(prefs2.preferredHashAlgorithms[0]).to.equal(config.preferHashAlgorithm);
|
||||||
|
expect(refKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true;
|
||||||
|
} finally {
|
||||||
|
openpgp.config.compression = compressionVal;
|
||||||
|
openpgp.config.preferHashAlgorithm = preferHashAlgorithmVal;
|
||||||
|
openpgp.config.showComment = showCommentVal;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('openpgp.revokeKey', async function() {
|
||||||
|
const showCommentVal = openpgp.config.showComment;
|
||||||
|
openpgp.config.showComment = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const userIds = { name: 'Test User', email: 'text2@example.com' };
|
||||||
|
const { key, revocationCertificate } = await openpgp.generateKey({ userIds });
|
||||||
|
|
||||||
|
const opt = { key };
|
||||||
|
const { privateKeyArmored: revKeyArmored } = await openpgp.revokeKey(opt);
|
||||||
|
expect(revKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false;
|
||||||
|
|
||||||
|
const opt2 = { key, config: { showComment: true } };
|
||||||
|
const { privateKeyArmored: revKeyArmored2 } = await openpgp.revokeKey(opt2);
|
||||||
|
expect(revKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true;
|
||||||
|
|
||||||
|
const opt3 = {
|
||||||
|
key,
|
||||||
|
revocationCertificate,
|
||||||
|
config: { rejectHashAlgorithms: new Set([openpgp.enums.hash.sha256, openpgp.enums.hash.sha512]) }
|
||||||
|
};
|
||||||
|
await expect(openpgp.revokeKey(opt3)).to.be.rejectedWith(/Insecure hash algorithm/);
|
||||||
|
} finally {
|
||||||
|
openpgp.config.showComment = showCommentVal;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('openpgp.decryptKey', async function() {
|
||||||
|
const userIds = { name: 'Test User', email: 'text2@example.com' };
|
||||||
|
const passphrase = '12345678';
|
||||||
|
|
||||||
|
const { key } = await openpgp.generateKey({ userIds, passphrase });
|
||||||
|
key.keyPacket.makeDummy();
|
||||||
|
|
||||||
|
const opt = {
|
||||||
|
privateKey: await openpgp.readKey({ armoredKey: key.armor() }),
|
||||||
|
passphrase,
|
||||||
|
config: { rejectHashAlgorithms: new Set([openpgp.enums.hash.sha256, openpgp.enums.hash.sha512]) }
|
||||||
|
};
|
||||||
|
await expect(openpgp.decryptKey(opt)).to.be.rejectedWith(/Insecure hash algorithm/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('openpgp.encryptKey', async function() {
|
||||||
|
const s2kIterationCountByteVal = openpgp.config.s2kIterationCountByte;
|
||||||
|
openpgp.config.s2kIterationCountByte = 224;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const passphrase = '12345678';
|
||||||
|
const userIds = { name: 'Test User', email: 'text2@example.com' };
|
||||||
|
const { key: privateKey } = await openpgp.generateKey({ userIds });
|
||||||
|
|
||||||
|
const encKey = await openpgp.encryptKey({ privateKey, userIds, passphrase });
|
||||||
|
expect(encKey.keyPacket.s2k.c).to.equal(openpgp.config.s2kIterationCountByte);
|
||||||
|
|
||||||
|
const config = { s2kIterationCountByte: 123 };
|
||||||
|
const encKey2 = await openpgp.encryptKey({ privateKey, userIds, passphrase, config });
|
||||||
|
expect(encKey2.keyPacket.s2k.c).to.equal(config.s2kIterationCountByte);
|
||||||
|
} finally {
|
||||||
|
openpgp.config.s2kIterationCountByte = s2kIterationCountByteVal;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('openpgp.encrypt', async function() {
|
||||||
|
const aeadProtectVal = openpgp.config.aeadProtect;
|
||||||
|
const compressionVal = openpgp.config.compression;
|
||||||
|
openpgp.config.aeadProtect = false;
|
||||||
|
openpgp.config.compression = openpgp.enums.compression.uncompressed;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const passwords = ['12345678'];
|
||||||
|
const message = openpgp.Message.fromText("test");
|
||||||
|
|
||||||
|
const armored = await openpgp.encrypt({ message, passwords });
|
||||||
|
const encrypted = await openpgp.readMessage({ armoredMessage: armored });
|
||||||
|
const { packets: [skesk, encData] } = encrypted;
|
||||||
|
expect(skesk.version).to.equal(4); // cfb
|
||||||
|
expect(encData.tag).to.equal(openpgp.enums.packet.symEncryptedIntegrityProtectedData);
|
||||||
|
const { packets: [literal] } = await encrypted.decrypt(null, passwords, null, encrypted.fromStream, openpgp.config);
|
||||||
|
expect(literal.tag).to.equal(openpgp.enums.packet.literalData);
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
aeadProtect: true,
|
||||||
|
compression: openpgp.enums.compression.zip,
|
||||||
|
deflateLevel: 1
|
||||||
|
};
|
||||||
|
const armored2 = await openpgp.encrypt({ message, passwords, config });
|
||||||
|
const encrypted2 = await openpgp.readMessage({ armoredMessage: armored2 });
|
||||||
|
const { packets: [skesk2, encData2] } = encrypted2;
|
||||||
|
expect(skesk2.version).to.equal(5);
|
||||||
|
expect(encData2.tag).to.equal(openpgp.enums.packet.AEADEncryptedData);
|
||||||
|
const { packets: [compressed] } = await encrypted2.decrypt(null, passwords, null, encrypted2.fromStream, openpgp.config);
|
||||||
|
expect(compressed.tag).to.equal(openpgp.enums.packet.compressedData);
|
||||||
|
expect(compressed.algorithm).to.equal("zip");
|
||||||
|
} finally {
|
||||||
|
openpgp.config.aeadProtect = aeadProtectVal;
|
||||||
|
openpgp.config.compression = compressionVal;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('openpgp.sign', async function() {
|
||||||
|
const userIds = { name: 'Test User', email: 'text2@example.com' };
|
||||||
|
const { privateKeyArmored } = await openpgp.generateKey({ userIds });
|
||||||
|
const key = await openpgp.readKey({ armoredKey: privateKeyArmored });
|
||||||
|
|
||||||
|
const message = openpgp.Message.fromText("test");
|
||||||
|
const opt = {
|
||||||
|
message,
|
||||||
|
privateKeys: key,
|
||||||
|
config: { rejectHashAlgorithms: new Set([openpgp.enums.hash.sha256, openpgp.enums.hash.sha512]) }
|
||||||
|
};
|
||||||
|
await expect(openpgp.sign(opt)).to.be.rejectedWith(/Insecure hash algorithm/);
|
||||||
|
opt.detached = true;
|
||||||
|
await expect(openpgp.sign(opt)).to.be.rejectedWith(/Insecure hash algorithm/);
|
||||||
|
|
||||||
|
const clearText = openpgp.CleartextMessage.fromText("test");
|
||||||
|
const opt2 = {
|
||||||
|
message: clearText,
|
||||||
|
privateKeys: key,
|
||||||
|
config: { rejectHashAlgorithms: new Set([openpgp.enums.hash.sha256, openpgp.enums.hash.sha512]) }
|
||||||
|
};
|
||||||
|
await expect(openpgp.sign(opt2)).to.be.rejectedWith(/Insecure hash algorithm/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('openpgp.verify', async function() {
|
||||||
|
const userIds = { name: 'Test User', email: 'text2@example.com' };
|
||||||
|
const { privateKeyArmored } = await openpgp.generateKey({ userIds });
|
||||||
|
const key = await openpgp.readKey({ armoredKey: privateKeyArmored });
|
||||||
|
const config = { rejectMessageHashAlgorithms: new Set([openpgp.enums.hash.sha256, openpgp.enums.hash.sha512]) };
|
||||||
|
|
||||||
|
|
||||||
|
const message = openpgp.Message.fromText("test");
|
||||||
|
const signed = await openpgp.sign({ message, privateKeys: key });
|
||||||
|
const opt = {
|
||||||
|
message: await openpgp.readMessage({ armoredMessage: signed }),
|
||||||
|
publicKeys: key,
|
||||||
|
config
|
||||||
|
};
|
||||||
|
const { signatures: [sig] } = await openpgp.verify(opt);
|
||||||
|
await expect(sig.error).to.match(/Insecure message hash algorithm/);
|
||||||
|
const armoredSignature = await openpgp.sign({ message, privateKeys: key, detached: true });
|
||||||
|
const opt2 = {
|
||||||
|
message,
|
||||||
|
signature: await openpgp.readSignature({ armoredSignature }),
|
||||||
|
publicKeys: key,
|
||||||
|
config
|
||||||
|
};
|
||||||
|
const { signatures: [sig2] } = await openpgp.verify(opt2);
|
||||||
|
await expect(sig2.error).to.match(/Insecure message hash algorithm/);
|
||||||
|
|
||||||
|
const cleartext = openpgp.CleartextMessage.fromText("test");
|
||||||
|
const signedCleartext = await openpgp.sign({ message: cleartext, privateKeys: key });
|
||||||
|
const opt3 = {
|
||||||
|
message: await openpgp.readCleartextMessage({ cleartextMessage: signedCleartext }),
|
||||||
|
publicKeys: key,
|
||||||
|
config
|
||||||
|
};
|
||||||
|
const { signatures: [sig3] } = await openpgp.verify(opt3);
|
||||||
|
await expect(sig3.error).to.match(/Insecure message hash algorithm/);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -7,6 +7,7 @@ module.exports = () => describe('General', function () {
|
|||||||
require('./signature.js')();
|
require('./signature.js')();
|
||||||
require('./key.js')();
|
require('./key.js')();
|
||||||
require('./openpgp.js')();
|
require('./openpgp.js')();
|
||||||
|
require('./config.js')();
|
||||||
require('./hkp.js')();
|
require('./hkp.js')();
|
||||||
require('./wkd.js')();
|
require('./wkd.js')();
|
||||||
require('./oid.js')();
|
require('./oid.js')();
|
||||||
|
@ -2162,16 +2162,17 @@ function versionSpecificTests() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Generated key is not unlocked by default', 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' };
|
||||||
let key;
|
const { key } = await openpgp.generateKey(opt);
|
||||||
return openpgp.generateKey(opt).then(function(newKey) {
|
return openpgp.encrypt({
|
||||||
key = newKey.key;
|
message: openpgp.Message.fromText('hello'),
|
||||||
return openpgp.Message.fromText('hello').encrypt([key]);
|
publicKeys: key
|
||||||
}).then(function(msg) {
|
}).then(async armoredMessage => openpgp.decrypt({
|
||||||
return msg.decrypt([key]);
|
message: await openpgp.readMessage({ armoredMessage }),
|
||||||
}).catch(function(err) {
|
privateKeys: key
|
||||||
expect(err.message).to.equal('Private key is not decrypted.');
|
})).catch(function(err) {
|
||||||
|
expect(err.message).to.match(/Private key is not decrypted./);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2725,7 +2726,7 @@ module.exports = () => describe('Key', function() {
|
|||||||
`.replace(/\s+/g, ''));
|
`.replace(/\s+/g, ''));
|
||||||
|
|
||||||
const packetlist = new openpgp.PacketList();
|
const packetlist = new openpgp.PacketList();
|
||||||
await packetlist.read(packetBytes, { PublicKeyPacket: openpgp.PublicKeyPacket });
|
await packetlist.read(packetBytes, { PublicKeyPacket: openpgp.PublicKeyPacket }, undefined, openpgp.config);
|
||||||
const key = packetlist[0];
|
const key = packetlist[0];
|
||||||
expect(key).to.exist;
|
expect(key).to.exist;
|
||||||
});
|
});
|
||||||
@ -2755,7 +2756,7 @@ module.exports = () => describe('Key', function() {
|
|||||||
|
|
||||||
const packetlist = new openpgp.PacketList();
|
const packetlist = new openpgp.PacketList();
|
||||||
|
|
||||||
await packetlist.read((await openpgp.unarmor(pub_sig_test)).data, openpgp);
|
await packetlist.read((await openpgp.unarmor(pub_sig_test)).data, openpgp, undefined, openpgp.config);
|
||||||
|
|
||||||
const subkeys = pubKey.getSubkeys();
|
const subkeys = pubKey.getSubkeys();
|
||||||
expect(subkeys).to.exist;
|
expect(subkeys).to.exist;
|
||||||
@ -2826,23 +2827,18 @@ module.exports = () => describe('Key', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not decrypt using a sign-only RSA key, unless explicitly configured', async function () {
|
it('should not decrypt using a sign-only RSA key, unless explicitly configured', async function () {
|
||||||
const allowSigningKeyDecryption = openpgp.config.allowInsecureDecryptionWithSigningKeys;
|
|
||||||
const key = await openpgp.readKey({ armoredKey: rsaSignOnly });
|
const key = await openpgp.readKey({ armoredKey: rsaSignOnly });
|
||||||
try {
|
|
||||||
openpgp.config.allowInsecureDecryptionWithSigningKeys = false;
|
|
||||||
await expect(openpgp.decrypt({
|
|
||||||
message: await openpgp.readMessage({ armoredMessage: encryptedRsaSignOnly }),
|
|
||||||
privateKeys: key
|
|
||||||
})).to.be.rejectedWith(/Session key decryption failed/);
|
|
||||||
|
|
||||||
openpgp.config.allowInsecureDecryptionWithSigningKeys = true;
|
await expect(openpgp.decrypt({
|
||||||
await expect(openpgp.decrypt({
|
message: await openpgp.readMessage({ armoredMessage: encryptedRsaSignOnly }),
|
||||||
message: await openpgp.readMessage({ armoredMessage: encryptedRsaSignOnly }),
|
privateKeys: key
|
||||||
privateKeys: key
|
})).to.be.rejectedWith(/Session key decryption failed/);
|
||||||
})).to.be.fulfilled;
|
|
||||||
} finally {
|
await expect(openpgp.decrypt({
|
||||||
openpgp.config.allowInsecureDecryptionWithSigningKeys = allowSigningKeyDecryption;
|
message: await openpgp.readMessage({ armoredMessage: encryptedRsaSignOnly }),
|
||||||
}
|
privateKeys: key,
|
||||||
|
config: { allowInsecureDecryptionWithSigningKeys: true }
|
||||||
|
})).to.be.fulfilled;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Method getExpirationTime V4 Key', async function() {
|
it('Method getExpirationTime V4 Key', async function() {
|
||||||
@ -3233,7 +3229,7 @@ module.exports = () => describe('Key', function() {
|
|||||||
|
|
||||||
const input = await openpgp.unarmor(revocation_certificate_arm4);
|
const input = await openpgp.unarmor(revocation_certificate_arm4);
|
||||||
const packetlist = new openpgp.PacketList();
|
const packetlist = new openpgp.PacketList();
|
||||||
await packetlist.read(input.data, { SignaturePacket: openpgp.SignaturePacket });
|
await packetlist.read(input.data, { SignaturePacket: openpgp.SignaturePacket }, undefined, openpgp.config);
|
||||||
const armored = openpgp.armor(openpgp.enums.armor.publicKey, packetlist.write());
|
const armored = openpgp.armor(openpgp.enums.armor.publicKey, packetlist.write());
|
||||||
|
|
||||||
expect(revocationCertificate.replace(/^Comment: .*$\n/mg, '')).to.equal(armored.replace(/^Comment: .*$\n/mg, ''));
|
expect(revocationCertificate.replace(/^Comment: .*$\n/mg, '')).to.equal(armored.replace(/^Comment: .*$\n/mg, ''));
|
||||||
|
@ -685,7 +685,7 @@ function withCompression(tests) {
|
|||||||
|
|
||||||
tests(
|
tests(
|
||||||
function(options) {
|
function(options) {
|
||||||
options.compression = compression;
|
options.config = { compression };
|
||||||
return options;
|
return options;
|
||||||
},
|
},
|
||||||
function() {
|
function() {
|
||||||
@ -798,31 +798,7 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('generateKey - integration tests', function() {
|
describe('generateKey - integration tests', function() {
|
||||||
let useNativeVal;
|
it('should work', function() {
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
useNativeVal = openpgp.config.useNative;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function() {
|
|
||||||
openpgp.config.useNative = useNativeVal;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work in JS', function() {
|
|
||||||
openpgp.config.useNative = false;
|
|
||||||
const opt = {
|
|
||||||
userIds: [{ name: 'Test User', email: 'text@example.com' }]
|
|
||||||
};
|
|
||||||
|
|
||||||
return openpgp.generateKey(opt).then(function(newKey) {
|
|
||||||
expect(newKey.key.getUserIds()[0]).to.equal('Test User <text@example.com>');
|
|
||||||
expect(newKey.publicKeyArmored).to.match(/^-----BEGIN PGP PUBLIC/);
|
|
||||||
expect(newKey.privateKeyArmored).to.match(/^-----BEGIN PGP PRIVATE/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work in with native crypto', function() {
|
|
||||||
openpgp.config.useNative = true;
|
|
||||||
const opt = {
|
const opt = {
|
||||||
userIds: [{ name: 'Test User', email: 'text@example.com' }]
|
userIds: [{ name: 'Test User', email: 'text@example.com' }]
|
||||||
};
|
};
|
||||||
@ -845,7 +821,6 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
|
|||||||
let privateKey;
|
let privateKey;
|
||||||
let publicKey;
|
let publicKey;
|
||||||
let publicKeyNoAEAD;
|
let publicKeyNoAEAD;
|
||||||
let useNativeVal;
|
|
||||||
let aeadProtectVal;
|
let aeadProtectVal;
|
||||||
let aeadModeVal;
|
let aeadModeVal;
|
||||||
let aeadChunkSizeByteVal;
|
let aeadChunkSizeByteVal;
|
||||||
@ -864,7 +839,6 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
|
|||||||
publicKey_1337 = privateKey_1337.toPublic();
|
publicKey_1337 = privateKey_1337.toPublic();
|
||||||
privateKeyMismatchingParams = await openpgp.readKey({ armoredKey: mismatchingKeyParams });
|
privateKeyMismatchingParams = await openpgp.readKey({ armoredKey: mismatchingKeyParams });
|
||||||
|
|
||||||
useNativeVal = openpgp.config.useNative;
|
|
||||||
aeadProtectVal = openpgp.config.aeadProtect;
|
aeadProtectVal = openpgp.config.aeadProtect;
|
||||||
aeadModeVal = openpgp.config.aeadMode;
|
aeadModeVal = openpgp.config.aeadMode;
|
||||||
aeadChunkSizeByteVal = openpgp.config.aeadChunkSizeByte;
|
aeadChunkSizeByteVal = openpgp.config.aeadChunkSizeByte;
|
||||||
@ -872,7 +846,6 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
openpgp.config.useNative = useNativeVal;
|
|
||||||
openpgp.config.aeadProtect = aeadProtectVal;
|
openpgp.config.aeadProtect = aeadProtectVal;
|
||||||
openpgp.config.aeadMode = aeadModeVal;
|
openpgp.config.aeadMode = aeadModeVal;
|
||||||
openpgp.config.aeadChunkSizeByte = aeadChunkSizeByteVal;
|
openpgp.config.aeadChunkSizeByte = aeadChunkSizeByteVal;
|
||||||
@ -2389,7 +2362,7 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
|
|||||||
|
|
||||||
return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
|
return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
|
||||||
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
||||||
return message.decrypt([privateKey_2038_2045]);
|
return message.decrypt([privateKey_2038_2045], undefined, undefined, undefined, openpgp.config);
|
||||||
}).then(async function (packets) {
|
}).then(async function (packets) {
|
||||||
const literals = packets.packets.filterByTag(openpgp.enums.packet.literalData);
|
const literals = packets.packets.filterByTag(openpgp.enums.packet.literalData);
|
||||||
expect(literals.length).to.equal(1);
|
expect(literals.length).to.equal(1);
|
||||||
@ -2410,7 +2383,7 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
|
|||||||
|
|
||||||
return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
|
return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
|
||||||
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
||||||
return message.decrypt([privateKey_2000_2008]);
|
return message.decrypt([privateKey_2000_2008], undefined, undefined, undefined, openpgp.config);
|
||||||
}).then(async function (packets) {
|
}).then(async function (packets) {
|
||||||
const literals = packets.packets.filterByTag(openpgp.enums.packet.literalData);
|
const literals = packets.packets.filterByTag(openpgp.enums.packet.literalData);
|
||||||
expect(literals.length).to.equal(1);
|
expect(literals.length).to.equal(1);
|
||||||
@ -2431,12 +2404,12 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
|
|||||||
|
|
||||||
return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
|
return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
|
||||||
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
||||||
return message.decrypt([privateKey_2000_2008]);
|
return message.decrypt([privateKey_2000_2008], undefined, undefined, undefined, openpgp.config);
|
||||||
}).then(async function (message) {
|
}).then(async function (message) {
|
||||||
const literals = message.packets.filterByTag(openpgp.enums.packet.literalData);
|
const literals = message.packets.filterByTag(openpgp.enums.packet.literalData);
|
||||||
expect(literals.length).to.equal(1);
|
expect(literals.length).to.equal(1);
|
||||||
expect(+literals[0].date).to.equal(+past);
|
expect(+literals[0].date).to.equal(+past);
|
||||||
const signatures = await message.verify([publicKey_2000_2008], past);
|
const signatures = await message.verify([publicKey_2000_2008], past, undefined, openpgp.config);
|
||||||
expect(await openpgp.stream.readToEnd(message.getText())).to.equal(plaintext);
|
expect(await openpgp.stream.readToEnd(message.getText())).to.equal(plaintext);
|
||||||
expect(+(await signatures[0].signature).packets[0].created).to.equal(+past);
|
expect(+(await signatures[0].signature).packets[0].created).to.equal(+past);
|
||||||
expect(await signatures[0].verified).to.be.true;
|
expect(await signatures[0].verified).to.be.true;
|
||||||
@ -2459,13 +2432,13 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
|
|||||||
|
|
||||||
return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
|
return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
|
||||||
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
||||||
return message.decrypt([privateKey_2038_2045]);
|
return message.decrypt([privateKey_2038_2045], undefined, undefined, undefined, openpgp.config);
|
||||||
}).then(async function (message) {
|
}).then(async function (message) {
|
||||||
const literals = message.packets.filterByTag(openpgp.enums.packet.literalData);
|
const literals = message.packets.filterByTag(openpgp.enums.packet.literalData);
|
||||||
expect(literals.length).to.equal(1);
|
expect(literals.length).to.equal(1);
|
||||||
expect(literals[0].format).to.equal('binary');
|
expect(literals[0].format).to.equal('binary');
|
||||||
expect(+literals[0].date).to.equal(+future);
|
expect(+literals[0].date).to.equal(+future);
|
||||||
const signatures = await message.verify([publicKey_2038_2045], future);
|
const signatures = await message.verify([publicKey_2038_2045], future, undefined, openpgp.config);
|
||||||
expect(await openpgp.stream.readToEnd(message.getLiteralData())).to.deep.equal(data);
|
expect(await openpgp.stream.readToEnd(message.getLiteralData())).to.deep.equal(data);
|
||||||
expect(+(await signatures[0].signature).packets[0].created).to.equal(+future);
|
expect(+(await signatures[0].signature).packets[0].created).to.equal(+future);
|
||||||
expect(await signatures[0].verified).to.be.true;
|
expect(await signatures[0].verified).to.be.true;
|
||||||
@ -2488,13 +2461,13 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
|
|||||||
|
|
||||||
return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
|
return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
|
||||||
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
||||||
return message.decrypt([privateKey_2038_2045]);
|
return message.decrypt([privateKey_2038_2045], undefined, undefined, undefined, openpgp.config);
|
||||||
}).then(async function (message) {
|
}).then(async function (message) {
|
||||||
const literals = message.packets.filterByTag(openpgp.enums.packet.literalData);
|
const literals = message.packets.filterByTag(openpgp.enums.packet.literalData);
|
||||||
expect(literals.length).to.equal(1);
|
expect(literals.length).to.equal(1);
|
||||||
expect(literals[0].format).to.equal('mime');
|
expect(literals[0].format).to.equal('mime');
|
||||||
expect(+literals[0].date).to.equal(+future);
|
expect(+literals[0].date).to.equal(+future);
|
||||||
const signatures = await message.verify([publicKey_2038_2045], future);
|
const signatures = await message.verify([publicKey_2038_2045], future, undefined, openpgp.config);
|
||||||
expect(await openpgp.stream.readToEnd(message.getLiteralData())).to.deep.equal(data);
|
expect(await openpgp.stream.readToEnd(message.getLiteralData())).to.deep.equal(data);
|
||||||
expect(+(await signatures[0].signature).packets[0].created).to.equal(+future);
|
expect(+(await signatures[0].signature).packets[0].created).to.equal(+future);
|
||||||
expect(await signatures[0].verified).to.be.true;
|
expect(await signatures[0].verified).to.be.true;
|
||||||
|
@ -65,49 +65,65 @@ module.exports = () => describe("Packet", function() {
|
|||||||
'=KXkj\n' +
|
'=KXkj\n' +
|
||||||
'-----END PGP PRIVATE KEY BLOCK-----';
|
'-----END PGP PRIVATE KEY BLOCK-----';
|
||||||
|
|
||||||
it('Symmetrically encrypted packet', async function() {
|
it('Symmetrically encrypted packet without integrity protection - allow decryption', async function() {
|
||||||
|
const aeadProtectVal = openpgp.config.aeadProtect;
|
||||||
|
const ignoreMdcErrorVal = openpgp.config.ignoreMdcError;
|
||||||
|
openpgp.config.aeadProtect = false;
|
||||||
|
openpgp.config.ignoreMdcError = true;
|
||||||
|
|
||||||
const message = new openpgp.PacketList();
|
const message = new openpgp.PacketList();
|
||||||
const testText = input.createSomeMessage();
|
const testText = input.createSomeMessage();
|
||||||
|
|
||||||
const literal = new openpgp.LiteralDataPacket();
|
const literal = new openpgp.LiteralDataPacket();
|
||||||
literal.setText(testText);
|
literal.setText(testText);
|
||||||
|
|
||||||
const enc = new openpgp.SymmetricallyEncryptedDataPacket();
|
try {
|
||||||
message.push(enc);
|
const enc = new openpgp.SymmetricallyEncryptedDataPacket();
|
||||||
enc.packets.push(literal);
|
message.push(enc);
|
||||||
|
enc.packets.push(literal);
|
||||||
|
|
||||||
const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]);
|
const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]);
|
||||||
const algo = 'aes256';
|
const algo = 'aes256';
|
||||||
|
|
||||||
await enc.encrypt(algo, key);
|
await enc.encrypt(algo, key, undefined, openpgp.config);
|
||||||
|
|
||||||
const msg2 = new openpgp.Message();
|
const msg2 = new openpgp.PacketList();
|
||||||
await msg2.packets.read(message.write(), { SymmetricallyEncryptedDataPacket: openpgp.SymmetricallyEncryptedDataPacket });
|
await msg2.read(message.write(), { SymmetricallyEncryptedDataPacket: openpgp.SymmetricallyEncryptedDataPacket });
|
||||||
msg2.packets[0].ignoreMdcError = true;
|
await msg2[0].decrypt(algo, key, undefined, openpgp.config);
|
||||||
const dec = await msg2.decrypt(null, null, [{ algorithm: algo, data: key }]);
|
|
||||||
|
|
||||||
expect(await stringify(dec.packets[0].data)).to.equal(stringify(literal.data));
|
expect(await stringify(msg2[0].packets[0].data)).to.equal(stringify(literal.data));
|
||||||
|
} finally {
|
||||||
|
openpgp.config.aeadProtect = aeadProtectVal;
|
||||||
|
openpgp.config.ignoreMdcError = ignoreMdcErrorVal;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Symmetrically encrypted packet - MDC error for modern cipher', async function() {
|
it('Symmetrically encrypted packet without integrity protection - disallow decryption by default', async function() {
|
||||||
const message = new openpgp.PacketList();
|
const aeadProtectVal = openpgp.config.aeadProtect;
|
||||||
const testText = input.createSomeMessage();
|
openpgp.config.aeadProtect = false;
|
||||||
|
|
||||||
const literal = new openpgp.LiteralDataPacket();
|
try {
|
||||||
literal.setText(testText);
|
const message = new openpgp.PacketList();
|
||||||
|
const testText = input.createSomeMessage();
|
||||||
|
|
||||||
const enc = new openpgp.SymmetricallyEncryptedDataPacket();
|
const literal = new openpgp.LiteralDataPacket();
|
||||||
message.push(enc);
|
literal.setText(testText);
|
||||||
await enc.packets.push(literal);
|
|
||||||
|
|
||||||
const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]);
|
const enc = new openpgp.SymmetricallyEncryptedDataPacket();
|
||||||
const algo = 'aes256';
|
message.push(enc);
|
||||||
|
await enc.packets.push(literal);
|
||||||
|
|
||||||
await enc.encrypt(algo, key);
|
const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]);
|
||||||
|
const algo = 'aes256';
|
||||||
|
|
||||||
const msg2 = new openpgp.PacketList();
|
await enc.encrypt(algo, key, undefined, openpgp.config);
|
||||||
await msg2.read(message.write(), { SymmetricallyEncryptedDataPacket: openpgp.SymmetricallyEncryptedDataPacket });
|
|
||||||
await expect(msg2[0].decrypt(algo, key)).to.eventually.be.rejectedWith('Decryption failed due to missing MDC.');
|
const msg2 = new openpgp.PacketList();
|
||||||
|
await msg2.read(message.write(), { SymmetricallyEncryptedDataPacket: openpgp.SymmetricallyEncryptedDataPacket });
|
||||||
|
await expect(msg2[0].decrypt(algo, key, undefined, openpgp.config)).to.eventually.be.rejectedWith('Decryption failed due to missing MDC.');
|
||||||
|
} finally {
|
||||||
|
openpgp.config.aeadProtect = aeadProtectVal;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Sym. encrypted integrity protected packet', async function() {
|
it('Sym. encrypted integrity protected packet', async function() {
|
||||||
@ -122,61 +138,40 @@ module.exports = () => describe("Packet", function() {
|
|||||||
msg.push(enc);
|
msg.push(enc);
|
||||||
literal.setText(testText);
|
literal.setText(testText);
|
||||||
enc.packets.push(literal);
|
enc.packets.push(literal);
|
||||||
await enc.encrypt(algo, key);
|
await enc.encrypt(algo, key, undefined, openpgp.config);
|
||||||
|
|
||||||
const msg2 = new openpgp.PacketList();
|
const msg2 = new openpgp.PacketList();
|
||||||
await msg2.read(msg.write(), openpgp);
|
await msg2.read(msg.write(), openpgp);
|
||||||
|
|
||||||
await msg2[0].decrypt(algo, key);
|
await msg2[0].decrypt(algo, key, undefined, openpgp.config);
|
||||||
|
|
||||||
expect(await stringify(msg2[0].packets[0].data)).to.equal(stringify(literal.data));
|
expect(await stringify(msg2[0].packets[0].data)).to.equal(stringify(literal.data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Sym. encrypted AEAD protected packet', function() {
|
it('Sym. encrypted AEAD protected packet', function() {
|
||||||
const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]);
|
|
||||||
const algo = 'aes256';
|
|
||||||
const testText = input.createSomeMessage();
|
|
||||||
const literal = new openpgp.LiteralDataPacket();
|
|
||||||
const enc = new openpgp.AEADEncryptedDataPacket();
|
|
||||||
const msg = new openpgp.PacketList();
|
|
||||||
|
|
||||||
msg.push(enc);
|
|
||||||
literal.setText(testText);
|
|
||||||
enc.packets.push(literal);
|
|
||||||
|
|
||||||
const msg2 = new openpgp.PacketList();
|
|
||||||
|
|
||||||
return enc.encrypt(algo, key).then(async function() {
|
|
||||||
await msg2.read(msg.write(), openpgp);
|
|
||||||
return msg2[0].decrypt(algo, key);
|
|
||||||
}).then(async function() {
|
|
||||||
expect(await openpgp.stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Sym. encrypted AEAD protected packet (AEAD)', async function() {
|
|
||||||
const aeadProtectVal = openpgp.config.aeadProtect;
|
const aeadProtectVal = openpgp.config.aeadProtect;
|
||||||
openpgp.config.aeadProtect = true;
|
openpgp.config.aeadProtect = false;
|
||||||
const testText = input.createSomeMessage();
|
|
||||||
|
|
||||||
const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]);
|
|
||||||
const algo = 'aes256';
|
|
||||||
|
|
||||||
const literal = new openpgp.LiteralDataPacket();
|
|
||||||
const enc = new openpgp.AEADEncryptedDataPacket();
|
|
||||||
const msg = new openpgp.PacketList();
|
|
||||||
|
|
||||||
msg.push(enc);
|
|
||||||
literal.setText(testText);
|
|
||||||
enc.packets.push(literal);
|
|
||||||
|
|
||||||
const msg2 = new openpgp.PacketList();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await enc.encrypt(algo, key);
|
const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]);
|
||||||
await msg2.read(msg.write(), openpgp);
|
const algo = 'aes256';
|
||||||
await msg2[0].decrypt(algo, key);
|
const testText = input.createSomeMessage();
|
||||||
expect(await openpgp.stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
|
const literal = new openpgp.LiteralDataPacket();
|
||||||
|
const enc = new openpgp.AEADEncryptedDataPacket();
|
||||||
|
const msg = new openpgp.PacketList();
|
||||||
|
|
||||||
|
msg.push(enc);
|
||||||
|
literal.setText(testText);
|
||||||
|
enc.packets.push(literal);
|
||||||
|
|
||||||
|
const msg2 = new openpgp.PacketList();
|
||||||
|
|
||||||
|
return enc.encrypt(algo, key, undefined, openpgp.config).then(async function() {
|
||||||
|
await msg2.read(msg.write(), openpgp);
|
||||||
|
return msg2[0].decrypt(algo, key);
|
||||||
|
}).then(async function() {
|
||||||
|
expect(await openpgp.stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
|
||||||
|
});
|
||||||
} finally {
|
} finally {
|
||||||
openpgp.config.aeadProtect = aeadProtectVal;
|
openpgp.config.aeadProtect = aeadProtectVal;
|
||||||
}
|
}
|
||||||
@ -208,10 +203,6 @@ module.exports = () => describe("Packet", function() {
|
|||||||
const encryptStub = cryptStub(webCrypto, 'encrypt');
|
const encryptStub = cryptStub(webCrypto, 'encrypt');
|
||||||
const decryptStub = cryptStub(webCrypto, 'decrypt');
|
const decryptStub = cryptStub(webCrypto, 'decrypt');
|
||||||
|
|
||||||
const aeadProtectVal = openpgp.config.aeadProtect;
|
|
||||||
const aeadChunkSizeByteVal = openpgp.config.aeadChunkSizeByte;
|
|
||||||
openpgp.config.aeadProtect = true;
|
|
||||||
openpgp.config.aeadChunkSizeByte = 0;
|
|
||||||
const testText = input.createSomeMessage();
|
const testText = input.createSomeMessage();
|
||||||
|
|
||||||
const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]);
|
const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]);
|
||||||
@ -229,15 +220,13 @@ module.exports = () => describe("Packet", function() {
|
|||||||
const msg2 = new openpgp.PacketList();
|
const msg2 = new openpgp.PacketList();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await enc.encrypt(algo, key);
|
await enc.encrypt(algo, key, undefined, { ...openpgp.config, aeadChunkSizeByte: 0 });
|
||||||
await msg2.read(msg.write(), openpgp);
|
await msg2.read(msg.write(), openpgp);
|
||||||
await msg2[0].decrypt(algo, key);
|
await msg2[0].decrypt(algo, key);
|
||||||
expect(await openpgp.stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
|
expect(await openpgp.stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
|
||||||
expect(encryptStub.callCount > 1).to.be.true;
|
expect(encryptStub.callCount > 1).to.be.true;
|
||||||
expect(decryptStub.callCount > 1).to.be.true;
|
expect(decryptStub.callCount > 1).to.be.true;
|
||||||
} finally {
|
} finally {
|
||||||
openpgp.config.aeadProtect = aeadProtectVal;
|
|
||||||
openpgp.config.aeadChunkSizeByte = aeadChunkSizeByteVal;
|
|
||||||
encryptStub.restore();
|
encryptStub.restore();
|
||||||
decryptStub.restore();
|
decryptStub.restore();
|
||||||
}
|
}
|
||||||
@ -257,11 +246,6 @@ module.exports = () => describe("Packet", function() {
|
|||||||
ab 01 3d e1 25 95 86 90 6e ab 24 76
|
ab 01 3d e1 25 95 86 90 6e ab 24 76
|
||||||
`.replace(/\s+/g, ''));
|
`.replace(/\s+/g, ''));
|
||||||
|
|
||||||
const aeadProtectVal = openpgp.config.aeadProtect;
|
|
||||||
const aeadChunkSizeByteVal = openpgp.config.aeadChunkSizeByte;
|
|
||||||
openpgp.config.aeadProtect = true;
|
|
||||||
openpgp.config.aeadChunkSizeByte = 14;
|
|
||||||
|
|
||||||
const iv = util.hexToUint8Array('b7 32 37 9f 73 c4 92 8d e2 5f ac fe 65 17 ec 10'.replace(/\s+/g, ''));
|
const iv = util.hexToUint8Array('b7 32 37 9f 73 c4 92 8d e2 5f ac fe 65 17 ec 10'.replace(/\s+/g, ''));
|
||||||
const key = util.hexToUint8Array('86 f1 ef b8 69 52 32 9f 24 ac d3 bf d0 e5 34 6d'.replace(/\s+/g, ''));
|
const key = util.hexToUint8Array('86 f1 ef b8 69 52 32 9f 24 ac d3 bf d0 e5 34 6d'.replace(/\s+/g, ''));
|
||||||
const algo = 'aes128';
|
const algo = 'aes128';
|
||||||
@ -281,15 +265,13 @@ module.exports = () => describe("Packet", function() {
|
|||||||
randomBytesStub.returns(iv);
|
randomBytesStub.returns(iv);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await enc.encrypt(algo, key);
|
await enc.encrypt(algo, key, undefined, { ...openpgp.config, aeadChunkSizeByte: 14 });
|
||||||
const data = msg.write();
|
const data = msg.write();
|
||||||
expect(await openpgp.stream.readToEnd(openpgp.stream.clone(data))).to.deep.equal(packetBytes);
|
expect(await openpgp.stream.readToEnd(openpgp.stream.clone(data))).to.deep.equal(packetBytes);
|
||||||
await msg2.read(data, openpgp);
|
await msg2.read(data, openpgp);
|
||||||
await msg2[0].decrypt(algo, key);
|
await msg2[0].decrypt(algo, key);
|
||||||
expect(await openpgp.stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
|
expect(await openpgp.stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
|
||||||
} finally {
|
} finally {
|
||||||
openpgp.config.aeadProtect = aeadProtectVal;
|
|
||||||
openpgp.config.aeadChunkSizeByte = aeadChunkSizeByteVal;
|
|
||||||
randomBytesStub.restore();
|
randomBytesStub.restore();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -323,7 +305,7 @@ module.exports = () => describe("Packet", function() {
|
|||||||
|
|
||||||
it('Public key encrypted symmetric key packet', function() {
|
it('Public key encrypted symmetric key packet', function() {
|
||||||
const rsa = openpgp.enums.publicKey.rsaEncryptSign;
|
const rsa = openpgp.enums.publicKey.rsaEncryptSign;
|
||||||
const keySize = util.getWebCryptoAll() ? 2048 : 512; // webkit webcrypto accepts minimum 2048 bit keys
|
const keySize = 1024;
|
||||||
|
|
||||||
return crypto.generateParams(rsa, keySize, 65537).then(function({ publicParams, privateParams }) {
|
return crypto.generateParams(rsa, keySize, 65537).then(function({ publicParams, privateParams }) {
|
||||||
const enc = new openpgp.PublicKeyEncryptedSessionKeyPacket();
|
const enc = new openpgp.PublicKeyEncryptedSessionKeyPacket();
|
||||||
@ -453,36 +435,43 @@ module.exports = () => describe("Packet", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Sym. encrypted session key reading/writing', async function() {
|
it('Sym. encrypted session key reading/writing (CFB)', async function() {
|
||||||
const passphrase = 'hello';
|
const aeadProtectVal = openpgp.config.aeadProtect;
|
||||||
const algo = 'aes256';
|
openpgp.config.aeadProtect = false;
|
||||||
const testText = input.createSomeMessage();
|
|
||||||
|
|
||||||
const literal = new openpgp.LiteralDataPacket();
|
try {
|
||||||
const key_enc = new openpgp.SymEncryptedSessionKeyPacket();
|
const passphrase = 'hello';
|
||||||
const enc = new openpgp.SymEncryptedIntegrityProtectedDataPacket();
|
const algo = 'aes256';
|
||||||
const msg = new openpgp.PacketList();
|
const testText = input.createSomeMessage();
|
||||||
|
|
||||||
msg.push(key_enc);
|
const literal = new openpgp.LiteralDataPacket();
|
||||||
msg.push(enc);
|
const skesk = new openpgp.SymEncryptedSessionKeyPacket();
|
||||||
|
const seip = new openpgp.SymEncryptedIntegrityProtectedDataPacket();
|
||||||
|
const msg = new openpgp.PacketList();
|
||||||
|
|
||||||
key_enc.sessionKeyAlgorithm = algo;
|
msg.push(skesk);
|
||||||
await key_enc.encrypt(passphrase);
|
msg.push(seip);
|
||||||
|
|
||||||
const key = key_enc.sessionKey;
|
skesk.sessionKeyAlgorithm = algo;
|
||||||
|
await skesk.encrypt(passphrase, openpgp.config);
|
||||||
|
|
||||||
literal.setText(testText);
|
const key = skesk.sessionKey;
|
||||||
enc.packets.push(literal);
|
|
||||||
await enc.encrypt(algo, key);
|
|
||||||
|
|
||||||
const msg2 = new openpgp.PacketList();
|
literal.setText(testText);
|
||||||
await msg2.read(msg.write(), openpgp);
|
seip.packets.push(literal);
|
||||||
|
await seip.encrypt(algo, key, undefined, openpgp.config);
|
||||||
|
|
||||||
await msg2[0].decrypt(passphrase);
|
const msg2 = new openpgp.PacketList();
|
||||||
const key2 = msg2[0].sessionKey;
|
await msg2.read(msg.write(), openpgp);
|
||||||
await msg2[1].decrypt(msg2[0].sessionKeyAlgorithm, key2);
|
|
||||||
|
|
||||||
expect(await stringify(msg2[1].packets[0].data)).to.equal(stringify(literal.data));
|
await msg2[0].decrypt(passphrase);
|
||||||
|
const key2 = msg2[0].sessionKey;
|
||||||
|
await msg2[1].decrypt(msg2[0].sessionKeyAlgorithm, key2);
|
||||||
|
|
||||||
|
expect(await stringify(msg2[1].packets[0].data)).to.equal(stringify(literal.data));
|
||||||
|
} finally {
|
||||||
|
openpgp.config.aeadProtect = aeadProtectVal;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Sym. encrypted session key reading/writing (AEAD)', async function() {
|
it('Sym. encrypted session key reading/writing (AEAD)', async function() {
|
||||||
@ -495,21 +484,21 @@ module.exports = () => describe("Packet", function() {
|
|||||||
const testText = input.createSomeMessage();
|
const testText = input.createSomeMessage();
|
||||||
|
|
||||||
const literal = new openpgp.LiteralDataPacket();
|
const literal = new openpgp.LiteralDataPacket();
|
||||||
const key_enc = new openpgp.SymEncryptedSessionKeyPacket();
|
const skesk = new openpgp.SymEncryptedSessionKeyPacket();
|
||||||
const enc = new openpgp.AEADEncryptedDataPacket();
|
const aeadEnc = new openpgp.AEADEncryptedDataPacket();
|
||||||
const msg = new openpgp.PacketList();
|
const msg = new openpgp.PacketList();
|
||||||
|
|
||||||
msg.push(key_enc);
|
msg.push(skesk);
|
||||||
msg.push(enc);
|
msg.push(aeadEnc);
|
||||||
|
|
||||||
key_enc.sessionKeyAlgorithm = algo;
|
skesk.sessionKeyAlgorithm = algo;
|
||||||
await key_enc.encrypt(passphrase);
|
await skesk.encrypt(passphrase, openpgp.config);
|
||||||
|
|
||||||
const key = key_enc.sessionKey;
|
const key = skesk.sessionKey;
|
||||||
|
|
||||||
literal.setText(testText);
|
literal.setText(testText);
|
||||||
enc.packets.push(literal);
|
aeadEnc.packets.push(literal);
|
||||||
await enc.encrypt(algo, key);
|
await aeadEnc.encrypt(algo, key, undefined, openpgp.config);
|
||||||
|
|
||||||
const msg2 = new openpgp.PacketList();
|
const msg2 = new openpgp.PacketList();
|
||||||
await msg2.read(msg.write(), openpgp);
|
await msg2.read(msg.write(), openpgp);
|
||||||
@ -566,22 +555,22 @@ module.exports = () => describe("Packet", function() {
|
|||||||
const algo = 'aes128';
|
const algo = 'aes128';
|
||||||
|
|
||||||
const literal = new openpgp.LiteralDataPacket(0);
|
const literal = new openpgp.LiteralDataPacket(0);
|
||||||
const key_enc = new openpgp.SymEncryptedSessionKeyPacket();
|
const skesk = new openpgp.SymEncryptedSessionKeyPacket();
|
||||||
const enc = new openpgp.AEADEncryptedDataPacket();
|
const encData = new openpgp.AEADEncryptedDataPacket();
|
||||||
const msg = new openpgp.PacketList();
|
const msg = new openpgp.PacketList();
|
||||||
|
|
||||||
msg.push(key_enc);
|
msg.push(skesk);
|
||||||
msg.push(enc);
|
msg.push(encData);
|
||||||
|
|
||||||
key_enc.sessionKeyAlgorithm = algo;
|
skesk.sessionKeyAlgorithm = algo;
|
||||||
await key_enc.encrypt(passphrase);
|
await skesk.encrypt(passphrase, openpgp.config);
|
||||||
|
|
||||||
const key = key_enc.sessionKey;
|
const key = skesk.sessionKey;
|
||||||
|
|
||||||
literal.setBytes(util.strToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary);
|
literal.setBytes(util.strToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary);
|
||||||
literal.filename = '';
|
literal.filename = '';
|
||||||
enc.packets.push(literal);
|
encData.packets.push(literal);
|
||||||
await enc.encrypt(algo, key);
|
await encData.encrypt(algo, key, undefined, openpgp.config);
|
||||||
|
|
||||||
const data = msg.write();
|
const data = msg.write();
|
||||||
expect(await openpgp.stream.readToEnd(openpgp.stream.clone(data))).to.deep.equal(packetBytes);
|
expect(await openpgp.stream.readToEnd(openpgp.stream.clone(data))).to.deep.equal(packetBytes);
|
||||||
@ -653,14 +642,14 @@ module.exports = () => describe("Packet", function() {
|
|||||||
msg.push(enc);
|
msg.push(enc);
|
||||||
|
|
||||||
key_enc.sessionKeyAlgorithm = algo;
|
key_enc.sessionKeyAlgorithm = algo;
|
||||||
await key_enc.encrypt(passphrase);
|
await key_enc.encrypt(passphrase, openpgp.config);
|
||||||
|
|
||||||
const key = key_enc.sessionKey;
|
const key = key_enc.sessionKey;
|
||||||
|
|
||||||
literal.setBytes(util.strToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary);
|
literal.setBytes(util.strToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary);
|
||||||
literal.filename = '';
|
literal.filename = '';
|
||||||
enc.packets.push(literal);
|
enc.packets.push(literal);
|
||||||
await enc.encrypt(algo, key);
|
await enc.encrypt(algo, key, undefined, openpgp.config);
|
||||||
|
|
||||||
const data = msg.write();
|
const data = msg.write();
|
||||||
expect(await openpgp.stream.readToEnd(openpgp.stream.clone(data))).to.deep.equal(packetBytes);
|
expect(await openpgp.stream.readToEnd(openpgp.stream.clone(data))).to.deep.equal(packetBytes);
|
||||||
@ -712,18 +701,18 @@ module.exports = () => describe("Packet", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Secret key reading with signature verification.', async function() {
|
it('Secret key reading with signature verification.', async function() {
|
||||||
const key = new openpgp.PacketList();
|
const packets = new openpgp.PacketList();
|
||||||
await key.read((await openpgp.unarmor(armored_key)).data, openpgp);
|
await packets.read((await openpgp.unarmor(armored_key)).data, openpgp);
|
||||||
|
const [keyPacket, userIdPacket, keySigPacket, subkeyPacket, subkeySigPacket] = packets;
|
||||||
|
expect(keySigPacket.verified).to.be.null;
|
||||||
|
expect(subkeySigPacket.verified).to.be.null;
|
||||||
|
|
||||||
expect(key[2].verified).to.be.null;
|
await keySigPacket.verify(
|
||||||
expect(key[4].verified).to.be.null;
|
keyPacket, openpgp.enums.signature.certGeneric, { userId: userIdPacket, key: keyPacket }
|
||||||
|
).then(async () => expect(keySigPacket.verified).to.be.true);
|
||||||
await key[2].verify(
|
await subkeySigPacket.verify(
|
||||||
key[0], openpgp.enums.signature.certGeneric, { userId: key[1], key: key[0] }
|
keyPacket, openpgp.enums.signature.keyBinding, { key: keyPacket, bind: subkeyPacket }
|
||||||
).then(async () => expect(key[2].verified).to.be.true);
|
).then(async () => expect(subkeySigPacket.verified).to.be.true);
|
||||||
await key[4].verify(
|
|
||||||
key[0], openpgp.enums.signature.keyBinding, { key: key[0], bind: key[3] }
|
|
||||||
).then(async () => expect(key[4].verified).to.be.true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Reading a signed, encrypted message.', async function() {
|
it('Reading a signed, encrypted message.', async function() {
|
||||||
@ -743,22 +732,27 @@ module.exports = () => describe("Packet", function() {
|
|||||||
'=htrB\n' +
|
'=htrB\n' +
|
||||||
'-----END PGP MESSAGE-----';
|
'-----END PGP MESSAGE-----';
|
||||||
|
|
||||||
const key = new openpgp.PacketList();
|
const packets = new openpgp.PacketList();
|
||||||
await key.read((await openpgp.unarmor(armored_key)).data, openpgp);
|
await packets.read((await openpgp.unarmor(armored_key)).data, openpgp);
|
||||||
await key[3].decrypt('test');
|
const keyPacket = packets[0];
|
||||||
|
const subkeyPacket = packets[3];
|
||||||
|
await subkeyPacket.decrypt('test');
|
||||||
|
|
||||||
const msg = new openpgp.PacketList();
|
const msg = new openpgp.PacketList();
|
||||||
await msg.read((await openpgp.unarmor(armored_msg)).data, openpgp);
|
await msg.read((await openpgp.unarmor(armored_msg)).data, openpgp);
|
||||||
|
const [pkesk, encData] = msg;
|
||||||
|
|
||||||
return msg[0].decrypt(key[3]).then(async () => {
|
return pkesk.decrypt(subkeyPacket).then(async () => {
|
||||||
await msg[1].decrypt(msg[0].sessionKeyAlgorithm, msg[0].sessionKey);
|
await encData.decrypt(pkesk.sessionKeyAlgorithm, pkesk.sessionKey);
|
||||||
|
|
||||||
const payload = msg[1].packets[0].packets;
|
const payload = encData.packets[0].packets;
|
||||||
payload.concat(await openpgp.stream.readToEnd(payload.stream, arr => arr));
|
payload.concat(await openpgp.stream.readToEnd(payload.stream, arr => arr));
|
||||||
|
const literal = payload[1];
|
||||||
|
const signature = payload[2];
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
payload[2].verify(key[0], openpgp.enums.signature.binary, payload[1]),
|
signature.verify(keyPacket, openpgp.enums.signature.binary, literal),
|
||||||
openpgp.stream.pipe(payload[1].getBytes(),new openpgp.stream.WritableStream())
|
openpgp.stream.pipe(literal.getBytes(), new openpgp.stream.WritableStream())
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -842,20 +836,20 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+
|
|||||||
|
|
||||||
it('Writing and encryption of a secret key packet (AEAD)', async function() {
|
it('Writing and encryption of a secret key packet (AEAD)', async function() {
|
||||||
const rsa = openpgp.enums.publicKey.rsaEncryptSign;
|
const rsa = openpgp.enums.publicKey.rsaEncryptSign;
|
||||||
const keySize = util.getWebCryptoAll() ? 2048 : 512; // webkit webcrypto accepts minimum 2048 bit keys
|
const { privateParams, publicParams } = await crypto.generateParams(rsa, 1024, 65537);
|
||||||
const { privateParams, publicParams } = await crypto.generateParams(rsa, keySize, 65537);
|
|
||||||
|
|
||||||
const secretKeyPacket = new openpgp.SecretKeyPacket();
|
const secretKeyPacket = new openpgp.SecretKeyPacket(undefined, { ...openpgp.config, v5Keys: true });
|
||||||
secretKeyPacket.privateParams = privateParams;
|
secretKeyPacket.privateParams = privateParams;
|
||||||
secretKeyPacket.publicParams = publicParams;
|
secretKeyPacket.publicParams = publicParams;
|
||||||
secretKeyPacket.algorithm = "rsaSign";
|
secretKeyPacket.algorithm = "rsaSign";
|
||||||
secretKeyPacket.isEncrypted = false;
|
secretKeyPacket.isEncrypted = false;
|
||||||
await secretKeyPacket.encrypt('hello');
|
await secretKeyPacket.encrypt('hello', openpgp.config);
|
||||||
|
expect(secretKeyPacket.s2k_usage).to.equal(253);
|
||||||
|
|
||||||
const raw = new openpgp.PacketList();
|
const raw = new openpgp.PacketList();
|
||||||
raw.push(secretKeyPacket);
|
raw.push(secretKeyPacket);
|
||||||
const packetList = new openpgp.PacketList();
|
const packetList = new openpgp.PacketList();
|
||||||
await packetList.read(raw.write(), openpgp);
|
await packetList.read(raw.write(), openpgp, undefined, openpgp.config);
|
||||||
const secretKeyPacket2 = packetList[0];
|
const secretKeyPacket2 = packetList[0];
|
||||||
await secretKeyPacket2.decrypt('hello');
|
await secretKeyPacket2.decrypt('hello');
|
||||||
|
|
||||||
@ -864,39 +858,29 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Writing and encryption of a secret key packet (CFB)', async function() {
|
it('Writing and encryption of a secret key packet (CFB)', async function() {
|
||||||
const aeadProtectVal = openpgp.config.aeadProtect;
|
|
||||||
openpgp.config.aeadProtect = false;
|
|
||||||
|
|
||||||
const rsa = openpgp.enums.publicKey.rsaEncryptSign;
|
const rsa = openpgp.enums.publicKey.rsaEncryptSign;
|
||||||
const keySize = util.getWebCryptoAll() ? 2048 : 512; // webkit webcrypto accepts minimum 2048 bit keys
|
const { privateParams, publicParams } = await crypto.generateParams(rsa, 1024, 65537);
|
||||||
|
const secretKeyPacket = new openpgp.SecretKeyPacket(undefined, { ...openpgp.config, v5Keys: false });
|
||||||
|
secretKeyPacket.privateParams = privateParams;
|
||||||
|
secretKeyPacket.publicParams = publicParams;
|
||||||
|
secretKeyPacket.algorithm = "rsaSign";
|
||||||
|
secretKeyPacket.isEncrypted = false;
|
||||||
|
await secretKeyPacket.encrypt('hello', openpgp.config);
|
||||||
|
expect(secretKeyPacket.s2k_usage).to.equal(254);
|
||||||
|
|
||||||
try {
|
const raw = new openpgp.PacketList();
|
||||||
const { privateParams, publicParams } = await crypto.generateParams(rsa, keySize, 65537);
|
raw.push(secretKeyPacket);
|
||||||
const secretKeyPacket = new openpgp.SecretKeyPacket();
|
const packetList = new openpgp.PacketList();
|
||||||
secretKeyPacket.privateParams = privateParams;
|
await packetList.read(raw.write(), openpgp, undefined, openpgp.config);
|
||||||
secretKeyPacket.publicParams = publicParams;
|
const secretKeyPacket2 = packetList[0];
|
||||||
secretKeyPacket.algorithm = "rsaSign";
|
await secretKeyPacket2.decrypt('hello');
|
||||||
secretKeyPacket.isEncrypted = false;
|
|
||||||
await secretKeyPacket.encrypt('hello');
|
|
||||||
|
|
||||||
const raw = new openpgp.PacketList();
|
|
||||||
raw.push(secretKeyPacket);
|
|
||||||
const packetList = new openpgp.PacketList();
|
|
||||||
await packetList.read(raw.write(), openpgp);
|
|
||||||
const secretKeyPacket2 = packetList[0];
|
|
||||||
await secretKeyPacket2.decrypt('hello');
|
|
||||||
} finally {
|
|
||||||
openpgp.config.aeadProtect = aeadProtectVal;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Writing and verification of a signature packet', function() {
|
it('Writing and verification of a signature packet', function() {
|
||||||
|
const rsa = openpgp.enums.publicKey.rsaEncryptSign;
|
||||||
const key = new openpgp.SecretKeyPacket();
|
const key = new openpgp.SecretKeyPacket();
|
||||||
|
|
||||||
const rsa = openpgp.enums.publicKey.rsaEncryptSign;
|
return crypto.generateParams(rsa, 1024, 65537).then(function({ privateParams, publicParams }) {
|
||||||
const keySize = util.getWebCryptoAll() ? 2048 : 512; // webkit webcrypto accepts minimum 2048 bit keys
|
|
||||||
|
|
||||||
return crypto.generateParams(rsa, keySize, 65537).then(function({ privateParams, publicParams }) {
|
|
||||||
const testText = input.createSomeMessage();
|
const testText = input.createSomeMessage();
|
||||||
|
|
||||||
key.publicParams = publicParams;
|
key.publicParams = publicParams;
|
||||||
|
@ -919,8 +919,8 @@ hUhMKMuiM3pRwdIyDOItkUWQmjEEw7/XmhgInkXsCw==
|
|||||||
|
|
||||||
it('Checks for critical bit in non-human-readable notations', async function() {
|
it('Checks for critical bit in non-human-readable notations', async function() {
|
||||||
try {
|
try {
|
||||||
openpgp.config.tolerant = false;
|
|
||||||
await openpgp.readSignature({
|
await openpgp.readSignature({
|
||||||
|
config: { tolerant: false },
|
||||||
armoredSignature: `-----BEGIN PGP SIGNATURE-----
|
armoredSignature: `-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
wsEfBAABCABJBYJfKDH0K5QAAAAAAB0ABXVua25vd25AdGVzdHMuc2VxdW9pYS1w
|
wsEfBAABCABJBYJfKDH0K5QAAAAAAB0ABXVua25vd25AdGVzdHMuc2VxdW9pYS1w
|
||||||
@ -940,8 +940,6 @@ bwM=
|
|||||||
throw new Error('openpgp.readSignature should throw but it did not.');
|
throw new Error('openpgp.readSignature should throw but it did not.');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e.message).to.equal('Unknown critical notation: unknown@tests.sequoia-pgp.org');
|
expect(e.message).to.equal('Unknown critical notation: unknown@tests.sequoia-pgp.org');
|
||||||
} finally {
|
|
||||||
openpgp.config.tolerant = true;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1625,8 +1623,7 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
|
|||||||
const privKey2 = await openpgp.readKey({ armoredKey: priv_key_arm2 });
|
const privKey2 = await openpgp.readKey({ armoredKey: priv_key_arm2 });
|
||||||
await privKey2.decrypt('hello world');
|
await privKey2.decrypt('hello world');
|
||||||
|
|
||||||
const opt = { rsaBits: 512, userIds: { name:'test', email:'a@b.com' }, passphrase: null };
|
const opt = { rsaBits: 2048, userIds: { name:'test', email:'a@b.com' }, passphrase: null };
|
||||||
if (util.getWebCryptoAll()) { opt.rsaBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
|
|
||||||
const { key: generatedKey } = await openpgp.generateKey(opt);
|
const { key: generatedKey } = await openpgp.generateKey(opt);
|
||||||
const detachedSig = await msg.signDetached([generatedKey, privKey2]);
|
const detachedSig = await msg.signDetached([generatedKey, privKey2]);
|
||||||
const result = await msg.verifyDetached(detachedSig, [generatedKey.toPublic(), pubKey2]);
|
const result = await msg.verifyDetached(detachedSig, [generatedKey.toPublic(), pubKey2]);
|
||||||
@ -1638,9 +1635,8 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
|
|||||||
const opt = { userIds: { name:'test', email:'a@b.com' }, passphrase: null };
|
const opt = { userIds: { name:'test', email:'a@b.com' }, passphrase: null };
|
||||||
return openpgp.generateKey(opt).then(function(gen) {
|
return openpgp.generateKey(opt).then(function(gen) {
|
||||||
const key = gen.key;
|
const key = gen.key;
|
||||||
let message = openpgp.Message.fromText('hello world');
|
const message = openpgp.Message.fromText('hello world');
|
||||||
message = message.sign([key]);
|
return message.sign([key]);
|
||||||
expect(message).to.exist;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ module.exports = function(config) {
|
|||||||
basePath: '..',
|
basePath: '..',
|
||||||
|
|
||||||
// hostname for local
|
// hostname for local
|
||||||
hostname: 'localhost',
|
hostname: '127.0.0.1',
|
||||||
|
|
||||||
// frameworks to use
|
// frameworks to use
|
||||||
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
||||||
@ -79,7 +79,8 @@ module.exports = function(config) {
|
|||||||
accessKey: process.env.BROWSERSTACK_KEY,
|
accessKey: process.env.BROWSERSTACK_KEY,
|
||||||
build: process.env.GITHUB_SHA,
|
build: process.env.GITHUB_SHA,
|
||||||
name: process.env.GITHUB_WORKFLOW,
|
name: process.env.GITHUB_WORKFLOW,
|
||||||
project: `openpgpjs/${process.env.GITHUB_EVENT_NAME || 'push'}${process.env.LIGHTWEIGHT ? '/lightweight' : ''}`
|
project: `openpgpjs/${process.env.GITHUB_EVENT_NAME || 'push'}${process.env.LIGHTWEIGHT ? '/lightweight' : ''}`,
|
||||||
|
timeout: 450
|
||||||
},
|
},
|
||||||
|
|
||||||
// define browsers
|
// define browsers
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
|
const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
|
||||||
|
|
||||||
const { readKey, Key, readCleartextMessage, CleartextMessage, enums, PacketList, SignaturePacket } = openpgp;
|
const { readKey, Key, readCleartextMessage, CleartextMessage, enums, PacketList, SignaturePacket } = openpgp;
|
||||||
const key = require('../../src/key');
|
|
||||||
|
|
||||||
const chai = require('chai');
|
const chai = require('chai');
|
||||||
chai.use(require('chai-as-promised'));
|
chai.use(require('chai-as-promised'));
|
||||||
@ -9,23 +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 key.generate({
|
const victimPrivKey = (await openpgp.generateKey({
|
||||||
userIds: [{ name: 'Victim', email: 'victim@example.com' }],
|
userIds: [{ name: 'Victim', email: 'victim@example.com' }],
|
||||||
type: 'rsa',
|
type: 'rsa',
|
||||||
rsaBits: 1024,
|
rsaBits: 2048,
|
||||||
subkeys: [{
|
subkeys: [{
|
||||||
sign: true
|
sign: true
|
||||||
}]
|
}]
|
||||||
});
|
})).key;
|
||||||
victimPrivKey.revocationSignatures = [];
|
victimPrivKey.revocationSignatures = [];
|
||||||
|
|
||||||
const attackerPrivKey = await key.generate({
|
const attackerPrivKey = (await openpgp.generateKey({
|
||||||
userIds: [{ name: 'Attacker', email: 'attacker@example.com' }],
|
userIds: [{ name: 'Attacker', email: 'attacker@example.com' }],
|
||||||
type: 'rsa',
|
type: 'rsa',
|
||||||
rsaBits: 1024,
|
rsaBits: 2048,
|
||||||
subkeys: [],
|
subkeys: [],
|
||||||
sign: false
|
sign: false
|
||||||
});
|
})).key;
|
||||||
attackerPrivKey.revocationSignatures = [];
|
attackerPrivKey.revocationSignatures = [];
|
||||||
const signed = await openpgp.sign({
|
const signed = await openpgp.sign({
|
||||||
message: await CleartextMessage.fromText('I am batman'),
|
message: await CleartextMessage.fromText('I am batman'),
|
||||||
|
@ -6,16 +6,18 @@
|
|||||||
* - if it fails to run, edit this file to match the actual library API, then edit the definitions file (openpgp.d.ts) accordingly.
|
* - if it fails to run, edit this file to match the actual library API, then edit the definitions file (openpgp.d.ts) accordingly.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { generateKey, readKey, readKeys, Key, readMessage, Message, CleartextMessage, encrypt, decrypt, sign, verify } from '../..';
|
import { generateKey, readKey, readKeys, Key, readMessage, Message, CleartextMessage, encrypt, decrypt, sign, verify, config } from '../..';
|
||||||
|
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|
||||||
// Generate keys
|
// Generate keys
|
||||||
const { publicKeyArmored, key } = await generateKey({ userIds: [{ email: "user@corp.co" }] });
|
const { publicKeyArmored, key } = await generateKey({ userIds: [{ email: "user@corp.co" }], config: { v5Keys: true } });
|
||||||
expect(key).to.be.instanceOf(Key);
|
expect(key).to.be.instanceOf(Key);
|
||||||
const privateKeys = [key];
|
const privateKeys = [key];
|
||||||
const publicKeys = [key.toPublic()];
|
const publicKeys = [key.toPublic()];
|
||||||
|
expect(key.toPublic().armor(config)).to.equal(publicKeyArmored);
|
||||||
|
|
||||||
// Parse keys
|
// Parse keys
|
||||||
expect(await readKey({ armoredKey: publicKeyArmored })).to.be.instanceOf(Key);
|
expect(await readKey({ armoredKey: publicKeyArmored })).to.be.instanceOf(Key);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user