Merge branch 'master' into fix/non-primary-non-revoked-sub-user
This commit is contained in:
commit
529973f2a2
10
README.md
10
README.md
|
@ -1,4 +1,4 @@
|
||||||
OpenPGP.js [](https://travis-ci.org/openpgpjs/openpgpjs)
|
OpenPGP.js [](https://travis-ci.org/openpgpjs/openpgpjs) [](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
|
||||||
|
|
||||||
|
|
|
@ -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": [
|
||||||
|
|
1420
dist/compat/openpgp.js
vendored
1420
dist/compat/openpgp.js
vendored
File diff suppressed because it is too large
Load Diff
4
dist/compat/openpgp.min.js
vendored
4
dist/compat/openpgp.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/compat/openpgp.worker.min.js
vendored
2
dist/compat/openpgp.worker.min.js
vendored
|
@ -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]);
|
513
dist/openpgp.js
vendored
513
dist/openpgp.js
vendored
File diff suppressed because it is too large
Load Diff
4
dist/openpgp.min.js
vendored
4
dist/openpgp.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/openpgp.worker.min.js
vendored
2
dist/openpgp.worker.min.js
vendored
|
@ -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
4
npm-shrinkwrap.json
generated
|
@ -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": {
|
||||||
|
|
|
@ -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": {
|
||||||
|
|
|
@ -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));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 () {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
92
src/key.js
92
src/key.js
|
@ -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;
|
||||||
|
|
|
@ -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');
|
||||||
}
|
}
|
||||||
|
|
|
@ -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'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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>}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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, []
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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');
|
||||||
});
|
});
|
||||||
|
|
49
test/security/preferred_algo_mismatch.js
Normal file
49
test/security/preferred_algo_mismatch.js
Normal 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.');
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user