Merge pull request #430 from openpgpjs/aes_gcm

Implement AES-GCM proposal (IETF draft)
This commit is contained in:
Tankred Hase 2016-03-25 14:35:19 +08:00
commit 10bf9ec41e
25 changed files with 523 additions and 184 deletions

View File

@ -19,10 +19,10 @@ matrix:
env: OPENPGPJSTEST='end2end-4' BROWSER='chrome 46'
- node_js: "4"
env: OPENPGPJSTEST='end2end-1' BROWSER='firefox 42'
- node_js: "4"
env: OPENPGPJSTEST='end2end-6' BROWSER='internet explorer 11'
- node_js: "4"
env: OPENPGPJSTEST='end2end-9' BROWSER='safari 9'
- node_js: "4"
env: OPENPGPJSTEST='end2end-6' BROWSER='internet explorer 11'
- node_js: "4"
env: OPENPGPJSTEST='end2end-0' BROWSER='firefox 38'
- node_js: "4"
@ -48,6 +48,7 @@ matrix:
- env: OPENPGPJSTEST='end2end-2' BROWSER='firefox beta'
- env: OPENPGPJSTEST='end2end-3' BROWSER='chrome 38'
- env: OPENPGPJSTEST='end2end-5' BROWSER='chrome beta'
- env: OPENPGPJSTEST='end2end-6' BROWSER='internet explorer 11'
- env: OPENPGPJSTEST='end2end-7' BROWSER='microsoft edge 20.10240'
- env: OPENPGPJSTEST='end2end-8' BROWSER='safari 8'
- env: OPENPGPJSTEST='end2end-10' BROWSER='android 4.4'

View File

@ -19,9 +19,11 @@ OpenPGP.js [![Build Status](https://travis-ci.org/openpgpjs/openpgpjs.svg?branch
* 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](http://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](http://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.use_native = false`.
* For environments that don't provide native crypto, the library falls back to [asm.js](http://caniuse.com/#feat=asmjs) implementations of AES-CFB, SHA-1, and SHA-256. We use [Rusha](https://github.com/srijs/rusha) and [asmCrypto Lite](https://github.com/openpgpjs/asmcrypto-lite) (a minimal subset of asmCrypto.js built specifically for OpenPGP.js).
* The library implements the [IETF proposal](https://tools.ietf.org/html/draft-ford-openpgp-format-00) for authenticated encryption using native AES-GCM. This makes symmetric encryption about 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. You can activate it by setting `openpgp.config.aead_protect = true`.
* For environments that don't provide native crypto, the library falls back to [asm.js](http://caniuse.com/#feat=asmjs) implementations of AES, SHA-1, and SHA-256. We use [Rusha](https://github.com/srijs/rusha) and [asmCrypto Lite](https://github.com/openpgpjs/asmcrypto-lite) (a minimal subset of asmCrypto.js built specifically for OpenPGP.js).
### Getting started
@ -47,6 +49,8 @@ Here are some examples of how to use the v2.x api. For more elaborate examples a
var openpgp = require('openpgp'); // use as CommonJS, AMD, ES6 module or via window.openpgp
openpgp.initWorker({ path:'openpgp.worker.js' }) // set the relative web worker path
openpgp.config.aead_protect = true // activate fast AES-GCM mode (experimental)
```
#### Encrypt and decrypt *String* data with a password

4
npm-shrinkwrap.json generated
View File

@ -3,9 +3,9 @@
"version": "2.1.0",
"dependencies": {
"asmcrypto-lite": {
"version": "1.0.1",
"version": "1.1.0",
"from": "asmcrypto-lite@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/asmcrypto-lite/-/asmcrypto-lite-1.0.1.tgz"
"resolved": "https://registry.npmjs.org/asmcrypto-lite/-/asmcrypto-lite-1.1.0.tgz"
},
"babel-preset-es2015": {
"version": "6.5.0",

View File

@ -37,11 +37,12 @@ export default {
prefer_hash_algorithm: enums.hash.sha256,
encryption_cipher: enums.symmetric.aes256,
compression: enums.compression.zip,
aead_protect: false, // use Authenticated Encryption with Additional Data (AEAD) protection for symmetric encryption
integrity_protect: true, // use integrity protection for symmetric encryption
ignore_mdc_error: false, // fail on decrypt if message is not integrity protected
rsa_blinding: true,
useNative: true, // use native node.js crypto and Web Crypto apis (if available)
zeroCopy: false, // use transferable objects between the Web Worker and main thread
use_native: true, // use native node.js crypto and Web Crypto apis (if available)
zero_copy: false, // use transferable objects between the Web Worker and main thread
debug: false,
show_version: true,
show_comment: true,

117
src/crypto/gcm.js Normal file
View File

@ -0,0 +1,117 @@
// OpenPGP.js - An OpenPGP implementation in javascript
// Copyright (C) 2016 Tankred Hase
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3.0 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/**
* @fileoverview This module wraps native AES-GCM en/decryption for both
* the WebCrypto api as well as node.js' crypto api.
*/
'use strict';
import util from '../util.js';
import config from '../config';
import asmCrypto from 'asmcrypto-lite';
const webCrypto = util.getWebCrypto(); // no GCM support in IE11, Safari 9
const nodeCrypto = util.getNodeCrypto();
const Buffer = util.getNodeBuffer();
export const ivLength = 12; // size of the IV in bytes
const TAG_LEN = 16; // size of the tag in bytes
const ALGO = 'AES-GCM';
/**
* Encrypt plaintext input.
* @param {String} cipher The symmetric cipher algorithm to use e.g. 'aes128'
* @param {Uint8Array} plaintext The cleartext input to be encrypted
* @param {Uint8Array} key The encryption key
* @param {Uint8Array} iv The initialization vector (12 bytes)
* @return {Promise<Uint8Array>} The ciphertext output
*/
export function encrypt(cipher, plaintext, key, iv) {
if (cipher.substr(0,3) !== 'aes') {
return Promise.reject(new Error('GCM mode supports only AES cipher'));
}
if (webCrypto && config.use_native && key.length !== 24) { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
return webEncrypt(plaintext, key, iv);
} else if (nodeCrypto && config.use_native) { // Node crypto library
return nodeEncrypt(plaintext, key, iv) ;
} else { // asm.js fallback
return Promise.resolve(asmCrypto.AES_GCM.encrypt(plaintext, key, iv));
}
}
/**
* Decrypt ciphertext input.
* @param {String} cipher The symmetric cipher algorithm to use e.g. 'aes128'
* @param {Uint8Array} ciphertext The ciphertext input to be decrypted
* @param {Uint8Array} key The encryption key
* @param {Uint8Array} iv The initialization vector (12 bytes)
* @return {Promise<Uint8Array>} The plaintext output
*/
export function decrypt(cipher, ciphertext, key, iv) {
if (cipher.substr(0,3) !== 'aes') {
return Promise.reject(new Error('GCM mode supports only AES cipher'));
}
if (webCrypto && config.use_native && key.length !== 24) { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
return webDecrypt(ciphertext, key, iv);
} else if (nodeCrypto && config.use_native) { // Node crypto library
return nodeDecrypt(ciphertext, key, iv);
} else { // asm.js fallback
return Promise.resolve(asmCrypto.AES_GCM.decrypt(ciphertext, key, iv));
}
}
//////////////////////////
// //
// Helper functions //
// //
//////////////////////////
function webEncrypt(pt, key, iv) {
return webCrypto.importKey('raw', key, { name: ALGO }, false, ['encrypt'])
.then(keyObj => webCrypto.encrypt({ name: ALGO, iv }, keyObj, pt))
.then(ct => new Uint8Array(ct));
}
function webDecrypt(ct, key, iv) {
return webCrypto.importKey('raw', key, { name: ALGO }, false, ['decrypt'])
.then(keyObj => webCrypto.decrypt({ name: ALGO, iv }, keyObj, ct))
.then(pt => new Uint8Array(pt));
}
function nodeEncrypt(pt, key, iv) {
pt = new Buffer(pt);
key = new Buffer(key);
iv = new Buffer(iv);
const en = new nodeCrypto.createCipheriv('aes-' + (key.length * 8) + '-gcm', key, iv);
const ct = Buffer.concat([en.update(pt), en.final(), en.getAuthTag()]); // append auth tag to ciphertext
return Promise.resolve(new Uint8Array(ct));
}
function nodeDecrypt(ct, key, iv) {
ct = new Buffer(ct);
key = new Buffer(key);
iv = new Buffer(iv);
const de = new nodeCrypto.createDecipheriv('aes-' + (key.length * 8) + '-gcm', key, iv);
de.setAuthTag(ct.slice(ct.length - TAG_LEN, ct.length)); // read auth tag at end of ciphertext
const pt = Buffer.concat([de.update(ct.slice(0, ct.length - TAG_LEN)), de.final()]);
return Promise.resolve(new Uint8Array(pt));
}

View File

@ -8,6 +8,7 @@
import cipher from './cipher';
import hash from './hash';
import cfb from './cfb';
import * as gcm from './gcm';
import publicKey from './public_key';
import signature from './signature';
import random from './random';
@ -21,6 +22,8 @@ const mod = {
hash: hash,
/** @see module:crypto/cfb */
cfb: cfb,
/** @see module:crypto/gcm */
gcm: gcm,
/** @see module:crypto/public_key */
publicKey: publicKey,
/** @see module:crypto/signature */

View File

@ -136,7 +136,7 @@ export default function RSA() {
// Generate a new random private key B bits long, using public expt E
function generate(B, E) {
var webCrypto = util.getWebCrypto();
var webCrypto = util.getWebCryptoAll();
//
// Native RSA keygen using Web Crypto

View File

@ -91,6 +91,7 @@ export default {
} else {
throw new Error('No secure random number generator available.');
}
return buf;
},
/**

View File

@ -94,7 +94,8 @@ export default {
publicSubkey: 14,
userAttribute: 17,
symEncryptedIntegrityProtected: 18,
modificationDetectionCode: 19
modificationDetectionCode: 19,
symEncryptedAEADProtected: 20 // see IETF draft: https://tools.ietf.org/html/draft-ford-openpgp-format-00#section-2.1
},
/** Data types in the literal packet

View File

@ -933,24 +933,21 @@ export function readArmored(armoredText) {
*/
export function generate(options) {
var packetlist, secretKeyPacket, userIdPacket, dataToSign, signaturePacket, secretSubkeyPacket, subkeySignaturePacket;
return Promise.resolve().then(() => {
options.keyType = options.keyType || enums.publicKey.rsa_encrypt_sign;
if (options.keyType !== enums.publicKey.rsa_encrypt_sign) { // RSA Encrypt-Only and RSA Sign-Only are deprecated and SHOULD NOT be generated
throw new Error('Only RSA Encrypt or Sign supported');
}
options.keyType = options.keyType || enums.publicKey.rsa_encrypt_sign;
// RSA Encrypt-Only and RSA Sign-Only are deprecated and SHOULD NOT be generated
if (options.keyType !== enums.publicKey.rsa_encrypt_sign) {
throw new Error('Only RSA Encrypt or Sign supported');
}
// Key without passphrase is unlocked by definition
if (!options.passphrase) {
options.unlocked = true;
}
if (String.prototype.isPrototypeOf(options.userIds) || typeof options.userIds === 'string') {
options.userIds = [options.userIds];
}
if (!options.passphrase) { // Key without passphrase is unlocked by definition
options.unlocked = true;
}
if (String.prototype.isPrototypeOf(options.userIds) || typeof options.userIds === 'string') {
options.userIds = [options.userIds];
}
// generate
var genSecretKey = generateSecretKey();
var genSecretSubkey = generateSecretSubkey();
return Promise.all([genSecretKey, genSecretSubkey]).then(wrapKeyObject);
return Promise.all([generateSecretKey(), generateSecretSubkey()]).then(wrapKeyObject);
});
function generateSecretKey() {
secretKeyPacket = new packet.SecretKey();
@ -990,8 +987,8 @@ export function generate(options) {
signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data];
signaturePacket.preferredSymmetricAlgorithms = [];
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.aes256);
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.aes192);
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.aes128);
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.aes192);
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.cast5);
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.tripledes);
signaturePacket.preferredHashAlgorithms = [];

View File

@ -92,19 +92,29 @@ Message.prototype.getSigningKeyIds = function() {
* @return {Message} new message with decrypted content
*/
Message.prototype.decrypt = function(privateKey, sessionKey, password) {
var keyObj = sessionKey || this.decryptSessionKey(privateKey, password);
if (!keyObj || !util.isUint8Array(keyObj.data) || !util.isString(keyObj.algorithm)) {
throw new Error('Invalid session key for decryption.');
}
var symEncryptedPacketlist = this.packets.filterByTag(enums.packet.symmetricallyEncrypted, enums.packet.symEncryptedIntegrityProtected);
if (symEncryptedPacketlist.length !== 0) {
var symEncryptedPacket = symEncryptedPacketlist[0];
symEncryptedPacket.decrypt(keyObj.algorithm, keyObj.data);
var resultMsg = new Message(symEncryptedPacket.packets);
// remove packets after decryption
symEncryptedPacket.packets = new packet.List();
return resultMsg;
}
return Promise.resolve().then(() => {
const keyObj = sessionKey || this.decryptSessionKey(privateKey, password);
if (!keyObj || !util.isUint8Array(keyObj.data) || !util.isString(keyObj.algorithm)) {
throw new Error('Invalid session key for decryption.');
}
const symEncryptedPacketlist = this.packets.filterByTag(
enums.packet.symmetricallyEncrypted,
enums.packet.symEncryptedIntegrityProtected,
enums.packet.symEncryptedAEADProtected
);
if (symEncryptedPacketlist.length === 0) {
return;
}
const symEncryptedPacket = symEncryptedPacketlist[0];
return symEncryptedPacket.decrypt(keyObj.algorithm, keyObj.data).then(() => {
const resultMsg = new Message(symEncryptedPacket.packets);
symEncryptedPacket.packets = new packet.List(); // remove packets after decryption
return resultMsg;
});
});
};
/**
@ -205,32 +215,35 @@ Message.prototype.getText = function() {
* @return {Message} new message with encrypted content
*/
Message.prototype.encrypt = function(keys, passwords) {
var symAlgo;
if (keys) {
symAlgo = keyModule.getPreferredSymAlgo(keys);
} else if (passwords) {
symAlgo = config.encryption_cipher;
} else {
throw new Error('No keys or passwords');
}
let symAlgo, msg, symEncryptedPacket;
return Promise.resolve().then(() => {
if (keys) {
symAlgo = keyModule.getPreferredSymAlgo(keys);
} else if (passwords) {
symAlgo = config.encryption_cipher;
} else {
throw new Error('No keys or passwords');
}
var sessionKey = crypto.generateSessionKey(enums.read(enums.symmetric, symAlgo));
var msg = encryptSessionKey(sessionKey, enums.read(enums.symmetric, symAlgo), keys, passwords);
var packetlist = msg.packets;
let sessionKey = crypto.generateSessionKey(enums.read(enums.symmetric, symAlgo));
msg = encryptSessionKey(sessionKey, enums.read(enums.symmetric, symAlgo), keys, passwords);
var symEncryptedPacket;
if (config.integrity_protect) {
symEncryptedPacket = new packet.SymEncryptedIntegrityProtected();
} else {
symEncryptedPacket = new packet.SymmetricallyEncrypted();
}
symEncryptedPacket.packets = this.packets;
symEncryptedPacket.encrypt(enums.read(enums.symmetric, symAlgo), sessionKey);
packetlist.push(symEncryptedPacket);
// remove packets after encryption
symEncryptedPacket.packets = new packet.List();
if (config.aead_protect) {
symEncryptedPacket = new packet.SymEncryptedAEADProtected();
} else if (config.integrity_protect) {
symEncryptedPacket = new packet.SymEncryptedIntegrityProtected();
} else {
symEncryptedPacket = new packet.SymmetricallyEncrypted();
}
symEncryptedPacket.packets = this.packets;
return msg;
return symEncryptedPacket.encrypt(enums.read(enums.symmetric, symAlgo), sessionKey);
}).then(() => {
msg.packets.push(symEncryptedPacket);
symEncryptedPacket.packets = new packet.List(); // remove packets after encryption
return msg;
});
};
/**

View File

@ -99,7 +99,7 @@ export function destroyWorker() {
export function generateKey({ userIds=[], passphrase, numBits=2048, unlocked=false } = {}) {
const options = formatUserIds({ userIds, passphrase, numBits, unlocked });
if (!util.getWebCrypto() && asyncProxy) { // use web worker if web crypto apis are not supported
if (!util.getWebCryptoAll() && asyncProxy) { // use web worker if web crypto apis are not supported
return asyncProxy.delegate('generateKey', options);
}
@ -109,18 +109,7 @@ export function generateKey({ userIds=[], passphrase, numBits=2048, unlocked=fal
privateKeyArmored: newKey.armor(),
publicKeyArmored: newKey.toPublic().armor()
})).catch(err => {
// js fallback already tried
if (config.debug) { console.error(err); }
if (!util.getWebCrypto()) {
throw new Error('Error generating keypair using js fallback');
}
// fall back to js keygen in a worker
if (config.debug) { console.log('Error generating keypair using native WebCrypto... falling back back to js'); }
return asyncProxy.delegate('generateKey', options);
}).catch(onError.bind(null, 'Error generating keypair'));
})).catch(onError.bind(null, 'Error generating keypair'));
}
/**
@ -169,17 +158,19 @@ export function decryptKey({ privateKey, passphrase }) {
export function encrypt({ data, publicKeys, privateKeys, passwords, filename, armor=true }) {
checkData(data); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords);
if (asyncProxy) { // use web worker if available
if (!nativeAEAD() && asyncProxy) { // use web worker if web crypto apis are not supported
return asyncProxy.delegate('encrypt', { data, publicKeys, privateKeys, passwords, filename, armor });
}
return execute(() => {
return Promise.resolve().then(() => {
let message = createMessage(data, filename);
if (privateKeys) { // sign the message only if private keys are specified
message = message.sign(privateKeys);
}
message = message.encrypt(publicKeys, passwords);
return message.encrypt(publicKeys, passwords);
}).then(message => {
if(armor) {
return {
@ -190,7 +181,7 @@ export function encrypt({ data, publicKeys, privateKeys, passwords, filename, ar
message: message
};
}, 'Error encrypting message');
}).catch(onError.bind(null, 'Error encrypting message'));
}
/**
@ -209,20 +200,19 @@ export function encrypt({ data, publicKeys, privateKeys, passwords, filename, ar
export function decrypt({ message, privateKey, publicKeys, sessionKey, password, format='utf8' }) {
checkMessage(message); publicKeys = toArray(publicKeys);
if (asyncProxy) { // use web worker if available
if (!nativeAEAD() && asyncProxy) { // use web worker if web crypto apis are not supported
return asyncProxy.delegate('decrypt', { message, privateKey, publicKeys, sessionKey, password, format });
}
return execute(() => {
return message.decrypt(privateKey, sessionKey, password).then(message => {
message = message.decrypt(privateKey, sessionKey, password);
const result = parseMessage(message, format);
if (publicKeys && result.data) { // verify only if publicKeys are specified
result.signatures = message.verify(publicKeys);
}
return result;
}, 'Error decrypting message');
}).catch(onError.bind(null, 'Error decrypting message'));
}
@ -483,3 +473,12 @@ function onError(message, error) {
// rethrow new high level error for api users
throw new Error(message + ': ' + error.message);
}
/**
* Check for AES-GCM support and configuration by the user. Only browsers that
* implement the current WebCrypto specification support native AES-GCM.
* @return {Boolean} If authenticated encryption should be used
*/
function nativeAEAD() {
return util.getWebCrypto() && config.aead_protect;
}

View File

@ -12,6 +12,8 @@ import * as packets from './all_packets.js'; // re-import module to parse packet
export { default as Compressed } from './compressed.js';
/** @see module:packet/sym_encrypted_integrity_protected */
export { default as SymEncryptedIntegrityProtected } from './sym_encrypted_integrity_protected.js';
/** @see module:packet/sym_encrypted_aead_protected */
export { default as SymEncryptedAEADProtected } from './sym_encrypted_aead_protected.js';
/** @see module:packet/public_key_encrypted_session_key */
export { default as PublicKeyEncryptedSessionKey } from './public_key_encrypted_session_key.js';
/** @see module:packet/sym_encrypted_session_key */

View File

@ -0,0 +1,88 @@
// OpenPGP.js - An OpenPGP implementation in javascript
// Copyright (C) 2016 Tankred Hase
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3.0 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/**
* Implementation of the Symmetrically Encrypted Authenticated Encryption with Additional Data (AEAD) Protected Data Packet
* {@link https://tools.ietf.org/html/draft-ford-openpgp-format-00#section-2.1}: AEAD Protected Data Packet
*/
'use strict';
import util from '../util.js';
import crypto from '../crypto';
import enums from '../enums.js';
const VERSION = 1; // A one-octet version number of the data packet.
const IV_LEN = crypto.gcm.ivLength; // currently only AES-GCM is supported
/**
* @constructor
*/
export default function SymEncryptedAEADProtected() {
this.tag = enums.packet.symEncryptedAEADProtected;
this.version = VERSION;
this.iv = null;
this.encrypted = null;
this.packets = null;
}
/**
* Parse an encrypted payload of bytes in the order: version, IV, ciphertext (see specification)
*/
SymEncryptedAEADProtected.prototype.read = function (bytes) {
let offset = 0;
if (bytes[offset] !== VERSION) { // The only currently defined value is 1.
throw new Error('Invalid packet version.');
}
offset++;
this.iv = bytes.subarray(offset, IV_LEN + offset);
offset += IV_LEN;
this.encrypted = bytes.subarray(offset, bytes.length);
};
/**
* Write the encrypted payload of bytes in the order: version, IV, ciphertext (see specification)
* @return {Uint8Array} The encrypted payload
*/
SymEncryptedAEADProtected.prototype.write = function () {
return util.concatUint8Array([new Uint8Array([this.version]), this.iv, this.encrypted]);
};
/**
* Decrypt the encrypted payload.
* @param {String} sessionKeyAlgorithm The session key's cipher algorithm e.g. 'aes128'
* @param {Uint8Array} key The session key used to encrypt the payload
* @return {Promise<undefined>} Nothing is returned
*/
SymEncryptedAEADProtected.prototype.decrypt = function (sessionKeyAlgorithm, key) {
return crypto.gcm.decrypt(sessionKeyAlgorithm, this.encrypted, key, this.iv).then(decrypted => {
this.packets.read(decrypted);
});
};
/**
* Encrypt the packet list payload.
* @param {String} sessionKeyAlgorithm The session key's cipher algorithm e.g. 'aes128'
* @param {Uint8Array} key The session key used to encrypt the payload
* @return {Promise<undefined>} Nothing is returned
*/
SymEncryptedAEADProtected.prototype.encrypt = function (sessionKeyAlgorithm, key) {
this.iv = crypto.random.getRandomValues(new Uint8Array(IV_LEN)); // generate new random IV
return crypto.gcm.encrypt(sessionKeyAlgorithm, this.packets.write(), key, this.iv).then(encrypted => {
this.encrypted = encrypted;
});
};

View File

@ -95,7 +95,7 @@ SymEncryptedIntegrityProtected.prototype.encrypt = function (sessionKeyAlgorithm
if(sessionKeyAlgorithm.substr(0,3) === 'aes') { // AES optimizations. Native code for node, asmCrypto for browser.
var blockSize = crypto.cipher[sessionKeyAlgorithm].blockSize;
if(nodeCrypto) { // Node crypto library. Only loaded if config.useNative === true
if(nodeCrypto) { // Node crypto library. Only loaded if config.use_native === true
var cipherObj = new nodeCrypto.createCipheriv('aes-' + sessionKeyAlgorithm.substr(3,3) + '-cfb',
new Buffer(key), new Buffer(new Uint8Array(blockSize)));
this.encrypted = new Uint8Array(cipherObj.update(new Buffer(util.concatUint8Array([prefix, tohash]))));
@ -108,6 +108,8 @@ SymEncryptedIntegrityProtected.prototype.encrypt = function (sessionKeyAlgorithm
this.encrypted = crypto.cfb.encrypt(prefixrandom, sessionKeyAlgorithm, tohash, key, false)
.subarray(0, prefix.length + tohash.length);
}
return Promise.resolve();
};
/**
@ -125,7 +127,7 @@ SymEncryptedIntegrityProtected.prototype.decrypt = function (sessionKeyAlgorithm
if(sessionKeyAlgorithm.substr(0,3) === 'aes') { // AES optimizations. Native code for node, asmCrypto for browser.
var blockSize = crypto.cipher[sessionKeyAlgorithm].blockSize;
if(nodeCrypto) { // Node crypto library. Only loaded if config.useNative === true
if(nodeCrypto) { // Node crypto library. Only loaded if config.use_native === true
var decipherObj = new nodeCrypto.createDecipheriv('aes-' + sessionKeyAlgorithm.substr(3,3) + '-cfb',
new Buffer(key), new Buffer(new Uint8Array(blockSize)));
decrypted = new Uint8Array(decipherObj.update(new Buffer(this.encrypted)));
@ -153,4 +155,6 @@ SymEncryptedIntegrityProtected.prototype.decrypt = function (sessionKeyAlgorithm
} else {
this.packets.read(decrypted.subarray(0, decrypted.length - 22));
}
return Promise.resolve();
};

View File

@ -73,11 +73,14 @@ SymmetricallyEncrypted.prototype.decrypt = function (sessionKeyAlgorithm, key) {
throw new Error('Decryption failed due to missing MDC in combination with modern cipher.');
}
this.packets.read(decrypted);
return Promise.resolve();
};
SymmetricallyEncrypted.prototype.encrypt = function (algo, key) {
var data = this.packets.write();
this.encrypted = crypto.cfb.encrypt(
crypto.getPrefixRandom(algo), algo, data, key, true);
this.encrypted = crypto.cfb.encrypt(crypto.getPrefixRandom(algo), algo, data, key, true);
return Promise.resolve();
};

View File

@ -61,7 +61,7 @@ export default {
* @return {Array<ArrayBuffer>} an array of binary data to be passed
*/
getTransferables: function(obj) {
if (config.zeroCopy && Object.prototype.isPrototypeOf(obj)) {
if (config.zero_copy && Object.prototype.isPrototypeOf(obj)) {
const transferables = [];
this.collectBuffers(obj, transferables);
return transferables.length ? transferables : undefined;
@ -450,12 +450,28 @@ export default {
},
/**
* Get native Web Cryptography api. The default configuration is to use
* the api when available. But it can also be deactivated with config.useNative
* 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.use_native
* @return {Object} The SubtleCrypto api or 'undefined'
*/
getWebCrypto: function() {
if (!config.useNative) {
if (!config.use_native) {
return;
}
return typeof window !== 'undefined' && window.crypto && window.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.use_native
* @return {Object} The SubtleCrypto api or 'undefined'
*/
getWebCryptoAll: function() {
if (!config.use_native) {
return;
}
@ -512,11 +528,11 @@ export default {
/**
* Get native Node.js crypto api. The default configuration is to use
* the api when available. But it can also be deactivated with config.useNative
* the api when available. But it can also be deactivated with config.use_native
* @return {Object} The crypto module or 'undefined'
*/
getNodeCrypto: function() {
if (!this.detectNode() || !config.useNative) {
if (!this.detectNode() || !config.use_native) {
return;
}

View File

@ -1,6 +1,6 @@
'use strict';
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp');
var openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp');
var chai = require('chai'),
expect = chai.expect;
@ -80,7 +80,7 @@ describe('API functional testing', function() {
0x51,0xe0,0x22,0xf0,0xff,0xa7,0x42,0xd4,0xde,0x0b,0x47,0x8f,0x2b,
0xf5,0x4d,0x04,0x32,0x91,0x89,0x4b,0x0e,0x05,0x8d,0x70,0xf9,0xbb,
0xe7,0xd6,0x76,0xea,0x0e,0x1a,0x90,0x30,0xf5,0x98,0x01,0xc5,0x73])];
var DSApubMPIstrs = [
new Uint8Array([0x08,0x00,0xa8,0x85,0x5c,0x28,0x05,0x94,0x03,0xbe,0x07,0x6c,0x13,0x3e,0x65,
0xfb,0xb5,0xe1,0x99,0x7c,0xfa,0x84,0xe3,0xac,0x47,0xa5,0xc4,0x46,0xd8,0x5f,
@ -143,7 +143,7 @@ describe('API functional testing', function() {
new Uint8Array([0x01,0x00,0x9b,0x58,0xa8,0xf4,0x04,0xb1,0xd5,0x14,0x09,0xe1,0xe1,0xa1,0x8a,
0x0b,0xa3,0xc3,0xa3,0x66,0xaa,0x27,0x99,0x50,0x1c,0x4d,0xba,0x24,0xee,0xdf,
0xdf,0xb8,0x8e,0x8e])];
var ElgamalpubMPIstrs = [
new Uint8Array([0x08,0x00,0xea,0xcc,0xbe,0xe2,0xe4,0x5a,0x51,0x18,0x93,0xa1,0x12,0x2f,0x00,
0x99,0x42,0xd8,0x5c,0x1c,0x2f,0xb6,0x3c,0xd9,0x94,0x61,0xb4,0x55,0x8d,0x4e,
@ -200,13 +200,13 @@ describe('API functional testing', function() {
RSAsecMPIs[i] = new openpgp.MPI();
RSAsecMPIs[i].read(RSAsecMPIstrs[i]);
}
var DSAsecMPIs = [];
for (i = 0; i < 1; i++) {
DSAsecMPIs[i] = new openpgp.MPI();
DSAsecMPIs[i].read(DSAsecMPIstrs[i]);
}
var DSApubMPIs = [];
for (i = 0; i < 4; i++) {
DSApubMPIs[i] = new openpgp.MPI();
@ -217,7 +217,7 @@ describe('API functional testing', function() {
ElgamalsecMPIs[i] = new openpgp.MPI();
ElgamalsecMPIs[i].read(ElgamalsecMPIstrs[i]);
}
var ElgamalpubMPIs = [];
for (i = 0; i < 3; i++) {
ElgamalpubMPIs[i] = new openpgp.MPI();
@ -287,6 +287,25 @@ describe('API functional testing', function() {
});
}
function testAESGCM(plaintext) {
symmAlgos.forEach(function(algo) {
if(algo.substr(0,3) === 'aes') {
it(algo, function(done) {
var key = openpgp.crypto.generateSessionKey(algo);
var iv = openpgp.crypto.random.getRandomValues(new Uint8Array(openpgp.crypto.gcm.ivLength));
openpgp.crypto.gcm.encrypt(algo, util.str2Uint8Array(plaintext), key, iv).then(function(ciphertext) {
return openpgp.crypto.gcm.decrypt(algo, ciphertext, key, iv);
}).then(function(decrypted) {
var decryptedStr = util.Uint8Array2str(decrypted);
expect(decryptedStr).to.equal(plaintext);
done();
});
});
}
});
}
it("Symmetric with OpenPGP CFB resync", function () {
testCFB("hello", true);
testCFB("1234567", true);
@ -301,11 +320,37 @@ describe('API functional testing', function() {
testCFB("12345678901234567890123456789012345678901234567890", false);
});
it("asmCrypto AES without OpenPGP CFB resync", function () {
testCFB("hello");
testCFB("1234567");
testCFB("foobarfoobar1234567890");
testCFB("12345678901234567890123456789012345678901234567890");
it.skip("asmCrypto AES without OpenPGP CFB resync", function () {
testAESCFB("hello");
testAESCFB("1234567");
testAESCFB("foobarfoobar1234567890");
testAESCFB("12345678901234567890123456789012345678901234567890");
});
describe('Symmetric AES-GCM (native)', function() {
var use_nativeVal;
beforeEach(function() {
use_nativeVal = openpgp.config.use_native;
openpgp.config.use_native = true;
});
afterEach(function() {
openpgp.config.use_native = use_nativeVal;
});
testAESGCM("12345678901234567890123456789012345678901234567890");
});
describe('Symmetric AES-GCM (asm.js fallback)', function() {
var use_nativeVal;
beforeEach(function() {
use_nativeVal = openpgp.config.use_native;
openpgp.config.use_native = false;
});
afterEach(function() {
openpgp.config.use_native = use_nativeVal;
});
testAESGCM("12345678901234567890123456789012345678901234567890");
});
it('Asymmetric using RSA with eme_pkcs1 padding', function (done) {

View File

@ -599,13 +599,13 @@ var pgp_desktop_priv =
expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes256);
});
it('getPreferredSymAlgo() - two key - AES192', function() {
it('getPreferredSymAlgo() - two key - AES128', function() {
var keys = openpgp.key.readArmored(twoKeys).keys;
var key1 = keys[0];
var key2 = keys[1];
key2.getPrimaryUser().selfCertificate.preferredSymmetricAlgorithms = [6,8,3];
key2.getPrimaryUser().selfCertificate.preferredSymmetricAlgorithms = [6,7,3];
var prefAlgo = openpgp.key.getPreferredSymAlgo([key1, key2]);
expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes192);
expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes128);
});
it('getPreferredSymAlgo() - two key - one without pref', function() {
@ -626,7 +626,7 @@ var pgp_desktop_priv =
expect(key.subKeys[0].bindingSignature.keyFlags[0] & keyFlags.encrypt_communication).to.equal(keyFlags.encrypt_communication);
expect(key.subKeys[0].bindingSignature.keyFlags[0] & keyFlags.encrypt_storage).to.equal(keyFlags.encrypt_storage);
var sym = openpgp.enums.symmetric;
expect(key.users[0].selfCertifications[0].preferredSymmetricAlgorithms).to.eql([sym.aes256, sym.aes192, sym.aes128, sym.cast5, sym.tripledes]);
expect(key.users[0].selfCertifications[0].preferredSymmetricAlgorithms).to.eql([sym.aes256, sym.aes128, sym.aes192, sym.cast5, sym.tripledes]);
var hash = openpgp.enums.hash;
expect(key.users[0].selfCertifications[0].preferredHashAlgorithms).to.eql([hash.sha256, hash.sha1, hash.sha512]);
var compr = openpgp.enums.compression;
@ -634,7 +634,7 @@ var pgp_desktop_priv =
expect(key.users[0].selfCertifications[0].features).to.eql(openpgp.config.integrity_protect ? [1] : null); // modification detection
};
var opt = {numBits: 512, userIds: 'test <a@b.com>', passphrase: 'hello'};
if (openpgp.util.getWebCrypto()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
openpgp.generateKey(opt).then(function(key) {
testPref(key.key);
testPref(openpgp.key.readArmored(key.publicKeyArmored).keys[0]);
@ -658,11 +658,15 @@ var pgp_desktop_priv =
it('Generated key is not unlocked by default', function(done) {
var opt = {numBits: 512, userIds: 'test <a@b.com>', passphrase: '123'};
if (openpgp.util.getWebCrypto()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
openpgp.generateKey(opt).then(function(key) {
var msg = openpgp.message.fromText('hello').encrypt([key.key]);
msg = msg.decrypt.bind(msg, key.key);
expect(msg).to.throw('Private key is not decrypted.');
if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
var key;
openpgp.generateKey(opt).then(function(newKey) {
key = newKey;
return openpgp.message.fromText('hello').encrypt([key.key]);
}).then(function(msg) {
return msg.decrypt(key.key);
}).catch(function(err) {
expect(err.message).to.equal('Private key is not decrypted.');
done();
});
});
@ -670,7 +674,7 @@ var pgp_desktop_priv =
it('Generate key - single userid', function(done) {
var userId = 'test <a@b.com>';
var opt = {numBits: 512, userIds: userId, passphrase: '123'};
if (openpgp.util.getWebCrypto()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
openpgp.generateKey(opt).then(function(key) {
key = key.key;
expect(key.users.length).to.equal(1);
@ -683,7 +687,7 @@ var pgp_desktop_priv =
var userId1 = 'test <a@b.com>';
var userId2 = 'test <b@c.com>';
var opt = {numBits: 512, userIds: [userId1, userId2], passphrase: '123'};
if (openpgp.util.getWebCrypto()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
openpgp.generateKey(opt).then(function(key) {
key = key.key;
expect(key.users.length).to.equal(2);

View File

@ -1,4 +1,4 @@
/* globals tryWorker: true */
/* globals tryTests: true */
'use strict';
@ -184,7 +184,7 @@ describe('OpenPGP.js public api tests', function() {
});
describe('generateKey - unit tests', function() {
var keyGenStub, keyObjStub, getWebCryptoStub;
var keyGenStub, keyObjStub, getWebCryptoAllStub;
beforeEach(function() {
keyObjStub = {
@ -201,13 +201,13 @@ describe('OpenPGP.js public api tests', function() {
};
keyGenStub = sinon.stub(openpgp.key, 'generate');
keyGenStub.returns(resolves(keyObjStub));
getWebCryptoStub = sinon.stub(openpgp.util, 'getWebCrypto');
getWebCryptoAllStub = sinon.stub(openpgp.util, 'getWebCryptoAll');
});
afterEach(function() {
keyGenStub.restore();
openpgp.destroyWorker();
getWebCryptoStub.restore();
getWebCryptoAllStub.restore();
});
it('should fail for invalid user name', function() {
@ -333,47 +333,28 @@ describe('OpenPGP.js public api tests', function() {
worker: workerStub
});
var proxyGenStub = sinon.stub(openpgp.getWorker(), 'delegate');
getWebCryptoStub.returns();
getWebCryptoAllStub.returns();
openpgp.generateKey();
expect(proxyGenStub.calledOnce).to.be.true;
expect(keyGenStub.calledOnce).to.be.false;
});
it('should delegate to async proxy after web crypto failure', function(done) {
var workerStub = {
postMessage: function() {}
};
openpgp.initWorker({
worker: workerStub
});
var proxyGenStub = sinon.stub(openpgp.getWorker(), 'delegate').returns(resolves('proxy_key'));
getWebCryptoStub.returns({});
keyGenStub.returns(rejects(new Error('Native webcrypto keygen failed on purpose :)')));
openpgp.generateKey().then(function(newKey) {
expect(keyGenStub.calledOnce).to.be.true;
expect(proxyGenStub.calledOnce).to.be.true;
expect(newKey).to.equal('proxy_key');
done();
});
});
});
describe('generateKey - integration tests', function() {
var useNativeVal;
var use_nativeVal;
beforeEach(function() {
useNativeVal = openpgp.config.useNative;
use_nativeVal = openpgp.config.use_native;
});
afterEach(function() {
openpgp.config.useNative = useNativeVal;
openpgp.config.use_native = use_nativeVal;
openpgp.destroyWorker();
});
it('should work in JS (without worker)', function(done) {
openpgp.config.useNative = false;
openpgp.config.use_native = false;
openpgp.destroyWorker();
var opt = {
userIds: [{ name: 'Test User', email: 'text@example.com' }],
@ -389,7 +370,7 @@ describe('OpenPGP.js public api tests', function() {
});
it('should work in JS (with worker)', function(done) {
openpgp.config.useNative = false;
openpgp.config.use_native = false;
openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
var opt = {
userIds: [{ name: 'Test User', email: 'text@example.com' }],
@ -405,12 +386,12 @@ describe('OpenPGP.js public api tests', function() {
});
it('should work in with native crypto', function(done) {
openpgp.config.useNative = true;
openpgp.config.use_native = true;
var opt = {
userIds: [{ name: 'Test User', email: 'text@example.com' }],
numBits: 512
};
if (openpgp.util.getWebCrypto()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
openpgp.generateKey(opt).then(function(newKey) {
expect(newKey.key.getUserIds()[0]).to.equal('Test User <text@example.com>');
@ -422,7 +403,7 @@ describe('OpenPGP.js public api tests', function() {
});
describe('encrypt, decrypt, sign, verify - integration tests', function() {
var privateKey, publicKey, zeroCopyVal;
var privateKey, publicKey, zero_copyVal, use_nativeVal, aead_protectVal;
beforeEach(function() {
publicKey = openpgp.key.readArmored(pub_key);
@ -431,11 +412,15 @@ describe('OpenPGP.js public api tests', function() {
privateKey = openpgp.key.readArmored(priv_key);
expect(privateKey.keys).to.have.length(1);
expect(privateKey.err).to.not.exist;
zeroCopyVal = openpgp.config.zeroCopy;
zero_copyVal = openpgp.config.zero_copy;
use_nativeVal = openpgp.config.use_native;
aead_protectVal = openpgp.config.aead_protect;
});
afterEach(function() {
openpgp.config.zeroCopy = zeroCopyVal;
openpgp.config.zero_copy = zero_copyVal;
openpgp.config.use_native = use_nativeVal;
openpgp.config.aead_protect = aead_protectVal;
});
it('Decrypting key with wrong passphrase returns false', function () {
@ -446,18 +431,43 @@ describe('OpenPGP.js public api tests', function() {
expect(privateKey.keys[0].decrypt(passphrase)).to.be.true;
});
describe('without Worker', tests);
tryTests('CFB mode (asm.js)', tests, {
if: true,
beforeEach: function() {
openpgp.config.use_native = true;
openpgp.config.aead_protect = false;
}
});
tryWorker('with Worker', tests, function() {
openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
}, function() {
openpgp.destroyWorker(); // cleanup worker in case of failure
tryTests('CFB mode (asm.js, worker)', tests, {
if: typeof window !== 'undefined' && window.Worker,
before: function() {
openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
},
beforeEach: function() {
openpgp.config.use_native = true;
openpgp.config.aead_protect = false;
},
after: function() {
openpgp.destroyWorker();
}
});
tryTests('GCM mode (native)', tests, {
if: openpgp.util.getWebCrypto() || openpgp.util.getNodeCrypto(),
beforeEach: function() {
openpgp.config.use_native = true;
openpgp.config.aead_protect = true;
}
});
function tests() {
it('Configuration', function(done){
openpgp.config.show_version = false;
openpgp.config.commentstring = 'different';
if (openpgp.getWorker()) { // init again to trigger config event
openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
}
openpgp.encrypt({ publicKeys:publicKey.keys, data:plaintext }).then(function(encrypted) {
expect(encrypted.data).to.exist;
expect(encrypted.data).not.to.match(/^Version:/);
@ -875,7 +885,7 @@ describe('OpenPGP.js public api tests', function() {
});
it('should encrypt and decrypt with binary data and transferable objects', function(done) {
openpgp.config.zeroCopy = true; // activate transferable objects
openpgp.config.zero_copy = true; // activate transferable objects
var encOpt = {
data: new Uint8Array([0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]),
passwords: password1,

View File

@ -121,6 +121,29 @@ describe("Packet", function() {
done();
});
it('Sym. encrypted AEAD protected packet', function(done) {
var 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]),
algo = 'aes256';
var literal = new openpgp.packet.Literal(),
enc = new openpgp.packet.SymEncryptedAEADProtected(),
msg = new openpgp.packet.List();
msg.push(enc);
literal.setText('Hello world!');
enc.packets.push(literal);
var msg2 = new openpgp.packet.List();
enc.encrypt(algo, key).then(function() {
msg2.read(msg.write());
return msg2[0].decrypt(algo, key);
}).then(function() {
expect(msg2[0].packets[0].data).to.deep.equal(literal.data);
done();
});
});
it('Sym encrypted session key with a compressed packet', function(done) {
var msg =
'-----BEGIN PGP MESSAGE-----\n' +
@ -150,7 +173,7 @@ describe("Packet", function() {
it('Public key encrypted symmetric key packet', function(done) {
var rsa = new openpgp.crypto.publicKey.rsa();
var keySize = openpgp.util.getWebCrypto() ? 2048 : 512; // webkit webcrypto accepts minimum 2048 bit keys
var keySize = openpgp.util.getWebCryptoAll() ? 2048 : 512; // webkit webcrypto accepts minimum 2048 bit keys
rsa.generate(keySize, "10001").then(function(mpiGen) {
@ -414,7 +437,7 @@ describe("Packet", function() {
key.push(new openpgp.packet.SecretKey());
var rsa = new openpgp.crypto.publicKey.rsa();
var keySize = openpgp.util.getWebCrypto() ? 2048 : 512; // webkit webcrypto accepts minimum 2048 bit keys
var keySize = openpgp.util.getWebCryptoAll() ? 2048 : 512; // webkit webcrypto accepts minimum 2048 bit keys
rsa.generate(keySize, "10001").then(function(mipGen) {
var mpi = [mipGen.n, mipGen.ee, mipGen.d, mipGen.p, mipGen.q, mipGen.u];
@ -443,7 +466,7 @@ describe("Packet", function() {
var key = new openpgp.packet.SecretKey();
var rsa = new openpgp.crypto.publicKey.rsa();
var keySize = openpgp.util.getWebCrypto() ? 2048 : 512; // webkit webcrypto accepts minimum 2048 bit keys
var keySize = openpgp.util.getWebCryptoAll() ? 2048 : 512; // webkit webcrypto accepts minimum 2048 bit keys
rsa.generate(keySize, "10001").then(function(mpiGen) {
var mpi = [mpiGen.n, mpiGen.ee, mpiGen.d, mpiGen.p, mpiGen.q, mpiGen.u];

View File

@ -304,12 +304,13 @@ describe("Signature", function() {
var msg = openpgp.message.readArmored(msg_arm1);
priv_key_gnupg_ext.subKeys[0].subKey.decrypt("abcd");
msg = msg.decrypt(priv_key_gnupg_ext);
var verified = msg.verify([pub_key]);
expect(verified).to.exist;
expect(verified).to.have.length(1);
expect(verified[0].valid).to.be.true;
done();
msg.decrypt(priv_key_gnupg_ext).then(function(msg) {
var verified = msg.verify([pub_key]);
expect(verified).to.exist;
expect(verified).to.have.length(1);
expect(verified[0].valid).to.be.true;
done();
});
});
it('Verify V4 signature. Hash: SHA1. PK: RSA. Signature Type: 0x00 (binary document)', function(done) {
@ -642,7 +643,7 @@ describe("Signature", function() {
it('Sign message with key without password', function(done) {
var opt = {numBits: 512, userIds: { name:'test', email:'a@b.com' }, passphrase: null};
if (openpgp.util.getWebCrypto()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
openpgp.generateKey(opt).then(function(gen) {
var key = gen.key;

View File

@ -145,7 +145,7 @@ describe('Util unit tests', function() {
});
describe('getTransferables', function() {
var zeroCopyVal,
var zero_copyVal,
buf1 = new Uint8Array(1),
buf2 = new Uint8Array(1),
obj = {
@ -157,16 +157,16 @@ describe('Util unit tests', function() {
};
beforeEach(function() {
zeroCopyVal = openpgp.config.zeroCopy;
openpgp.config.zeroCopy = true;
zero_copyVal = openpgp.config.zero_copy;
openpgp.config.zero_copy = true;
});
afterEach(function() {
openpgp.config.zeroCopy = zeroCopyVal;
openpgp.config.zero_copy = zero_copyVal;
});
it('should return undefined when zeroCopy is false', function() {
openpgp.config.zeroCopy = false;
it('should return undefined when zero_copy is false', function() {
openpgp.config.zero_copy = false;
expect(openpgp.util.getTransferables(obj)).to.be.undefined;
});
it('should return undefined for no input', function() {

View File

@ -6,17 +6,19 @@
return new Promise(function(res, rej) { rej(val); });
};
(typeof window !== 'undefined' ? window : global).tryWorker = function(name, tests, beforeFn, afterFn) {
if (typeof window !== 'undefined' && window.Worker) {
(typeof window !== 'undefined' ? window : global).tryTests = function(name, tests, options) {
if (options.if) {
describe(name, function() {
before(beforeFn);
if (options.before) { before(options.before); }
if (options.beforeEach) { beforeEach(options.beforeEach); }
tests();
after(afterFn);
if (options.afterEach) { afterEach(options.afterEach); }
if (options.after) { after(options.after); }
});
} else {
describe.skip(name + ' (No Web Worker support --> skipping tests)', tests);
describe.skip(name + ' (no support --> skipping tests)', tests);
}
};

View File

@ -1,4 +1,4 @@
/* globals tryWorker: true */
/* globals tryTests: true */
'use strict';
@ -35,11 +35,15 @@ var pub_key =
var plaintext = 'short message\nnext line\n한국어/조선말';
var pubKey;
tryWorker('Async Proxy', tests, function() {
openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
pubKey = openpgp.key.readArmored(pub_key).keys[0];
}, function() {
openpgp.destroyWorker();
tryTests('Async Proxy', tests, {
if: typeof window !== 'undefined' && window.Worker,
before: function() {
openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
pubKey = openpgp.key.readArmored(pub_key).keys[0];
},
after: function() {
openpgp.destroyWorker();
}
});
function tests() {