crypto-refresh: add support for Argon2 S2K (#1597)

In terms of API, this feature is backwards compatible, no breaking changes.
However, since a Wasm module is loaded for the Argon2 computation, browser apps
might need to make changes to their CSP policy in order to use the feature.

Newly introduced config fields:
- `config.s2kType` (defaulting to `enums.s2k.iterated`): s2k to use on
password-based encryption as well as private key encryption;
- `config.s2kArgon2Params` (defaulting to "uniformly safe settings" from Argon
RFC): parameters to use on encryption when `config.s2kType` is set to
`enums.s2k.argon2`;
This commit is contained in:
larabr
2023-04-04 14:22:13 +02:00
committed by larabr
parent 204f32791d
commit ebf22f2ee7
14 changed files with 387 additions and 32 deletions

View File

@@ -15,6 +15,7 @@ const { isAEADSupported } = require('../../src/key');
const input = require('./testInputs');
const detectNode = () => typeof globalThis.process === 'object' && typeof globalThis.process.versions === 'object';
const detectBrowser = () => typeof navigator === 'object';
const pub_key = [
'-----BEGIN PGP PUBLIC KEY BLOCK-----',
@@ -1243,6 +1244,25 @@ VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
expect(unlocked.isDecrypted()).to.be.true;
});
it('should support encrypting with argon2 s2k', async function() {
const key = await openpgp.readKey({ armoredKey: gnuDummyKeySigningSubkey });
const locked = await openpgp.encryptKey({
privateKey: key,
passphrase: passphrase,
config: { s2kType: openpgp.enums.s2k.argon2 }
});
expect(key.isDecrypted()).to.be.true;
expect(locked.isDecrypted()).to.be.false;
expect(locked.keyPacket.isDummy()).to.be.true;
const unlocked = await openpgp.decryptKey({
privateKey: locked,
passphrase: passphrase
});
expect(key.isDecrypted()).to.be.true;
expect(unlocked.isDecrypted()).to.be.true;
expect(unlocked.keyPacket.isDummy()).to.be.true;
});
it('should encrypt gnu-dummy key', async function() {
const key = await openpgp.readKey({ armoredKey: gnuDummyKeySigningSubkey });
const locked = await openpgp.encryptKey({
@@ -2150,6 +2170,50 @@ VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
data: util.hexToUint8Array('3e99c1bb485e70a1fcef09a7ad8d38d171015243bbdd853e1a2b0e334d122ff3')
})).to.be.rejectedWith(/No encryption keys or passwords provided/);
});
it('supports decrypting with argon2 s2k (memory-heavy params)', async function() {
const passwords = 'password';
// Test vector from https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#appendix-A.8.1
const armoredMessage = `-----BEGIN PGP MESSAGE-----
Comment: Encrypted using AES with 128-bit key
Comment: Session key: 01FE16BBACFD1E7B78EF3B865187374F
wycEBwScUvg8J/leUNU1RA7N/zE2AQQVnlL8rSLPP5VlQsunlO+ECxHSPgGYGKY+
YJz4u6F+DDlDBOr5NRQXt/KJIf4m4mOlKyC/uqLbpnLJZMnTq3o79GxBTdIdOzhH
XfA3pqV4mTzF
-----END PGP MESSAGE-----`;
const expectedSessionKey = util.hexToUint8Array('01FE16BBACFD1E7B78EF3B865187374F');
try {
const [decryptedSessionKey] = await openpgp.decryptSessionKeys({
message: await openpgp.readMessage({ armoredMessage }),
passwords
});
expect(decryptedSessionKey.data).to.deep.equal(expectedSessionKey);
expect(decryptedSessionKey.algorithm).to.equal('aes128');
} catch (err) {
if (detectBrowser()) { // Expected to fail in the CI, especially in Browserstack
expect(err.message).to.match(/Could not allocate required memory/);
}
}
});
// keep this after the 'memory-heavy' test to confirm that the Wasm module was successfully reloaded
it('supports encrypting with argon2 s2k', async function() {
const config = { s2kType: openpgp.enums.s2k.argon2 };
const passwords = 'password';
const sessionKey = {
algorithm: 'aes128',
data: util.hexToUint8Array('01FE16BBACFD1E7B78EF3B865187374F')
};
const encrypted = await openpgp.encryptSessionKey({ ...sessionKey, passwords, config, format: 'object' });
expect(encrypted.packets).to.have.length(1);
const skesk = encrypted.packets[0];
expect(skesk.s2k.type).to.equal('argon2');
const [decryptedSessionKey] = await openpgp.decryptSessionKeys({ message: encrypted, passwords });
expect(decryptedSessionKey).to.deep.equal(sessionKey);
});
});
describe('encrypt, decrypt, sign, verify - integration tests', function() {

View File

@@ -1042,7 +1042,7 @@ kePFjAnu9cpynKXu3usf8+FuBw2zLsg1Id1n7ttxoAte416KjBN9lFBt8mcu
await expect(
openpgp.PacketList.fromBinary(binaryMessage, allAllowedPackets, { ...openpgp.config, ignoreUnsupportedPackets: false })
).to.be.rejectedWith(/Unknown S2K type/);
).to.be.rejectedWith(/Unsupported S2K type/);
});
it('Throws on disallowed packet even with tolerant mode enabled', async function() {