mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-03-30 15:08:32 +00:00
Add support for v6 key packets
Compared to v5 keys, v6 keys contain additional length fields to aid in parsing the key, but omit the secret key material length field. Additionally, unencrypted v6 secret key packets don't include the count of the optional fields, as per the updated crypto refresh. Since they are always absent, the count is not needed. Finally, unencrypted v6 secret keys do not include the two-byte checksum.
This commit is contained in:
parent
4521de2bea
commit
31c2a2575d
@ -106,10 +106,10 @@ class PublicKeyPacket {
|
||||
*/
|
||||
async read(bytes) {
|
||||
let pos = 0;
|
||||
// A one-octet version number (3, 4 or 5).
|
||||
// A one-octet version number (4, 5 or 6).
|
||||
this.version = bytes[pos++];
|
||||
|
||||
if (this.version === 4 || this.version === 5) {
|
||||
if (this.version === 4 || this.version === 5 || this.version === 6) {
|
||||
// - A four-octet number denoting the time that the key was created.
|
||||
this.created = util.readDate(bytes.subarray(pos, pos + 4));
|
||||
pos += 4;
|
||||
@ -117,7 +117,7 @@ class PublicKeyPacket {
|
||||
// - A one-octet number denoting the public-key algorithm of this key.
|
||||
this.algorithm = bytes[pos++];
|
||||
|
||||
if (this.version === 5) {
|
||||
if (this.version >= 5) {
|
||||
// - A four-octet scalar octet count for the following key material.
|
||||
pos += 4;
|
||||
}
|
||||
@ -147,7 +147,7 @@ class PublicKeyPacket {
|
||||
arr.push(new Uint8Array([this.algorithm]));
|
||||
|
||||
const params = crypto.serializeParams(this.algorithm, this.publicParams);
|
||||
if (this.version === 5) {
|
||||
if (this.version >= 5) {
|
||||
// A four-octet scalar octet count for the following key material
|
||||
arr.push(util.writeNumber(params.length, 4));
|
||||
}
|
||||
@ -163,10 +163,9 @@ class PublicKeyPacket {
|
||||
writeForHash(version) {
|
||||
const bytes = this.writePublicKey();
|
||||
|
||||
if (version === 5) {
|
||||
return util.concatUint8Array([new Uint8Array([0x9A]), util.writeNumber(bytes.length, 4), bytes]);
|
||||
}
|
||||
return util.concatUint8Array([new Uint8Array([0x99]), util.writeNumber(bytes.length, 2), bytes]);
|
||||
const versionOctet = 0x95 + version;
|
||||
const lengthOctets = version >= 5 ? 4 : 2;
|
||||
return util.concatUint8Array([new Uint8Array([versionOctet]), util.writeNumber(bytes.length, lengthOctets), bytes]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -201,7 +200,7 @@ class PublicKeyPacket {
|
||||
await this.computeFingerprint();
|
||||
this.keyID = new KeyID();
|
||||
|
||||
if (this.version === 5) {
|
||||
if (this.version >= 5) {
|
||||
this.keyID.read(this.fingerprint.subarray(0, 8));
|
||||
} else if (this.version === 4) {
|
||||
this.keyID.read(this.fingerprint.subarray(12, 20));
|
||||
@ -216,7 +215,7 @@ class PublicKeyPacket {
|
||||
async computeFingerprint() {
|
||||
const toHash = this.writeForHash(this.version);
|
||||
|
||||
if (this.version === 5) {
|
||||
if (this.version >= 5) {
|
||||
this.fingerprint = await crypto.hash.sha256(toHash);
|
||||
} else if (this.version === 4) {
|
||||
this.fingerprint = await crypto.hash.sha1(toHash);
|
||||
|
@ -100,6 +100,14 @@ class SecretKeyPacket extends PublicKeyPacket {
|
||||
i++;
|
||||
}
|
||||
|
||||
// - Only for a version 6 packet where the secret key material is
|
||||
// encrypted (that is, where the previous octet is not zero), a one-
|
||||
// octet scalar octet count of the cumulative length of all the
|
||||
// following optional string-to-key parameter fields.
|
||||
if (this.version === 6 && this.s2kUsage) {
|
||||
i++;
|
||||
}
|
||||
|
||||
try {
|
||||
// - [Optional] If string-to-key usage octet was 255, 254, or 253, a
|
||||
// one-octet symmetric encryption algorithm.
|
||||
@ -112,6 +120,12 @@ class SecretKeyPacket extends PublicKeyPacket {
|
||||
this.aead = bytes[i++];
|
||||
}
|
||||
|
||||
// - [Optional] Only for a version 6 packet, and if string-to-key usage
|
||||
// octet was 255, 254, or 253, an one-octet count of the following field.
|
||||
if (this.version === 6) {
|
||||
i++;
|
||||
}
|
||||
|
||||
// - [Optional] If string-to-key usage octet was 255, 254, or 253, a
|
||||
// string-to-key specifier. The length of the string-to-key
|
||||
// specifier is implied by its type, as described above.
|
||||
@ -157,9 +171,14 @@ class SecretKeyPacket extends PublicKeyPacket {
|
||||
this.isEncrypted = !!this.s2kUsage;
|
||||
|
||||
if (!this.isEncrypted) {
|
||||
const cleartext = this.keyMaterial.subarray(0, -2);
|
||||
if (!util.equalsUint8Array(util.writeChecksum(cleartext), this.keyMaterial.subarray(-2))) {
|
||||
throw new Error('Key checksum mismatch');
|
||||
let cleartext;
|
||||
if (this.version === 6) {
|
||||
cleartext = this.keyMaterial;
|
||||
} else {
|
||||
cleartext = this.keyMaterial.subarray(0, -2);
|
||||
if (!util.equalsUint8Array(util.writeChecksum(cleartext), this.keyMaterial.subarray(-2))) {
|
||||
throw new Error('Key checksum mismatch');
|
||||
}
|
||||
}
|
||||
try {
|
||||
const { privateParams } = crypto.parsePrivateKeyParams(this.algorithm, cleartext, this.publicParams);
|
||||
@ -200,10 +219,18 @@ class SecretKeyPacket extends PublicKeyPacket {
|
||||
optionalFieldsArr.push(this.aead);
|
||||
}
|
||||
|
||||
const s2k = this.s2k.write();
|
||||
|
||||
// - [Optional] Only for a version 6 packet, and if string-to-key usage
|
||||
// octet was 255, 254, or 253, an one-octet count of the following field.
|
||||
if (this.version === 6) {
|
||||
optionalFieldsArr.push(s2k.length);
|
||||
}
|
||||
|
||||
// - [Optional] If string-to-key usage octet was 255, 254, or 253, a
|
||||
// string-to-key specifier. The length of the string-to-key
|
||||
// specifier is implied by its type, as described above.
|
||||
optionalFieldsArr.push(...this.s2k.write());
|
||||
optionalFieldsArr.push(...s2k);
|
||||
}
|
||||
|
||||
// - [Optional] If secret data is encrypted (string-to-key usage octet
|
||||
@ -213,7 +240,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
||||
optionalFieldsArr.push(...this.iv);
|
||||
}
|
||||
|
||||
if (this.version === 5) {
|
||||
if (this.version === 5 || (this.version === 6 && this.s2kUsage)) {
|
||||
arr.push(new Uint8Array([optionalFieldsArr.length]));
|
||||
}
|
||||
arr.push(new Uint8Array(optionalFieldsArr));
|
||||
@ -228,7 +255,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
||||
}
|
||||
arr.push(this.keyMaterial);
|
||||
|
||||
if (!this.s2kUsage) {
|
||||
if (!this.s2kUsage && this.version !== 6) {
|
||||
arr.push(util.writeChecksum(this.keyMaterial));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user