Skip to content

Commit

Permalink
add/use test fixtures from Node.js
Browse files Browse the repository at this point in the history
  • Loading branch information
boorad committed Jan 26, 2024
1 parent 6ef6f65 commit 2215b9e
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 89 deletions.
30 changes: 0 additions & 30 deletions example/src/components/Indentator.tsx

This file was deleted.

125 changes: 93 additions & 32 deletions example/src/testing/Tests/pbkdf2Tests/pbkdf2Tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { Buffer } from '@craftzdog/react-native-buffer';
import type { Done } from 'mocha';
import { fixtures } from './fixtures';

type TestFixture = [string, string, number, number, string];

function ab2str(buf: ArrayBuffer) {
return Buffer.from(buf).toString('hex');
}
Expand All @@ -16,16 +18,79 @@ function ab2str(buf: ArrayBuffer) {
// https://stackoverflow.com/questions/15593184/pbkdf2-hmac-sha-512-test-vectors

describe('pbkdf2', () => {
// RFC 6070 tests from Node.js
{
const test = (
pass: string,
salt: string,
iterations: number,
hash: string,
length: number,
expected: string,
done: Done
) => {
QuickCrypto.pbkdf2(
pass,
salt,
iterations,
length,
hash,
function (err, result) {
try {
expect(err).to.eql(null);
expect(result).to.not.eql(null);
expect(ab2str(result as ArrayBuffer)).to.equal(expected);
done();
} catch (e) {
done(e);
}
}
);
};

const kTests: TestFixture[] = [
['password', 'salt', 1, 20, '120fb6cffcf8b32c43e7225256c4f837a86548c9'],
['password', 'salt', 2, 20, 'ae4d0c95af6b46d32d0adff928f06dd02a303f8e'],
[
'password',
'salt',
4096,
20,
'c5e478d59288c841aa530db6845c4c8d962893a0',
],
[
'passwordPASSWORDpassword',
'saltSALTsaltSALTsaltSALTsaltSALTsalt',
4096,
25,
'348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c',
],
['pass\0word', 'sa\0lt', 4096, 16, '89b69d0516f829893c696226650a8687'],
[
'password',
'salt',
32,
32,
'64c486c55d30d4c5a079b8823b7d7cb37ff0556f537da8410233bcec330ed956',
],
];

kTests.forEach(([pass, salt, iterations, length, expected]) => {
const hash = 'sha256';
it(`RFC 6070 - ${pass} ${salt} ${iterations} ${hash} ${length}`, (done: Done) => {
test(pass, salt, iterations, hash, length, expected, done);
});
});
}

// eslint-disable-next-line @typescript-eslint/no-shadow
var Buffer = require('safe-buffer').Buffer;

it(' defaults to sha1 and handles buffers', (done: Done) => {
var resultSync = QuickCrypto.pbkdf2Sync('password', 'salt', 1, 32);
chai
.expect(ab2str(resultSync))
.to.eql(
'0c60c80f961f0e71f3a9b524af6012062fe037a6e0f0eb94fe8fc46bdc637164'
);
expect(ab2str(resultSync)).to.eql(
'0c60c80f961f0e71f3a9b524af6012062fe037a6e0f0eb94fe8fc46bdc637164'
);

QuickCrypto.pbkdf2(
Buffer.from('password'),
Expand All @@ -34,12 +99,10 @@ describe('pbkdf2', () => {
32,

function (_, result) {
chai
// @ts-expect-error
.expect(ab2str(result))
.to.eql(
'0c60c80f961f0e71f3a9b524af6012062fe037a6e0f0eb94fe8fc46bdc637164'
);
// @ts-expect-error
expect(ab2str(result)).to.eql(
'0c60c80f961f0e71f3a9b524af6012062fe037a6e0f0eb94fe8fc46bdc637164'
);
done();
}
);
Expand Down Expand Up @@ -155,32 +218,30 @@ describe('pbkdf2', () => {
it(' async w/ ' + description, function () {
function noop() {}
chai
.expect(
QuickCrypto.pbkdf2(
f.key,
f.salt,
f.iterations,
f.dkLen,
f.algo,
noop
)
expect(
QuickCrypto.pbkdf2(
f.key,
f.salt,
f.iterations,
f.dkLen,
f.algo,
noop
)
.to.throw(new RegExp(f.exception));
)
.to.throw(new RegExp(f.exception));
});
it(' sync w/' + description, function () {
chai
.expect(
QuickCrypto.pbkdf2Sync(
f.key,
f.salt,
f.iterations,
f.dkLen,
f.algo
)
expect(
QuickCrypto.pbkdf2Sync(
f.key,
f.salt,
f.iterations,
f.dkLen,
f.algo
)
.to.throw(new RegExp(f.exception));
)
.to.throw(new RegExp(f.exception));
});
}); */
});
Expand Down
84 changes: 60 additions & 24 deletions example/src/testing/Tests/webcryptoTests/webcryptoTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { expect } from 'chai';
import { atob, btoa } from 'react-native-quick-base64';
import crypto from 'react-native-quick-crypto';
import { describe, it } from '../../MochaRNAdapter';
import type { HashAlgorithm } from '../../../../../src/keys';

// Tests that a key pair can be used for encryption / decryption.
// function testEncryptDecrypt(publicKey: any, privateKey: any) {
Expand Down Expand Up @@ -39,6 +40,15 @@ import { describe, it } from '../../MochaRNAdapter';
// }
// }

type TestFixture = [
string,
string,
number,
HashAlgorithm | string,
number,
string
];

function base64ToArrayBuffer(val: string): ArrayBuffer {
var binaryString = atob(val);
var bytes = new Uint8Array(binaryString.length);
Expand Down Expand Up @@ -79,30 +89,56 @@ describe('webcrypto', () => {
);
});

it('PBKDF2 importKey raw/deriveBits', async () => {
const key = await crypto.subtle.importKey(
'raw',
'password',
{ name: 'PBKDF2' },
false,
['deriveBits']
);
// PBKDF2 deriveBits()
{
const test = async (
pass: string,
salt: string,
iterations: number,
hash: HashAlgorithm | string,
length: number,
expected: string
) => {
const key = await crypto.subtle.importKey(
'raw',
pass,
{ name: 'PBKDF2', hash },
false,
['deriveBits']
);

const bits = await crypto.subtle.deriveBits(
{
name: 'PBKDF2',
salt: 'salt',
iterations: 1,
hash: {
name: 'SHA-512',
const bits = await crypto.subtle.deriveBits(
{
name: 'PBKDF2',
salt,
iterations,
hash,
},
},
key,
512
);
const pbkdf2Key = arrayBufferToBase64(bits);
expect(pbkdf2Key).to.equal(
'hn9wzxreAs/zdSWZo6U9xK80x6ZpgVrl1RNVThyM8lLALUcKKFoFAbrZmb/pQ8CPBQI119aLHaVeY/c7YKV/zg=='
);
});
key,
length
);
const pbkdf2Key = arrayBufferToBase64(bits);
expect(pbkdf2Key).to.equal(expected);
};

const kTests: TestFixture[] = [
[
'hello',
'there',
10,
'SHA-256',
512,
'f72d1cf4853fffbd16a42751765d11f8dc7939498ee7b7' +
'ce7678b4cb16fad88098110a83e71f4483ce73203f7a64' +
'719d293280f780f9fafdcf46925c5c0588b3',
],
['hello', 'there', 5, 'SHA-384', 128, '201509b012c9cd2fbe7ea938f0c509b3'],
];

kTests.forEach(async ([pass, salt, iterations, hash, length, expected]) => {
it(`PBKDF2 importKey raw/deriveBits - ${pass} ${salt} ${iterations} ${hash} ${length}`, async () => {
await test(pass, salt, iterations, hash, length, expected);
});
});
}
});
15 changes: 15 additions & 0 deletions src/Hashnames.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { HashAlgorithm } from './keys';

export enum HashContext {
Node,
WebCrypto,
Expand Down Expand Up @@ -76,3 +78,16 @@ export function normalizeHashName(
} catch (_e) {}
return name;
}

// TODO: https://github.com/nodejs/node/blob/main/lib/internal/crypto/util.js#L303-L379 maybe?
export const normalizeHash = (
hash: HashAlgorithm | string | undefined
): HashAlgorithm => {
if (typeof hash === 'string') {
return { name: hash };
} else if (typeof hash === 'undefined') {
return { name: 'unknown' };
} else {
return hash;
}
};
2 changes: 1 addition & 1 deletion src/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export type SubtleAlgorithm = {
name: 'ECDSA' | 'ECDH' | 'PBKDF2';
salt?: string;
iterations?: number;
hash?: HashAlgorithm;
hash?: HashAlgorithm | string;
namedCurve?: NamedCurve;
length?: number;
};
Expand Down
6 changes: 4 additions & 2 deletions src/pbkdf2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
bufferLikeToArrayBuffer,
normalizeHashName,
HashContext,
normalizeHash,
} from './Utils';
import type { CryptoKey, SubtleAlgorithm } from './keys';
import { promisify } from 'util';
Expand Down Expand Up @@ -130,7 +131,8 @@ export async function pbkdf2DeriveBits(
length: number
): Promise<ArrayBuffer> {
const { iterations, hash, salt } = algorithm;
if (!hash || !hash.name) {
const normalizedHash = normalizeHash(hash);
if (!normalizedHash || !normalizedHash.name) {
throw lazyDOMException('hash cannot be blank', 'OperationError');
}
if (!iterations || iterations === 0) {
Expand All @@ -156,7 +158,7 @@ export async function pbkdf2DeriveBits(
sanitizedSalt,
iterations,
length / 8,
hash.name
normalizedHash.name
);
if (!result) {
throw lazyDOMException(
Expand Down

0 comments on commit 2215b9e

Please sign in to comment.