mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-03-30 15:08:32 +00:00
Implement Padding Packet
This commit is contained in:
parent
9d85938ed7
commit
6ae87b9208
@ -223,7 +223,8 @@ export default {
|
||||
userAttribute: 17,
|
||||
symEncryptedIntegrityProtectedData: 18,
|
||||
modificationDetectionCode: 19,
|
||||
aeadEncryptedData: 20 // see IETF draft: https://tools.ietf.org/html/draft-ford-openpgp-format-00#section-2.1
|
||||
aeadEncryptedData: 20, // see IETF draft: https://tools.ietf.org/html/draft-ford-openpgp-format-00#section-2.1
|
||||
padding: 21
|
||||
},
|
||||
|
||||
/** Data types in the literal packet
|
||||
|
@ -21,3 +21,4 @@ export { default as UserIDPacket } from './userid';
|
||||
export { default as SecretSubkeyPacket } from './secret_subkey';
|
||||
export { default as SignaturePacket } from './signature';
|
||||
export { default as TrustPacket } from './trust';
|
||||
export { default as PaddingPacket } from './padding';
|
||||
|
@ -74,10 +74,11 @@ class PacketList extends Array {
|
||||
await writer.ready;
|
||||
const done = await readPackets(readable, async parsed => {
|
||||
try {
|
||||
if (parsed.tag === enums.packet.marker || parsed.tag === enums.packet.trust) {
|
||||
if (parsed.tag === enums.packet.marker || parsed.tag === enums.packet.trust || parsed.tag === enums.packet.padding) {
|
||||
// According to the spec, these packet types should be ignored and not cause parsing errors, even if not esplicitly allowed:
|
||||
// - Marker packets MUST be ignored when received: https://github.com/openpgpjs/openpgpjs/issues/1145
|
||||
// - Trust packets SHOULD be ignored outside of keyrings (unsupported): https://datatracker.ietf.org/doc/html/rfc4880#section-5.10
|
||||
// - [Padding Packets] MUST be ignored when received: https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#name-padding-packet-tag-21
|
||||
return;
|
||||
}
|
||||
const packet = newPacketFromTag(parsed.tag, allowedPackets);
|
||||
|
63
src/packet/padding.js
Normal file
63
src/packet/padding.js
Normal file
@ -0,0 +1,63 @@
|
||||
// OpenPGP.js - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2022 Proton AG
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3.0 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
import crypto from '../crypto';
|
||||
import enums from '../enums';
|
||||
|
||||
/**
|
||||
* Implementation of the Padding Packet
|
||||
*
|
||||
* {@link https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#name-padding-packet-tag-21}:
|
||||
* Padding Packet
|
||||
*/
|
||||
class PaddingPacket {
|
||||
static get tag() {
|
||||
return enums.packet.padding;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.padding = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a padding packet
|
||||
* @param {Uint8Array | ReadableStream<Uint8Array>} bytes
|
||||
*/
|
||||
read(bytes) {
|
||||
// Padding packets are ignored, so this function is never called.
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the padding packet
|
||||
* @returns {Uint8Array} The padding packet.
|
||||
*/
|
||||
write() {
|
||||
return this.padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create random padding.
|
||||
* @param {Number} length - The length of padding to be generated.
|
||||
* @throws {Error} if padding generation was not successful
|
||||
* @async
|
||||
*/
|
||||
async createPadding(length) {
|
||||
this.padding = await crypto.random.getRandomBytes(length);
|
||||
}
|
||||
}
|
||||
|
||||
export default PaddingPacket;
|
@ -280,6 +280,168 @@ export default () => describe('Packet', function() {
|
||||
}
|
||||
});
|
||||
|
||||
it('Sym. encrypted AEAD protected packet test vector (SEIPDv2 - EAX)', async function() {
|
||||
// From https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#appendix-A-5
|
||||
|
||||
const nodeCrypto = util.getNodeCrypto();
|
||||
if (!nodeCrypto) return;
|
||||
|
||||
const packetBytes = util.hexToUint8Array(`
|
||||
d2 69 02 07 01 06
|
||||
9f f9 0e 3b 32 19 64 f3 a4 29 13 c8 dc c6 61 93
|
||||
25 01 52 27 ef b7 ea ea a4 9f 04 c2 e6 74 17 5d
|
||||
4a 3d 22 6e d6 af cb 9c a9 ac 12 2c 14 70 e1 1c
|
||||
63 d4 c0 ab 24 1c 6a 93 8a d4 8b f9 9a 5a 99 b9
|
||||
0b ba 83 25 de
|
||||
61 04 75 40 25 8a b7 95 9a 95 ad 05 1d da 96 eb
|
||||
15 43 1d fe f5 f5 e2 25 5c a7 82 61 54 6e 33 9a
|
||||
`.replace(/\s+/g, ''));
|
||||
|
||||
const padding = util.hexToUint8Array('ae 5b f0 cd 67 05 50 03 55 81 6c b0 c8 ff'.replace(/\s+/g, ''));
|
||||
const salt = util.hexToUint8Array('9f f9 0e 3b 32 19 64 f3 a4 29 13 c8 dc c6 61 93 25 01 52 27 ef b7 ea ea a4 9f 04 c2 e6 74 17 5d'.replace(/\s+/g, ''));
|
||||
const key = util.hexToUint8Array('38 81 ba fe 98 54 12 45 9b 86 c3 6f 98 cb 9a 5e'.replace(/\s+/g, ''));
|
||||
const algo = openpgp.enums.symmetric.aes128;
|
||||
|
||||
const randomBytesStub = sinon.stub(nodeCrypto, 'randomBytes');
|
||||
randomBytesStub.withArgs(14).returns(padding);
|
||||
randomBytesStub.withArgs(32).returns(salt);
|
||||
|
||||
const literal = new openpgp.LiteralDataPacket(0);
|
||||
literal.setBytes(util.stringToUint8Array('Hello, world!'), openpgp.enums.literal.binary);
|
||||
literal.filename = '';
|
||||
const pad = new openpgp.PaddingPacket();
|
||||
await pad.createPadding(14);
|
||||
const enc = new openpgp.SymEncryptedIntegrityProtectedDataPacket();
|
||||
enc.version = 2;
|
||||
enc.aeadAlgorithm = openpgp.enums.aead.eax;
|
||||
enc.packets = new openpgp.PacketList();
|
||||
enc.packets.push(literal);
|
||||
enc.packets.push(pad);
|
||||
const msg = new openpgp.PacketList();
|
||||
msg.push(enc);
|
||||
|
||||
const msg2 = new openpgp.PacketList();
|
||||
|
||||
try {
|
||||
await enc.encrypt(algo, key, { ...openpgp.config, aeadChunkSizeByte: 6 });
|
||||
const data = msg.write();
|
||||
expect(await stream.readToEnd(stream.clone(data))).to.deep.equal(packetBytes);
|
||||
await msg2.read(data, allAllowedPackets);
|
||||
await msg2[0].decrypt(algo, key);
|
||||
expect(await stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
|
||||
} finally {
|
||||
randomBytesStub.restore();
|
||||
}
|
||||
});
|
||||
|
||||
it('Sym. encrypted AEAD protected packet test vector (SEIPDv2 - OCB)', async function() {
|
||||
// From https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#appendix-A-5
|
||||
|
||||
const nodeCrypto = util.getNodeCrypto();
|
||||
if (!nodeCrypto) return;
|
||||
|
||||
const packetBytes = util.hexToUint8Array(`
|
||||
d2 69 02 07 02 06
|
||||
20 a6 61 f7 31 fc 9a 30 32 b5 62 33 26 02 7e 3a
|
||||
5d 8d b5 74 8e be ff 0b 0c 59 10 d0 9e cd d6 41
|
||||
ff 9f d3 85 62 75 80 35 bc 49 75 4c e1 bf 3f ff
|
||||
a7 da d0 a3 b8 10 4f 51 33 cf 42 a4 10 0a 83 ee
|
||||
f4 ca 1b 48 01
|
||||
a8 84 6b f4 2b cd a7 c8 ce 9d 65 e2 12 f3 01 cb
|
||||
cd 98 fd ca de 69 4a 87 7a d4 24 73 23 f6 e8 57
|
||||
`.replace(/\s+/g, ''));
|
||||
|
||||
const padding = util.hexToUint8Array('ae 6a a1 64 9b 56 aa 83 5b 26 13 90 2b d2'.replace(/\s+/g, ''));
|
||||
const salt = util.hexToUint8Array('20 a6 61 f7 31 fc 9a 30 32 b5 62 33 26 02 7e 3a 5d 8d b5 74 8e be ff 0b 0c 59 10 d0 9e cd d6 41'.replace(/\s+/g, ''));
|
||||
const key = util.hexToUint8Array('28 e7 9a b8 23 97 d3 c6 3d e2 4a c2 17 d7 b7 91'.replace(/\s+/g, ''));
|
||||
const algo = openpgp.enums.symmetric.aes128;
|
||||
|
||||
const randomBytesStub = sinon.stub(nodeCrypto, 'randomBytes');
|
||||
randomBytesStub.withArgs(14).returns(padding);
|
||||
randomBytesStub.withArgs(32).returns(salt);
|
||||
|
||||
const literal = new openpgp.LiteralDataPacket(0);
|
||||
literal.setBytes(util.stringToUint8Array('Hello, world!'), openpgp.enums.literal.binary);
|
||||
literal.filename = '';
|
||||
const pad = new openpgp.PaddingPacket();
|
||||
await pad.createPadding(14);
|
||||
const enc = new openpgp.SymEncryptedIntegrityProtectedDataPacket();
|
||||
enc.version = 2;
|
||||
enc.aeadAlgorithm = openpgp.enums.aead.ocb;
|
||||
enc.packets = new openpgp.PacketList();
|
||||
enc.packets.push(literal);
|
||||
enc.packets.push(pad);
|
||||
const msg = new openpgp.PacketList();
|
||||
msg.push(enc);
|
||||
|
||||
const msg2 = new openpgp.PacketList();
|
||||
|
||||
try {
|
||||
await enc.encrypt(algo, key, { ...openpgp.config, aeadChunkSizeByte: 6 });
|
||||
const data = msg.write();
|
||||
expect(await stream.readToEnd(stream.clone(data))).to.deep.equal(packetBytes);
|
||||
await msg2.read(data, allAllowedPackets);
|
||||
await msg2[0].decrypt(algo, key);
|
||||
expect(await stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
|
||||
} finally {
|
||||
randomBytesStub.restore();
|
||||
}
|
||||
});
|
||||
|
||||
it('Sym. encrypted AEAD protected packet test vector (SEIPDv2 - GCM)', async function() {
|
||||
// From https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#appendix-A-5
|
||||
|
||||
const nodeCrypto = util.getNodeCrypto();
|
||||
if (!nodeCrypto) return;
|
||||
|
||||
const packetBytes = util.hexToUint8Array(`
|
||||
d2 69 02 07 03 06
|
||||
fc b9 44 90 bc b9 8b bd c9 d1 06 c6 09 02 66 94
|
||||
0f 72 e8 9e dc 21 b5 59 6b 15 76 b1 01 ed 0f 9f
|
||||
fc 6f c6 d6 5b bf d2 4d cd 07 90 96 6e 6d 1e 85
|
||||
a3 00 53 78 4c b1 d8 b6 a0 69 9e f1 21 55 a7 b2
|
||||
ad 62 58 53 1b
|
||||
57 65 1f d7 77 79 12 fa 95 e3 5d 9b 40 21 6f 69
|
||||
a4 c2 48 db 28 ff 43 31 f1 63 29 07 39 9e 6f f9
|
||||
`.replace(/\s+/g, ''));
|
||||
|
||||
const padding = util.hexToUint8Array('1c e2 26 9a 9e dd ef 81 03 21 72 b7 ed 7c'.replace(/\s+/g, ''));
|
||||
const salt = util.hexToUint8Array('fc b9 44 90 bc b9 8b bd c9 d1 06 c6 09 02 66 94 0f 72 e8 9e dc 21 b5 59 6b 15 76 b1 01 ed 0f 9f'.replace(/\s+/g, ''));
|
||||
const key = util.hexToUint8Array('19 36 fc 85 68 98 02 74 bb 90 0d 83 19 36 0c 77'.replace(/\s+/g, ''));
|
||||
const algo = openpgp.enums.symmetric.aes128;
|
||||
|
||||
const randomBytesStub = sinon.stub(nodeCrypto, 'randomBytes');
|
||||
randomBytesStub.withArgs(14).returns(padding);
|
||||
randomBytesStub.withArgs(32).returns(salt);
|
||||
|
||||
const literal = new openpgp.LiteralDataPacket(0);
|
||||
literal.setBytes(util.stringToUint8Array('Hello, world!'), openpgp.enums.literal.binary);
|
||||
literal.filename = '';
|
||||
const pad = new openpgp.PaddingPacket();
|
||||
await pad.createPadding(14);
|
||||
const enc = new openpgp.SymEncryptedIntegrityProtectedDataPacket();
|
||||
enc.version = 2;
|
||||
enc.aeadAlgorithm = openpgp.enums.aead.gcm;
|
||||
enc.packets = new openpgp.PacketList();
|
||||
enc.packets.push(literal);
|
||||
enc.packets.push(pad);
|
||||
const msg = new openpgp.PacketList();
|
||||
msg.push(enc);
|
||||
|
||||
const msg2 = new openpgp.PacketList();
|
||||
|
||||
try {
|
||||
await enc.encrypt(algo, key, { ...openpgp.config, aeadChunkSizeByte: 6 });
|
||||
const data = msg.write();
|
||||
expect(await stream.readToEnd(stream.clone(data))).to.deep.equal(packetBytes);
|
||||
await msg2.read(data, allAllowedPackets);
|
||||
await msg2[0].decrypt(algo, key);
|
||||
expect(await stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
|
||||
} finally {
|
||||
randomBytesStub.restore();
|
||||
}
|
||||
});
|
||||
|
||||
it('Sym. encrypted session key with a compressed packet', async function() {
|
||||
const msg =
|
||||
'-----BEGIN PGP MESSAGE-----\n' +
|
||||
|
Loading…
x
Reference in New Issue
Block a user