Implement version 5 Secret-Key Packet Format
This commit is contained in:
parent
5d43b44e50
commit
c2f898279b
|
@ -468,7 +468,7 @@ Key.prototype.getExpirationTime = async function() {
|
||||||
if (this.primaryKey.version === 3) {
|
if (this.primaryKey.version === 3) {
|
||||||
return getExpirationTime(this.primaryKey);
|
return getExpirationTime(this.primaryKey);
|
||||||
}
|
}
|
||||||
if (this.primaryKey.version === 4) {
|
if (this.primaryKey.version >= 4) {
|
||||||
const primaryUser = await this.getPrimaryUser(null);
|
const primaryUser = await this.getPrimaryUser(null);
|
||||||
const selfCert = primaryUser.selfCertification;
|
const selfCert = primaryUser.selfCertification;
|
||||||
const keyExpiry = getExpirationTime(this.primaryKey, selfCert);
|
const keyExpiry = getExpirationTime(this.primaryKey, selfCert);
|
||||||
|
@ -1383,7 +1383,7 @@ function getExpirationTime(keyPacket, signature) {
|
||||||
expirationTime = keyPacket.created.getTime() + keyPacket.expirationTimeV3*24*3600*1000;
|
expirationTime = keyPacket.created.getTime() + keyPacket.expirationTimeV3*24*3600*1000;
|
||||||
}
|
}
|
||||||
// check V4 expiration time
|
// check V4 expiration time
|
||||||
if (keyPacket.version === 4 && signature.keyNeverExpires === false) {
|
if (keyPacket.version >= 4 && signature.keyNeverExpires === false) {
|
||||||
expirationTime = keyPacket.created.getTime() + signature.keyExpirationTime*1000;
|
expirationTime = keyPacket.created.getTime() + signature.keyExpirationTime*1000;
|
||||||
}
|
}
|
||||||
return expirationTime ? new Date(expirationTime) : Infinity;
|
return expirationTime ? new Date(expirationTime) : Infinity;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
/**
|
/**
|
||||||
* @requires type/keyid
|
* @requires type/keyid
|
||||||
* @requires type/mpi
|
* @requires type/mpi
|
||||||
|
* @requires config
|
||||||
* @requires crypto
|
* @requires crypto
|
||||||
* @requires enums
|
* @requires enums
|
||||||
* @requires util
|
* @requires util
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
|
|
||||||
import type_keyid from '../type/keyid';
|
import type_keyid from '../type/keyid';
|
||||||
import type_mpi from '../type/mpi';
|
import type_mpi from '../type/mpi';
|
||||||
|
import config from '../config';
|
||||||
import crypto from '../crypto';
|
import crypto from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
@ -52,7 +54,7 @@ function PublicKey(date=new Date()) {
|
||||||
* Packet version
|
* Packet version
|
||||||
* @type {Integer}
|
* @type {Integer}
|
||||||
*/
|
*/
|
||||||
this.version = 4;
|
this.version = config.aead_protect === 'draft04' ? 5 : 4;
|
||||||
/**
|
/**
|
||||||
* Key creation date.
|
* Key creation date.
|
||||||
* @type {Date}
|
* @type {Date}
|
||||||
|
@ -88,10 +90,10 @@ function PublicKey(date=new Date()) {
|
||||||
*/
|
*/
|
||||||
PublicKey.prototype.read = function (bytes) {
|
PublicKey.prototype.read = function (bytes) {
|
||||||
let pos = 0;
|
let pos = 0;
|
||||||
// A one-octet version number (3 or 4).
|
// A one-octet version number (3, 4 or 5).
|
||||||
this.version = bytes[pos++];
|
this.version = bytes[pos++];
|
||||||
|
|
||||||
if (this.version === 3 || this.version === 4) {
|
if (this.version === 3 || this.version === 4 || this.version === 5) {
|
||||||
// - A four-octet number denoting the time that the key was created.
|
// - A four-octet number denoting the time that the key was created.
|
||||||
this.created = util.readDate(bytes.subarray(pos, pos + 4));
|
this.created = util.readDate(bytes.subarray(pos, pos + 4));
|
||||||
pos += 4;
|
pos += 4;
|
||||||
|
@ -106,20 +108,25 @@ PublicKey.prototype.read = function (bytes) {
|
||||||
// - A one-octet number denoting the public-key algorithm of this key.
|
// - A one-octet number denoting the public-key algorithm of this key.
|
||||||
this.algorithm = enums.read(enums.publicKey, bytes[pos++]);
|
this.algorithm = enums.read(enums.publicKey, bytes[pos++]);
|
||||||
const algo = enums.write(enums.publicKey, this.algorithm);
|
const algo = enums.write(enums.publicKey, this.algorithm);
|
||||||
|
|
||||||
|
if (this.version === 5) {
|
||||||
|
// - A four-octet scalar octet count for the following key material.
|
||||||
|
pos += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - A series of values comprising the key material. This is
|
||||||
|
// algorithm-specific and described in section XXXX.
|
||||||
const types = crypto.getPubKeyParamTypes(algo);
|
const types = crypto.getPubKeyParamTypes(algo);
|
||||||
this.params = crypto.constructParams(types);
|
this.params = crypto.constructParams(types);
|
||||||
|
|
||||||
const b = bytes.subarray(pos, bytes.length);
|
for (let i = 0; i < types.length && pos < bytes.length; i++) {
|
||||||
let p = 0;
|
pos += this.params[i].read(bytes.subarray(pos, bytes.length));
|
||||||
|
if (pos > bytes.length) {
|
||||||
for (let i = 0; i < types.length && p < b.length; i++) {
|
throw new Error('Error reading MPI @:' + pos);
|
||||||
p += this.params[i].read(b.subarray(p, b.length));
|
|
||||||
if (p > b.length) {
|
|
||||||
throw new Error('Error reading MPI @:' + p);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return p + 6;
|
return pos;
|
||||||
}
|
}
|
||||||
throw new Error('Version ' + this.version + ' of the key packet is unsupported.');
|
throw new Error('Version ' + this.version + ' of the key packet is unsupported.');
|
||||||
};
|
};
|
||||||
|
@ -143,14 +150,18 @@ PublicKey.prototype.write = function () {
|
||||||
if (this.version === 3) {
|
if (this.version === 3) {
|
||||||
arr.push(util.writeNumber(this.expirationTimeV3, 2));
|
arr.push(util.writeNumber(this.expirationTimeV3, 2));
|
||||||
}
|
}
|
||||||
// Algorithm-specific params
|
// A one-octet number denoting the public-key algorithm of this key
|
||||||
const algo = enums.write(enums.publicKey, this.algorithm);
|
const algo = enums.write(enums.publicKey, this.algorithm);
|
||||||
const paramCount = crypto.getPubKeyParamTypes(algo).length;
|
|
||||||
arr.push(new Uint8Array([algo]));
|
arr.push(new Uint8Array([algo]));
|
||||||
for (let i = 0; i < paramCount; i++) {
|
|
||||||
arr.push(this.params[i].write());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const paramCount = crypto.getPubKeyParamTypes(algo).length;
|
||||||
|
const params = util.concatUint8Array(this.params.slice(0, paramCount).map(param => param.write()));
|
||||||
|
if (this.version === 5) {
|
||||||
|
// A four-octet scalar octet count for the following key material
|
||||||
|
arr.push(util.writeNumber(params.length, 4));
|
||||||
|
}
|
||||||
|
// Algorithm-specific params
|
||||||
|
arr.push(params);
|
||||||
return util.concatUint8Array(arr);
|
return util.concatUint8Array(arr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -178,7 +189,9 @@ PublicKey.prototype.getKeyId = function () {
|
||||||
return this.keyid;
|
return this.keyid;
|
||||||
}
|
}
|
||||||
this.keyid = new type_keyid();
|
this.keyid = new type_keyid();
|
||||||
if (this.version === 4) {
|
if (this.version === 5) {
|
||||||
|
this.keyid.read(util.hex_to_Uint8Array(this.getFingerprint()).subarray(0, 8));
|
||||||
|
} else if (this.version === 4) {
|
||||||
this.keyid.read(util.hex_to_Uint8Array(this.getFingerprint()).subarray(12, 20));
|
this.keyid.read(util.hex_to_Uint8Array(this.getFingerprint()).subarray(12, 20));
|
||||||
} else if (this.version === 3) {
|
} else if (this.version === 3) {
|
||||||
const arr = this.params[0].write();
|
const arr = this.params[0].write();
|
||||||
|
@ -195,13 +208,18 @@ PublicKey.prototype.getFingerprint = function () {
|
||||||
if (this.fingerprint) {
|
if (this.fingerprint) {
|
||||||
return this.fingerprint;
|
return this.fingerprint;
|
||||||
}
|
}
|
||||||
let toHash = '';
|
let toHash;
|
||||||
if (this.version === 4) {
|
if (this.version === 5) {
|
||||||
|
const bytes = this.writePublicKey();
|
||||||
|
toHash = util.concatUint8Array([new Uint8Array([0x9A]), util.writeNumber(bytes.length, 4), bytes]);
|
||||||
|
this.fingerprint = util.Uint8Array_to_str(crypto.hash.sha256(toHash));
|
||||||
|
} else if (this.version === 4) {
|
||||||
toHash = this.writeOld();
|
toHash = this.writeOld();
|
||||||
this.fingerprint = util.Uint8Array_to_str(crypto.hash.sha1(toHash));
|
this.fingerprint = util.Uint8Array_to_str(crypto.hash.sha1(toHash));
|
||||||
} else if (this.version === 3) {
|
} else if (this.version === 3) {
|
||||||
const algo = enums.write(enums.publicKey, this.algorithm);
|
const algo = enums.write(enums.publicKey, this.algorithm);
|
||||||
const paramCount = crypto.getPubKeyParamTypes(algo).length;
|
const paramCount = crypto.getPubKeyParamTypes(algo).length;
|
||||||
|
toHash = '';
|
||||||
for (let i = 0; i < paramCount; i++) {
|
for (let i = 0; i < paramCount; i++) {
|
||||||
toHash += this.params[i].toString();
|
toHash += this.params[i].toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,7 @@ function get_hash_fn(hash) {
|
||||||
// Helper function
|
// Helper function
|
||||||
|
|
||||||
function parse_cleartext_params(hash_algorithm, cleartext, algorithm) {
|
function parse_cleartext_params(hash_algorithm, cleartext, algorithm) {
|
||||||
|
if (hash_algorithm) {
|
||||||
const hashlen = get_hash_len(hash_algorithm);
|
const hashlen = get_hash_len(hash_algorithm);
|
||||||
const hashfn = get_hash_fn(hash_algorithm);
|
const hashfn = get_hash_fn(hash_algorithm);
|
||||||
|
|
||||||
|
@ -86,7 +87,8 @@ function parse_cleartext_params(hash_algorithm, cleartext, algorithm) {
|
||||||
const hash = util.Uint8Array_to_str(hashfn(cleartext));
|
const hash = util.Uint8Array_to_str(hashfn(cleartext));
|
||||||
|
|
||||||
if (hash !== hashtext) {
|
if (hash !== hashtext) {
|
||||||
return new Error("Incorrect key passphrase");
|
throw new Error("Incorrect key passphrase");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const algo = enums.write(enums.publicKey, algorithm);
|
const algo = enums.write(enums.publicKey, algorithm);
|
||||||
|
@ -115,17 +117,21 @@ function write_cleartext_params(hash_algorithm, algorithm, params) {
|
||||||
|
|
||||||
const bytes = util.concatUint8Array(arr);
|
const bytes = util.concatUint8Array(arr);
|
||||||
|
|
||||||
|
if (hash_algorithm) {
|
||||||
const hash = get_hash_fn(hash_algorithm)(bytes);
|
const hash = get_hash_fn(hash_algorithm)(bytes);
|
||||||
|
|
||||||
return util.concatUint8Array([bytes, hash]);
|
return util.concatUint8Array([bytes, hash]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 5.5.3. Secret-Key Packet Formats
|
// 5.5.3. Secret-Key Packet Formats
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal parser for private keys as specified in
|
* Internal parser for private keys as specified in
|
||||||
* {@link https://tools.ietf.org/html/rfc4880#section-5.5.3|RFC 4880 section 5.5.3}
|
* {@link https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-04#section-5.5.3|RFC4880bis-04 section 5.5.3}
|
||||||
* @param {String} bytes Input string to read the packet from
|
* @param {String} bytes Input string to read the packet from
|
||||||
*/
|
*/
|
||||||
SecretKey.prototype.read = function (bytes) {
|
SecretKey.prototype.read = function (bytes) {
|
||||||
|
@ -148,9 +154,6 @@ SecretKey.prototype.read = function (bytes) {
|
||||||
// key data. These algorithm-specific fields are as described
|
// key data. These algorithm-specific fields are as described
|
||||||
// below.
|
// below.
|
||||||
const privParams = parse_cleartext_params('mod', bytes.subarray(1, bytes.length), this.algorithm);
|
const privParams = parse_cleartext_params('mod', bytes.subarray(1, bytes.length), this.algorithm);
|
||||||
if (privParams instanceof Error) {
|
|
||||||
throw privParams;
|
|
||||||
}
|
|
||||||
this.params = this.params.concat(privParams);
|
this.params = this.params.concat(privParams);
|
||||||
this.isDecrypted = true;
|
this.isDecrypted = true;
|
||||||
}
|
}
|
||||||
|
@ -194,15 +197,29 @@ SecretKey.prototype.encrypt = async function (passphrase) {
|
||||||
const s2k = new type_s2k();
|
const s2k = new type_s2k();
|
||||||
s2k.salt = await crypto.random.getRandomBytes(8);
|
s2k.salt = await crypto.random.getRandomBytes(8);
|
||||||
const symmetric = 'aes256';
|
const symmetric = 'aes256';
|
||||||
const cleartext = write_cleartext_params('sha1', this.algorithm, this.params);
|
const hash = this.version === 5 ? null : 'sha1';
|
||||||
|
const cleartext = write_cleartext_params(hash, this.algorithm, this.params);
|
||||||
const key = produceEncryptionKey(s2k, passphrase, symmetric);
|
const key = produceEncryptionKey(s2k, passphrase, symmetric);
|
||||||
const blockLen = crypto.cipher[symmetric].blockSize;
|
const blockLen = crypto.cipher[symmetric].blockSize;
|
||||||
const iv = await crypto.random.getRandomBytes(blockLen);
|
const iv = await crypto.random.getRandomBytes(blockLen);
|
||||||
|
|
||||||
const arr = [new Uint8Array([254, enums.write(enums.symmetric, symmetric)])];
|
let arr;
|
||||||
|
|
||||||
|
if (this.version === 5) {
|
||||||
|
const aead = 'eax';
|
||||||
|
const optionalFields = util.concatUint8Array([new Uint8Array([enums.write(enums.symmetric, symmetric), enums.write(enums.aead, aead)]), s2k.write(), iv]);
|
||||||
|
arr = [new Uint8Array([253, optionalFields.length])];
|
||||||
|
arr.push(optionalFields);
|
||||||
|
const mode = crypto[aead];
|
||||||
|
const encrypted = await mode.encrypt(symmetric, cleartext, key, iv.subarray(0, mode.ivLength), new Uint8Array());
|
||||||
|
arr.push(util.writeNumber(encrypted.length, 4));
|
||||||
|
arr.push(encrypted);
|
||||||
|
} else {
|
||||||
|
arr = [new Uint8Array([254, enums.write(enums.symmetric, symmetric)])];
|
||||||
arr.push(s2k.write());
|
arr.push(s2k.write());
|
||||||
arr.push(iv);
|
arr.push(iv);
|
||||||
arr.push(crypto.cfb.normalEncrypt(symmetric, key, cleartext, iv));
|
arr.push(crypto.cfb.normalEncrypt(symmetric, key, cleartext, iv));
|
||||||
|
}
|
||||||
|
|
||||||
this.encrypted = util.concatUint8Array(arr);
|
this.encrypted = util.concatUint8Array(arr);
|
||||||
return true;
|
return true;
|
||||||
|
@ -230,17 +247,31 @@ SecretKey.prototype.decrypt = async function (passphrase) {
|
||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let symmetric;
|
let symmetric;
|
||||||
|
let aead;
|
||||||
let key;
|
let key;
|
||||||
|
|
||||||
const s2k_usage = this.encrypted[i++];
|
const s2k_usage = this.encrypted[i++];
|
||||||
|
|
||||||
// - [Optional] If string-to-key usage octet was 255 or 254, a one-
|
// - Only for a version 5 packet, a one-octet scalar octet count of
|
||||||
// octet symmetric encryption algorithm.
|
// the next 4 optional fields.
|
||||||
if (s2k_usage === 255 || s2k_usage === 254) {
|
if (this.version === 5) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - [Optional] If string-to-key usage octet was 255, 254, or 253, a
|
||||||
|
// one-octet symmetric encryption algorithm.
|
||||||
|
if (s2k_usage === 255 || s2k_usage === 254 || s2k_usage === 253) {
|
||||||
symmetric = this.encrypted[i++];
|
symmetric = this.encrypted[i++];
|
||||||
symmetric = enums.read(enums.symmetric, symmetric);
|
symmetric = enums.read(enums.symmetric, symmetric);
|
||||||
|
|
||||||
// - [Optional] If string-to-key usage octet was 255 or 254, a
|
// - [Optional] If string-to-key usage octet was 253, a one-octet
|
||||||
|
// AEAD algorithm.
|
||||||
|
if (s2k_usage === 253) {
|
||||||
|
aead = this.encrypted[i++];
|
||||||
|
aead = enums.read(enums.aead, aead);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - [Optional] If string-to-key usage octet was 255, 254, or 253, a
|
||||||
// string-to-key specifier. The length of the string-to-key
|
// string-to-key specifier. The length of the string-to-key
|
||||||
// specifier is implied by its type, as described above.
|
// specifier is implied by its type, as described above.
|
||||||
const s2k = new type_s2k();
|
const s2k = new type_s2k();
|
||||||
|
@ -263,16 +294,32 @@ SecretKey.prototype.decrypt = async function (passphrase) {
|
||||||
|
|
||||||
i += iv.length;
|
i += iv.length;
|
||||||
|
|
||||||
|
// - Only for a version 5 packet, a four-octet scalar octet count for
|
||||||
|
// the following key material.
|
||||||
|
if (this.version === 5) {
|
||||||
|
i += 4;
|
||||||
|
}
|
||||||
|
|
||||||
const ciphertext = this.encrypted.subarray(i, this.encrypted.length);
|
const ciphertext = this.encrypted.subarray(i, this.encrypted.length);
|
||||||
const cleartext = crypto.cfb.normalDecrypt(symmetric, key, ciphertext, iv);
|
let cleartext;
|
||||||
const hash = s2k_usage === 254 ?
|
if (aead) {
|
||||||
'sha1' :
|
const mode = crypto[aead];
|
||||||
|
try {
|
||||||
|
cleartext = await mode.decrypt(symmetric, ciphertext, key, iv.subarray(0, mode.ivLength), new Uint8Array());
|
||||||
|
} catch(err) {
|
||||||
|
if (err.message.startsWith('Authentication tag mismatch')) {
|
||||||
|
throw new Error('Incorrect key passphrase: ' + err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cleartext = crypto.cfb.normalDecrypt(symmetric, key, ciphertext, iv);
|
||||||
|
}
|
||||||
|
const hash =
|
||||||
|
s2k_usage === 253 ? null :
|
||||||
|
s2k_usage === 254 ? 'sha1' :
|
||||||
'mod';
|
'mod';
|
||||||
|
|
||||||
const privParams = parse_cleartext_params(hash, cleartext, this.algorithm);
|
const privParams = parse_cleartext_params(hash, cleartext, this.algorithm);
|
||||||
if (privParams instanceof Error) {
|
|
||||||
throw privParams;
|
|
||||||
}
|
|
||||||
this.params = this.params.concat(privParams);
|
this.params = this.params.concat(privParams);
|
||||||
this.isDecrypted = true;
|
this.isDecrypted = true;
|
||||||
this.encrypted = null;
|
this.encrypted = null;
|
||||||
|
|
|
@ -6,6 +6,23 @@ chai.use(require('chai-as-promised'));
|
||||||
const { expect } = chai;
|
const { expect } = chai;
|
||||||
|
|
||||||
describe('Key', function() {
|
describe('Key', function() {
|
||||||
|
describe('V4', tests);
|
||||||
|
|
||||||
|
describe('V5', function() {
|
||||||
|
let aead_protectVal;
|
||||||
|
beforeEach(function() {
|
||||||
|
aead_protectVal = openpgp.config.aead_protect;
|
||||||
|
openpgp.config.aead_protect = 'draft04';
|
||||||
|
});
|
||||||
|
afterEach(function() {
|
||||||
|
openpgp.config.aead_protect = aead_protectVal;
|
||||||
|
});
|
||||||
|
|
||||||
|
tests();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function tests() {
|
||||||
const twoKeys =
|
const twoKeys =
|
||||||
['-----BEGIN PGP PUBLIC KEY BLOCK-----',
|
['-----BEGIN PGP PUBLIC KEY BLOCK-----',
|
||||||
'Version: GnuPG v2.0.19 (GNU/Linux)',
|
'Version: GnuPG v2.0.19 (GNU/Linux)',
|
||||||
|
@ -893,6 +910,21 @@ p92yZgB3r2+f6/GIe2+7
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Parsing V5 public key packet', function() {
|
||||||
|
// Manually modified from https://gitlab.com/openpgp-wg/rfc4880bis/blob/00b2092/back.mkd#sample-eddsa-key
|
||||||
|
let packetBytes = openpgp.util.hex_to_Uint8Array(`
|
||||||
|
98 37 05 53 f3 5f 0b 16 00 00 00 2d 09 2b 06 01 04 01 da 47
|
||||||
|
0f 01 01 07 40 3f 09 89 94 bd d9 16 ed 40 53 19
|
||||||
|
79 34 e4 a8 7c 80 73 3a 12 80 d6 2f 80 10 99 2e
|
||||||
|
43 ee 3b 24 06
|
||||||
|
`.replace(/\s+/g, ''));
|
||||||
|
|
||||||
|
let packetlist = new openpgp.packet.List();
|
||||||
|
packetlist.read(packetBytes);
|
||||||
|
let key = packetlist[0];
|
||||||
|
expect(key).to.exist;
|
||||||
|
});
|
||||||
|
|
||||||
it('Testing key ID and fingerprint for V3 and V4 keys', function(done) {
|
it('Testing key ID and fingerprint for V3 and V4 keys', function(done) {
|
||||||
const pubKeysV4 = openpgp.key.readArmored(twoKeys);
|
const pubKeysV4 = openpgp.key.readArmored(twoKeys);
|
||||||
expect(pubKeysV4).to.exist;
|
expect(pubKeysV4).to.exist;
|
||||||
|
@ -1574,4 +1606,4 @@ p92yZgB3r2+f6/GIe2+7
|
||||||
expect(error.message).to.equal('Error encrypting message: Could not find valid key packet for encryption in key ' + key.primaryKey.getKeyId().toHex());
|
expect(error.message).to.equal('Error encrypting message: Could not find valid key packet for encryption in key ' + key.primaryKey.getKeyId().toHex());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
|
@ -637,6 +637,38 @@ describe("Packet", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Writing and encryption of a secret key packet. (draft04)', function() {
|
||||||
|
let aead_protectVal = openpgp.config.aead_protect;
|
||||||
|
openpgp.config.aead_protect = 'draft04';
|
||||||
|
|
||||||
|
const key = new openpgp.packet.List();
|
||||||
|
key.push(new openpgp.packet.SecretKey());
|
||||||
|
|
||||||
|
const rsa = openpgp.crypto.publicKey.rsa;
|
||||||
|
const keySize = openpgp.util.getWebCryptoAll() ? 2048 : 512; // webkit webcrypto accepts minimum 2048 bit keys
|
||||||
|
|
||||||
|
return rsa.generate(keySize, "10001").then(async function(mpiGen) {
|
||||||
|
let mpi = [mpiGen.n, mpiGen.e, mpiGen.d, mpiGen.p, mpiGen.q, mpiGen.u];
|
||||||
|
mpi = mpi.map(function(k) {
|
||||||
|
return new openpgp.MPI(k);
|
||||||
|
});
|
||||||
|
|
||||||
|
key[0].params = mpi;
|
||||||
|
key[0].algorithm = "rsa_sign";
|
||||||
|
await key[0].encrypt('hello');
|
||||||
|
|
||||||
|
const raw = key.write();
|
||||||
|
|
||||||
|
const key2 = new openpgp.packet.List();
|
||||||
|
key2.read(raw);
|
||||||
|
await key2[0].decrypt('hello');
|
||||||
|
|
||||||
|
expect(key[0].params.toString()).to.equal(key2[0].params.toString());
|
||||||
|
}).finally(function() {
|
||||||
|
openpgp.config.aead_protect = aead_protectVal;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('Writing and verification of a signature packet.', function() {
|
it('Writing and verification of a signature packet.', function() {
|
||||||
const key = new openpgp.packet.SecretKey();
|
const key = new openpgp.packet.SecretKey();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user