Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove internal, unused RandomBuffer #1593

Merged
merged 3 commits into from
Feb 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/crypto/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,7 @@ export async function getPrefixRandom(algo) {
* Generating a session key for the specified symmetric algorithm
* See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms.
* @param {module:enums.symmetric} algo - Symmetric encryption algorithm
* @returns {Promise<Uint8Array>} Random bytes as a string to be used as a key.
* @async
* @returns {Uint8Array} Random bytes as a string to be used as a key.
*/
export function generateSessionKey(algo) {
const { keySize } = getCipher(algo);
Expand Down
14 changes: 6 additions & 8 deletions src/crypto/pkcs1.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,13 @@ hash_headers[11] = [0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
* Create padding with secure random data
* @private
* @param {Integer} length - Length of the padding in bytes
* @returns {Promise<Uint8Array>} Random padding.
* @async
* @returns {Uint8Array} Random padding.
*/
async function getPKCS1Padding(length) {
function getPKCS1Padding(length) {
const result = new Uint8Array(length);
let count = 0;
while (count < length) {
const randomBytes = await getRandomBytes(length - count);
const randomBytes = getRandomBytes(length - count);
for (let i = 0; i < randomBytes.length; i++) {
if (randomBytes[i] !== 0) {
result[count++] = randomBytes[i];
Expand All @@ -72,18 +71,17 @@ async function getPKCS1Padding(length) {
* @see {@link https://tools.ietf.org/html/rfc4880#section-13.1.1|RFC 4880 13.1.1}
* @param {Uint8Array} message - Message to be encoded
* @param {Integer} keyLength - The length in octets of the key modulus
* @returns {Promise<Uint8Array>} EME-PKCS1 padded message.
* @async
* @returns {Uint8Array} EME-PKCS1 padded message.
*/
export async function emeEncode(message, keyLength) {
export function emeEncode(message, keyLength) {
const mLength = message.length;
// length checking
if (mLength > keyLength - 11) {
throw new Error('Message too long');
}
// Generate an octet string PS of length k - mLen - 3 consisting of
// pseudo-randomly generated nonzero octets
const PS = await getPKCS1Padding(keyLength - mLength - 3);
const PS = getPKCS1Padding(keyLength - mLength - 3);
// Concatenate PS, the message M, and other padding to form an
// encoded message EM of length k octets as EM = 0x00 || 0x02 || PS || 0x00 || M.
const encoded = new Uint8Array(keyLength);
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/public_key/elgamal.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export async function encrypt(data, p, g, y) {
g = new BigInteger(g);
y = new BigInteger(y);

const padded = await emeEncode(data, p.byteLength());
const padded = emeEncode(data, p.byteLength());
const m = new BigInteger(padded);

// OpenPGP uses a "special" version of ElGamal where g is generator of the full group Z/pZ*
Expand Down
6 changes: 3 additions & 3 deletions src/crypto/public_key/elliptic/curves.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ class Curve {
case 'node':
return nodeGenKeyPair(this.name);
case 'curve25519': {
const privateKey = await getRandomBytes(32);
const privateKey = getRandomBytes(32);
privateKey[0] = (privateKey[0] & 127) | 64;
privateKey[31] &= 248;
const secretKey = privateKey.slice().reverse();
Expand All @@ -191,15 +191,15 @@ class Curve {
return { publicKey, privateKey };
}
case 'ed25519': {
const privateKey = await getRandomBytes(32);
const privateKey = getRandomBytes(32);
const keyPair = nacl.sign.keyPair.fromSeed(privateKey);
const publicKey = util.concatUint8Array([new Uint8Array([0x40]), keyPair.publicKey]);
return { publicKey, privateKey };
}
}
const indutnyCurve = await getIndutnyCurve(this.name);
keyPair = await indutnyCurve.genKeyPair({
entropy: util.uint8ArrayToString(await getRandomBytes(32))
entropy: util.uint8ArrayToString(getRandomBytes(32))
});
return { publicKey: new Uint8Array(keyPair.getPublic('array', false)), privateKey: keyPair.getPrivate().toArrayLike(Uint8Array) };
}
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/public_key/elliptic/ecdh.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ async function kdf(hashAlgo, X, length, param, stripLeading = false, stripTraili
async function genPublicEphemeralKey(curve, Q) {
switch (curve.type) {
case 'curve25519': {
const d = await getRandomBytes(32);
const d = getRandomBytes(32);
const { secretKey, sharedKey } = await genPrivateEphemeralKey(curve, Q, null, d);
let { publicKey } = nacl.box.keyPair.fromSecretKey(secretKey);
publicKey = util.concatUint8Array([new Uint8Array([0x40]), publicKey]);
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/public_key/elliptic/ecdsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export async function validateParams(oid, Q, d) {
switch (curve.type) {
case 'web':
case 'node': {
const message = await getRandomBytes(8);
const message = getRandomBytes(8);
const hashAlgo = enums.hash.sha256;
const hashed = await hash.digest(hashAlgo, message);
try {
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/public_key/rsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ async function nodeEncrypt(data, n, e) {
async function bnEncrypt(data, n, e) {
const BigInteger = await util.getBigInteger();
n = new BigInteger(n);
data = new BigInteger(await emeEncode(data, n.byteLength()));
data = new BigInteger(emeEncode(data, n.byteLength()));
e = new BigInteger(e);
if (data.gte(n)) {
throw new Error('Message size cannot exceed modulus size');
Expand Down
76 changes: 2 additions & 74 deletions src/crypto/random.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,88 +26,18 @@ import util from '../util';

const nodeCrypto = util.getNodeCrypto();

/**
* Buffer for secure random numbers
*/
class RandomBuffer {
constructor() {
this.buffer = null;
this.size = null;
this.callback = null;
}

/**
* Initialize buffer
* @param {Integer} size - size of buffer
*/
init(size, callback) {
this.buffer = new Uint8Array(size);
this.size = 0;
this.callback = callback;
}

/**
* Concat array of secure random numbers to buffer
* @param {Uint8Array} buf
*/
set(buf) {
if (!this.buffer) {
throw new Error('RandomBuffer is not initialized');
}
if (!(buf instanceof Uint8Array)) {
throw new Error('Invalid type: buf not an Uint8Array');
}
const freeSpace = this.buffer.length - this.size;
if (buf.length > freeSpace) {
buf = buf.subarray(0, freeSpace);
}
// set buf with offset old size of buffer
this.buffer.set(buf, this.size);
this.size += buf.length;
}

/**
* Take numbers out of buffer and copy to array
* @param {Uint8Array} buf - The destination array
*/
async get(buf) {
if (!this.buffer) {
throw new Error('RandomBuffer is not initialized');
}
if (!(buf instanceof Uint8Array)) {
throw new Error('Invalid type: buf not an Uint8Array');
}
if (this.size < buf.length) {
if (!this.callback) {
throw new Error('Random number buffer depleted');
}
// Wait for random bytes from main context, then try again
await this.callback();
return this.get(buf);
}
for (let i = 0; i < buf.length; i++) {
buf[i] = this.buffer[--this.size];
// clear buffer value
this.buffer[this.size] = 0;
}
}
}

/**
* Retrieve secure random byte array of the specified length
* @param {Integer} length - Length in bytes to generate
* @returns {Promise<Uint8Array>} Random byte array.
* @async
* @returns {Uint8Array} Random byte array.
*/
export async function getRandomBytes(length) {
export function getRandomBytes(length) {
const buf = new Uint8Array(length);
if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
crypto.getRandomValues(buf);
} else if (nodeCrypto) {
const bytes = nodeCrypto.randomBytes(buf.length);
buf.set(bytes);
} else if (randomBuffer.buffer) {
await randomBuffer.get(buf);
} else {
throw new Error('No secure random number generator available.');
}
Expand Down Expand Up @@ -137,5 +67,3 @@ export async function getRandomBigInteger(min, max) {
const r = new BigInteger(await getRandomBytes(bytes + 8));
return r.mod(modulus).add(min);
}

export const randomBuffer = new RandomBuffer();
4 changes: 2 additions & 2 deletions src/message.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ export class Message {
pkeskPacketCopy.read(serialisedPKESK);
const randomSessionKey = {
sessionKeyAlgorithm,
sessionKey: await crypto.generateSessionKey(sessionKeyAlgorithm)
sessionKey: crypto.generateSessionKey(sessionKeyAlgorithm)
};
try {
await pkeskPacketCopy.decrypt(decryptionKeyPacket, randomSessionKey);
Expand Down Expand Up @@ -345,7 +345,7 @@ export class Message {
enums.read(enums.aead, await getPreferredAlgo('aead', encryptionKeys, date, userIDs, config)) :
undefined;

const sessionKeyData = await crypto.generateSessionKey(algo);
const sessionKeyData = crypto.generateSessionKey(algo);
return { data: sessionKeyData, algorithm: algorithmName, aeadAlgorithm: aeadAlgorithmName };
}

Expand Down
2 changes: 1 addition & 1 deletion src/packet/aead_encrypted_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class AEADEncryptedDataPacket {
this.cipherAlgorithm = sessionKeyAlgorithm;

const { ivLength } = crypto.getAEADMode(this.aeadAlgorithm);
this.iv = await crypto.random.getRandomBytes(ivLength); // generate new random IV
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);
Expand Down
4 changes: 2 additions & 2 deletions src/packet/secret_key.js
Original file line number Diff line number Diff line change
Expand Up @@ -283,13 +283,13 @@ class SecretKeyPacket extends PublicKeyPacket {
}

this.s2k = new S2K(config);
this.s2k.salt = await crypto.random.getRandomBytes(8);
this.s2k.salt = crypto.random.getRandomBytes(8);
const cleartext = crypto.serializeParams(this.algorithm, this.privateParams);
this.symmetric = enums.symmetric.aes256;
const key = await produceEncryptionKey(this.s2k, passphrase, this.symmetric);

const { blockSize } = crypto.getCipher(this.symmetric);
this.iv = await crypto.random.getRandomBytes(blockSize);
this.iv = crypto.random.getRandomBytes(blockSize);

if (config.aeadProtect) {
this.s2kUsage = 253;
Expand Down
6 changes: 3 additions & 3 deletions src/packet/sym_encrypted_session_key.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,18 +179,18 @@ class SymEncryptedSessionKeyPacket {
this.sessionKeyEncryptionAlgorithm = algo;

this.s2k = new S2K(config);
this.s2k.salt = await crypto.random.getRandomBytes(8);
this.s2k.salt = crypto.random.getRandomBytes(8);

const { blockSize, keySize } = crypto.getCipher(algo);
const encryptionKey = await this.s2k.produceKey(passphrase, keySize);

if (this.sessionKey === null) {
this.sessionKey = await crypto.generateSessionKey(this.sessionKeyAlgorithm);
this.sessionKey = crypto.generateSessionKey(this.sessionKeyAlgorithm);
}

if (this.version === 5) {
const mode = crypto.getAEADMode(this.aeadAlgorithm);
this.iv = await crypto.random.getRandomBytes(mode.ivLength); // generate new random IV
this.iv = crypto.random.getRandomBytes(mode.ivLength); // generate new random IV
const associatedData = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, this.sessionKeyEncryptionAlgorithm, this.aeadAlgorithm]);
const modeInstance = await mode(algo, encryptionKey);
this.encrypted = await modeInstance.encrypt(this.sessionKey, this.iv, associatedData);
Expand Down
10 changes: 5 additions & 5 deletions test/crypto/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ module.exports = () => describe('API functional testing', function() {
await Promise.all(symmAlgoNames.map(async function(algoName) {
const algo = openpgp.enums.write(openpgp.enums.symmetric, algoName);
const { blockSize } = crypto.getCipher(algo);
const symmKey = await crypto.generateSessionKey(algo);
const symmKey = crypto.generateSessionKey(algo);
const IV = new Uint8Array(blockSize);
const symmencData = await crypto.mode.cfb.encrypt(algo, symmKey, util.stringToUint8Array(plaintext), IV, config);
const text = util.uint8ArrayToString(await crypto.mode.cfb.decrypt(algo, symmKey, symmencData, new Uint8Array(blockSize)));
Expand All @@ -269,8 +269,8 @@ module.exports = () => describe('API functional testing', function() {

});

it('Asymmetric using RSA with eme_pkcs1 padding', async function () {
const symmKey = await crypto.generateSessionKey(openpgp.enums.symmetric.aes256);
it('Asymmetric using RSA with eme_pkcs1 padding', function () {
const symmKey = crypto.generateSessionKey(openpgp.enums.symmetric.aes256);
return crypto.publicKeyEncrypt(algoRSA, RSAPublicParams, symmKey).then(RSAEncryptedData => {
return crypto.publicKeyDecrypt(
algoRSA, RSAPublicParams, RSAPrivateParams, RSAEncryptedData
Expand All @@ -280,8 +280,8 @@ module.exports = () => describe('API functional testing', function() {
});
});

it('Asymmetric using Elgamal with eme_pkcs1 padding', async function () {
const symmKey = await crypto.generateSessionKey(openpgp.enums.symmetric.aes256);
it('Asymmetric using Elgamal with eme_pkcs1 padding', function () {
const symmKey = crypto.generateSessionKey(openpgp.enums.symmetric.aes256);
return crypto.publicKeyEncrypt(algoElGamal, elGamalPublicParams, symmKey).then(ElgamalEncryptedData => {
return crypto.publicKeyDecrypt(
algoElGamal, elGamalPublicParams, elGamalPrivateParams, ElgamalEncryptedData
Expand Down
4 changes: 2 additions & 2 deletions test/crypto/gcm.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ module.exports = () => describe('Symmetric AES-GCM (experimental)', function() {
this.skip(); // eslint-disable-line no-invalid-this
}
const algo = openpgp.enums.write(openpgp.enums.symmetric, algoName);
const key = await crypto.generateSessionKey(algo);
const iv = await crypto.random.getRandomBytes(crypto.mode.gcm.ivLength);
const key = crypto.generateSessionKey(algo);
const iv = crypto.random.getRandomBytes(crypto.mode.gcm.ivLength);

const nativeEncryptSpy = webCrypto ? sinonSandbox.spy(webCrypto, 'encrypt') : sinonSandbox.spy(nodeCrypto, 'createCipheriv');
const nativeDecryptSpy = webCrypto ? sinonSandbox.spy(webCrypto, 'decrypt') : sinonSandbox.spy(nodeCrypto, 'createDecipheriv');
Expand Down
1 change: 0 additions & 1 deletion test/crypto/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
module.exports = () => describe('Crypto', function () {
require('./cipher')();
require('./hash')();
require('./random.js')();
require('./crypto.js')();
require('./elliptic.js')();
require('./ecdh.js')();
Expand Down