Merge branch 'master' into fix/non-primary-non-revoked-sub-user

This commit is contained in:
Sanjana Rajan 2018-12-23 17:52:01 +01:00 committed by GitHub
commit 529973f2a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 1370 additions and 1103 deletions

View File

@ -1,4 +1,4 @@
OpenPGP.js [![Build Status](https://travis-ci.org/openpgpjs/openpgpjs.svg?branch=master)](https://travis-ci.org/openpgpjs/openpgpjs) OpenPGP.js [![Build Status](https://travis-ci.org/openpgpjs/openpgpjs.svg?branch=master)](https://travis-ci.org/openpgpjs/openpgpjs) [![Join the chat on Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/openpgpjs/openpgpjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
========== ==========
[OpenPGP.js](https://openpgpjs.org/) is a JavaScript implementation of the OpenPGP protocol. This is defined in [RFC 4880](https://tools.ietf.org/html/rfc4880). [OpenPGP.js](https://openpgpjs.org/) is a JavaScript implementation of the OpenPGP protocol. This is defined in [RFC 4880](https://tools.ietf.org/html/rfc4880).
@ -379,17 +379,17 @@ var options = {
openpgp.generateKey(options).then(function(key) { openpgp.generateKey(options).then(function(key) {
var privkey = key.privateKeyArmored; // '-----BEGIN PGP PRIVATE KEY BLOCK ... ' var privkey = key.privateKeyArmored; // '-----BEGIN PGP PRIVATE KEY BLOCK ... '
var pubkey = key.publicKeyArmored; // '-----BEGIN PGP PUBLIC KEY BLOCK ... ' var pubkey = key.publicKeyArmored; // '-----BEGIN PGP PUBLIC KEY BLOCK ... '
var revocationSignature = key.revocationSignature; // '-----BEGIN PGP PUBLIC KEY BLOCK ... ' var revocationCertificate = key.revocationCertificate; // '-----BEGIN PGP PUBLIC KEY BLOCK ... '
}); });
``` ```
#### Revoke a key #### Revoke a key
Using a revocation signature: Using a revocation certificate:
```js ```js
var options = { var options = {
key: openpgp.key.readArmored(pubkey).keys[0], key: openpgp.key.readArmored(pubkey).keys[0],
revocationSignature: revocationSignature revocationCertificate: revocationCertificate
}; };
``` ```
@ -587,7 +587,7 @@ For debugging browser errors, you can open `test/unittests.html` in a browser or
### How do I get involved? ### How do I get involved?
You want to help, great! Go ahead and fork our repo, make your changes and send us a pull request. You want to help, great! It's probably best to send us a message on [Gitter](https://gitter.im/openpgpjs/openpgpjs) before you start your undertaking, to make sure nobody else is working on it, and so we can discuss the best course of action. Other than that, just go ahead and fork our repo, make your changes and send us a pull request! :)
### License ### License

View File

@ -1,6 +1,6 @@
{ {
"name": "openpgp", "name": "openpgp",
"version": "4.2.2", "version": "4.3.0",
"license": "LGPL-3.0+", "license": "LGPL-3.0+",
"homepage": "https://openpgpjs.org/", "homepage": "https://openpgpjs.org/",
"authors": [ "authors": [

1358
dist/compat/openpgp.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
/*! OpenPGP.js v4.2.2 - 2018-12-07 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */ /*! OpenPGP.js v4.3.0 - 2018-12-17 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
!function(){return function e(n,r,t){function o(a,f){if(!r[a]){if(!n[a]){var u="function"==typeof require&&require;if(!f&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var s=r[a]={exports:{}};n[a][0].call(s.exports,function(e){return o(n[a][1][e]||e)},s,s.exports,e,n,r,t)}return r[a].exports}for(var i="function"==typeof require&&require,a=0;a<t.length;a++)o(t[a]);return o}}()({1:[function(e,n,r){self.window=self,importScripts("openpgp.min.js");var t=window.openpgp,o=[],i=6e4;function a(e){self.postMessage(e,t.util.getTransferables(e.data))}t.crypto.random.randomBuffer.init(i,function(){return o.length||self.postMessage({event:"request-seed",amount:i}),new Promise(function(e){o.push(e)})}),self.onmessage=function(e){var n,r=e.data||{};switch(r.event){case"configure":n=r.config,Object.keys(n).forEach(function(e){t.config[e]=n[e]});break;case"seed-random":!function(e){e instanceof Uint8Array||(e=new Uint8Array(e));t.crypto.random.randomBuffer.set(e)}(r.buf);var i=o;o=[];for(var f=0;f<i.length;f++)i[f]();break;default:!function(e,n,r){if("function"!=typeof t[n])return void a({id:e,event:"method-return",err:"Unknown Worker Event"});r=t.packet.clone.parseClonedPackets(r,n),t.util.restoreStreams(r),t[n](r).then(function(n){a({id:e,event:"method-return",data:t.packet.clone.clonePackets(n)})}).catch(function(n){t.util.print_debug_error(n),a({id:e,event:"method-return",err:n.message,stack:n.stack})})}(r.id,r.event,r.options||{})}}},{}]},{},[1]); !function(){return function e(n,r,t){function o(a,f){if(!r[a]){if(!n[a]){var u="function"==typeof require&&require;if(!f&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var s=r[a]={exports:{}};n[a][0].call(s.exports,function(e){return o(n[a][1][e]||e)},s,s.exports,e,n,r,t)}return r[a].exports}for(var i="function"==typeof require&&require,a=0;a<t.length;a++)o(t[a]);return o}}()({1:[function(e,n,r){self.window=self,importScripts("openpgp.min.js");var t=window.openpgp,o=[],i=6e4;function a(e){self.postMessage(e,t.util.getTransferables(e.data))}t.crypto.random.randomBuffer.init(i,function(){return o.length||self.postMessage({event:"request-seed",amount:i}),new Promise(function(e){o.push(e)})}),self.onmessage=function(e){var n,r=e.data||{};switch(r.event){case"configure":n=r.config,Object.keys(n).forEach(function(e){t.config[e]=n[e]});break;case"seed-random":!function(e){e instanceof Uint8Array||(e=new Uint8Array(e));t.crypto.random.randomBuffer.set(e)}(r.buf);var i=o;o=[];for(var f=0;f<i.length;f++)i[f]();break;default:!function(e,n,r){if("function"!=typeof t[n])return void a({id:e,event:"method-return",err:"Unknown Worker Event"});r=t.packet.clone.parseClonedPackets(r,n),t.util.restoreStreams(r),t[n](r).then(function(n){a({id:e,event:"method-return",data:t.packet.clone.clonePackets(n)})}).catch(function(n){t.util.print_debug_error(n),a({id:e,event:"method-return",err:n.message,stack:n.stack})})}(r.id,r.event,r.options||{})}}},{}]},{},[1]);

451
dist/openpgp.js vendored
View File

@ -20979,6 +20979,8 @@ process.chdir = function (dir) {
process.umask = function() { return 0; }; process.umask = function() { return 0; };
},{}],69:[function(require,module,exports){ },{}],69:[function(require,module,exports){
'use strict';
/* /*
node-bzip - a pure-javascript Node.JS module for decoding bzip2 data node-bzip - a pure-javascript Node.JS module for decoding bzip2 data
@ -21011,7 +21013,7 @@ Robert Sedgewick, and Jon L. Bentley.
var BITMASK = [0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF]; var BITMASK = [0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF];
// offset in bytes // offset in bytes
var BitReader = function(stream) { var BitReader = function BitReader(stream) {
this.stream = stream; this.stream = stream;
this.bitOffset = 0; this.bitOffset = 0;
this.curByte = 0; this.curByte = 0;
@ -21041,7 +21043,7 @@ BitReader.prototype.read = function(bits) {
} else { } else {
result <<= bits; result <<= bits;
var shift = remaining - bits; var shift = remaining - bits;
result |= (this.curByte & (BITMASK[bits] << shift)) >> shift; result |= (this.curByte & BITMASK[bits] << shift) >> shift;
this.bitOffset += bits; this.bitOffset += bits;
bits = 0; bits = 0;
} }
@ -21060,7 +21062,8 @@ BitReader.prototype.seek = function(pos) {
// reads 6 bytes worth of data using the read method // reads 6 bytes worth of data using the read method
BitReader.prototype.pi = function () { BitReader.prototype.pi = function () {
var buf = new Uint8Array(6), i; var buf = new Uint8Array(6),
i;
for (i = 0; i < buf.length; i++) { for (i = 0; i < buf.length; i++) {
buf[i] = this.read(8); buf[i] = this.read(8);
} }
@ -21074,6 +21077,8 @@ function bufToHex(buf) {
module.exports = BitReader; module.exports = BitReader;
},{}],70:[function(require,module,exports){ },{}],70:[function(require,module,exports){
"use strict";
/* CRC32, used in Bzip2 implementation. /* CRC32, used in Bzip2 implementation.
* This is a port of CRC32.java from the jbzip2 implementation at * This is a port of CRC32.java from the jbzip2 implementation at
* https://code.google.com/p/jbzip2 * https://code.google.com/p/jbzip2
@ -21104,47 +21109,14 @@ module.exports = BitReader;
* Copyright (c) 2013 C. Scott Ananian * Copyright (c) 2013 C. Scott Ananian
* with the same licensing terms as Matthew Francis' original implementation. * with the same licensing terms as Matthew Francis' original implementation.
*/ */
module.exports = (function() { module.exports = function () {
/** /**
* A static CRC lookup table * A static CRC lookup table
*/ */
var crc32Lookup = new Uint32Array([ var crc32Lookup = new Uint32Array([0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4]);
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
]);
var CRC32 = function() { var CRC32 = function CRC32() {
/** /**
* The current CRC * The current CRC
*/ */
@ -21154,7 +21126,7 @@ module.exports = (function() {
* @return The current CRC * @return The current CRC
*/ */
this.getCRC = function () { this.getCRC = function () {
return (~crc) >>> 0; // return an unsigned value return ~crc >>> 0; // return an unsigned value
}; };
/** /**
@ -21162,7 +21134,7 @@ module.exports = (function() {
* @param value The value to update the CRC with * @param value The value to update the CRC with
*/ */
this.updateCRC = function (value) { this.updateCRC = function (value) {
crc = (crc << 8) ^ crc32Lookup[((crc >>> 24) ^ value) & 0xff]; crc = crc << 8 ^ crc32Lookup[(crc >>> 24 ^ value) & 0xff];
}; };
/** /**
@ -21172,14 +21144,16 @@ module.exports = (function() {
*/ */
this.updateCRCRun = function (value, count) { this.updateCRCRun = function (value, count) {
while (count-- > 0) { while (count-- > 0) {
crc = (crc << 8) ^ crc32Lookup[((crc >>> 24) ^ value) & 0xff]; crc = crc << 8 ^ crc32Lookup[(crc >>> 24 ^ value) & 0xff];
} }
}; };
}; };
return CRC32; return CRC32;
})(); }();
},{}],71:[function(require,module,exports){ },{}],71:[function(require,module,exports){
'use strict';
/* /*
seek-bzip - a pure-javascript module for seeking within bzip2 data seek-bzip - a pure-javascript module for seeking within bzip2 data
@ -21228,8 +21202,9 @@ var GROUP_SIZE = 50;
var WHOLEPI = "314159265359"; var WHOLEPI = "314159265359";
var SQRTPI = "177245385090"; var SQRTPI = "177245385090";
var mtf = function(array, index) { var mtf = function mtf(array, index) {
var src = array[index], i; var src = array[index],
i;
for (i = index; i > 0; i--) { for (i = index; i > 0; i--) {
array[i] = array[i - 1]; array[i] = array[i - 1];
} }
@ -21257,15 +21232,17 @@ ErrorMessages[Err.DATA_ERROR] = "Data error";
ErrorMessages[Err.OUT_OF_MEMORY] = "Out of memory"; ErrorMessages[Err.OUT_OF_MEMORY] = "Out of memory";
ErrorMessages[Err.OBSOLETE_INPUT] = "Obsolete (pre 0.9.5) bzip format not supported."; ErrorMessages[Err.OBSOLETE_INPUT] = "Obsolete (pre 0.9.5) bzip format not supported.";
var _throw = function(status, optDetail) { var _throw = function _throw(status, optDetail) {
var msg = ErrorMessages[status] || 'unknown error'; var msg = ErrorMessages[status] || 'unknown error';
if (optDetail) { msg += ': '+optDetail; } if (optDetail) {
msg += ': ' + optDetail;
}
var e = new TypeError(msg); var e = new TypeError(msg);
e.errorCode = status; e.errorCode = status;
throw e; throw e;
}; };
var Bunzip = function(inputStream, outputStream) { var Bunzip = function Bunzip(inputStream, outputStream) {
this.writePos = this.writeCurrent = this.writeCount = 0; this.writePos = this.writeCurrent = this.writeCount = 0;
this._start_bunzip(inputStream, outputStream); this._start_bunzip(inputStream, outputStream);
@ -21283,13 +21260,10 @@ Bunzip.prototype._init_block = function() {
Bunzip.prototype._start_bunzip = function (inputStream, outputStream) { Bunzip.prototype._start_bunzip = function (inputStream, outputStream) {
/* Ensure that file starts with "BZh['1'-'9']." */ /* Ensure that file starts with "BZh['1'-'9']." */
var buf = new Uint8Array(4); var buf = new Uint8Array(4);
if (inputStream.read(buf, 0, 4) !== 4 || if (inputStream.read(buf, 0, 4) !== 4 || String.fromCharCode(buf[0], buf[1], buf[2]) !== 'BZh') _throw(Err.NOT_BZIP_DATA, 'bad magic');
String.fromCharCode(buf[0], buf[1], buf[2]) !== 'BZh')
_throw(Err.NOT_BZIP_DATA, 'bad magic');
var level = buf[3] - 0x30; var level = buf[3] - 0x30;
if (level < 1 || level > 9) if (level < 1 || level > 9) _throw(Err.NOT_BZIP_DATA, 'level out of range');
_throw(Err.NOT_BZIP_DATA, 'level out of range');
this.reader = new BitReader(inputStream); this.reader = new BitReader(inputStream);
@ -21307,61 +21281,53 @@ Bunzip.prototype._get_next_block = function() {
/* Read in header signature and CRC, then validate signature. /* Read in header signature and CRC, then validate signature.
(last block signature means CRC is for whole file, return now) */ (last block signature means CRC is for whole file, return now) */
var h = reader.pi(); var h = reader.pi();
if (h === SQRTPI) { // last block if (h === SQRTPI) {
// last block
return false; /* no more blocks */ return false; /* no more blocks */
} }
if (h !== WHOLEPI) if (h !== WHOLEPI) _throw(Err.NOT_BZIP_DATA);
_throw(Err.NOT_BZIP_DATA);
this.targetBlockCRC = reader.read(32) >>> 0; // (convert to unsigned) this.targetBlockCRC = reader.read(32) >>> 0; // (convert to unsigned)
this.streamCRC = (this.targetBlockCRC ^ this.streamCRC = (this.targetBlockCRC ^ (this.streamCRC << 1 | this.streamCRC >>> 31)) >>> 0;
((this.streamCRC << 1) | (this.streamCRC>>>31))) >>> 0;
/* We can add support for blockRandomised if anybody complains. There was /* We can add support for blockRandomised if anybody complains. There was
some code for this in busybox 1.0.0-pre3, but nobody ever noticed that some code for this in busybox 1.0.0-pre3, but nobody ever noticed that
it didn't actually work. */ it didn't actually work. */
if (reader.read(1)) if (reader.read(1)) _throw(Err.OBSOLETE_INPUT);
_throw(Err.OBSOLETE_INPUT);
var origPointer = reader.read(24); var origPointer = reader.read(24);
if (origPointer > this.dbufSize) if (origPointer > this.dbufSize) _throw(Err.DATA_ERROR, 'initial position out of bounds');
_throw(Err.DATA_ERROR, 'initial position out of bounds');
/* mapping table: if some byte values are never used (encoding things /* mapping table: if some byte values are never used (encoding things
like ascii text), the compression code removes the gaps to have fewer like ascii text), the compression code removes the gaps to have fewer
symbols to deal with, and writes a sparse bitfield indicating which symbols to deal with, and writes a sparse bitfield indicating which
values were present. We make a translation table to convert the symbols values were present. We make a translation table to convert the symbols
back to the corresponding bytes. */ back to the corresponding bytes. */
var t = reader.read(16); var t = reader.read(16);
var symToByte = new Uint8Array(256), symTotal = 0; var symToByte = new Uint8Array(256),
symTotal = 0;
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
if (t & (1 << (0xF - i))) { if (t & 1 << 0xF - i) {
var o = i * 16; var o = i * 16;
k = reader.read(16); k = reader.read(16);
for (j = 0; j < 16; j++) for (j = 0; j < 16; j++) if (k & 1 << 0xF - j) symToByte[symTotal++] = o + j;
if (k & (1 << (0xF - j)))
symToByte[symTotal++] = o + j;
} }
} }
/* How many different huffman coding groups does this block use? */ /* How many different huffman coding groups does this block use? */
var groupCount = reader.read(3); var groupCount = reader.read(3);
if (groupCount < MIN_GROUPS || groupCount > MAX_GROUPS) if (groupCount < MIN_GROUPS || groupCount > MAX_GROUPS) _throw(Err.DATA_ERROR);
_throw(Err.DATA_ERROR);
/* nSelectors: Every GROUP_SIZE many symbols we select a new huffman coding /* nSelectors: Every GROUP_SIZE many symbols we select a new huffman coding
group. Read in the group selector list, which is stored as MTF encoded group. Read in the group selector list, which is stored as MTF encoded
bit runs. (MTF=Move To Front, as each value is used it's moved to the bit runs. (MTF=Move To Front, as each value is used it's moved to the
start of the list.) */ start of the list.) */
var nSelectors = reader.read(15); var nSelectors = reader.read(15);
if (nSelectors === 0) if (nSelectors === 0) _throw(Err.DATA_ERROR);
_throw(Err.DATA_ERROR);
var mtfSymbol = new Uint8Array(256); var mtfSymbol = new Uint8Array(256);
for (i = 0; i < groupCount; i++) for (i = 0; i < groupCount; i++) mtfSymbol[i] = i;
mtfSymbol[i] = i;
var selectors = new Uint8Array(nSelectors); // was 32768... var selectors = new Uint8Array(nSelectors); // was 32768...
for (i = 0; i < nSelectors; i++) { for (i = 0; i < nSelectors; i++) {
/* Get next value */ /* Get next value */
for (j = 0; reader.read(1); j++) for (j = 0; reader.read(1); j++) if (j >= groupCount) _throw(Err.DATA_ERROR);
if (j >= groupCount) _throw(Err.DATA_ERROR);
/* Decode MTF to get the next selector */ /* Decode MTF to get the next selector */
selectors[i] = mtf(mtfSymbol, j); selectors[i] = mtf(mtfSymbol, j);
} }
@ -21369,9 +21335,11 @@ Bunzip.prototype._get_next_block = function() {
/* Read the huffman coding tables for each group, which code for symTotal /* Read the huffman coding tables for each group, which code for symTotal
literal symbols, plus two run symbols (RUNA, RUNB) */ literal symbols, plus two run symbols (RUNA, RUNB) */
var symCount = symTotal + 2; var symCount = symTotal + 2;
var groups = [], hufGroup; var groups = [],
hufGroup;
for (j = 0; j < groupCount; j++) { for (j = 0; j < groupCount; j++) {
var length = new Uint8Array(symCount), temp = new Uint16Array(MAX_HUFCODE_BITS + 1); var length = new Uint8Array(symCount),
temp = new Uint16Array(MAX_HUFCODE_BITS + 1);
/* Read huffman code lengths for each symbol. They're stored in /* Read huffman code lengths for each symbol. They're stored in
a way similar to mtf; record a starting value for the first symbol, a way similar to mtf; record a starting value for the first symbol,
and an offset from the previous value for everys symbol after that. */ and an offset from the previous value for everys symbol after that. */
@ -21381,12 +21349,8 @@ Bunzip.prototype._get_next_block = function() {
if (t < 1 || t > MAX_HUFCODE_BITS) _throw(Err.DATA_ERROR); if (t < 1 || t > MAX_HUFCODE_BITS) _throw(Err.DATA_ERROR);
/* If first bit is 0, stop. Else second bit indicates whether /* If first bit is 0, stop. Else second bit indicates whether
to increment or decrement the value. */ to increment or decrement the value. */
if(!reader.read(1)) if (!reader.read(1)) break;
break; if (!reader.read(1)) t++;else t--;
if(!reader.read(1))
t++;
else
t--;
} }
length[i] = t; length[i] = t;
} }
@ -21395,10 +21359,7 @@ Bunzip.prototype._get_next_block = function() {
var minLen, maxLen; var minLen, maxLen;
minLen = maxLen = length[0]; minLen = maxLen = length[0];
for (i = 1; i < symCount; i++) { for (i = 1; i < symCount; i++) {
if (length[i] > maxLen) if (length[i] > maxLen) maxLen = length[i];else if (length[i] < minLen) minLen = length[i];
maxLen = length[i];
else if (length[i] < minLen)
minLen = length[i];
} }
/* Calculate permute[], base[], and limit[] tables from length[]. /* Calculate permute[], base[], and limit[] tables from length[].
@ -21422,13 +21383,10 @@ Bunzip.prototype._get_next_block = function() {
var pp = 0; var pp = 0;
for (i = minLen; i <= maxLen; i++) { for (i = minLen; i <= maxLen; i++) {
temp[i] = hufGroup.limit[i] = 0; temp[i] = hufGroup.limit[i] = 0;
for (t = 0; t < symCount; t++) for (t = 0; t < symCount; t++) if (length[t] === i) hufGroup.permute[pp++] = t;
if (length[t] === i)
hufGroup.permute[pp++] = t;
} }
/* Count symbols coded for at each bit length */ /* Count symbols coded for at each bit length */
for (i = 0; i < symCount; i++) for (i = 0; i < symCount; i++) temp[length[i]]++;
temp[length[i]]++;
/* Calculate limit[] (the largest symbol-coding value at each bit /* Calculate limit[] (the largest symbol-coding value at each bit
* length, which is (previous limit<<1)+symbols at this level), and * length, which is (previous limit<<1)+symbols at this level), and
* base[] (number of symbols to ignore at each bit length, which is * base[] (number of symbols to ignore at each bit length, which is
@ -21457,31 +21415,38 @@ Bunzip.prototype._get_next_block = function() {
/* Initialize symbol occurrence counters and symbol Move To Front table */ /* Initialize symbol occurrence counters and symbol Move To Front table */
var byteCount = new Uint32Array(256); var byteCount = new Uint32Array(256);
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++) mtfSymbol[i] = i;
mtfSymbol[i] = i;
/* Loop through compressed symbols. */ /* Loop through compressed symbols. */
var runPos = 0, dbufCount = 0, selector = 0, uc; var runPos = 0,
dbufCount = 0,
selector = 0,
uc;
var dbuf = this.dbuf = new Uint32Array(this.dbufSize); var dbuf = this.dbuf = new Uint32Array(this.dbufSize);
symCount = 0; symCount = 0;
for (;;) { for (;;) {
/* Determine which huffman coding group to use. */ /* Determine which huffman coding group to use. */
if (!(symCount--)) { if (!symCount--) {
symCount = GROUP_SIZE - 1; symCount = GROUP_SIZE - 1;
if (selector >= nSelectors) { _throw(Err.DATA_ERROR); } if (selector >= nSelectors) {
_throw(Err.DATA_ERROR);
}
hufGroup = groups[selectors[selector++]]; hufGroup = groups[selectors[selector++]];
} }
/* Read next huffman-coded symbol. */ /* Read next huffman-coded symbol. */
i = hufGroup.minLen; i = hufGroup.minLen;
j = reader.read(i); j = reader.read(i);
for (;; i++) { for (;; i++) {
if (i > hufGroup.maxLen) { _throw(Err.DATA_ERROR); } if (i > hufGroup.maxLen) {
if (j <= hufGroup.limit[i]) _throw(Err.DATA_ERROR);
break; }
j = (j << 1) | reader.read(1); if (j <= hufGroup.limit[i]) break;
j = j << 1 | reader.read(1);
} }
/* Huffman decode value to get nextSym (with bounds checking) */ /* Huffman decode value to get nextSym (with bounds checking) */
j -= hufGroup.base[i]; j -= hufGroup.base[i];
if (j < 0 || j >= MAX_SYMBOLS) { _throw(Err.DATA_ERROR); } if (j < 0 || j >= MAX_SYMBOLS) {
_throw(Err.DATA_ERROR);
}
var nextSym = hufGroup.permute[j]; var nextSym = hufGroup.permute[j];
/* We have now decoded the symbol, which indicates either a new literal /* We have now decoded the symbol, which indicates either a new literal
byte, or a repeated run of the most recent literal byte. First, byte, or a repeated run of the most recent literal byte. First,
@ -21500,10 +21465,7 @@ Bunzip.prototype._get_next_block = function() {
the basic or 0/1 method (except all bits 0, which would use no the basic or 0/1 method (except all bits 0, which would use no
symbols, but a run of length 0 doesn't mean anything in this symbols, but a run of length 0 doesn't mean anything in this
context). Thus space is saved. */ context). Thus space is saved. */
if (nextSym === SYMBOL_RUNA) if (nextSym === SYMBOL_RUNA) t += runPos;else t += 2 * runPos;
t += runPos;
else
t += 2 * runPos;
runPos <<= 1; runPos <<= 1;
continue; continue;
} }
@ -21513,15 +21475,15 @@ Bunzip.prototype._get_next_block = function() {
literal used is the one at the head of the mtfSymbol array.) */ literal used is the one at the head of the mtfSymbol array.) */
if (runPos) { if (runPos) {
runPos = 0; runPos = 0;
if (dbufCount + t > this.dbufSize) { _throw(Err.DATA_ERROR); } if (dbufCount + t > this.dbufSize) {
_throw(Err.DATA_ERROR);
}
uc = symToByte[mtfSymbol[0]]; uc = symToByte[mtfSymbol[0]];
byteCount[uc] += t; byteCount[uc] += t;
while (t--) while (t--) dbuf[dbufCount++] = uc;
dbuf[dbufCount++] = uc;
} }
/* Is this the terminating symbol? */ /* Is this the terminating symbol? */
if (nextSym > symTotal) if (nextSym > symTotal) break;
break;
/* At this point, nextSym indicates a new literal character. Subtract /* At this point, nextSym indicates a new literal character. Subtract
one to get the position in the MTF array at which this literal is one to get the position in the MTF array at which this literal is
currently to be found. (Note that the result can't be -1 or 0, currently to be found. (Note that the result can't be -1 or 0,
@ -21529,7 +21491,9 @@ Bunzip.prototype._get_next_block = function() {
first symbol in the mtf array, position 0, would have been handled first symbol in the mtf array, position 0, would have been handled
as part of a run above. Therefore 1 unused mtf position minus as part of a run above. Therefore 1 unused mtf position minus
2 non-literal nextSym values equals -1.) */ 2 non-literal nextSym values equals -1.) */
if (dbufCount >= this.dbufSize) { _throw(Err.DATA_ERROR); } if (dbufCount >= this.dbufSize) {
_throw(Err.DATA_ERROR);
}
i = nextSym - 1; i = nextSym - 1;
uc = mtf(mtfSymbol, i); uc = mtf(mtfSymbol, i);
uc = symToByte[uc]; uc = symToByte[uc];
@ -21543,7 +21507,9 @@ Bunzip.prototype._get_next_block = function() {
Now undo the Burrows-Wheeler transform on dbuf. Now undo the Burrows-Wheeler transform on dbuf.
See http://dogma.net/markn/articles/bwt/bwt.htm See http://dogma.net/markn/articles/bwt/bwt.htm
*/ */
if (origPointer < 0 || origPointer >= dbufCount) { _throw(Err.DATA_ERROR); } if (origPointer < 0 || origPointer >= dbufCount) {
_throw(Err.DATA_ERROR);
}
/* Turn byteCount into cumulative occurrence counts of 0 to n-1. */ /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */
j = 0; j = 0;
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
@ -21554,16 +21520,18 @@ Bunzip.prototype._get_next_block = function() {
/* Figure out what order dbuf would be in if we sorted it. */ /* Figure out what order dbuf would be in if we sorted it. */
for (i = 0; i < dbufCount; i++) { for (i = 0; i < dbufCount; i++) {
uc = dbuf[i] & 0xff; uc = dbuf[i] & 0xff;
dbuf[byteCount[uc]] |= (i << 8); dbuf[byteCount[uc]] |= i << 8;
byteCount[uc]++; byteCount[uc]++;
} }
/* Decode first byte by hand to initialize "previous" byte. Note that it /* Decode first byte by hand to initialize "previous" byte. Note that it
doesn't get output, and if the first three characters are identical doesn't get output, and if the first three characters are identical
it doesn't qualify as a run (hence writeRunCountdown=5). */ it doesn't qualify as a run (hence writeRunCountdown=5). */
var pos = 0, current = 0, run = 0; var pos = 0,
current = 0,
run = 0;
if (dbufCount) { if (dbufCount) {
pos = dbuf[origPointer]; pos = dbuf[origPointer];
current = (pos & 0xff); current = pos & 0xff;
pos >>= 8; pos >>= 8;
run = -1; run = -1;
} }
@ -21586,11 +21554,16 @@ Bunzip.prototype._read_bunzip = function(outputBuffer, len) {
decoded, which results in this returning RETVAL_LAST_BLOCK, also decoded, which results in this returning RETVAL_LAST_BLOCK, also
equal to -1... Confusing, I'm returning 0 here to indicate no equal to -1... Confusing, I'm returning 0 here to indicate no
bytes written into the buffer */ bytes written into the buffer */
if (this.writeCount < 0) { return 0; } if (this.writeCount < 0) {
return 0;
}
var gotcount = 0; var gotcount = 0;
var dbuf = this.dbuf, pos = this.writePos, current = this.writeCurrent; var dbuf = this.dbuf,
var dbufCount = this.writeCount, outputsize = this.outputsize; pos = this.writePos,
current = this.writeCurrent;
var dbufCount = this.writeCount,
outputsize = this.outputsize;
var run = this.writeRun; var run = this.writeRun;
while (dbufCount) { while (dbufCount) {
@ -21612,33 +21585,38 @@ Bunzip.prototype._read_bunzip = function(outputBuffer, len) {
this.outputStream.writeByte(outbyte); this.outputStream.writeByte(outbyte);
this.nextoutput++; this.nextoutput++;
} }
if (current != previous) if (current != previous) run = 0;
run = 0;
} }
this.writeCount = dbufCount; this.writeCount = dbufCount;
// check CRC // check CRC
if (this.blockCRC.getCRC() !== this.targetBlockCRC) { if (this.blockCRC.getCRC() !== this.targetBlockCRC) {
_throw(Err.DATA_ERROR, "Bad block CRC "+ _throw(Err.DATA_ERROR, "Bad block CRC " + "(got " + this.blockCRC.getCRC().toString(16) + " expected " + this.targetBlockCRC.toString(16) + ")");
"(got "+this.blockCRC.getCRC().toString(16)+
" expected "+this.targetBlockCRC.toString(16)+")");
} }
return this.nextoutput; return this.nextoutput;
}; };
var coerceInputStream = function(input) { var coerceInputStream = function coerceInputStream(input) {
if ('readByte' in input) { return input; } if ('readByte' in input) {
return input;
}
var inputStream = new Stream(); var inputStream = new Stream();
inputStream.pos = 0; inputStream.pos = 0;
inputStream.readByte = function() { return input[this.pos++]; }; inputStream.readByte = function () {
inputStream.seek = function(pos) { this.pos = pos; }; return input[this.pos++];
inputStream.eof = function() { return this.pos >= input.length; }; };
inputStream.seek = function (pos) {
this.pos = pos;
};
inputStream.eof = function () {
return this.pos >= input.length;
};
return inputStream; return inputStream;
}; };
var coerceOutputStream = function(output) { var coerceOutputStream = function coerceOutputStream(output) {
var outputStream = new Stream(); var outputStream = new Stream();
var resizeOk = true; var resizeOk = true;
if (output) { if (output) {
if (typeof(output)==='number') { if (typeof output === 'number') {
outputStream.buffer = new Uint8Array(output); outputStream.buffer = new Uint8Array(output);
resizeOk = false; resizeOk = false;
} else if ('writeByte' in output) { } else if ('writeByte' in output) {
@ -21662,8 +21640,7 @@ var coerceOutputStream = function(output) {
outputStream.getBuffer = function () { outputStream.getBuffer = function () {
// trim buffer // trim buffer
if (this.pos !== this.buffer.length) { if (this.pos !== this.buffer.length) {
if (!resizeOk) if (!resizeOk) throw new TypeError('outputsize does not match decoded input');
throw new TypeError('outputsize does not match decoded input');
var newBuffer = new Uint8Array(this.pos); var newBuffer = new Uint8Array(this.pos);
newBuffer.set(this.buffer.subarray(0, this.pos)); newBuffer.set(this.buffer.subarray(0, this.pos));
this.buffer = newBuffer; this.buffer = newBuffer;
@ -21691,20 +21668,15 @@ Bunzip.decode = function(input, output, multistream) {
} else { } else {
var targetStreamCRC = bz.reader.read(32) >>> 0; // (convert to unsigned) var targetStreamCRC = bz.reader.read(32) >>> 0; // (convert to unsigned)
if (targetStreamCRC !== bz.streamCRC) { if (targetStreamCRC !== bz.streamCRC) {
_throw(Err.DATA_ERROR, "Bad stream CRC "+ _throw(Err.DATA_ERROR, "Bad stream CRC " + "(got " + bz.streamCRC.toString(16) + " expected " + targetStreamCRC.toString(16) + ")");
"(got "+bz.streamCRC.toString(16)+
" expected "+targetStreamCRC.toString(16)+")");
} }
if (multistream && if (multistream && 'eof' in inputStream && !inputStream.eof()) {
'eof' in inputStream &&
!inputStream.eof()) {
// note that start_bunzip will also resync the bit reader to next byte // note that start_bunzip will also resync the bit reader to next byte
bz._start_bunzip(inputStream, outputStream); bz._start_bunzip(inputStream, outputStream);
} else break; } else break;
} }
} }
if ('getBuffer' in outputStream) if ('getBuffer' in outputStream) return outputStream.getBuffer();
return outputStream.getBuffer();
}; };
Bunzip.decodeBlock = function (input, pos, output) { Bunzip.decodeBlock = function (input, pos, output) {
// make a stream from a buffer, if necessary // make a stream from a buffer, if necessary
@ -21725,8 +21697,7 @@ Bunzip.decodeBlock = function(input, pos, output) {
bz._read_bunzip(); bz._read_bunzip();
// XXX keep writing? // XXX keep writing?
} }
if ('getBuffer' in outputStream) if ('getBuffer' in outputStream) return outputStream.getBuffer();
return outputStream.getBuffer();
}; };
/* Reads bzip2 file from stream or buffer `input`, and invoke /* Reads bzip2 file from stream or buffer `input`, and invoke
* `callback(position, size)` once for each bzip2 block, * `callback(position, size)` once for each bzip2 block,
@ -21746,7 +21717,9 @@ Bunzip.table = function(input, callback, multistream) {
} }
var outputStream = new Stream(); var outputStream = new Stream();
outputStream.pos = 0; outputStream.pos = 0;
outputStream.writeByte = function() { this.pos++; }; outputStream.writeByte = function () {
this.pos++;
};
var bz = new Bunzip(inputStream, outputStream); var bz = new Bunzip(inputStream, outputStream);
var blockSize = bz.dbufSize; var blockSize = bz.dbufSize;
@ -21754,7 +21727,9 @@ Bunzip.table = function(input, callback, multistream) {
if ('eof' in inputStream && inputStream.eof()) break; if ('eof' in inputStream && inputStream.eof()) break;
var position = inputStream.pos * 8 + bz.reader.bitOffset; var position = inputStream.pos * 8 + bz.reader.bitOffset;
if (bz.reader.hasByte) { position -= 8; } if (bz.reader.hasByte) {
position -= 8;
}
if (bz._init_block()) { if (bz._init_block()) {
var start = outputStream.pos; var start = outputStream.pos;
@ -21762,13 +21737,10 @@ Bunzip.table = function(input, callback, multistream) {
callback(position, outputStream.pos - start); callback(position, outputStream.pos - start);
} else { } else {
var crc = bz.reader.read(32); // (but we ignore the crc) var crc = bz.reader.read(32); // (but we ignore the crc)
if (multistream && if (multistream && 'eof' in inputStream && !inputStream.eof()) {
'eof' in inputStream &&
!inputStream.eof()) {
// note that start_bunzip will also resync the bit reader to next byte // note that start_bunzip will also resync the bit reader to next byte
bz._start_bunzip(inputStream, outputStream); bz._start_bunzip(inputStream, outputStream);
console.assert(bz.dbufSize === blockSize, console.assert(bz.dbufSize === blockSize, "shouldn't change block size within multistream file");
"shouldn't change block size within multistream file");
} else break; } else break;
} }
} }
@ -21782,9 +21754,10 @@ Bunzip.license = pjson.license;
module.exports = Bunzip; module.exports = Bunzip;
},{"../package.json":73,"./bitreader":69,"./crc32":70,"./stream":72}],72:[function(require,module,exports){ },{"../package.json":73,"./bitreader":69,"./crc32":70,"./stream":72}],72:[function(require,module,exports){
"use strict";
/* very simple input/output stream interface */ /* very simple input/output stream interface */
var Stream = function() { var Stream = function Stream() {};
};
// input streams ////////////// // input streams //////////////
/** Returns the next byte, or -1 for EOF. */ /** Returns the next byte, or -1 for EOF. */
@ -21797,8 +21770,9 @@ Stream.prototype.read = function(buffer, bufOffset, length) {
var bytesRead = 0; var bytesRead = 0;
while (bytesRead < length) { while (bytesRead < length) {
var c = this.readByte(); var c = this.readByte();
if (c < 0) { // EOF if (c < 0) {
return (bytesRead===0) ? -1 : bytesRead; // EOF
return bytesRead === 0 ? -1 : bytesRead;
} }
buffer[bufOffset++] = c; buffer[bufOffset++] = c;
bytesRead++; bytesRead++;
@ -21820,8 +21794,7 @@ Stream.prototype.write = function(buffer, bufOffset, length) {
} }
return length; return length;
}; };
Stream.prototype.flush = function() { Stream.prototype.flush = function () {};
};
module.exports = Stream; module.exports = Stream;
@ -23782,7 +23755,7 @@ exports.default = {
* @memberof module:config * @memberof module:config
* @property {String} versionstring A version string to be included in armored messages * @property {String} versionstring A version string to be included in armored messages
*/ */
versionstring: "OpenPGP.js v4.2.2", versionstring: "OpenPGP.js v4.3.0",
/** /**
* @memberof module:config * @memberof module:config
* @property {String} commentstring A comment string to be included in armored messages * @property {String} commentstring A comment string to be included in armored messages
@ -24184,7 +24157,7 @@ exports.default = {
cipherfn = new _cipher2.default[cipherfn](key); cipherfn = new _cipher2.default[cipherfn](key);
const block_size = cipherfn.blockSize; const block_size = cipherfn.blockSize;
let iblock = new Uint8Array(block_size); const iblock = new Uint8Array(block_size);
let ablock = new Uint8Array(block_size); let ablock = new Uint8Array(block_size);
let i; let i;
@ -24192,24 +24165,6 @@ exports.default = {
let n; let n;
let text = new Uint8Array(ciphertext.length - block_size); let text = new Uint8Array(ciphertext.length - block_size);
// initialisation vector
for (i = 0; i < block_size; i++) {
iblock[i] = 0;
}
iblock = cipherfn.encrypt(iblock);
for (i = 0; i < block_size; i++) {
ablock[i] = ciphertext[i];
iblock[i] ^= ablock[i];
}
ablock = cipherfn.encrypt(ablock);
// test check octets
if (iblock[block_size - 2] !== (ablock[0] ^ ciphertext[block_size]) || iblock[block_size - 1] !== (ablock[1] ^ ciphertext[block_size + 1])) {
throw new Error('CFB decrypt: invalid key');
}
/* RFC4880: Tag 18 and Resync: /* RFC4880: Tag 18 and Resync:
* [...] Unlike the Symmetrically Encrypted Data Packet, no * [...] Unlike the Symmetrically Encrypted Data Packet, no
* special CFB resynchronization is done after encrypting this prefix * special CFB resynchronization is done after encrypting this prefix
@ -25394,6 +25349,7 @@ exports.default = {
* @returns {Object} * @returns {Object}
*/ */
tripledes: _des2.default.TripleDES, tripledes: _des2.default.TripleDES,
'3des': _des2.default.TripleDES,
/** /**
* CAST-128 Block Cipher (ID 3) * CAST-128 Block Cipher (ID 3)
* @function * @function
@ -25812,7 +25768,7 @@ function rightXorMut(data, padding) {
function pad(data, padding, padding2) { function pad(data, padding, padding2) {
// if |M| in {n, 2n, 3n, ...} // if |M| in {n, 2n, 3n, ...}
if (data.length % blockLength === 0) { if (data.length && data.length % blockLength === 0) {
// then return M xor→ B, // then return M xor→ B,
return rightXorMut(data, padding); return rightXorMut(data, padding);
} }
@ -28017,7 +27973,11 @@ Curve.prototype.keyFromSecret = function (secret) {
}; };
Curve.prototype.keyFromPublic = function (pub) { Curve.prototype.keyFromPublic = function (pub) {
return new _key2.default(this, { pub: pub }); const keyPair = new _key2.default(this, { pub: pub });
if (this.keyType === _enums2.default.publicKey.ecdsa && keyPair.keyPair.validate().result !== true) {
throw new Error('Invalid elliptic public key');
}
return keyPair;
}; };
Curve.prototype.genKeyPair = async function () { Curve.prototype.genKeyPair = async function () {
@ -32467,6 +32427,22 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options) {
packetlist.push(secretKeyPacket); packetlist.push(secretKeyPacket);
await Promise.all(options.userIds.map(async function (userId, index) { await Promise.all(options.userIds.map(async function (userId, index) {
function createdPreferredAlgos(algos, configAlgo) {
if (configAlgo) {
// Not `uncompressed` / `plaintext`
const configIndex = algos.indexOf(configAlgo);
if (configIndex >= 1) {
// If it is included and not in first place,
algos.splice(configIndex, 1); // remove it.
}
if (configIndex !== 0) {
// If it was included and not in first place, or wasn't included,
algos.unshift(configAlgo); // add it to the front.
}
}
return algos;
}
const userIdPacket = new _packet2.default.Userid(); const userIdPacket = new _packet2.default.Userid();
userIdPacket.format(userId); userIdPacket.format(userId);
@ -32478,26 +32454,16 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options) {
signaturePacket.publicKeyAlgorithm = secretKeyPacket.algorithm; signaturePacket.publicKeyAlgorithm = secretKeyPacket.algorithm;
signaturePacket.hashAlgorithm = await getPreferredHashAlgo(null, secretKeyPacket); signaturePacket.hashAlgorithm = await getPreferredHashAlgo(null, secretKeyPacket);
signaturePacket.keyFlags = [_enums2.default.keyFlags.certify_keys | _enums2.default.keyFlags.sign_data]; signaturePacket.keyFlags = [_enums2.default.keyFlags.certify_keys | _enums2.default.keyFlags.sign_data];
signaturePacket.preferredSymmetricAlgorithms = []; 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)
signaturePacket.preferredSymmetricAlgorithms.push(_enums2.default.symmetric.aes256); _enums2.default.symmetric.aes256, _enums2.default.symmetric.aes128, _enums2.default.symmetric.aes192, _enums2.default.symmetric.cast5, _enums2.default.symmetric.tripledes], _config2.default.encryption_cipher);
signaturePacket.preferredSymmetricAlgorithms.push(_enums2.default.symmetric.aes128);
signaturePacket.preferredSymmetricAlgorithms.push(_enums2.default.symmetric.aes192);
signaturePacket.preferredSymmetricAlgorithms.push(_enums2.default.symmetric.cast5);
signaturePacket.preferredSymmetricAlgorithms.push(_enums2.default.symmetric.tripledes);
if (_config2.default.aead_protect && _config2.default.aead_protect_version === 4) { if (_config2.default.aead_protect && _config2.default.aead_protect_version === 4) {
signaturePacket.preferredAeadAlgorithms = []; signaturePacket.preferredAeadAlgorithms = createdPreferredAlgos([_enums2.default.aead.eax, _enums2.default.aead.ocb], _config2.default.aead_mode);
signaturePacket.preferredAeadAlgorithms.push(_enums2.default.aead.eax);
signaturePacket.preferredAeadAlgorithms.push(_enums2.default.aead.ocb);
} }
signaturePacket.preferredHashAlgorithms = []; signaturePacket.preferredHashAlgorithms = createdPreferredAlgos([
// prefer fast asm.js implementations (SHA-256). SHA-1 will not be secure much longer...move to bottom of list // prefer fast asm.js implementations (SHA-256). SHA-1 will not be secure much longer...move to bottom of list
signaturePacket.preferredHashAlgorithms.push(_enums2.default.hash.sha256); _enums2.default.hash.sha256, _enums2.default.hash.sha512, _enums2.default.hash.sha1], _config2.default.prefer_hash_algorithm);
signaturePacket.preferredHashAlgorithms.push(_enums2.default.hash.sha512); signaturePacket.preferredCompressionAlgorithms = createdPreferredAlgos([_enums2.default.compression.zlib, _enums2.default.compression.zip], _config2.default.compression);
signaturePacket.preferredHashAlgorithms.push(_enums2.default.hash.sha1);
signaturePacket.preferredCompressionAlgorithms = [];
signaturePacket.preferredCompressionAlgorithms.push(_enums2.default.compression.zlib);
signaturePacket.preferredCompressionAlgorithms.push(_enums2.default.compression.zip);
if (index === 0) { if (index === 0) {
signaturePacket.isPrimaryUserID = true; signaturePacket.isPrimaryUserID = true;
} }
@ -32701,7 +32667,7 @@ async function getPreferredHashAlgo(key, keyPacket, date = new Date(), userId =
*/ */
async function getPreferredAlgo(type, keys, date = new Date(), userId = {}) { async function getPreferredAlgo(type, keys, date = new Date(), userId = {}) {
const prefProperty = type === 'symmetric' ? 'preferredSymmetricAlgorithms' : 'preferredAeadAlgorithms'; const prefProperty = type === 'symmetric' ? 'preferredSymmetricAlgorithms' : 'preferredAeadAlgorithms';
const defaultAlgo = type === 'symmetric' ? _config2.default.encryption_cipher : _config2.default.aead_mode; const defaultAlgo = type === 'symmetric' ? _enums2.default.symmetric.aes128 : _enums2.default.aead.eax;
const prioMap = {}; const prioMap = {};
await Promise.all(keys.map(async function (key) { await Promise.all(keys.map(async function (key) {
const primaryUser = await key.getPrimaryUser(date, userId); const primaryUser = await key.getPrimaryUser(date, userId);
@ -33343,6 +33309,7 @@ Message.prototype.decrypt = async function (privateKeys, passwords, sessionKeys,
Message.prototype.decryptSessionKeys = async function (privateKeys, passwords) { Message.prototype.decryptSessionKeys = async function (privateKeys, passwords) {
let keyPackets = []; let keyPackets = [];
let exception;
if (passwords) { if (passwords) {
const symESKeyPacketlist = this.packets.filterByTag(_enums2.default.packet.symEncryptedSessionKey); const symESKeyPacketlist = this.packets.filterByTag(_enums2.default.packet.symEncryptedSessionKey);
if (!symESKeyPacketlist) { if (!symESKeyPacketlist) {
@ -33371,10 +33338,17 @@ Message.prototype.decryptSessionKeys = async function (privateKeys, passwords) {
throw new Error('No public key encrypted session key packet found.'); throw new Error('No public key encrypted session key packet found.');
} }
await Promise.all(pkESKeyPacketlist.map(async function (keyPacket) { await Promise.all(pkESKeyPacketlist.map(async function (keyPacket) {
const privateKeyPackets = new _packet2.default.List(); await Promise.all(privateKeys.map(async function (privateKey) {
privateKeys.forEach(privateKey => { const primaryUser = await privateKey.getPrimaryUser(); // TODO: Pass userId from somewhere.
privateKeyPackets.concat(privateKey.getKeys(keyPacket.publicKeyId).map(key => key.keyPacket)); let algos = [_enums2.default.symmetric.aes256, // Old OpenPGP.js default fallback
}); _enums2.default.symmetric.aes128, // RFC4880bis fallback
_enums2.default.symmetric.tripledes // RFC4880 fallback
];
if (primaryUser && primaryUser.selfCertification.preferredSymmetricAlgorithms) {
algos = algos.concat(primaryUser.selfCertification.preferredSymmetricAlgorithms);
}
const privateKeyPackets = privateKey.getKeys(keyPacket.publicKeyId).map(key => key.keyPacket);
await Promise.all(privateKeyPackets.map(async function (privateKeyPacket) { await Promise.all(privateKeyPackets.map(async function (privateKeyPacket) {
if (!privateKeyPacket) { if (!privateKeyPacket) {
return; return;
@ -33384,11 +33358,16 @@ Message.prototype.decryptSessionKeys = async function (privateKeys, passwords) {
} }
try { try {
await keyPacket.decrypt(privateKeyPacket); await keyPacket.decrypt(privateKeyPacket);
if (!algos.includes(_enums2.default.write(_enums2.default.symmetric, keyPacket.sessionKeyAlgorithm))) {
throw new Error('A non-preferred symmetric algorithm was used.');
}
keyPackets.push(keyPacket); keyPackets.push(keyPacket);
} catch (err) { } catch (err) {
_util2.default.print_debug_error(err); _util2.default.print_debug_error(err);
exception = err;
} }
})); }));
}));
_webStreamTools2.default.cancel(keyPacket.encrypted); // Don't keep copy of encrypted data in memory. _webStreamTools2.default.cancel(keyPacket.encrypted); // Don't keep copy of encrypted data in memory.
keyPacket.encrypted = null; keyPacket.encrypted = null;
})); }));
@ -33412,7 +33391,7 @@ Message.prototype.decryptSessionKeys = async function (privateKeys, passwords) {
return keyPackets.map(packet => ({ data: packet.sessionKey, algorithm: packet.sessionKeyAlgorithm })); return keyPackets.map(packet => ({ data: packet.sessionKey, algorithm: packet.sessionKeyAlgorithm }));
} }
throw new Error('Session key decryption failed.'); throw exception || new Error('Session key decryption failed.');
}; };
/** /**
@ -33420,7 +33399,8 @@ Message.prototype.decryptSessionKeys = async function (privateKeys, passwords) {
* @returns {(Uint8Array|null)} literal body of the message as Uint8Array * @returns {(Uint8Array|null)} literal body of the message as Uint8Array
*/ */
Message.prototype.getLiteralData = function () { Message.prototype.getLiteralData = function () {
const literal = this.packets.findPacket(_enums2.default.packet.literal); const msg = this.unwrapCompressed();
const literal = msg.packets.findPacket(_enums2.default.packet.literal);
return literal && literal.getBytes() || null; return literal && literal.getBytes() || null;
}; };
@ -33429,7 +33409,8 @@ Message.prototype.getLiteralData = function () {
* @returns {(String|null)} filename of literal data packet as string * @returns {(String|null)} filename of literal data packet as string
*/ */
Message.prototype.getFilename = function () { Message.prototype.getFilename = function () {
const literal = this.packets.findPacket(_enums2.default.packet.literal); const msg = this.unwrapCompressed();
const literal = msg.packets.findPacket(_enums2.default.packet.literal);
return literal && literal.getFilename() || null; return literal && literal.getFilename() || null;
}; };
@ -33438,7 +33419,8 @@ Message.prototype.getFilename = function () {
* @returns {(String|null)} literal body of the message interpreted as text * @returns {(String|null)} literal body of the message interpreted as text
*/ */
Message.prototype.getText = function () { Message.prototype.getText = function () {
const literal = this.packets.findPacket(_enums2.default.packet.literal); const msg = this.unwrapCompressed();
const literal = msg.packets.findPacket(_enums2.default.packet.literal);
if (literal) { if (literal) {
return literal.getText(); return literal.getText();
} }
@ -33802,25 +33784,38 @@ Message.prototype.verifyDetached = function (signature, keys, date = new Date())
* @async * @async
*/ */
async function createVerificationObject(signature, literalDataList, keys, date = new Date()) { async function createVerificationObject(signature, literalDataList, keys, date = new Date()) {
let keyPacket = null; let primaryKey = 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
const result = await key.getSigningKey(signature.issuerKeyId, date); const result = await key.getSigningKey(signature.issuerKeyId, null);
if (result) { if (result) {
keyPacket = result.keyPacket; primaryKey = key;
signingKey = result;
} }
})); }));
const signaturePacket = signature.correspondingSig || signature;
const verifiedSig = { const verifiedSig = {
keyid: signature.issuerKeyId, keyid: signature.issuerKeyId,
verified: keyPacket ? signature.verify(keyPacket, signature.signatureType, literalDataList[0]) : Promise.resolve(null) verified: (async () => {
}; if (!signingKey) {
return null;
verifiedSig.signature = Promise.resolve(signature.correspondingSig || signature).then(signature => { }
const verified = await signature.verify(signingKey.keyPacket, signature.signatureType, literalDataList[0]);
const sig = await signaturePacket;
if (sig.isExpired(date) || !(sig.created >= signingKey.getCreationTime() && sig.created < (await (signingKey === primaryKey ? signingKey.getExpirationTime() : signingKey.getExpirationTime(primaryKey, date))))) {
return null;
}
return verified;
})(),
signature: (async () => {
const sig = await signaturePacket;
const packetlist = new _packet2.default.List(); const packetlist = new _packet2.default.List();
packetlist.push(signature); packetlist.push(sig);
return new _signature.Signature(packetlist); return new _signature.Signature(packetlist);
}); })()
};
// Mark potential promise rejections as "handled". This is needed because in // Mark potential promise rejections as "handled". This is needed because in
// some cases, we reject them before the user has a reasonable chance to // some cases, we reject them before the user has a reasonable chance to
@ -36307,24 +36302,10 @@ List.prototype.filterByTag = function (...args) {
/** /**
* Traverses packet tree and returns first matching packet * Traverses packet tree and returns first matching packet
* @param {module:enums.packet} type The packet type * @param {module:enums.packet} type The packet type
* @returns {module:packet/packet|null} * @returns {module:packet/packet|undefined}
*/ */
List.prototype.findPacket = function (type) { List.prototype.findPacket = function (type) {
const packetlist = this.filterByTag(type); return this.find(packet => packet.tag === type);
if (packetlist.length) {
return packetlist[0];
}
let found = null;
for (let i = 0; i < this.length; i++) {
if (this[i].packets.length) {
found = this[i].packets.findPacket(type);
if (found) {
return found;
}
}
}
return null;
}; };
/** /**
@ -36473,6 +36454,11 @@ function PublicKey(date = new Date()) {
* @type {Date} * @type {Date}
*/ */
this.created = _util2.default.normalizeDate(date); this.created = _util2.default.normalizeDate(date);
/**
* Public key algorithm.
* @type {String}
*/
this.algorithm = null;
/** /**
* Algorithm specific params * Algorithm specific params
* @type {Array<Object>} * @type {Array<Object>}
@ -36736,7 +36722,10 @@ function PublicKeyEncryptedSessionKey() {
this.version = 3; this.version = 3;
this.publicKeyId = new _keyid2.default(); this.publicKeyId = new _keyid2.default();
this.publicKeyAlgorithm = null;
this.sessionKey = null; this.sessionKey = null;
this.sessionKeyAlgorithm = null;
/** @type {Array<module:type/mpi>} */ /** @type {Array<module:type/mpi>} */
this.encrypted = []; this.encrypted = [];
@ -36857,7 +36846,7 @@ PublicKeyEncryptedSessionKey.prototype.decrypt = async function (key) {
key = _util2.default.str_to_Uint8Array(decoded.substring(1, decoded.length - 2)); key = _util2.default.str_to_Uint8Array(decoded.substring(1, decoded.length - 2));
if (!_util2.default.equalsUint8Array(checksum, _util2.default.write_checksum(key))) { if (!_util2.default.equalsUint8Array(checksum, _util2.default.write_checksum(key))) {
throw new Error('Checksum mismatch'); throw new Error('Decryption error');
} else { } else {
this.sessionKey = key; this.sessionKey = key;
this.sessionKeyAlgorithm = _enums2.default.read(_enums2.default.symmetric, decoded.charCodeAt(0)); this.sessionKeyAlgorithm = _enums2.default.read(_enums2.default.symmetric, decoded.charCodeAt(0));
@ -38056,6 +38045,10 @@ Signature.prototype.verify = async function (key, signatureType, data) {
const publicKeyAlgorithm = _enums2.default.write(_enums2.default.publicKey, this.publicKeyAlgorithm); const publicKeyAlgorithm = _enums2.default.write(_enums2.default.publicKey, this.publicKeyAlgorithm);
const hashAlgorithm = _enums2.default.write(_enums2.default.hash, this.hashAlgorithm); const hashAlgorithm = _enums2.default.write(_enums2.default.hash, this.hashAlgorithm);
if (publicKeyAlgorithm !== _enums2.default.write(_enums2.default.publicKey, key.algorithm)) {
throw new Error('Public key algorithm used to sign signature does not match issuer key algorithm.');
}
let toHash; let toHash;
let hash; let hash;
if (this.hashed) { if (this.hashed) {

4
dist/openpgp.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
/*! OpenPGP.js v4.2.2 - 2018-12-07 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */ /*! OpenPGP.js v4.3.0 - 2018-12-17 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
!function(){return function e(n,r,t){function o(a,f){if(!r[a]){if(!n[a]){var u="function"==typeof require&&require;if(!f&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var s=r[a]={exports:{}};n[a][0].call(s.exports,function(e){return o(n[a][1][e]||e)},s,s.exports,e,n,r,t)}return r[a].exports}for(var i="function"==typeof require&&require,a=0;a<t.length;a++)o(t[a]);return o}}()({1:[function(e,n,r){self.window=self,importScripts("openpgp.min.js");var t=window.openpgp,o=[],i=6e4;function a(e){self.postMessage(e,t.util.getTransferables(e.data))}t.crypto.random.randomBuffer.init(i,function(){return o.length||self.postMessage({event:"request-seed",amount:i}),new Promise(function(e){o.push(e)})}),self.onmessage=function(e){var n,r=e.data||{};switch(r.event){case"configure":n=r.config,Object.keys(n).forEach(function(e){t.config[e]=n[e]});break;case"seed-random":!function(e){e instanceof Uint8Array||(e=new Uint8Array(e));t.crypto.random.randomBuffer.set(e)}(r.buf);var i=o;o=[];for(var f=0;f<i.length;f++)i[f]();break;default:!function(e,n,r){if("function"!=typeof t[n])return void a({id:e,event:"method-return",err:"Unknown Worker Event"});r=t.packet.clone.parseClonedPackets(r,n),t.util.restoreStreams(r),t[n](r).then(function(n){a({id:e,event:"method-return",data:t.packet.clone.clonePackets(n)})}).catch(function(n){t.util.print_debug_error(n),a({id:e,event:"method-return",err:n.message,stack:n.stack})})}(r.id,r.event,r.options||{})}}},{}]},{},[1]); !function(){return function e(n,r,t){function o(a,f){if(!r[a]){if(!n[a]){var u="function"==typeof require&&require;if(!f&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var s=r[a]={exports:{}};n[a][0].call(s.exports,function(e){return o(n[a][1][e]||e)},s,s.exports,e,n,r,t)}return r[a].exports}for(var i="function"==typeof require&&require,a=0;a<t.length;a++)o(t[a]);return o}}()({1:[function(e,n,r){self.window=self,importScripts("openpgp.min.js");var t=window.openpgp,o=[],i=6e4;function a(e){self.postMessage(e,t.util.getTransferables(e.data))}t.crypto.random.randomBuffer.init(i,function(){return o.length||self.postMessage({event:"request-seed",amount:i}),new Promise(function(e){o.push(e)})}),self.onmessage=function(e){var n,r=e.data||{};switch(r.event){case"configure":n=r.config,Object.keys(n).forEach(function(e){t.config[e]=n[e]});break;case"seed-random":!function(e){e instanceof Uint8Array||(e=new Uint8Array(e));t.crypto.random.randomBuffer.set(e)}(r.buf);var i=o;o=[];for(var f=0;f<i.length;f++)i[f]();break;default:!function(e,n,r){if("function"!=typeof t[n])return void a({id:e,event:"method-return",err:"Unknown Worker Event"});r=t.packet.clone.parseClonedPackets(r,n),t.util.restoreStreams(r),t[n](r).then(function(n){a({id:e,event:"method-return",data:t.packet.clone.clonePackets(n)})}).catch(function(n){t.util.print_debug_error(n),a({id:e,event:"method-return",err:n.message,stack:n.stack})})}(r.id,r.event,r.options||{})}}},{}]},{},[1]);

4
npm-shrinkwrap.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "openpgp", "name": "openpgp",
"version": "4.2.2", "version": "4.3.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -7417,7 +7417,7 @@
} }
}, },
"web-stream-tools": { "web-stream-tools": {
"version": "github:openpgpjs/web-stream-tools#9ab800d46add161db496506d67338202ad0114ce", "version": "github:openpgpjs/web-stream-tools#84a497715c9df271a673f8616318264ab42ab3cc",
"from": "github:openpgpjs/web-stream-tools" "from": "github:openpgpjs/web-stream-tools"
}, },
"websocket-driver": { "websocket-driver": {

View File

@ -1,7 +1,7 @@
{ {
"name": "openpgp", "name": "openpgp",
"description": "OpenPGP.js is a Javascript implementation of the OpenPGP protocol. This is defined in RFC 4880.", "description": "OpenPGP.js is a Javascript implementation of the OpenPGP protocol. This is defined in RFC 4880.",
"version": "4.2.2", "version": "4.3.0",
"license": "LGPL-3.0+", "license": "LGPL-3.0+",
"homepage": "https://openpgpjs.org/", "homepage": "https://openpgpjs.org/",
"engines": { "engines": {

View File

@ -68,12 +68,12 @@ CleartextMessage.prototype.getSigningKeyIds = function() {
* @param {Array<module:key.Key>} privateKeys private keys with decrypted secret key data for signing * @param {Array<module:key.Key>} privateKeys private keys with decrypted secret key data for signing
* @param {Signature} signature (optional) any existing detached signature * @param {Signature} signature (optional) any existing detached signature
* @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 {Object} userId (optional) user ID 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' }]
* @returns {Promise<module:cleartext.CleartextMessage>} new cleartext message with signed content * @returns {Promise<module:cleartext.CleartextMessage>} new cleartext message with signed content
* @async * @async
*/ */
CleartextMessage.prototype.sign = async function(privateKeys, signature=null, date=new Date(), userId={}) { CleartextMessage.prototype.sign = async function(privateKeys, signature=null, date=new Date(), userIds=[]) {
return new CleartextMessage(this.text, await this.signDetached(privateKeys, signature, date, userId)); return new CleartextMessage(this.text, await this.signDetached(privateKeys, signature, date, userIds));
}; };
/** /**
@ -81,15 +81,15 @@ CleartextMessage.prototype.sign = async function(privateKeys, signature=null, da
* @param {Array<module:key.Key>} privateKeys private keys with decrypted secret key data for signing * @param {Array<module:key.Key>} privateKeys private keys with decrypted secret key data for signing
* @param {Signature} signature (optional) any existing detached signature * @param {Signature} signature (optional) any existing detached signature
* @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 {Object} userId (optional) user ID 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' }]
* @returns {Promise<module:signature.Signature>} new detached signature of message content * @returns {Promise<module:signature.Signature>} new detached signature of message content
* @async * @async
*/ */
CleartextMessage.prototype.signDetached = async function(privateKeys, signature=null, date=new Date(), userId={}) { CleartextMessage.prototype.signDetached = async function(privateKeys, signature=null, date=new Date(), userIds=[]) {
const literalDataPacket = new packet.Literal(); const literalDataPacket = new packet.Literal();
literalDataPacket.setText(this.text); literalDataPacket.setText(this.text);
return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, date, userId)); return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, date, userIds));
}; };
/** /**

View File

@ -181,7 +181,7 @@ export default {
cipherfn = new cipher[cipherfn](key); cipherfn = new cipher[cipherfn](key);
const block_size = cipherfn.blockSize; const block_size = cipherfn.blockSize;
let iblock = new Uint8Array(block_size); const iblock = new Uint8Array(block_size);
let ablock = new Uint8Array(block_size); let ablock = new Uint8Array(block_size);
let i; let i;
@ -189,30 +189,10 @@ export default {
let n; let n;
let text = new Uint8Array(ciphertext.length - block_size); let text = new Uint8Array(ciphertext.length - block_size);
// initialisation vector
for (i = 0; i < block_size; i++) {
iblock[i] = 0;
}
iblock = cipherfn.encrypt(iblock);
for (i = 0; i < block_size; i++) {
ablock[i] = ciphertext[i];
iblock[i] ^= ablock[i];
}
ablock = cipherfn.encrypt(ablock);
// test check octets
if (iblock[block_size - 2] !== (ablock[0] ^ ciphertext[block_size]) ||
iblock[block_size - 1] !== (ablock[1] ^ ciphertext[block_size + 1])) {
throw new Error('CFB decrypt: invalid key');
}
/* RFC4880: Tag 18 and Resync: /* RFC4880: Tag 18 and Resync:
* [...] Unlike the Symmetrically Encrypted Data Packet, no * [...] Unlike the Symmetrically Encrypted Data Packet, no
* special CFB resynchronization is done after encrypting this prefix * special CFB resynchronization is done after encrypting this prefix
* data. See "OpenPGP CFB Mode" below for more details. * data. See "OpenPGP CFB Mode" below for more details.
*/ */
j = 0; j = 0;

View File

@ -48,7 +48,7 @@ function rightXorMut(data, padding) {
function pad(data, padding, padding2) { function pad(data, padding, padding2) {
// if |M| in {n, 2n, 3n, ...} // if |M| in {n, 2n, 3n, ...}
if (data.length % blockLength === 0) { if (data.length && data.length % blockLength === 0) {
// then return M xor→ B, // then return M xor→ B,
return rightXorMut(data, padding); return rightXorMut(data, padding);
} }

View File

@ -177,7 +177,14 @@ Curve.prototype.keyFromSecret = function (secret) { // Only for ed25519
}; };
Curve.prototype.keyFromPublic = function (pub) { Curve.prototype.keyFromPublic = function (pub) {
return new KeyPair(this, { pub: pub }); const keyPair = new KeyPair(this, { pub: pub });
if (
this.keyType === enums.publicKey.ecdsa &&
keyPair.keyPair.validate().result !== true
) {
throw new Error('Invalid elliptic public key');
}
return keyPair;
}; };
Curve.prototype.genKeyPair = async function () { Curve.prototype.genKeyPair = async function () {

View File

@ -291,7 +291,9 @@ function dearmor(input) {
if (line.indexOf('=') === -1 && line.indexOf('-') === -1) { if (line.indexOf('=') === -1 && line.indexOf('-') === -1) {
await writer.write(line); await writer.write(line);
} else { } else {
let remainder = line + await reader.readToEnd(); let remainder = await reader.readToEnd();
if (!remainder.length) remainder = '';
remainder = line + remainder;
remainder = remainder.replace(/[\t\r ]+$/mg, ''); remainder = remainder.replace(/[\t\r ]+$/mg, '');
const parts = remainder.split(reSplit); const parts = remainder.split(reSplit);
if (parts.length === 1) { if (parts.length === 1) {

View File

@ -290,7 +290,7 @@ async function getLatestValidSignature(signatures, primaryKey, signatureType, da
/** /**
* Returns last created key or key by given keyId that is available for signing and verification * Returns last created key or key by given keyId that is available for signing and verification
* @param {module:type/keyid} keyId, optional * @param {module:type/keyid} keyId, optional
* @param {Date} date 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
* @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
@ -510,13 +510,17 @@ Key.prototype.getExpirationTime = async function(capabilities, keyId, userId) {
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 = await this.getEncryptionKey(keyId, null, userId); const encryptKey =
await this.getEncryptionKey(keyId, expiry, userId) ||
await this.getEncryptionKey(keyId, null, userId);
if (!encryptKey) return null; if (!encryptKey) return null;
const encryptExpiry = await encryptKey.getExpirationTime(this.keyPacket); const encryptExpiry = await encryptKey.getExpirationTime(this.keyPacket);
if (encryptExpiry < expiry) expiry = encryptExpiry; if (encryptExpiry < expiry) expiry = encryptExpiry;
} }
if (capabilities === 'sign' || capabilities === 'encrypt_sign') { if (capabilities === 'sign' || capabilities === 'encrypt_sign') {
const signKey = await this.getSigningKey(keyId, null, userId); const signKey =
await this.getSigningKey(keyId, expiry, userId) ||
await this.getSigningKey(keyId, null, userId);
if (!signKey) return null; if (!signKey) return null;
const signExpiry = await signKey.getExpirationTime(this.keyPacket); const signExpiry = await signKey.getExpirationTime(this.keyPacket);
if (signExpiry < expiry) expiry = signExpiry; if (signExpiry < expiry) expiry = signExpiry;
@ -528,7 +532,7 @@ Key.prototype.getExpirationTime = async function(capabilities, keyId, userId) {
* Returns primary user and most significant (latest valid) self signature * Returns primary user and most significant (latest valid) self signature
* - if multiple primary users exist, returns the one with the latest self signature * - if multiple primary users exist, returns the one with the latest self signature
* - otherwise, returns the user with the latest self signature * - otherwise, returns the user with the latest self signature
* @param {Date} date 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
* @returns {Promise<{user: module:key.User, * @returns {Promise<{user: module:key.User,
* selfCertification: module:packet.Signature}>} The primary user and the self signature * selfCertification: module:packet.Signature}>} The primary user and the self signature
@ -742,11 +746,13 @@ Key.prototype.applyRevocationCertificate = async function(revocationCertificate)
/** /**
* Signs primary user of key * Signs primary user of key
* @param {Array<module:key.Key>} privateKey decrypted private keys for signing * @param {Array<module:key.Key>} privateKey decrypted private keys for signing
* @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
* @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
*/ */
Key.prototype.signPrimaryUser = async function(privateKeys) { Key.prototype.signPrimaryUser = async function(privateKeys, date, userId) {
const { index, user } = await this.getPrimaryUser() || {}; const { index, user } = await this.getPrimaryUser(date, userId) || {};
if (!user) { if (!user) {
throw new Error('Could not find primary user'); throw new Error('Could not find primary user');
} }
@ -776,13 +782,15 @@ Key.prototype.signAllUsers = async function(privateKeys) {
* - 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 {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
* @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
*/ */
Key.prototype.verifyPrimaryUser = async function(keys) { Key.prototype.verifyPrimaryUser = async function(keys, date, userId) {
const primaryKey = this.keyPacket; const primaryKey = this.keyPacket;
const { user } = await this.getPrimaryUser() || {}; const { user } = await this.getPrimaryUser(date, userId) || {};
if (!user) { if (!user) {
throw new Error('Could not find primary user'); throw new Error('Could not find primary user');
} }
@ -1454,6 +1462,19 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options) {
packetlist.push(secretKeyPacket); packetlist.push(secretKeyPacket);
await Promise.all(options.userIds.map(async function(userId, index) { await Promise.all(options.userIds.map(async function(userId, index) {
function createdPreferredAlgos(algos, configAlgo) {
if (configAlgo) { // Not `uncompressed` / `plaintext`
const configIndex = algos.indexOf(configAlgo);
if (configIndex >= 1) { // If it is included and not in first place,
algos.splice(configIndex, 1); // remove it.
}
if (configIndex !== 0) { // If it was included and not in first place, or wasn't included,
algos.unshift(configAlgo); // add it to the front.
}
}
return algos;
}
const userIdPacket = new packet.Userid(); const userIdPacket = new packet.Userid();
userIdPacket.format(userId); userIdPacket.format(userId);
@ -1465,26 +1486,30 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options) {
signaturePacket.publicKeyAlgorithm = secretKeyPacket.algorithm; signaturePacket.publicKeyAlgorithm = secretKeyPacket.algorithm;
signaturePacket.hashAlgorithm = await getPreferredHashAlgo(null, secretKeyPacket); signaturePacket.hashAlgorithm = await getPreferredHashAlgo(null, secretKeyPacket);
signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data]; signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data];
signaturePacket.preferredSymmetricAlgorithms = []; 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)
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.aes256); enums.symmetric.aes256,
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.aes128); enums.symmetric.aes128,
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.aes192); enums.symmetric.aes192,
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.cast5); enums.symmetric.cast5,
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.tripledes); enums.symmetric.tripledes
], config.encryption_cipher);
if (config.aead_protect && config.aead_protect_version === 4) { if (config.aead_protect && config.aead_protect_version === 4) {
signaturePacket.preferredAeadAlgorithms = []; signaturePacket.preferredAeadAlgorithms = createdPreferredAlgos([
signaturePacket.preferredAeadAlgorithms.push(enums.aead.eax); enums.aead.eax,
signaturePacket.preferredAeadAlgorithms.push(enums.aead.ocb); enums.aead.ocb
], config.aead_mode);
} }
signaturePacket.preferredHashAlgorithms = []; signaturePacket.preferredHashAlgorithms = createdPreferredAlgos([
// prefer fast asm.js implementations (SHA-256). SHA-1 will not be secure much longer...move to bottom of list // prefer fast asm.js implementations (SHA-256). SHA-1 will not be secure much longer...move to bottom of list
signaturePacket.preferredHashAlgorithms.push(enums.hash.sha256); enums.hash.sha256,
signaturePacket.preferredHashAlgorithms.push(enums.hash.sha512); enums.hash.sha512,
signaturePacket.preferredHashAlgorithms.push(enums.hash.sha1); enums.hash.sha1
signaturePacket.preferredCompressionAlgorithms = []; ], config.prefer_hash_algorithm);
signaturePacket.preferredCompressionAlgorithms.push(enums.compression.zlib); signaturePacket.preferredCompressionAlgorithms = createdPreferredAlgos([
signaturePacket.preferredCompressionAlgorithms.push(enums.compression.zip); enums.compression.zlib,
enums.compression.zip
], config.compression);
if (index === 0) { if (index === 0) {
signaturePacket.isPrimaryUserID = true; signaturePacket.isPrimaryUserID = true;
} }
@ -1618,7 +1643,7 @@ function isDataExpired(keyPacket, signature, date=new Date()) {
const normDate = util.normalizeDate(date); const normDate = util.normalizeDate(date);
if (normDate !== null) { if (normDate !== null) {
const expirationTime = getExpirationTime(keyPacket, signature); const expirationTime = getExpirationTime(keyPacket, signature);
return !(keyPacket.created <= normDate && normDate < expirationTime) || return !(keyPacket.created <= normDate && normDate <= expirationTime) ||
(signature && signature.isExpired(date)); (signature && signature.isExpired(date));
} }
return false; return false;
@ -1687,16 +1712,16 @@ export async function getPreferredHashAlgo(key, keyPacket, date=new Date(), user
* @param {symmetric|aead} type Type of preference to return * @param {symmetric|aead} type Type of preference to return
* @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 {Object} userId (optional) user ID * @param {Array} userIds (optional) user IDs
* @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(), userId={}) { export async function getPreferredAlgo(type, keys, date=new Date(), userIds=[]) {
const prefProperty = type === 'symmetric' ? 'preferredSymmetricAlgorithms' : 'preferredAeadAlgorithms'; const prefProperty = type === 'symmetric' ? 'preferredSymmetricAlgorithms' : 'preferredAeadAlgorithms';
const defaultAlgo = type === 'symmetric' ? config.encryption_cipher : config.aead_mode; const defaultAlgo = type === 'symmetric' ? enums.symmetric.aes128 : enums.aead.eax;
const prioMap = {}; const prioMap = {};
await Promise.all(keys.map(async function(key) { await Promise.all(keys.map(async function(key, i) {
const primaryUser = await key.getPrimaryUser(date, userId); const primaryUser = await key.getPrimaryUser(date, userIds[i]);
if (!primaryUser || !primaryUser.selfCertification[prefProperty]) { if (!primaryUser || !primaryUser.selfCertification[prefProperty]) {
return defaultAlgo; return defaultAlgo;
} }
@ -1725,14 +1750,15 @@ export async function getPreferredAlgo(type, keys, date=new Date(), userId={}) {
* Returns whether aead is supported by all keys in the set * Returns whether aead is supported by all keys in the set
* @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
* @returns {Promise<Boolean>} * @returns {Promise<Boolean>}
* @async * @async
*/ */
export async function isAeadSupported(keys, date=new Date(), userId={}) { export async function isAeadSupported(keys, date=new Date(), userIds=[]) {
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) { await Promise.all(keys.map(async function(key, i) {
const primaryUser = await key.getPrimaryUser(date, userId); const primaryUser = await key.getPrimaryUser(date, userIds[i]);
if (!primaryUser || !primaryUser.selfCertification.features || if (!primaryUser || !primaryUser.selfCertification.features ||
!(primaryUser.selfCertification.features[0] & enums.features.aead)) { !(primaryUser.selfCertification.features[0] & enums.features.aead)) {
supported = false; supported = false;

View File

@ -153,6 +153,7 @@ Message.prototype.decrypt = async function(privateKeys, passwords, sessionKeys,
Message.prototype.decryptSessionKeys = async function(privateKeys, passwords) { Message.prototype.decryptSessionKeys = async function(privateKeys, passwords) {
let keyPackets = []; let keyPackets = [];
let exception;
if (passwords) { if (passwords) {
const symESKeyPacketlist = this.packets.filterByTag(enums.packet.symEncryptedSessionKey); const symESKeyPacketlist = this.packets.filterByTag(enums.packet.symEncryptedSessionKey);
if (!symESKeyPacketlist) { if (!symESKeyPacketlist) {
@ -181,10 +182,19 @@ Message.prototype.decryptSessionKeys = async function(privateKeys, passwords) {
throw new Error('No public key encrypted session key packet found.'); throw new Error('No public key encrypted session key packet found.');
} }
await Promise.all(pkESKeyPacketlist.map(async function(keyPacket) { await Promise.all(pkESKeyPacketlist.map(async function(keyPacket) {
const privateKeyPackets = new packet.List(); await Promise.all(privateKeys.map(async function(privateKey) {
privateKeys.forEach(privateKey => { const primaryUser = await privateKey.getPrimaryUser(); // TODO: Pass userId from somewhere.
privateKeyPackets.concat(privateKey.getKeys(keyPacket.publicKeyId).map(key => key.keyPacket)); let algos = [
}); enums.symmetric.aes256, // Old OpenPGP.js default fallback
enums.symmetric.aes128, // RFC4880bis fallback
enums.symmetric.tripledes, // RFC4880 fallback
enums.symmetric.cast5 // Golang OpenPGP fallback
];
if (primaryUser && primaryUser.selfCertification.preferredSymmetricAlgorithms) {
algos = algos.concat(primaryUser.selfCertification.preferredSymmetricAlgorithms);
}
const privateKeyPackets = privateKey.getKeys(keyPacket.publicKeyId).map(key => key.keyPacket);
await Promise.all(privateKeyPackets.map(async function(privateKeyPacket) { await Promise.all(privateKeyPackets.map(async function(privateKeyPacket) {
if (!privateKeyPacket) { if (!privateKeyPacket) {
return; return;
@ -194,11 +204,16 @@ Message.prototype.decryptSessionKeys = async function(privateKeys, passwords) {
} }
try { try {
await keyPacket.decrypt(privateKeyPacket); await keyPacket.decrypt(privateKeyPacket);
if (!algos.includes(enums.write(enums.symmetric, keyPacket.sessionKeyAlgorithm))) {
throw new Error('A non-preferred symmetric algorithm was used.');
}
keyPackets.push(keyPacket); keyPackets.push(keyPacket);
} catch (err) { } catch (err) {
util.print_debug_error(err); util.print_debug_error(err);
exception = err;
} }
})); }));
}));
stream.cancel(keyPacket.encrypted); // Don't keep copy of encrypted data in memory. stream.cancel(keyPacket.encrypted); // Don't keep copy of encrypted data in memory.
keyPacket.encrypted = null; keyPacket.encrypted = null;
})); }));
@ -222,7 +237,7 @@ Message.prototype.decryptSessionKeys = async function(privateKeys, passwords) {
return keyPackets.map(packet => ({ data: packet.sessionKey, algorithm: packet.sessionKeyAlgorithm })); return keyPackets.map(packet => ({ data: packet.sessionKey, algorithm: packet.sessionKeyAlgorithm }));
} }
throw new Error('Session key decryption failed.'); throw exception || new Error('Session key decryption failed.');
}; };
/** /**
@ -230,7 +245,8 @@ Message.prototype.decryptSessionKeys = async function(privateKeys, passwords) {
* @returns {(Uint8Array|null)} literal body of the message as Uint8Array * @returns {(Uint8Array|null)} literal body of the message as Uint8Array
*/ */
Message.prototype.getLiteralData = function() { Message.prototype.getLiteralData = function() {
const literal = this.packets.findPacket(enums.packet.literal); const msg = this.unwrapCompressed();
const literal = msg.packets.findPacket(enums.packet.literal);
return (literal && literal.getBytes()) || null; return (literal && literal.getBytes()) || null;
}; };
@ -239,7 +255,8 @@ Message.prototype.getLiteralData = function() {
* @returns {(String|null)} filename of literal data packet as string * @returns {(String|null)} filename of literal data packet as string
*/ */
Message.prototype.getFilename = function() { Message.prototype.getFilename = function() {
const literal = this.packets.findPacket(enums.packet.literal); const msg = this.unwrapCompressed();
const literal = msg.packets.findPacket(enums.packet.literal);
return (literal && literal.getFilename()) || null; return (literal && literal.getFilename()) || null;
}; };
@ -248,7 +265,8 @@ Message.prototype.getFilename = function() {
* @returns {(String|null)} literal body of the message interpreted as text * @returns {(String|null)} literal body of the message interpreted as text
*/ */
Message.prototype.getText = function() { Message.prototype.getText = function() {
const literal = this.packets.findPacket(enums.packet.literal); const msg = this.unwrapCompressed();
const literal = msg.packets.findPacket(enums.packet.literal);
if (literal) { if (literal) {
return literal.getText(); return literal.getText();
} }
@ -262,12 +280,12 @@ Message.prototype.getText = function() {
* @param {Object} sessionKey (optional) session key in the form: { data:Uint8Array, algorithm:String, [aeadAlgorithm:String] } * @param {Object} sessionKey (optional) session key in the form: { data:Uint8Array, algorithm:String, [aeadAlgorithm:String] }
* @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs * @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs
* @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 {Object} userId (optional) user ID 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 {Boolean} streaming (optional) whether to process data as a stream * @param {Boolean} streaming (optional) whether to process data as a stream
* @returns {Promise<Message>} new message with encrypted content * @returns {Promise<Message>} new message with encrypted content
* @async * @async
*/ */
Message.prototype.encrypt = async function(keys, passwords, sessionKey, wildcard=false, date=new Date(), userId={}, streaming) { Message.prototype.encrypt = async function(keys, passwords, sessionKey, wildcard=false, date=new Date(), userIds=[], streaming) {
let symAlgo; let symAlgo;
let aeadAlgo; let aeadAlgo;
let symEncryptedPacket; let symEncryptedPacket;
@ -280,9 +298,9 @@ Message.prototype.encrypt = async function(keys, passwords, sessionKey, wildcard
aeadAlgo = sessionKey.aeadAlgorithm; aeadAlgo = sessionKey.aeadAlgorithm;
sessionKey = sessionKey.data; sessionKey = sessionKey.data;
} else if (keys && keys.length) { } else if (keys && keys.length) {
symAlgo = enums.read(enums.symmetric, await getPreferredAlgo('symmetric', keys, date, userId)); symAlgo = enums.read(enums.symmetric, await getPreferredAlgo('symmetric', keys, date, userIds));
if (config.aead_protect && config.aead_protect_version === 4 && await isAeadSupported(keys, date, userId)) { if (config.aead_protect && config.aead_protect_version === 4 && await isAeadSupported(keys, date, userIds)) {
aeadAlgo = enums.read(enums.aead, await getPreferredAlgo('aead', keys, date, userId)); aeadAlgo = enums.read(enums.aead, await getPreferredAlgo('aead', keys, date, userIds));
} }
} else if (passwords && passwords.length) { } else if (passwords && passwords.length) {
symAlgo = enums.read(enums.symmetric, config.encryption_cipher); symAlgo = enums.read(enums.symmetric, config.encryption_cipher);
@ -295,7 +313,7 @@ Message.prototype.encrypt = async function(keys, passwords, sessionKey, wildcard
sessionKey = await crypto.generateSessionKey(symAlgo); sessionKey = await crypto.generateSessionKey(symAlgo);
} }
const msg = await encryptSessionKey(sessionKey, symAlgo, aeadAlgo, keys, passwords, wildcard, date, userId); const msg = await encryptSessionKey(sessionKey, symAlgo, aeadAlgo, keys, passwords, wildcard, date, userIds);
if (config.aead_protect && (config.aead_protect_version !== 4 || aeadAlgo)) { if (config.aead_protect && (config.aead_protect_version !== 4 || aeadAlgo)) {
symEncryptedPacket = new packet.SymEncryptedAEADProtected(); symEncryptedPacket = new packet.SymEncryptedAEADProtected();
@ -330,16 +348,16 @@ Message.prototype.encrypt = async function(keys, passwords, sessionKey, wildcard
* @param {Array<String>} passwords (optional) for message encryption * @param {Array<String>} passwords (optional) for message encryption
* @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs * @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs
* @param {Date} date (optional) override the date * @param {Date} date (optional) override the date
* @param {Object} userId (optional) user ID 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' }]
* @returns {Promise<Message>} new message with encrypted content * @returns {Promise<Message>} new message with encrypted content
* @async * @async
*/ */
export async function encryptSessionKey(sessionKey, symAlgo, aeadAlgo, publicKeys, passwords, wildcard=false, date=new Date(), userId={}) { export async function encryptSessionKey(sessionKey, symAlgo, aeadAlgo, publicKeys, passwords, wildcard=false, date=new Date(), userIds=[]) {
const packetlist = new packet.List(); const packetlist = new packet.List();
if (publicKeys) { if (publicKeys) {
const results = await Promise.all(publicKeys.map(async function(publicKey) { const results = await Promise.all(publicKeys.map(async function(publicKey) {
const encryptionKey = await publicKey.getEncryptionKey(undefined, date, userId); const encryptionKey = await publicKey.getEncryptionKey(undefined, date, userIds);
if (!encryptionKey) { if (!encryptionKey) {
throw new Error('Could not find valid key packet for encryption in key ' + throw new Error('Could not find valid key packet for encryption in key ' +
publicKey.getKeyId().toHex()); publicKey.getKeyId().toHex());
@ -399,11 +417,11 @@ export async function encryptSessionKey(sessionKey, symAlgo, aeadAlgo, publicKey
* @param {Array<module:key.Key>} privateKeys private keys with decrypted secret key data for signing * @param {Array<module:key.Key>} privateKeys private keys with decrypted secret key data for signing
* @param {Signature} signature (optional) any existing detached signature to add to the message * @param {Signature} signature (optional) any existing detached signature to add to the message
* @param {Date} date (optional) override the creation time of the signature * @param {Date} date (optional) override the creation time of the signature
* @param {Object} userId (optional) user ID 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' }]
* @returns {Promise<Message>} new message with signed content * @returns {Promise<Message>} new message with signed content
* @async * @async
*/ */
Message.prototype.sign = async function(privateKeys=[], signature=null, date=new Date(), userId={}) { Message.prototype.sign = async function(privateKeys=[], signature=null, date=new Date(), userIds=[]) {
const packetlist = new packet.List(); const packetlist = new packet.List();
const literalDataPacket = this.packets.findPacket(enums.packet.literal); const literalDataPacket = this.packets.findPacket(enums.packet.literal);
@ -437,14 +455,14 @@ Message.prototype.sign = async function(privateKeys=[], signature=null, date=new
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(undefined, date, userId); const signingKey = await privateKey.getSigningKey(undefined, date, userIds);
if (!signingKey) { if (!signingKey) {
throw new Error('Could not find valid key packet for signing in key ' + throw new Error('Could not find valid key packet for signing in key ' +
privateKey.getKeyId().toHex()); privateKey.getKeyId().toHex());
} }
const onePassSig = new packet.OnePassSignature(); const onePassSig = new packet.OnePassSignature();
onePassSig.signatureType = signatureType; onePassSig.signatureType = signatureType;
onePassSig.hashAlgorithm = await getPreferredHashAlgo(privateKey, signingKey.keyPacket, date, userId); onePassSig.hashAlgorithm = await getPreferredHashAlgo(privateKey, signingKey.keyPacket, date, userIds);
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) {
@ -486,16 +504,16 @@ Message.prototype.compress = function(compression) {
* @param {Array<module:key.Key>} privateKeys private keys with decrypted secret key data for signing * @param {Array<module:key.Key>} privateKeys private keys with decrypted secret key data for signing
* @param {Signature} signature (optional) any existing detached signature * @param {Signature} signature (optional) any existing detached signature
* @param {Date} date (optional) override the creation time of the signature * @param {Date} date (optional) override the creation time of the signature
* @param {Object} userId (optional) user ID 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' }]
* @returns {Promise<module:signature.Signature>} new detached signature of message content * @returns {Promise<module:signature.Signature>} new detached signature of message content
* @async * @async
*/ */
Message.prototype.signDetached = async function(privateKeys=[], signature=null, date=new Date(), userId={}) { Message.prototype.signDetached = async function(privateKeys=[], signature=null, date=new Date(), userIds=[]) {
const literalDataPacket = this.packets.findPacket(enums.packet.literal); const literalDataPacket = this.packets.findPacket(enums.packet.literal);
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, date, userId)); return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, date, userIds));
}; };
/** /**
@ -504,18 +522,19 @@ Message.prototype.signDetached = async function(privateKeys=[], signature=null,
* @param {Array<module:key.Key>} privateKeys private keys with decrypted secret key data for signing * @param {Array<module:key.Key>} privateKeys private keys with decrypted secret key data for signing
* @param {Signature} signature (optional) any existing detached signature to append * @param {Signature} signature (optional) any existing detached signature to append
* @param {Date} date (optional) override the creationtime of the signature * @param {Date} date (optional) override the creationtime of the signature
* @param {Object} userId (optional) user ID 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' }]
* @returns {Promise<module:packet.List>} list of signature packets * @returns {Promise<module:packet.List>} list of signature packets
* @async * @async
*/ */
export async function createSignaturePackets(literalDataPacket, privateKeys, signature=null, date=new Date(), userId={}) { export async function createSignaturePackets(literalDataPacket, privateKeys, signature=null, date=new Date(), userIds=[]) {
const packetlist = new packet.List(); const packetlist = new packet.List();
// If data packet was created from Uint8Array, use binary, otherwise use text // If data packet was created from Uint8Array, use binary, otherwise use text
const signatureType = literalDataPacket.text === null ? const signatureType = literalDataPacket.text === null ?
enums.signature.binary : enums.signature.text; enums.signature.binary : enums.signature.text;
await Promise.all(privateKeys.map(async privateKey => { await Promise.all(privateKeys.map(async (privateKey, i) => {
const userId = userIds[i];
if (privateKey.isPublic()) { if (privateKey.isPublic()) {
throw new Error('Need private key for signing'); throw new Error('Need private key for signing');
} }

View File

@ -65,7 +65,7 @@ let asyncProxy; // instance of the asyncproxy
* @param {Array<Object>} workers alternative to path parameter: web workers initialized with 'openpgp.worker.js' * @param {Array<Object>} workers alternative to path parameter: web workers initialized with 'openpgp.worker.js'
*/ */
export function initWorker({ path='openpgp.worker.js', n = 1, workers = [] } = {}) { export function initWorker({ path='openpgp.worker.js', n = 1, workers = [] } = {}) {
if (workers.length || (typeof window !== 'undefined' && window.Worker)) { if (workers.length || (typeof window !== 'undefined' && window.Worker && window.MessageChannel)) {
asyncProxy = new AsyncProxy({ path, n, workers, config }); asyncProxy = new AsyncProxy({ path, n, workers, config });
return true; return true;
} }
@ -288,8 +288,8 @@ export function encryptKey({ privateKey, passphrase }) {
* @param {Boolean} returnSessionKey (optional) if the unencrypted session key should be added to returned object * @param {Boolean} returnSessionKey (optional) if the unencrypted session key should be added to returned object
* @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs * @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs
* @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 {Object} fromUserId (optional) user ID to sign with, e.g. { name:'Steve Sender', email:'steve@openpgp.org' } * @param {Array} 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} toUserId (optional) user ID to encrypt for, e.g. { name:'Robert Receiver', email:'robert@openpgp.org' } * @param {Array} toUserIds (optional) array of user IDs to encrypt for, one per key in `publicKeys`, e.g. [{ name:'Robert Receiver', email:'robert@openpgp.org' }]
* @returns {Promise<Object>} Object containing encrypted (and optionally signed) message in the form: * @returns {Promise<Object>} Object containing encrypted (and optionally signed) message in the form:
* *
* { * {
@ -302,11 +302,11 @@ export function encryptKey({ privateKey, passphrase }) {
* @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, returnSessionKey=false, wildcard=false, date=new Date(), fromUserId={}, toUserId={} }) { export function encrypt({ message, publicKeys, privateKeys, passwords, sessionKey, compression=config.compression, armor=true, streaming=message&&message.fromStream, detached=false, signature=null, returnSessionKey=false, wildcard=false, date=new Date(), fromUserIds=[], toUserIds=[] }) {
checkMessage(message); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords); checkMessage(message); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords); fromUserIds = toArray(fromUserIds); toUserIds = toArray(toUserIds);
if (!nativeAEAD() && asyncProxy) { // use web worker if web crypto apis are not supported if (!nativeAEAD() && asyncProxy) { // use web worker if web crypto apis are not supported
return asyncProxy.delegate('encrypt', { message, publicKeys, privateKeys, passwords, sessionKey, compression, armor, streaming, detached, signature, returnSessionKey, wildcard, date, fromUserId, toUserId }); return asyncProxy.delegate('encrypt', { message, publicKeys, privateKeys, passwords, sessionKey, compression, armor, streaming, detached, signature, returnSessionKey, wildcard, date, fromUserIds, toUserIds });
} }
const result = {}; const result = {};
return Promise.resolve().then(async function() { return Promise.resolve().then(async function() {
@ -315,14 +315,14 @@ export function encrypt({ message, publicKeys, privateKeys, passwords, sessionKe
} }
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
if (detached) { if (detached) {
const detachedSignature = await message.signDetached(privateKeys, signature, date, fromUserId); const detachedSignature = await message.signDetached(privateKeys, signature, date, fromUserIds);
result.signature = armor ? detachedSignature.armor() : detachedSignature; result.signature = armor ? detachedSignature.armor() : detachedSignature;
} else { } else {
message = await message.sign(privateKeys, signature, date, fromUserId); message = await message.sign(privateKeys, signature, date, fromUserIds);
} }
} }
message = message.compress(compression); message = message.compress(compression);
return message.encrypt(publicKeys, passwords, sessionKey, wildcard, date, toUserId, streaming); return message.encrypt(publicKeys, passwords, sessionKey, wildcard, date, toUserIds, streaming);
}).then(async encrypted => { }).then(async encrypted => {
if (armor) { if (armor) {
@ -405,7 +405,7 @@ export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKe
* @param {'web'|'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'|'node'|false} streaming (optional) whether to return data as a stream. Defaults to the type of stream `message` was created from, if any.
* @param {Boolean} detached (optional) if the return value should contain a detached signature * @param {Boolean} detached (optional) if the return value should contain a detached signature
* @param {Date} date (optional) override the creation date of the signature * @param {Date} date (optional) override the creation date of the signature
* @param {Object} fromUserId (optional) user ID to sign with, e.g. { name:'Steve Sender', email:'steve@openpgp.org' } * @param {Array} fromUserIds (optional) array of user IDs to sign with, one per key in `privateKeys`, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
* @returns {Promise<Object>} Object containing signed message in the form: * @returns {Promise<Object>} Object containing signed message in the form:
* *
* { * {
@ -422,23 +422,23 @@ export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKe
* @async * @async
* @static * @static
*/ */
export function sign({ message, privateKeys, armor=true, streaming=message&&message.fromStream, detached=false, date=new Date(), fromUserId={} }) { export function sign({ message, privateKeys, armor=true, streaming=message&&message.fromStream, detached=false, date=new Date(), fromUserIds=[] }) {
checkCleartextOrMessage(message); checkCleartextOrMessage(message);
privateKeys = toArray(privateKeys); privateKeys = toArray(privateKeys); fromUserIds = toArray(fromUserIds);
if (asyncProxy) { // use web worker if available if (asyncProxy) { // use web worker if available
return asyncProxy.delegate('sign', { return asyncProxy.delegate('sign', {
message, privateKeys, armor, streaming, detached, date, fromUserId message, privateKeys, armor, streaming, detached, date, fromUserIds
}); });
} }
const result = {}; const result = {};
return Promise.resolve().then(async function() { return Promise.resolve().then(async function() {
if (detached) { if (detached) {
const signature = await message.signDetached(privateKeys, undefined, date, fromUserId); const signature = await message.signDetached(privateKeys, undefined, date, fromUserIds);
result.signature = armor ? signature.armor() : signature; result.signature = armor ? signature.armor() : signature;
} else { } else {
message = await message.sign(privateKeys, undefined, date, fromUserId); message = await message.sign(privateKeys, undefined, date, fromUserIds);
if (armor) { if (armor) {
result.data = message.armor(); result.data = message.armor();
} else { } else {
@ -509,21 +509,21 @@ export function verify({ message, publicKeys, streaming=message&&message.fromStr
* @param {String|Array<String>} passwords (optional) passwords for the message * @param {String|Array<String>} passwords (optional) passwords for the message
* @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs * @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs
* @param {Date} date (optional) override the date * @param {Date} date (optional) override the date
* @param {Object} toUserId (optional) user ID to encrypt for, 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' }]
* @returns {Promise<Message>} the encrypted session key packets contained in a message object * @returns {Promise<Message>} the encrypted session key packets contained in a message object
* @async * @async
* @static * @static
*/ */
export function encryptSessionKey({ data, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard=false, date=new Date(), toUserId={} }) { export function encryptSessionKey({ data, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard=false, date=new Date(), toUserIds=[] }) {
checkBinary(data); checkString(algorithm, 'algorithm'); publicKeys = toArray(publicKeys); passwords = toArray(passwords); checkBinary(data); checkString(algorithm, 'algorithm'); publicKeys = toArray(publicKeys); passwords = toArray(passwords); toUserIds = toArray(toUserIds);
if (asyncProxy) { // use web worker if available if (asyncProxy) { // use web worker if available
return asyncProxy.delegate('encryptSessionKey', { data, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard, date, toUserId }); return asyncProxy.delegate('encryptSessionKey', { data, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard, date, toUserIds });
} }
return Promise.resolve().then(async function() { return Promise.resolve().then(async function() {
return { message: await messageLib.encryptSessionKey(data, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard, date, toUserId) }; return { message: await messageLib.encryptSessionKey(data, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard, date, toUserIds) };
}).catch(onError.bind(null, 'Error encrypting session key')); }).catch(onError.bind(null, 'Error encrypting session key'));
} }

View File

@ -168,24 +168,10 @@ List.prototype.filterByTag = function (...args) {
/** /**
* Traverses packet tree and returns first matching packet * Traverses packet tree and returns first matching packet
* @param {module:enums.packet} type The packet type * @param {module:enums.packet} type The packet type
* @returns {module:packet/packet|null} * @returns {module:packet/packet|undefined}
*/ */
List.prototype.findPacket = function (type) { List.prototype.findPacket = function (type) {
const packetlist = this.filterByTag(type); return this.find(packet => packet.tag === type);
if (packetlist.length) {
return packetlist[0];
}
let found = null;
for (let i = 0; i < this.length; i++) {
if (this[i].packets.length) {
found = this[i].packets.findPacket(type);
if (found) {
return found;
}
}
}
return null;
}; };
/** /**

View File

@ -62,6 +62,11 @@ function PublicKey(date=new Date()) {
* @type {Date} * @type {Date}
*/ */
this.created = util.normalizeDate(date); this.created = util.normalizeDate(date);
/**
* Public key algorithm.
* @type {String}
*/
this.algorithm = null;
/** /**
* Algorithm specific params * Algorithm specific params
* @type {Array<Object>} * @type {Array<Object>}

View File

@ -52,7 +52,10 @@ function PublicKeyEncryptedSessionKey() {
this.version = 3; this.version = 3;
this.publicKeyId = new type_keyid(); this.publicKeyId = new type_keyid();
this.publicKeyAlgorithm = null;
this.sessionKey = null; this.sessionKey = null;
this.sessionKeyAlgorithm = null;
/** @type {Array<module:type/mpi>} */ /** @type {Array<module:type/mpi>} */
this.encrypted = []; this.encrypted = [];
@ -150,7 +153,7 @@ PublicKeyEncryptedSessionKey.prototype.decrypt = async function (key) {
key = util.str_to_Uint8Array(decoded.substring(1, decoded.length - 2)); key = util.str_to_Uint8Array(decoded.substring(1, decoded.length - 2));
if (!util.equalsUint8Array(checksum, util.write_checksum(key))) { if (!util.equalsUint8Array(checksum, util.write_checksum(key))) {
throw new Error('Checksum mismatch'); throw new Error('Decryption error');
} else { } else {
this.sessionKey = key; this.sessionKey = key;
this.sessionKeyAlgorithm = enums.read(enums.symmetric, decoded.charCodeAt(0)); this.sessionKeyAlgorithm = enums.read(enums.symmetric, decoded.charCodeAt(0));

View File

@ -666,6 +666,10 @@ Signature.prototype.verify = async function (key, signatureType, data) {
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);
if (publicKeyAlgorithm !== enums.write(enums.publicKey, key.algorithm)) {
throw new Error('Public key algorithm used to sign signature does not match issuer key algorithm.');
}
let toHash; let toHash;
let hash; let hash;
if (this.hashed) { if (this.hashed) {
@ -723,7 +727,7 @@ Signature.prototype.isExpired = function (date=new Date()) {
const normDate = util.normalizeDate(date); const normDate = util.normalizeDate(date);
if (normDate !== null) { if (normDate !== null) {
const expirationTime = this.getExpirationTime(); const expirationTime = this.getExpirationTime();
return !(this.created <= normDate && normDate < expirationTime); return !(this.created <= normDate && normDate <= expirationTime);
} }
return false; return false;
}; };

View File

@ -165,7 +165,7 @@ export default {
}, },
normalizeDate: function (time = Date.now()) { normalizeDate: function (time = Date.now()) {
return time === null ? time : new Date(Math.floor(+time / 1000) * 1000); return time === null || time === Infinity ? time : new Date(Math.floor(+time / 1000) * 1000);
}, },
/** /**

View File

@ -223,7 +223,17 @@ describe('Elliptic Curve Cryptography', async function () {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]); ]);
const secp256k1_dummy_point = new Uint8Array([ const secp256k1_point = new Uint8Array([
0x04,
0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC,
0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07,
0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9,
0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98,
0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65,
0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, 0xA8,
0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19,
0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, 0xB8]);
const secp256k1_invalid_point = new Uint8Array([
0x04, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -233,7 +243,7 @@ describe('Elliptic Curve Cryptography', async function () {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
const secp256k1_invalid_point = new Uint8Array([ const secp256k1_invalid_point_format = new Uint8Array([
0x04, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -255,13 +265,18 @@ describe('Elliptic Curve Cryptography', async function () {
'secp256k1', 8, [], [], [], [] 'secp256k1', 8, [], [], [], []
)).to.be.rejectedWith(Error, /Unknown point format/), )).to.be.rejectedWith(Error, /Unknown point format/),
expect(verify_signature( expect(verify_signature(
'secp256k1', 8, [], [], [], secp256k1_invalid_point 'secp256k1', 8, [], [], [], secp256k1_invalid_point_format
)).to.be.rejectedWith(Error, /Unknown point format/) )).to.be.rejectedWith(Error, /Unknown point format/)
]); ]);
}); });
it('Invalid point', function (done) {
expect(verify_signature(
'secp256k1', 8, [], [], [], secp256k1_invalid_point
)).to.be.rejectedWith(Error, /Invalid elliptic public key/).notify(done);
});
it('Invalid signature', function (done) { it('Invalid signature', function (done) {
expect(verify_signature( expect(verify_signature(
'secp256k1', 8, [], [], [], secp256k1_dummy_point 'secp256k1', 8, [], [], [], secp256k1_point
)).to.eventually.be.false.notify(done); )).to.eventually.be.false.notify(done);
}); });
@ -331,11 +346,21 @@ describe('Elliptic Curve Cryptography', async function () {
]); ]);
const secp256k1_point = new Uint8Array([ const secp256k1_point = new Uint8Array([
0x04, 0x04,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC,
0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07,
0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9,
0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98,
0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65,
0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, 0xA8,
0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19,
0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, 0xB8]);
const secp256k1_invalid_point = new Uint8Array([
0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
@ -354,6 +379,11 @@ describe('Elliptic Curve Cryptography', async function () {
'secp256k1', 2, 7, [], [], [], [] 'secp256k1', 2, 7, [], [], [], []
)).to.be.rejectedWith(Error, /Unknown point format/).notify(done); )).to.be.rejectedWith(Error, /Unknown point format/).notify(done);
}); });
it('Invalid elliptic public key', function (done) {
expect(decrypt_message(
'secp256k1', 2, 7, secp256k1_value, secp256k1_invalid_point, secp256k1_data, []
)).to.be.rejectedWith(Error, /Invalid elliptic public key/).notify(done);
});
it('Invalid key data integrity', function (done) { it('Invalid key data integrity', function (done) {
expect(decrypt_message( expect(decrypt_message(
'secp256k1', 2, 7, secp256k1_value, secp256k1_point, secp256k1_data, [] 'secp256k1', 2, 7, secp256k1_value, secp256k1_point, secp256k1_data, []

View File

@ -1640,6 +1640,49 @@ function versionSpecificTests() {
}); });
}); });
it('Preferences of generated key - with config values', async function() {
const encryption_cipherVal = openpgp.config.encryption_cipher;
const prefer_hash_algorithmVal = openpgp.config.prefer_hash_algorithm;
const compressionVal = openpgp.config.compression;
const aead_modeVal = openpgp.config.aead_mode;
openpgp.config.encryption_cipher = openpgp.enums.symmetric.aes192;
openpgp.config.prefer_hash_algorithm = openpgp.enums.hash.sha224;
openpgp.config.compression = openpgp.enums.compression.zlib;
openpgp.config.aead_mode = openpgp.enums.aead.experimental_gcm;
const testPref = function(key) {
// key flags
const keyFlags = openpgp.enums.keyFlags;
expect(key.users[0].selfCertifications[0].keyFlags[0] & keyFlags.certify_keys).to.equal(keyFlags.certify_keys);
expect(key.users[0].selfCertifications[0].keyFlags[0] & keyFlags.sign_data).to.equal(keyFlags.sign_data);
expect(key.subKeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encrypt_communication).to.equal(keyFlags.encrypt_communication);
expect(key.subKeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encrypt_storage).to.equal(keyFlags.encrypt_storage);
const sym = openpgp.enums.symmetric;
expect(key.users[0].selfCertifications[0].preferredSymmetricAlgorithms).to.eql([sym.aes192, sym.aes256, sym.aes128, sym.cast5, sym.tripledes]);
if (openpgp.config.aead_protect && openpgp.config.aead_protect_version === 4) {
const aead = openpgp.enums.aead;
expect(key.users[0].selfCertifications[0].preferredAeadAlgorithms).to.eql([aead.experimental_gcm, aead.eax, aead.ocb]);
}
const hash = openpgp.enums.hash;
expect(key.users[0].selfCertifications[0].preferredHashAlgorithms).to.eql([hash.sha224, hash.sha256, hash.sha512, hash.sha1]);
const compr = openpgp.enums.compression;
expect(key.users[0].selfCertifications[0].preferredCompressionAlgorithms).to.eql([compr.zlib, compr.zip]);
expect(key.users[0].selfCertifications[0].features).to.eql(openpgp.config.aead_protect && openpgp.config.aead_protect_version === 4 ? [7] : [1]);
};
const opt = {numBits: 512, userIds: 'test <a@b.com>', passphrase: 'hello'};
if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
try {
const key = await openpgp.generateKey(opt);
testPref(key.key);
testPref((await openpgp.key.readArmored(key.publicKeyArmored)).keys[0]);
} finally {
openpgp.config.encryption_cipher = encryption_cipherVal;
openpgp.config.prefer_hash_algorithm = prefer_hash_algorithmVal;
openpgp.config.compression = compressionVal;
openpgp.config.aead_mode = aead_modeVal;
}
});
it('Generated key is not unlocked by default', function() { it('Generated key is not unlocked by default', function() {
const opt = {numBits: 512, userIds: 'test <a@b.com>', passphrase: '123'}; const opt = {numBits: 512, userIds: 'test <a@b.com>', passphrase: '123'};
if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
@ -2223,16 +2266,21 @@ describe('Key', function() {
const pubKey = (await openpgp.key.readArmored(priv_key_2000_2008)).keys[0]; const pubKey = (await openpgp.key.readArmored(priv_key_2000_2008)).keys[0];
expect(pubKey).to.exist; expect(pubKey).to.exist;
expect(pubKey).to.be.an.instanceof(openpgp.key.Key); expect(pubKey).to.be.an.instanceof(openpgp.key.Key);
pubKey.users[0].selfCertifications[0].keyFlags = [1];
const expirationTime = await pubKey.getExpirationTime(); const expirationTime = await pubKey.getExpirationTime();
expect(expirationTime).to.equal(Infinity); expect(expirationTime).to.equal(Infinity);
const encryptExpirationTime = await pubKey.getExpirationTime('encrypt_sign'); const encryptExpirationTime = await pubKey.getExpirationTime('encrypt_sign');
expect(encryptExpirationTime.toISOString()).to.equal('2008-02-12T17:12:08.000Z'); expect(encryptExpirationTime.toISOString()).to.equal('2008-02-12T17:12:08.000Z');
}); });
it('Getting an encryption packet ', async function () { it('Method getExpirationTime V4 Key with capabilities - capable primary key', async function() {
const { keys: [pubKey] } = await openpgp.key.readArmored(revoked_primary_user); const pubKey = (await openpgp.key.readArmored(priv_key_2000_2008)).keys[0];
const encPacket = await pubKey.getEncryptionKey(); expect(pubKey).to.exist;
expect(encPacket).to.not.be.null; expect(pubKey).to.be.an.instanceof(openpgp.key.Key);
const expirationTime = await pubKey.getExpirationTime();
expect(expirationTime).to.equal(Infinity);
const encryptExpirationTime = await pubKey.getExpirationTime('encrypt_sign');
expect(encryptExpirationTime).to.equal(Infinity);
}); });
it('update() - throw error if fingerprints not equal', async function() { it('update() - throw error if fingerprints not equal', async function() {
@ -2436,14 +2484,14 @@ describe('Key', function() {
expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes256); expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes256);
}); });
it("getPreferredAlgo('symmetric') - two key - AES128", async function() { it("getPreferredAlgo('symmetric') - two key - AES192", async function() {
const keys = (await openpgp.key.readArmored(twoKeys)).keys; const keys = (await openpgp.key.readArmored(twoKeys)).keys;
const key1 = keys[0]; const key1 = keys[0];
const key2 = keys[1]; const key2 = keys[1];
const primaryUser = await key2.getPrimaryUser(); const primaryUser = await key2.getPrimaryUser();
primaryUser.selfCertification.preferredSymmetricAlgorithms = [6,7,3]; primaryUser.selfCertification.preferredSymmetricAlgorithms = [6,8,3];
const prefAlgo = await openpgp.key.getPreferredAlgo('symmetric', [key1, key2]); const prefAlgo = await openpgp.key.getPreferredAlgo('symmetric', [key1, key2]);
expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes128); expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes192);
}); });
it("getPreferredAlgo('symmetric') - two key - one without pref", async function() { it("getPreferredAlgo('symmetric') - two key - one without pref", async function() {
@ -2453,7 +2501,7 @@ describe('Key', function() {
const primaryUser = await key2.getPrimaryUser(); const primaryUser = await key2.getPrimaryUser();
primaryUser.selfCertification.preferredSymmetricAlgorithms = null; primaryUser.selfCertification.preferredSymmetricAlgorithms = null;
const prefAlgo = await openpgp.key.getPreferredAlgo('symmetric', [key1, key2]); const prefAlgo = await openpgp.key.getPreferredAlgo('symmetric', [key1, key2]);
expect(prefAlgo).to.equal(openpgp.config.encryption_cipher); expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes128);
}); });
it("getPreferredAlgo('aead') - one key - OCB", async function() { it("getPreferredAlgo('aead') - one key - OCB", async function() {
@ -2477,7 +2525,7 @@ describe('Key', function() {
const primaryUser2 = await key2.getPrimaryUser(); const primaryUser2 = await key2.getPrimaryUser();
primaryUser2.selfCertification.features = [7]; // Monkey-patch AEAD feature flag primaryUser2.selfCertification.features = [7]; // Monkey-patch AEAD feature flag
const prefAlgo = await openpgp.key.getPreferredAlgo('aead', [key1, key2]); const prefAlgo = await openpgp.key.getPreferredAlgo('aead', [key1, key2]);
expect(prefAlgo).to.equal(openpgp.config.aead_mode); expect(prefAlgo).to.equal(openpgp.enums.aead.eax);
const supported = await openpgp.key.isAeadSupported([key1, key2]); const supported = await openpgp.key.isAeadSupported([key1, key2]);
expect(supported).to.be.true; expect(supported).to.be.true;
}); });
@ -2490,7 +2538,7 @@ describe('Key', function() {
primaryUser.selfCertification.features = [7]; // Monkey-patch AEAD feature flag primaryUser.selfCertification.features = [7]; // Monkey-patch AEAD feature flag
primaryUser.selfCertification.preferredAeadAlgorithms = [2,1]; primaryUser.selfCertification.preferredAeadAlgorithms = [2,1];
const prefAlgo = await openpgp.key.getPreferredAlgo('aead', [key1, key2]); const prefAlgo = await openpgp.key.getPreferredAlgo('aead', [key1, key2]);
expect(prefAlgo).to.equal(openpgp.config.aead_mode); expect(prefAlgo).to.equal(openpgp.enums.aead.eax);
const supported = await openpgp.key.isAeadSupported([key1, key2]); const supported = await openpgp.key.isAeadSupported([key1, key2]);
expect(supported).to.be.false; expect(supported).to.be.false;
}); });
@ -2560,9 +2608,9 @@ VYGdb3eNlV8CfoEC
publicKey.users[0].selfCertifications[0].isPrimaryUserID = true; publicKey.users[0].selfCertifications[0].isPrimaryUserID = true;
// Set second user to prefer aes128. We will select this user. // Set second user to prefer aes128. We will select this user.
publicKey.users[1].selfCertifications[0].preferredSymmetricAlgorithms = [openpgp.enums.symmetric.aes128]; publicKey.users[1].selfCertifications[0].preferredSymmetricAlgorithms = [openpgp.enums.symmetric.aes128];
const encrypted = await openpgp.encrypt({message: openpgp.message.fromText('hello'), publicKeys: publicKey, privateKeys: privateKey, toUserId: {name: 'Test User', email: 'b@c.com'}, armor: false}); const encrypted = await openpgp.encrypt({message: openpgp.message.fromText('hello'), publicKeys: publicKey, privateKeys: privateKey, toUserIds: {name: 'Test User', email: 'b@c.com'}, armor: false});
expect(encrypted.message.packets[0].sessionKeyAlgorithm).to.equal('aes128'); expect(encrypted.message.packets[0].sessionKeyAlgorithm).to.equal('aes128');
await expect(openpgp.encrypt({message: openpgp.message.fromText('hello'), publicKeys: publicKey, privateKeys: privateKey, toUserId: {name: 'Test User', email: 'c@c.com'}, armor: false})).to.be.rejectedWith('Could not find user that matches that user ID'); await expect(openpgp.encrypt({message: openpgp.message.fromText('hello'), publicKeys: publicKey, privateKeys: privateKey, toUserIds: {name: 'Test User', email: 'c@c.com'}, armor: false})).to.be.rejectedWith('Could not find user that matches that user ID');
}); });
it('Sign - specific user', async function() { it('Sign - specific user', async function() {
@ -2578,11 +2626,11 @@ VYGdb3eNlV8CfoEC
privateKey.users[0].userId.parse('Test User <b@c.com>'); privateKey.users[0].userId.parse('Test User <b@c.com>');
// Set second user to prefer aes128. We will select this user. // Set second user to prefer aes128. We will select this user.
privateKey.users[1].selfCertifications[0].preferredHashAlgorithms = [openpgp.enums.hash.sha512]; privateKey.users[1].selfCertifications[0].preferredHashAlgorithms = [openpgp.enums.hash.sha512];
const signed = await openpgp.sign({message: openpgp.cleartext.fromText('hello'), privateKeys: privateKey, fromUserId: {name: 'Test McTestington', email: 'test@example.com'}, armor: false}); const signed = await openpgp.sign({message: openpgp.cleartext.fromText('hello'), privateKeys: privateKey, fromUserIds: {name: 'Test McTestington', email: 'test@example.com'}, armor: false});
expect(signed.message.signature.packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512); expect(signed.message.signature.packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512);
const encrypted = await openpgp.encrypt({message: openpgp.message.fromText('hello'), publicKeys: publicKey, privateKeys: privateKey, fromUserId: {name: 'Test McTestington', email: 'test@example.com'}, detached: true, armor: false}); const encrypted = await openpgp.encrypt({message: openpgp.message.fromText('hello'), publicKeys: publicKey, privateKeys: privateKey, fromUserIds: {name: 'Test McTestington', email: 'test@example.com'}, detached: true, armor: false});
expect(encrypted.signature.packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512); expect(encrypted.signature.packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512);
await expect(openpgp.encrypt({message: openpgp.message.fromText('hello'), publicKeys: publicKey, privateKeys: privateKey, fromUserId: {name: 'Not Test McTestington', email: 'test@example.com'}, detached: true, armor: false})).to.be.rejectedWith('Could not find user that matches that user ID'); await expect(openpgp.encrypt({message: openpgp.message.fromText('hello'), publicKeys: publicKey, privateKeys: privateKey, fromUserIds: {name: 'Not Test McTestington', email: 'test@example.com'}, detached: true, armor: false})).to.be.rejectedWith('Could not find user that matches that user ID');
}); });
it('Find a valid subkey binding signature among many invalid ones', async function() { it('Find a valid subkey binding signature among many invalid ones', async function() {

View File

@ -2,4 +2,5 @@ describe('Security', function () {
require('./message_signature_bypass'); require('./message_signature_bypass');
require('./unsigned_subpackets'); require('./unsigned_subpackets');
require('./subkey_trust'); require('./subkey_trust');
require('./preferred_algo_mismatch');
}); });

View File

@ -0,0 +1,49 @@
const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp');
const { key, cleartext, enums, packet: { List, Signature } } = openpgp;
const chai = require('chai');
chai.use(require('chai-as-promised'));
const expect = chai.expect;
const messageArmor = `-----BEGIN PGP MESSAGE-----
Version: OpenPGP.js VERSION
Comment: https://openpgpjs.org
wYwD3eCUoDfD5yoBA/98Ceee8cVOuwZMscnFXzkldJV6Km/Uozcwsx0+Epqb
31qF6QosSgEBNGet5PXxV3VU5BnjSeMnK3500NFGgLZUYKLqdHmtwj4hIz7S
VpX1fVpp5n8729Fuv9MhRcFrrIrRj5h6Mj8G7xIgCQm+uJTla3X8wRXss8/p
y57epbYHO9JGAZsQl6kFLOsgtlV/NPwAtjsH/AzsQs3Y6WcudHh0XB3E+ncK
BLn6oaBjcnlwdGVk0wJnjV2YZRiZ7V3lUIDdYIMNpL+5qA==
=IoHy
-----END PGP MESSAGE-----`;
const privateKeyArmor = `-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: OpenPGP.js VERSION
Comment: https://openpgpjs.org
xcEYBFvbA08BBACl8U5VEY7TNq1PAzwU0f3soqNfFpKtNFt+LY3q5sasouJ7
zE4/TPYrAaAoM5/yOjfvbfJP5myBUCtkdtIRIY2iP2uOPhfaly8U+zH25Qnq
bmgLfvu4ytPAPrKZF8f98cIeJmHD81SPRgDMuB2U9wwgN6stgVBBCUS+lu/L
/4pyuwARAQABAAP+Jz6BIvcrCuJ0bCo8rEPZRHxWHKfO+m1Wcem+FV6Mf8lp
vJNdsfS2hwc0ZC2JVxTTo6kh1CmPYamfCXxcQ7bmsqWkkq/6d17zKE6BqE/n
spW7qTnZ14VPC0iPrBetAWRlCk+m0cEkRnBxqPOVBNd6VPcZyM7GUOGf/kiw
AsHf+nECANkN1tsqLJ3+pH2MRouF7yHevQ9OGg+rwetBO2a8avvcsAuoFjVw
hERpkHv/PQjKAE7KcBzqLLad0QbrQW+sUcMCAMO3to0tSBJrNA9YkrViT76I
siiahSB/FC9JlO+T46xncRleZeBHc0zoVAP+W/PjRo2CR4ydtwjjalrxcKX9
E6kCALfDyhkRNzZLxg2XOGDWyeXqe80VWnMBqTZK73nZlACRcUoXuvjRc15Q
K2c3/nZ7LMyQidj8XsTq4sz1zfWz4Cejj80cVGVzdCBVc2VyIDx0ZXN0QGV4
YW1wbGUuY29tPsK1BBABCAApBQJb2wNPAgsJCRDd4JSgN8PnKgQVCAoCAxYC
AQIZAQIbDwIeBwMiAQIAABGjA/4y6HjthMU03AC3bIUyYPv6EJc9czS5wysa
5rKuNhzka0Klb0INcX1YZ8usPIIl1rtr8f8xxCdSiqhJpn+uqIPVROHi0XLG
ej3gSJM5i1lIt1jxyJlvVI/7W0vzuE85KDzGXQFNFyO/T9D7T1SDHnS8KbBh
EnxUPL95HuMKoVkf4w==
=oopr
-----END PGP PRIVATE KEY BLOCK-----`;
it('Does not accept message encrypted with algo not mentioned in preferred algorithms', async function() {
const message = await openpgp.message.readArmored(messageArmor);
const privKey = (await openpgp.key.readArmored(privateKeyArmor)).keys[0];
await expect(openpgp.decrypt({ message, privateKeys: [privKey] })).to.be.rejectedWith('A non-preferred symmetric algorithm was used.');
});