larabr 2a8969b437 Internal: improve tree-shaking for crypto modules
Every submodule under the 'crypto' directory was exported-imported
even if a handful of functions where actually needed.
We now only export entire modules behind default exports if it makes
sense for readability and if the different submodules would be
imported together anyway (e.g. `cipherMode` exports are all needed
by the SEIPD class).

We've also dropped exports that are not used outside of the crypto modules,
e.g. pkcs5 helpers.
2024-11-22 14:32:39 +01:00

159 lines
7.0 KiB
JavaScript

import sinon from 'sinon';
import { use as chaiUse, expect } from 'chai';
import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
import openpgp from '../initOpenpgp.js';
import * as crypto from '../../src/crypto';
import * as random from '../../src/crypto/random.js';
import util from '../../src/util.js';
/* eslint-disable no-invalid-this */
export default () => describe('basic RSA cryptography', function () {
let sinonSandbox;
let getWebCryptoStub;
let getNodeCryptoStub;
beforeEach(function () {
sinonSandbox = sinon.createSandbox();
enableNative();
});
afterEach(function () {
sinonSandbox.restore();
});
const detectNative = () => !!(util.getWebCrypto() || util.getNodeCrypto());
const disableNative = () => {
enableNative();
// stubbed functions return undefined
getWebCryptoStub = sinonSandbox.stub(util, 'getWebCrypto');
getNodeCryptoStub = sinonSandbox.stub(util, 'getNodeCrypto');
};
const enableNative = () => {
getWebCryptoStub && getWebCryptoStub.restore();
getNodeCryptoStub && getNodeCryptoStub.restore();
};
it('generate rsa key', async function() {
const bits = 1024;
const keyObject = await crypto.publicKey.rsa.generate(bits, 65537);
expect(keyObject.n).to.exist;
expect(keyObject.e).to.exist;
expect(keyObject.d).to.exist;
expect(keyObject.p).to.exist;
expect(keyObject.q).to.exist;
expect(keyObject.u).to.exist;
expect(util.uint8ArrayBitLength(keyObject.n)).to.equal(bits);
});
it('generate rsa key - without native crypto', async function() {
const bits = 1024;
disableNative();
const keyObject = await crypto.publicKey.rsa.generate(bits, 65537);
enableNative();
expect(keyObject.n).to.exist;
expect(keyObject.e).to.exist;
expect(keyObject.d).to.exist;
expect(keyObject.p).to.exist;
expect(keyObject.q).to.exist;
expect(keyObject.u).to.exist;
expect(util.uint8ArrayBitLength(keyObject.n)).to.equal(bits);
});
it('sign and verify using generated key params', async function() {
const bits = 1024;
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const message = random.getRandomBytes(64);
const hashAlgo = openpgp.enums.write(openpgp.enums.hash, 'sha256');
const hashed = await crypto.computeDigest(hashAlgo, message);
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
const signature = await crypto.publicKey.rsa.sign(hashAlgo, message, n, e, d, p, q, u, hashed);
expect(signature).to.exist;
const verify = await crypto.publicKey.rsa.verify(hashAlgo, message, signature, n, e, hashed);
expect(verify).to.be.true;
});
it('encrypt and decrypt using generated key params', async function() {
const bits = 1024;
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
const message = crypto.generateSessionKey(openpgp.enums.symmetric.aes256);
const encrypted = await crypto.publicKey.rsa.encrypt(message, n, e);
const decrypted = await crypto.publicKey.rsa.decrypt(encrypted, n, e, d, p, q, u);
expect(decrypted).to.deep.equal(message);
});
it('decrypt nodeCrypto by bnCrypto and vice versa', async function() {
if (!util.getNodeCrypto()) {
this.skip(); // webcrypto does not implement RSA PKCS#1 v.15 decryption
}
const bits = 1024;
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
const message = crypto.generateSessionKey(openpgp.enums.symmetric.aes256);
disableNative();
const encryptedBn = await crypto.publicKey.rsa.encrypt(message, n, e);
enableNative();
const decrypted1 = await crypto.publicKey.rsa.decrypt(encryptedBn, n, e, d, p, q, u);
expect(decrypted1).to.deep.equal(message);
const encryptedNode = await crypto.publicKey.rsa.encrypt(message, n, e);
disableNative();
const decrypted2 = await crypto.publicKey.rsa.decrypt(encryptedNode, n, e, d, p, q, u);
expect(decrypted2).to.deep.equal(message);
});
it('compare native crypto and bnSign', async function() {
if (!detectNative()) { this.skip(); }
const bits = 1024;
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
const message = random.getRandomBytes(64);
const hashName = 'sha256';
const hashAlgo = openpgp.enums.write(openpgp.enums.hash, hashName);
const hashed = await crypto.computeDigest(hashAlgo, message);
enableNative();
const signatureNative = await crypto.publicKey.rsa.sign(hashAlgo, message, n, e, d, p, q, u, hashed);
disableNative();
const signatureBN = await crypto.publicKey.rsa.sign(hashAlgo, message, n, e, d, p, q, u, hashed);
expect(util.uint8ArrayToHex(signatureNative)).to.be.equal(util.uint8ArrayToHex(signatureBN));
});
it('compare native crypto and bnSign: throw on key size shorter than digest size', async function() {
if (!detectNative()) { this.skip(); }
const bits = 512;
const hashName = 'sha512'; // digest too long for a 512-bit key
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
const message = random.getRandomBytes(64);
const hashAlgo = openpgp.enums.write(openpgp.enums.hash, hashName);
const hashed = await crypto.computeDigest(hashAlgo, message);
enableNative();
await expect(crypto.publicKey.rsa.sign(hashAlgo, message, n, e, d, p, q, u, hashed)).to.be.rejectedWith(/Digest size cannot exceed key modulus size/);
disableNative();
await expect(crypto.publicKey.rsa.sign(hashAlgo, message, n, e, d, p, q, u, hashed)).to.be.rejectedWith(/Digest size cannot exceed key modulus size/);
});
it('compare native crypto and bnVerify', async function() {
if (!detectNative()) { this.skip(); }
const bits = 1024;
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
const message = random.getRandomBytes(64);
const hashName = 'sha256';
const hashAlgo = openpgp.enums.write(openpgp.enums.hash, hashName);
const hashed = await crypto.computeDigest(hashAlgo, message);
enableNative();
const signatureNative = await crypto.publicKey.rsa.sign(hashAlgo, message, n, e, d, p, q, u, hashed);
const verifyNative = await crypto.publicKey.rsa.verify(hashAlgo, message, signatureNative, n, e);
disableNative();
const verifyBN = await crypto.publicKey.rsa.verify(hashAlgo, message, signatureNative, n, e, hashed);
expect(verifyNative).to.be.true;
expect(verifyBN).to.be.true;
});
});