Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,7 @@ expect(result).toStrictEqual(expectedResult);
// Key derivation
const context = 'BLAKE3 2019-12-27 16:29:52 test vectors context';
const baseKey = symmetric.genSymmetricKey(); // Uint8Array
const key = await deriveKey.deriveSymmetricCryptoKeyFromContext(context, baseKey);
expect(key).instanceOf(CryptoKey);
const key = await deriveKey.deriveSymmetricKeyFromContext(context, baseKey);

const password = 'your password';
const { keyHex, saltHex } = await deriveKey.getKeyFromPasswordHex(password);
Expand Down
43 changes: 0 additions & 43 deletions src/derive-key/deriveKeysFromKey.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { blake3 } from '@noble/hashes/blake3.js';
import { AES_KEY_BIT_LENGTH, CONTEXT_DERIVE } from '../constants';
import { UTF8ToUint8 } from '../utils';
import { importSymmetricCryptoKey } from '../symmetric-crypto';

/**
* Derives a symmetric key from the base key and context string
Expand All @@ -15,31 +14,6 @@ export function deriveSymmetricKeyFromContext(context: string, baseKey: Uint8Arr
return blake3(baseKey, { context: UTF8ToUint8(context) });
}

/**
* Derives a symmetric CryptoKey from the base key and context string
*
* @param context - The context string.
* The context string should be hardcoded, globally unique, and application-specific.
* @param baseKey - The base key (NOT PASSWORD!)
* @returns The derived secret CryptoKey
*/
export async function deriveSymmetricCryptoKeyFromContext(context: string, baseKey: Uint8Array): Promise<CryptoKey> {
try {
if (baseKey.length != AES_KEY_BIT_LENGTH / 8) {
throw new Error(`Base key length must be exactly ${AES_KEY_BIT_LENGTH / 8} bytes`);
}
if (!context) {
throw new Error('Context is empry');
}
const keyBytes = deriveSymmetricKeyFromContext(context, baseKey);
const key = await importSymmetricCryptoKey(keyBytes);

return key;
} catch (error) {
throw new Error('Failed to derive CryptoKey from base key and context', { cause: error });
}
}

/**
* Derives a symmetric key from two keys
*
Expand All @@ -51,23 +25,6 @@ export function deriveSymmetricKeyFromTwoKeys(key1: Uint8Array, key2: Uint8Array
return deriveSymmetricKeyFromTwoKeysAndContext(key1, key2, CONTEXT_DERIVE);
}

/**
* Derives a symmetric CryptoKey from two keys
*
* @param key1 - The 32-bytes key
* @param key2 - The 32-bytes key
* @returns The derived secret CryptoKey
*/
export async function deriveSymmetricCryptoKeyFromTwoKeys(key1: Uint8Array, key2: Uint8Array): Promise<CryptoKey> {
try {
const keyBytes = deriveSymmetricKeyFromTwoKeys(key1, key2);
const key = await importSymmetricCryptoKey(keyBytes);
return key;
} catch (error) {
throw new Error('Failed to derive symmetric CryptoKey from two keys', { cause: error });
}
}

/**
* Derives a symmetric key from two keys and context
*
Expand Down
3 changes: 0 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ export {
} from './asymmetric-crypto';
export {
deriveSymmetricKeyFromTwoKeys,
deriveSymmetricCryptoKeyFromTwoKeys,
deriveSymmetricKeyFromTwoKeysAndContext,
deriveSymmetricKeyFromContext,
deriveSymmetricCryptoKeyFromContext,
getKeyFromPassword,
getKeyFromPasswordAndSalt,
getKeyFromPasswordHex,
Expand Down Expand Up @@ -71,7 +69,6 @@ export {
exportSymmetricCryptoKey,
genSymmetricCryptoKey,
genSymmetricKey,
deriveSymmetricCryptoKey,
} from './symmetric-crypto';
export {
uint8ArrayToHex,
Expand Down
15 changes: 0 additions & 15 deletions src/symmetric-crypto/keys.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { AES_ALGORITHM, AES_KEY_BIT_LENGTH, KEY_FORMAT } from '../constants';
import { randomBytes } from '@noble/post-quantum/utils.js';
import { getBytesFromData } from '../hash';

/**
* Converts Uint8Array into CryptoKey
Expand Down Expand Up @@ -60,17 +59,3 @@ export async function genSymmetricCryptoKey(): Promise<CryptoKey> {
export function genSymmetricKey(): Uint8Array {
return randomBytes(AES_KEY_BIT_LENGTH / 8);
}

/**
* Derives CryptoKey from the given key material
*
* @returns The derived CryptoKey.
*/
export async function deriveSymmetricCryptoKey(keyMaterial: Uint8Array): Promise<CryptoKey> {
try {
const hashBuffer = getBytesFromData(AES_KEY_BIT_LENGTH / 8, keyMaterial);
return importSymmetricCryptoKey(hashBuffer);
} catch (error) {
throw new Error('Failed to derive CryptoKey from the given key material', { cause: error });
}
}
55 changes: 10 additions & 45 deletions tests/derive-keys/deriveKeys.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { describe, expect, it } from 'vitest';
import {
deriveSymmetricKeyFromTwoKeys,
deriveSymmetricCryptoKeyFromContext,
deriveSymmetricCryptoKeyFromTwoKeys,
deriveSymmetricKeyFromContext
} from '../../src/derive-key';
import { AES_KEY_BIT_LENGTH, AES_ALGORITHM } from '../../src/constants';
import { uint8ArrayToHex } from '../../src/utils';
import { AES_KEY_BIT_LENGTH } from '../../src/constants';
import { genSymmetricKey } from '../../src/symmetric-crypto';

describe('Test derive key', () => {
Expand All @@ -15,48 +15,20 @@ describe('Test derive key', () => {
}
return result;
}

it('should derive symmetric key', async () => {
const context = 'BLAKE3 2019-12-27 16:29:52 test vectors context';
const baseKey = createTestInput(32);
const key = await deriveSymmetricCryptoKeyFromContext(context, baseKey);
expect(key).instanceOf(CryptoKey);
});

it('derive symmetric key should throw an error if context is an empty string', async () => {
const context = '';
const baseKey = createTestInput(32);
await expect(deriveSymmetricCryptoKeyFromContext(context, baseKey)).rejects.toThrowError(
/Failed to derive CryptoKey from base key and context/,
);
});

it('derive symmetric key should throw an error if base key is too short', async () => {
const context = 'test context';
const baseKey = createTestInput(2);
await expect(deriveSymmetricCryptoKeyFromContext(context, baseKey)).rejects.toThrowError(
/Failed to derive CryptoKey from base key and context/,
);
});

it('should derive symmetric crypto key', async () => {
const context = 'BLAKE3 2019-12-27 16:29:52 test vectors context';
const baseKey = createTestInput(32);
const key = await deriveSymmetricCryptoKeyFromContext(context, baseKey);
expect(key).toBeInstanceOf(CryptoKey);
const alg = key.algorithm as AesKeyAlgorithm;
expect(alg.name).toBe(AES_ALGORITHM);
expect(alg.length).toBe(AES_KEY_BIT_LENGTH);
it('should derive symmetric key from two keys', async () => {
const context = 'BLAKE3 2019-12-27 16:29:52 test vectors context';
const input = createTestInput(63);
const blake3TestResult = 'b6451e30b953c206e34644c6803724e9d2725e0893039cfc49584f991f451af3';
const result = deriveSymmetricKeyFromContext(context, input);
const resultHex = uint8ArrayToHex(result);
expect(resultHex).toBe(blake3TestResult);
});

it('should derive symmetric key from two keys', async () => {
const key1 = genSymmetricKey();
const key2 = genSymmetricKey();
const key = await deriveSymmetricKeyFromTwoKeys(key1, key2);
expect(key.length).toBe(AES_KEY_BIT_LENGTH / 8);

const cryptoKey = await deriveSymmetricCryptoKeyFromTwoKeys(key1, key2);
expect(cryptoKey).instanceOf(CryptoKey);
});

it('derive symmetric key from two keys should fail for small key', async () => {
Expand All @@ -68,12 +40,5 @@ describe('Test derive key', () => {
expect(() => deriveSymmetricKeyFromTwoKeys(key2, short_key)).toThrowError(
/Failed to derive symmetric key from two keys/,
);

await expect(deriveSymmetricCryptoKeyFromTwoKeys(short_key, key2)).rejects.toThrowError(
/Failed to derive symmetric CryptoKey from two keys/,
);
await expect(deriveSymmetricCryptoKeyFromTwoKeys(key2, short_key)).rejects.toThrowError(
/Failed to derive symmetric CryptoKey from two keys/,
);
});
});
15 changes: 1 addition & 14 deletions tests/symmetric-crypto/keys.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { describe, expect, it } from 'vitest';
import {
exportSymmetricCryptoKey,
genSymmetricCryptoKey,
genSymmetricKey,
deriveSymmetricCryptoKey,
} from '../../src/symmetric-crypto';
import { exportSymmetricCryptoKey, genSymmetricCryptoKey, genSymmetricKey } from '../../src/symmetric-crypto';
import { AES_ALGORITHM, AES_KEY_BIT_LENGTH } from '../../src/constants';

describe('Test symmetric key functions', () => {
Expand Down Expand Up @@ -42,12 +37,4 @@ describe('Test symmetric key functions', () => {
/Failed to export symmetric CryptoKey/,
);
});

it('should sucessfully derive CryptoKey', async () => {
const keyMaterial = new TextEncoder().encode(
'Srp6AzybbyludWuaVwGoHa1C2H0Qtv7JR0sKGLSWe8Ho8_q9hezfYD2RYb9IUrW999pH4VlABgDLse484zAapg',
);
const key = await deriveSymmetricCryptoKey(keyMaterial);
expect(key).toBeInstanceOf(CryptoKey);
});
});
Loading