mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-06-13 01:26:42 +00:00
Implement SEIPD v2
This commit is contained in:
parent
939622e827
commit
9d85938ed7
@ -9,7 +9,7 @@ import util from '../util';
|
||||
const webCrypto = util.getWebCrypto();
|
||||
const nodeCrypto = util.getNodeCrypto();
|
||||
|
||||
export default async function HKDF(hashAlgo, inputKey, salt, info, outLen) {
|
||||
export default async function computeHKDF(hashAlgo, inputKey, salt, info, outLen) {
|
||||
const hash = enums.read(enums.webHash, hashAlgo);
|
||||
if (!hash) throw new Error('Hash algo not supported with HKDF');
|
||||
|
||||
|
@ -308,7 +308,7 @@ export async function isAEADSupported(keys, date = new Date(), userIDs = [], con
|
||||
await Promise.all(keys.map(async function(key, i) {
|
||||
const selfCertification = await key.getPrimarySelfSignature(date, userIDs[i], config);
|
||||
if (!selfCertification.features ||
|
||||
!(selfCertification.features[0] & enums.features.aead)) {
|
||||
!(selfCertification.features[0] & enums.features.seipdv2)) {
|
||||
supported = false;
|
||||
}
|
||||
}));
|
||||
|
@ -392,13 +392,12 @@ export class Message {
|
||||
|
||||
const msg = await Message.encryptSessionKey(sessionKeyData, algorithmName, aeadAlgorithmName, encryptionKeys, passwords, wildcard, encryptionKeyIDs, date, userIDs, config);
|
||||
|
||||
let symEncryptedPacket;
|
||||
const symEncryptedPacket = new SymEncryptedIntegrityProtectedDataPacket();
|
||||
if (aeadAlgorithmName) {
|
||||
symEncryptedPacket = new AEADEncryptedDataPacket();
|
||||
symEncryptedPacket.version = 2;
|
||||
symEncryptedPacket.aeadAlgorithm = enums.write(enums.aead, aeadAlgorithmName);
|
||||
} else {
|
||||
symEncryptedPacket = new SymEncryptedIntegrityProtectedDataPacket();
|
||||
}
|
||||
|
||||
symEncryptedPacket.packets = this.packets;
|
||||
|
||||
const algorithm = enums.write(enums.symmetric, algorithmName);
|
||||
|
@ -21,6 +21,7 @@ import enums from '../enums';
|
||||
import util from '../util';
|
||||
import defaultConfig from '../config';
|
||||
import { UnsupportedError } from './packet';
|
||||
import { runAEAD } from './sym_encrypted_integrity_protected_data';
|
||||
|
||||
import LiteralDataPacket from './literal_data';
|
||||
import CompressedDataPacket from './compressed_data';
|
||||
@ -101,7 +102,7 @@ class AEADEncryptedDataPacket {
|
||||
*/
|
||||
async decrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
|
||||
this.packets = await PacketList.fromBinary(
|
||||
await this.crypt('decrypt', key, stream.clone(this.encrypted)),
|
||||
await runAEAD(this, 'decrypt', key, stream.clone(this.encrypted)),
|
||||
allowedPackets,
|
||||
config
|
||||
);
|
||||
@ -122,86 +123,7 @@ class AEADEncryptedDataPacket {
|
||||
this.iv = crypto.random.getRandomBytes(ivLength); // generate new random IV
|
||||
this.chunkSizeByte = config.aeadChunkSizeByte;
|
||||
const data = this.packets.write();
|
||||
this.encrypted = await this.crypt('encrypt', key, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* En/decrypt the payload.
|
||||
* @param {encrypt|decrypt} fn - Whether to encrypt or decrypt
|
||||
* @param {Uint8Array} key - The session key used to en/decrypt the payload
|
||||
* @param {Uint8Array | ReadableStream<Uint8Array>} data - The data to en/decrypt
|
||||
* @returns {Promise<Uint8Array | ReadableStream<Uint8Array>>}
|
||||
* @async
|
||||
*/
|
||||
async crypt(fn, key, data) {
|
||||
const mode = crypto.getAEADMode(this.aeadAlgorithm);
|
||||
const modeInstance = await mode(this.cipherAlgorithm, key);
|
||||
const tagLengthIfDecrypting = fn === 'decrypt' ? mode.tagLength : 0;
|
||||
const tagLengthIfEncrypting = fn === 'encrypt' ? mode.tagLength : 0;
|
||||
const chunkSize = 2 ** (this.chunkSizeByte + 6) + tagLengthIfDecrypting; // ((uint64_t)1 << (c + 6))
|
||||
const adataBuffer = new ArrayBuffer(21);
|
||||
const adataArray = new Uint8Array(adataBuffer, 0, 13);
|
||||
const adataTagArray = new Uint8Array(adataBuffer);
|
||||
const adataView = new DataView(adataBuffer);
|
||||
const chunkIndexArray = new Uint8Array(adataBuffer, 5, 8);
|
||||
adataArray.set([0xC0 | AEADEncryptedDataPacket.tag, this.version, this.cipherAlgorithm, this.aeadAlgorithm, this.chunkSizeByte], 0);
|
||||
let chunkIndex = 0;
|
||||
let latestPromise = Promise.resolve();
|
||||
let cryptedBytes = 0;
|
||||
let queuedBytes = 0;
|
||||
const iv = this.iv;
|
||||
return stream.transformPair(data, async (readable, writable) => {
|
||||
if (util.isStream(readable) !== 'array') {
|
||||
const buffer = new TransformStream({}, {
|
||||
highWaterMark: util.getHardwareConcurrency() * 2 ** (this.chunkSizeByte + 6),
|
||||
size: array => array.length
|
||||
});
|
||||
stream.pipe(buffer.readable, writable);
|
||||
writable = buffer.writable;
|
||||
}
|
||||
const reader = stream.getReader(readable);
|
||||
const writer = stream.getWriter(writable);
|
||||
try {
|
||||
while (true) {
|
||||
let chunk = await reader.readBytes(chunkSize + tagLengthIfDecrypting) || new Uint8Array();
|
||||
const finalChunk = chunk.subarray(chunk.length - tagLengthIfDecrypting);
|
||||
chunk = chunk.subarray(0, chunk.length - tagLengthIfDecrypting);
|
||||
let cryptedPromise;
|
||||
let done;
|
||||
if (!chunkIndex || chunk.length) {
|
||||
reader.unshift(finalChunk);
|
||||
cryptedPromise = modeInstance[fn](chunk, mode.getNonce(iv, chunkIndexArray), adataArray);
|
||||
queuedBytes += chunk.length - tagLengthIfDecrypting + tagLengthIfEncrypting;
|
||||
} else {
|
||||
// After the last chunk, we either encrypt a final, empty
|
||||
// data chunk to get the final authentication tag or
|
||||
// validate that final authentication tag.
|
||||
adataView.setInt32(13 + 4, cryptedBytes); // Should be setInt64(13, ...)
|
||||
cryptedPromise = modeInstance[fn](finalChunk, mode.getNonce(iv, chunkIndexArray), adataTagArray);
|
||||
queuedBytes += tagLengthIfEncrypting;
|
||||
done = true;
|
||||
}
|
||||
cryptedBytes += chunk.length - tagLengthIfDecrypting;
|
||||
// eslint-disable-next-line no-loop-func
|
||||
latestPromise = latestPromise.then(() => cryptedPromise).then(async crypted => {
|
||||
await writer.ready;
|
||||
await writer.write(crypted);
|
||||
queuedBytes -= crypted.length;
|
||||
}).catch(err => writer.abort(err));
|
||||
if (done || queuedBytes > writer.desiredSize) {
|
||||
await latestPromise; // Respect backpressure
|
||||
}
|
||||
if (!done) {
|
||||
adataView.setInt32(5 + 4, ++chunkIndex); // Should be setInt64(5, ...)
|
||||
} else {
|
||||
await writer.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
await writer.abort(e);
|
||||
}
|
||||
});
|
||||
this.encrypted = await runAEAD(this, 'encrypt', key, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
import * as stream from '@openpgp/web-stream-tools';
|
||||
import crypto from '../crypto';
|
||||
import computeHKDF from '../crypto/hkdf';
|
||||
import enums from '../enums';
|
||||
import util from '../util';
|
||||
import defaultConfig from '../config';
|
||||
@ -36,8 +37,6 @@ const allowedPackets = /*#__PURE__*/ util.constructAllowedPackets([
|
||||
SignaturePacket
|
||||
]);
|
||||
|
||||
const VERSION = 1; // A one-octet version number of the data packet.
|
||||
|
||||
/**
|
||||
* Implementation of the Sym. Encrypted Integrity Protected Data Packet (Tag 18)
|
||||
*
|
||||
@ -54,28 +53,55 @@ class SymEncryptedIntegrityProtectedDataPacket {
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.version = VERSION;
|
||||
this.version = 1;
|
||||
|
||||
// The following 4 fields are for V2 only.
|
||||
/** @type {enums.symmetric} */
|
||||
this.cipherAlgorithm = null;
|
||||
/** @type {enums.aead} */
|
||||
this.aeadAlgorithm = null;
|
||||
this.chunkSizeByte = null;
|
||||
this.salt = null;
|
||||
|
||||
this.encrypted = null;
|
||||
this.packets = null;
|
||||
}
|
||||
|
||||
async read(bytes) {
|
||||
await stream.parse(bytes, async reader => {
|
||||
const version = await reader.readByte();
|
||||
// - A one-octet version number. The only currently defined value is 1.
|
||||
if (version !== VERSION) {
|
||||
this.version = await reader.readByte();
|
||||
// - A one-octet version number with value 1 or 2.
|
||||
if (this.version !== 1 && this.version !== 2) {
|
||||
throw new UnsupportedError(`Version ${version} of the SEIP packet is unsupported.`);
|
||||
}
|
||||
|
||||
if (this.version === 2) {
|
||||
// - A one-octet cipher algorithm.
|
||||
this.cipherAlgorithm = await reader.readByte();
|
||||
// - A one-octet AEAD algorithm.
|
||||
this.aeadAlgorithm = await reader.readByte();
|
||||
// - A one-octet chunk size.
|
||||
this.chunkSizeByte = await reader.readByte();
|
||||
// - Thirty-two octets of salt. The salt is used to derive the message key and must be unique.
|
||||
this.salt = await reader.readBytes(32);
|
||||
}
|
||||
|
||||
// For V1:
|
||||
// - Encrypted data, the output of the selected symmetric-key cipher
|
||||
// operating in Cipher Feedback mode with shift amount equal to the
|
||||
// block size of the cipher (CFB-n where n is the block size).
|
||||
// For V2:
|
||||
// - Encrypted data, the output of the selected symmetric-key cipher operating in the given AEAD mode.
|
||||
// - A final, summary authentication tag for the AEAD mode.
|
||||
this.encrypted = reader.remainder();
|
||||
});
|
||||
}
|
||||
|
||||
write() {
|
||||
return util.concat([new Uint8Array([VERSION]), this.encrypted]);
|
||||
if (this.version === 2) {
|
||||
return util.concat([new Uint8Array([this.version, this.cipherAlgorithm, this.aeadAlgorithm, this.chunkSizeByte]), this.salt, this.encrypted]);
|
||||
}
|
||||
return util.concat([new Uint8Array([this.version]), this.encrypted]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,18 +114,27 @@ class SymEncryptedIntegrityProtectedDataPacket {
|
||||
* @async
|
||||
*/
|
||||
async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
|
||||
const { blockSize } = crypto.getCipher(sessionKeyAlgorithm);
|
||||
|
||||
let bytes = this.packets.write();
|
||||
if (stream.isArrayStream(bytes)) bytes = await stream.readToEnd(bytes);
|
||||
const prefix = await crypto.getPrefixRandom(sessionKeyAlgorithm);
|
||||
const mdc = new Uint8Array([0xD3, 0x14]); // modification detection code packet
|
||||
|
||||
const tohash = util.concat([prefix, bytes, mdc]);
|
||||
const hash = await crypto.hash.sha1(stream.passiveClone(tohash));
|
||||
const plaintext = util.concat([tohash, hash]);
|
||||
if (this.version === 2) {
|
||||
this.cipherAlgorithm = sessionKeyAlgorithm;
|
||||
|
||||
this.encrypted = await crypto.mode.cfb.encrypt(sessionKeyAlgorithm, key, plaintext, new Uint8Array(blockSize), config);
|
||||
this.salt = crypto.random.getRandomBytes(32);
|
||||
this.chunkSizeByte = config.aeadChunkSizeByte;
|
||||
this.encrypted = await runAEAD(this, 'encrypt', key, bytes);
|
||||
} else {
|
||||
const { blockSize } = crypto.getCipher(sessionKeyAlgorithm);
|
||||
|
||||
const prefix = await crypto.getPrefixRandom(sessionKeyAlgorithm);
|
||||
const mdc = new Uint8Array([0xD3, 0x14]); // modification detection code packet
|
||||
|
||||
const tohash = util.concat([prefix, bytes, mdc]);
|
||||
const hash = await crypto.hash.sha1(stream.passiveClone(tohash));
|
||||
const plaintext = util.concat([tohash, hash]);
|
||||
|
||||
this.encrypted = await crypto.mode.cfb.encrypt(sessionKeyAlgorithm, key, plaintext, new Uint8Array(blockSize), config);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -113,33 +148,152 @@ class SymEncryptedIntegrityProtectedDataPacket {
|
||||
* @async
|
||||
*/
|
||||
async decrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
|
||||
const { blockSize } = crypto.getCipher(sessionKeyAlgorithm);
|
||||
let encrypted = stream.clone(this.encrypted);
|
||||
if (stream.isArrayStream(encrypted)) encrypted = await stream.readToEnd(encrypted);
|
||||
const decrypted = await crypto.mode.cfb.decrypt(sessionKeyAlgorithm, key, encrypted, new Uint8Array(blockSize));
|
||||
|
||||
// there must be a modification detection code packet as the
|
||||
// last packet and everything gets hashed except the hash itself
|
||||
const realHash = stream.slice(stream.passiveClone(decrypted), -20);
|
||||
const tohash = stream.slice(decrypted, 0, -20);
|
||||
const verifyHash = Promise.all([
|
||||
stream.readToEnd(await crypto.hash.sha1(stream.passiveClone(tohash))),
|
||||
stream.readToEnd(realHash)
|
||||
]).then(([hash, mdc]) => {
|
||||
if (!util.equalsUint8Array(hash, mdc)) {
|
||||
throw new Error('Modification detected.');
|
||||
let packetbytes;
|
||||
if (this.version === 2) {
|
||||
packetbytes = await runAEAD(this, 'decrypt', key, encrypted);
|
||||
} else {
|
||||
const { blockSize } = crypto.getCipher(sessionKeyAlgorithm);
|
||||
const decrypted = await crypto.mode.cfb.decrypt(sessionKeyAlgorithm, key, encrypted, new Uint8Array(blockSize));
|
||||
|
||||
// there must be a modification detection code packet as the
|
||||
// last packet and everything gets hashed except the hash itself
|
||||
const realHash = stream.slice(stream.passiveClone(decrypted), -20);
|
||||
const tohash = stream.slice(decrypted, 0, -20);
|
||||
const verifyHash = Promise.all([
|
||||
stream.readToEnd(await crypto.hash.sha1(stream.passiveClone(tohash))),
|
||||
stream.readToEnd(realHash)
|
||||
]).then(([hash, mdc]) => {
|
||||
if (!util.equalsUint8Array(hash, mdc)) {
|
||||
throw new Error('Modification detected.');
|
||||
}
|
||||
return new Uint8Array();
|
||||
});
|
||||
const bytes = stream.slice(tohash, blockSize + 2); // Remove random prefix
|
||||
packetbytes = stream.slice(bytes, 0, -2); // Remove MDC packet
|
||||
packetbytes = stream.concat([packetbytes, stream.fromAsync(() => verifyHash)]);
|
||||
if (!util.isStream(encrypted) || !config.allowUnauthenticatedStream) {
|
||||
packetbytes = await stream.readToEnd(packetbytes);
|
||||
}
|
||||
return new Uint8Array();
|
||||
});
|
||||
const bytes = stream.slice(tohash, blockSize + 2); // Remove random prefix
|
||||
let packetbytes = stream.slice(bytes, 0, -2); // Remove MDC packet
|
||||
packetbytes = stream.concat([packetbytes, stream.fromAsync(() => verifyHash)]);
|
||||
if (!util.isStream(encrypted) || !config.allowUnauthenticatedStream) {
|
||||
packetbytes = await stream.readToEnd(packetbytes);
|
||||
}
|
||||
|
||||
this.packets = await PacketList.fromBinary(packetbytes, allowedPackets, config);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export default SymEncryptedIntegrityProtectedDataPacket;
|
||||
|
||||
/**
|
||||
* En/decrypt the payload.
|
||||
* @param {encrypt|decrypt} fn - Whether to encrypt or decrypt
|
||||
* @param {Uint8Array} key - The session key used to en/decrypt the payload
|
||||
* @param {Uint8Array | ReadableStream<Uint8Array>} data - The data to en/decrypt
|
||||
* @returns {Promise<Uint8Array | ReadableStream<Uint8Array>>}
|
||||
* @async
|
||||
*/
|
||||
export async function runAEAD(packet, fn, key, data) {
|
||||
const isSEIPDv2 = packet instanceof SymEncryptedIntegrityProtectedDataPacket && packet.version === 2;
|
||||
const isAEADP = !isSEIPDv2 && packet.constructor.tag === enums.packet.aeadEncryptedData; // no `instanceof` to avoid importing the corresponding class (circular import)
|
||||
if (!isSEIPDv2 && !isAEADP) throw new Error('Unexpected packet type');
|
||||
|
||||
const mode = crypto.getAEADMode(packet.aeadAlgorithm);
|
||||
const tagLengthIfDecrypting = fn === 'decrypt' ? mode.tagLength : 0;
|
||||
const tagLengthIfEncrypting = fn === 'encrypt' ? mode.tagLength : 0;
|
||||
const chunkSize = 2 ** (packet.chunkSizeByte + 6) + tagLengthIfDecrypting; // ((uint64_t)1 << (c + 6))
|
||||
const chunkIndexSizeIfAEADEP = isAEADP ? 8 : 0;
|
||||
const adataBuffer = new ArrayBuffer(13 + chunkIndexSizeIfAEADEP);
|
||||
const adataArray = new Uint8Array(adataBuffer, 0, 5 + chunkIndexSizeIfAEADEP);
|
||||
const adataTagArray = new Uint8Array(adataBuffer);
|
||||
const adataView = new DataView(adataBuffer);
|
||||
const chunkIndexArray = new Uint8Array(adataBuffer, 5, 8);
|
||||
adataArray.set([0xC0 | packet.constructor.tag, packet.version, packet.cipherAlgorithm, packet.aeadAlgorithm, packet.chunkSizeByte], 0);
|
||||
let chunkIndex = 0;
|
||||
let latestPromise = Promise.resolve();
|
||||
let cryptedBytes = 0;
|
||||
let queuedBytes = 0;
|
||||
let iv;
|
||||
let ivView;
|
||||
if (isSEIPDv2) {
|
||||
const { keySize } = crypto.getCipher(packet.cipherAlgorithm);
|
||||
const { ivLength } = mode;
|
||||
const info = new Uint8Array(adataBuffer, 0, 5);
|
||||
const derived = await computeHKDF(enums.hash.sha256, key, packet.salt, info, keySize + ivLength);
|
||||
key = derived.subarray(0, keySize);
|
||||
iv = derived.subarray(keySize); // The last 8 bytes of HKDF output are unneeded, but this avoids one copy.
|
||||
iv.fill(0, iv.length - 8);
|
||||
ivView = new DataView(iv.buffer, iv.byteOffset, iv.byteLength);
|
||||
} else { // AEADEncryptedDataPacket
|
||||
iv = packet.iv;
|
||||
// ivView is unused in this case
|
||||
}
|
||||
const modeInstance = await mode(packet.cipherAlgorithm, key);
|
||||
return stream.transformPair(data, async (readable, writable) => {
|
||||
if (util.isStream(readable) !== 'array') {
|
||||
const buffer = new TransformStream({}, {
|
||||
highWaterMark: util.getHardwareConcurrency() * 2 ** (packet.chunkSizeByte + 6),
|
||||
size: array => array.length
|
||||
});
|
||||
stream.pipe(buffer.readable, writable);
|
||||
writable = buffer.writable;
|
||||
}
|
||||
const reader = stream.getReader(readable);
|
||||
const writer = stream.getWriter(writable);
|
||||
try {
|
||||
while (true) {
|
||||
let chunk = await reader.readBytes(chunkSize + tagLengthIfDecrypting) || new Uint8Array();
|
||||
const finalChunk = chunk.subarray(chunk.length - tagLengthIfDecrypting);
|
||||
chunk = chunk.subarray(0, chunk.length - tagLengthIfDecrypting);
|
||||
let cryptedPromise;
|
||||
let done;
|
||||
let nonce;
|
||||
if (isSEIPDv2) { // SEIPD V2
|
||||
nonce = iv;
|
||||
} else { // AEADEncryptedDataPacket
|
||||
nonce = iv.slice();
|
||||
for (let i = 0; i < 8; i++) {
|
||||
nonce[iv.length - 8 + i] ^= chunkIndexArray[i];
|
||||
}
|
||||
}
|
||||
if (!chunkIndex || chunk.length) {
|
||||
reader.unshift(finalChunk);
|
||||
cryptedPromise = modeInstance[fn](chunk, nonce, adataArray);
|
||||
queuedBytes += chunk.length - tagLengthIfDecrypting + tagLengthIfEncrypting;
|
||||
} else {
|
||||
// After the last chunk, we either encrypt a final, empty
|
||||
// data chunk to get the final authentication tag or
|
||||
// validate that final authentication tag.
|
||||
adataView.setInt32(5 + chunkIndexSizeIfAEADEP + 4, cryptedBytes); // Should be setInt64(5 + chunkIndexSizeIfAEADEP, ...)
|
||||
cryptedPromise = modeInstance[fn](finalChunk, nonce, adataTagArray);
|
||||
queuedBytes += tagLengthIfEncrypting;
|
||||
done = true;
|
||||
}
|
||||
cryptedBytes += chunk.length - tagLengthIfDecrypting;
|
||||
// eslint-disable-next-line no-loop-func
|
||||
latestPromise = latestPromise.then(() => cryptedPromise).then(async crypted => {
|
||||
await writer.ready;
|
||||
await writer.write(crypted);
|
||||
queuedBytes -= crypted.length;
|
||||
}).catch(err => writer.abort(err));
|
||||
if (done || queuedBytes > writer.desiredSize) {
|
||||
await latestPromise; // Respect backpressure
|
||||
}
|
||||
if (!done) {
|
||||
if (isSEIPDv2) { // SEIPD V2
|
||||
ivView.setInt32(iv.length - 4, ++chunkIndex); // Should be setInt64(iv.length - 8, ...)
|
||||
} else { // AEADEncryptedDataPacket
|
||||
adataView.setInt32(5 + 4, ++chunkIndex); // Should be setInt64(5, ...)
|
||||
}
|
||||
} else {
|
||||
await writer.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
await writer.ready.catch(() => {});
|
||||
await writer.abort(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -119,6 +119,7 @@ class MemoryBenchamrkSuite {
|
||||
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
|
||||
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1].version === 1);
|
||||
await openpgp.decrypt({ message: encryptedMessage, passwords, config });
|
||||
});
|
||||
|
||||
@ -131,6 +132,7 @@ class MemoryBenchamrkSuite {
|
||||
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
|
||||
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1].version === 1);
|
||||
await openpgp.decrypt({ message: encryptedMessage, passwords, config });
|
||||
});
|
||||
|
||||
@ -142,7 +144,8 @@ class MemoryBenchamrkSuite {
|
||||
|
||||
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
|
||||
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.AEADEncryptedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1].version === 2);
|
||||
await openpgp.decrypt({ message: encryptedMessage, passwords, config });
|
||||
});
|
||||
|
||||
@ -154,7 +157,8 @@ class MemoryBenchamrkSuite {
|
||||
|
||||
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
|
||||
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.AEADEncryptedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1].version === 2);
|
||||
await openpgp.decrypt({ message: encryptedMessage, passwords, config });
|
||||
});
|
||||
|
||||
@ -176,6 +180,7 @@ class MemoryBenchamrkSuite {
|
||||
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
|
||||
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1].version === 1);
|
||||
const { data: decryptedData } = await openpgp.decrypt({ message: encryptedMessage, passwords, config });
|
||||
// read out output stream to trigger decryption
|
||||
await new Promise(resolve => {
|
||||
@ -201,6 +206,7 @@ class MemoryBenchamrkSuite {
|
||||
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
|
||||
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1].version === 1);
|
||||
const { data: decryptedData } = await openpgp.decrypt({ message: encryptedMessage, passwords, config });
|
||||
// read out output stream to trigger decryption
|
||||
await new Promise(resolve => {
|
||||
@ -225,7 +231,8 @@ class MemoryBenchamrkSuite {
|
||||
|
||||
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
|
||||
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.AEADEncryptedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1].version === 2);
|
||||
const { data: decryptedData } = await openpgp.decrypt({ message: encryptedMessage, passwords, config });
|
||||
// read out output stream to trigger decryption
|
||||
await new Promise(resolve => {
|
||||
@ -250,7 +257,8 @@ class MemoryBenchamrkSuite {
|
||||
|
||||
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
|
||||
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.AEADEncryptedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1].version === 2);
|
||||
const { data: decryptedData } = await openpgp.decrypt({ message: encryptedMessage, passwords, config });
|
||||
// read out output stream to trigger decryption
|
||||
await new Promise(resolve => {
|
||||
@ -276,6 +284,7 @@ class MemoryBenchamrkSuite {
|
||||
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
|
||||
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1].version === 1);
|
||||
const { data: decryptedData } = await openpgp.decrypt({ message: encryptedMessage, passwords, config });
|
||||
// read out output stream to trigger decryption
|
||||
await new Promise(resolve => {
|
||||
@ -301,6 +310,7 @@ class MemoryBenchamrkSuite {
|
||||
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
|
||||
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1].version === 1);
|
||||
const { data: decryptedData } = await openpgp.decrypt({
|
||||
message: encryptedMessage,
|
||||
passwords,
|
||||
@ -329,7 +339,8 @@ class MemoryBenchamrkSuite {
|
||||
|
||||
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
|
||||
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.AEADEncryptedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
|
||||
assert.ok(encryptedMessage.packets[1].version === 2);
|
||||
const { data: decryptedData } = await openpgp.decrypt({ message: encryptedMessage, passwords, config });
|
||||
// read out output stream to trigger decryption
|
||||
await new Promise(resolve => {
|
||||
|
@ -272,6 +272,7 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
|
||||
const { packets: [skesk, encData] } = encrypted;
|
||||
expect(skesk.version).to.equal(4); // cfb
|
||||
expect(encData.constructor.tag).to.equal(openpgp.enums.packet.symEncryptedIntegrityProtectedData);
|
||||
expect(encData.version).to.equal(1);
|
||||
const { packets: [literal] } = await encrypted.decrypt(null, passwords, null, encrypted.fromStream, openpgp.config);
|
||||
expect(literal.constructor.tag).to.equal(openpgp.enums.packet.literalData);
|
||||
|
||||
@ -284,7 +285,8 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
|
||||
const encrypted2 = await openpgp.readMessage({ armoredMessage: armored2 });
|
||||
const { packets: [skesk2, encData2] } = encrypted2;
|
||||
expect(skesk2.version).to.equal(5);
|
||||
expect(encData2.constructor.tag).to.equal(openpgp.enums.packet.aeadEncryptedData);
|
||||
expect(encData2.constructor.tag).to.equal(openpgp.enums.packet.symEncryptedIntegrityProtectedData);
|
||||
expect(encData2.version).to.equal(2);
|
||||
const { packets: [compressed] } = await encrypted2.decrypt(null, passwords, null, encrypted2.fromStream, openpgp.config);
|
||||
expect(compressed.constructor.tag).to.equal(openpgp.enums.packet.compressedData);
|
||||
expect(compressed.algorithm).to.equal(openpgp.enums.compression.zip);
|
||||
|
@ -2300,10 +2300,10 @@ XfA3pqV4mTzF
|
||||
openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.experimentalGCM;
|
||||
openpgp.config.v6Keys = true;
|
||||
|
||||
// Monkey-patch AEAD feature flag
|
||||
publicKey.users[0].selfCertifications[0].features = [7];
|
||||
publicKey_2000_2008.users[0].selfCertifications[0].features = [7];
|
||||
publicKey_2038_2045.users[0].selfCertifications[0].features = [7];
|
||||
// Monkey-patch SEIPD V2 feature flag
|
||||
publicKey.users[0].selfCertifications[0].features = [9];
|
||||
publicKey_2000_2008.users[0].selfCertifications[0].features = [9];
|
||||
publicKey_2038_2045.users[0].selfCertifications[0].features = [9];
|
||||
}
|
||||
});
|
||||
|
||||
@ -2313,10 +2313,10 @@ XfA3pqV4mTzF
|
||||
openpgp.config.aeadProtect = true;
|
||||
openpgp.config.aeadChunkSizeByte = 0;
|
||||
|
||||
// Monkey-patch AEAD feature flag
|
||||
publicKey.users[0].selfCertifications[0].features = [7];
|
||||
publicKey_2000_2008.users[0].selfCertifications[0].features = [7];
|
||||
publicKey_2038_2045.users[0].selfCertifications[0].features = [7];
|
||||
// Monkey-patch SEIPD V2 feature flag
|
||||
publicKey.users[0].selfCertifications[0].features = [9];
|
||||
publicKey_2000_2008.users[0].selfCertifications[0].features = [9];
|
||||
publicKey_2038_2045.users[0].selfCertifications[0].features = [9];
|
||||
}
|
||||
});
|
||||
|
||||
@ -2326,10 +2326,10 @@ XfA3pqV4mTzF
|
||||
openpgp.config.aeadProtect = true;
|
||||
openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.ocb;
|
||||
|
||||
// Monkey-patch AEAD feature flag
|
||||
publicKey.users[0].selfCertifications[0].features = [7];
|
||||
publicKey_2000_2008.users[0].selfCertifications[0].features = [7];
|
||||
publicKey_2038_2045.users[0].selfCertifications[0].features = [7];
|
||||
// Monkey-patch SEIPD V2 feature flag
|
||||
publicKey.users[0].selfCertifications[0].features = [9];
|
||||
publicKey_2000_2008.users[0].selfCertifications[0].features = [9];
|
||||
publicKey_2038_2045.users[0].selfCertifications[0].features = [9];
|
||||
}
|
||||
});
|
||||
|
||||
@ -2626,7 +2626,7 @@ XfA3pqV4mTzF
|
||||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||||
expect(encrypted).to.match(/^-----BEGIN PGP MESSAGE/);
|
||||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||||
expect(!!decOpt.message.packets.findPacket(openpgp.enums.packet.aeadEncryptedData)).to.equal(false);
|
||||
expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(false);
|
||||
return openpgp.decrypt(decOpt);
|
||||
}).then(function (decrypted) {
|
||||
expect(decrypted.data).to.equal(plaintext);
|
||||
@ -2649,7 +2649,7 @@ XfA3pqV4mTzF
|
||||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||||
expect(encrypted).to.match(/^-----BEGIN PGP MESSAGE/);
|
||||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||||
expect(!!decOpt.message.packets.findPacket(openpgp.enums.packet.aeadEncryptedData)).to.equal(false);
|
||||
expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(false);
|
||||
return openpgp.decrypt(decOpt);
|
||||
}).then(function (decrypted) {
|
||||
expect(decrypted.data).to.equal(plaintext);
|
||||
@ -2668,7 +2668,7 @@ XfA3pqV4mTzF
|
||||
};
|
||||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||||
expect(!!decOpt.message.packets.findPacket(openpgp.enums.packet.aeadEncryptedData)).to.equal(openpgp.config.aeadProtect);
|
||||
expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(openpgp.config.aeadProtect);
|
||||
return openpgp.decrypt(decOpt);
|
||||
}).then(async function (decrypted) {
|
||||
expect(decrypted.data).to.equal(plaintext);
|
||||
@ -2692,7 +2692,7 @@ XfA3pqV4mTzF
|
||||
};
|
||||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||||
expect(!!decOpt.message.packets.findPacket(openpgp.enums.packet.aeadEncryptedData)).to.equal(openpgp.config.aeadProtect);
|
||||
expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(openpgp.config.aeadProtect);
|
||||
return openpgp.decrypt(decOpt);
|
||||
}).then(async function (decrypted) {
|
||||
expect(decrypted.data).to.equal(plaintext);
|
||||
@ -2715,7 +2715,7 @@ XfA3pqV4mTzF
|
||||
};
|
||||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||||
expect(!!decOpt.message.packets.findPacket(openpgp.enums.packet.aeadEncryptedData)).to.equal(false);
|
||||
expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(false);
|
||||
return openpgp.decrypt(decOpt);
|
||||
}).then(async function (decrypted) {
|
||||
expect(decrypted.data).to.equal(plaintext);
|
||||
@ -2746,7 +2746,7 @@ XfA3pqV4mTzF
|
||||
};
|
||||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||||
expect(!!decOpt.message.packets.findPacket(openpgp.enums.packet.aeadEncryptedData)).to.equal(openpgp.config.aeadProtect);
|
||||
expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(openpgp.config.aeadProtect);
|
||||
return openpgp.decrypt(decOpt);
|
||||
}).then(async function (decrypted) {
|
||||
expect(decrypted.data).to.equal(plaintext);
|
||||
@ -2775,7 +2775,7 @@ XfA3pqV4mTzF
|
||||
detached: true
|
||||
});
|
||||
const message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||||
expect(!!message.packets.findPacket(openpgp.enums.packet.aeadEncryptedData)).to.equal(openpgp.config.aeadProtect);
|
||||
expect(message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(openpgp.config.aeadProtect);
|
||||
const decrypted = await openpgp.decrypt({
|
||||
message,
|
||||
signature: await openpgp.readSignature({ armoredSignature: signed }),
|
||||
|
@ -152,7 +152,7 @@ export default () => describe('Packet', function() {
|
||||
expect(await stringify(msg2[0].packets[0].data)).to.equal(stringify(literal.data));
|
||||
});
|
||||
|
||||
it('Sym. encrypted AEAD protected packet', function() {
|
||||
it('Sym. encrypted AEAD protected packet (AEADP)', function() {
|
||||
const aeadProtectVal = openpgp.config.aeadProtect;
|
||||
openpgp.config.aeadProtect = false;
|
||||
|
||||
@ -201,7 +201,7 @@ export default () => describe('Packet', function() {
|
||||
return cryptStub;
|
||||
}
|
||||
|
||||
it('Sym. encrypted AEAD protected packet is encrypted in parallel (AEAD, GCM)', async function() {
|
||||
it('Sym. encrypted AEAD protected packet is encrypted in parallel (AEADP, GCM)', async function() {
|
||||
const webCrypto = util.getWebCrypto();
|
||||
if (!webCrypto || util.getNodeCrypto()) return;
|
||||
const encryptStub = cryptStub(webCrypto, 'encrypt');
|
||||
@ -236,7 +236,7 @@ export default () => describe('Packet', function() {
|
||||
}
|
||||
});
|
||||
|
||||
it('Sym. encrypted AEAD protected packet test vector (AEAD)', async function() {
|
||||
it('AEAD Encrypted Data packet test vector (AEADP)', async function() {
|
||||
// From https://gitlab.com/openpgp-wg/rfc4880bis/commit/00b20923e6233fb6ff1666ecd5acfefceb32907d
|
||||
|
||||
const nodeCrypto = util.getNodeCrypto();
|
||||
@ -516,7 +516,7 @@ export default () => describe('Packet', function() {
|
||||
}
|
||||
});
|
||||
|
||||
it('Sym. encrypted session key reading/writing test vector (EAX, AEAD)', async function() {
|
||||
it('Sym. encrypted session key reading/writing test vector (AEAD, EAX)', async function() {
|
||||
// From https://gitlab.com/openpgp-wg/rfc4880bis/blob/00b20923/back.mkd#sample-aead-eax-encryption-and-decryption
|
||||
|
||||
const nodeCrypto = util.getNodeCrypto();
|
||||
|
Loading…
x
Reference in New Issue
Block a user