Files
libcrypto/test/kdf.test.ts
T
2024-09-12 00:08:49 +02:00

185 lines
6.1 KiB
TypeScript

import {describe, expect, test} from 'bun:test'
import {kdf, PrivateWrap, SecretBox, SecretWrap} from '..'
async function test_keys(k1: CryptoKey, k2: CryptoKey, usage: kdf.Usage | kdf.DHusage, should_box: boolean, should_unbox: boolean) {
if (usage === kdf.Usage.wrap || usage == kdf.DHusage.wrap) {
const payload = await SecretBox.gen(true)
const box = await SecretWrap.wrap(payload, k1)
if (should_box) expect(box).not.toBeNull()
else return
const unbox = await box!.unwrap(k2)
if (should_unbox) expect(unbox).not.toBeNull()
} else {
const payload = crypto.getRandomValues(new Uint8Array(16))
const box = await SecretBox.encrypt(payload, k1)
if (should_box) expect(box).not.toBeNull()
else return
const unbox = await box!.decrypt(k2)
if (should_unbox) {
expect(unbox).not.toBeNull()
expect(unbox).toEqual(payload)
}
}
}
describe('HKDF', () => {
function test_key(k: CryptoKey, usage: kdf.Usage) {
expect(k.extractable).toBeFalse()
expect(k.type).toEqual('secret')
expect(k.usages).toContainAllValues(usage === kdf.Usage.wrap ? ['wrapKey', 'unwrapKey'] : ['encrypt', 'decrypt'])
}
const seed1 = crypto.getRandomValues(new Uint8Array(32))
const seed2 = crypto.getRandomValues(new Uint8Array(32))
expect(seed1).not.toEqual(seed2)
const usage1 = kdf.Usage.wrap
const usage2 = kdf.Usage.box
test('Base case', async () => {
const k1 = await kdf.hkdf(seed1, usage1)
test_key(k1!, usage1)
const k2 = await kdf.hkdf(seed1, usage1)
test_key(k2!, usage1)
expect(k1!.usages).toContainAllValues(k2!.usages)
await test_keys(k1!, k2!, usage1, true, true)
})
test('Different seed', async () => {
const k1 = await kdf.hkdf(seed1, usage1)
test_key(k1!, usage1)
const k2 = await kdf.hkdf(seed2, usage1)
test_key(k2!, usage1)
expect(k1!.usages).toContainAllValues(k2!.usages)
await test_keys(k1!, k2!, usage1, true, false)
})
test('Different usage', async () => {
const k1 = await kdf.hkdf(seed1, usage1)
test_key(k1!, usage1)
const k2 = await kdf.hkdf(seed1, usage2)
test_key(k2!, usage2)
expect(k1!.usages).not.toContainAllValues(k2!.usages)
await test_keys(k1!, k2!, usage1, true, false)
await test_keys(k1!, k2!, usage2, false, false)
})
test('Different context', async () => {
const k1 = await kdf.hkdf(seed1, usage1, 'abc')
test_key(k1!, usage1)
const k2 = await kdf.hkdf(seed1, usage1, 'def')
test_key(k2!, usage1)
expect(k1!.usages).toContainAllValues(k2!.usages)
await test_keys(k1!, k2!, usage1, true, false)
})
test('Minimum size', async () => {
const k = await kdf.hkdf(new Uint8Array(31), usage1)
expect(k).toBeNull()
})
})
describe('PBKDF', () => {
const pwd1 = 'abc'
const pwd2 = 'def'
expect(pwd1).not.toEqual(pwd2)
const salt1 = crypto.getRandomValues(new Uint8Array(16))
const salt2 = crypto.getRandomValues(new Uint8Array(16))
expect(salt1).not.toEqual(salt2)
test('Base case', async () => {
const k1 = await kdf.pbkdf(salt1, pwd1)
const k2 = await kdf.pbkdf(salt1, pwd1)
expect(k1).toEqual(k2)
})
test('Different salt', async () => {
const k1 = await kdf.pbkdf(salt1, pwd1)
const k2 = await kdf.pbkdf(salt2, pwd1)
expect(k1).not.toEqual(k2)
})
test('Different password', async () => {
const k1 = await kdf.pbkdf(salt1, pwd1)
const k2 = await kdf.pbkdf(salt1, pwd2)
expect(k1).not.toEqual(k2)
})
test('Different strengths', async () => {
const k1 = await kdf.pbkdf(salt1, pwd2, kdf.Strength.weak)
const k2 = await kdf.pbkdf(salt1, pwd1, kdf.Strength.moderate)
const k3 = await kdf.pbkdf(salt1, pwd2, kdf.Strength.strong)
expect(k1).not.toEqual(k2)
expect(k1).not.toEqual(k3)
expect(k2).not.toEqual(k3)
})
test('Minimum salt size', async () => {
const k = await kdf.pbkdf(new Uint8Array(15), pwd1)
expect(k).toBeNull()
})
})
describe('ECDH', async () => {
const p1 = await PrivateWrap.gen(false)
const p2 = await PrivateWrap.gen(false)
const p3 = await PrivateWrap.gen(false)
const usage1 = kdf.DHusage.wrap
const usage2 = kdf.DHusage.box
function test_key(k: CryptoKey, usage: kdf.DHusage) {
expect(k.usages).toContainAllValues(usage === kdf.DHusage.wrap ? ['wrapKey', 'unwrapKey'] : ['encrypt', 'decrypt'])
expect(k.type).toEqual('secret')
expect(k.extractable).toBeFalse()
}
test('base case', async () => {
const k1 = await kdf.ecdh(p1.privateKey, p2.publicKey, usage1)
test_key(k1!, usage1)
const k2 = await kdf.ecdh(p2.privateKey, p1.publicKey, usage1)
test_key(k2!, usage1)
expect(k1!.usages).toContainAllValues(k2!.usages)
await test_keys(k1!, k2!, usage1, true, true)
})
test('Different pubkeys', async () => {
const k1 = await kdf.ecdh(p1.privateKey, p2.publicKey, usage1)
test_key(k1!, usage1)
const k2 = await kdf.ecdh(p2.privateKey, p3.publicKey, usage1)
test_key(k2!, usage1)
expect(k1!.usages).toContainAllValues(k2!.usages)
await test_keys(k1!, k2!, usage1, true, false)
})
test('Different privkeys', async () => {
const k1 = await kdf.ecdh(p1.privateKey, p2.publicKey, usage1)
test_key(k1!, usage1)
const k2 = await kdf.ecdh(p3.privateKey, p1.publicKey, usage1)
test_key(k2!, usage1)
expect(k1!.usages).toContainAllValues(k2!.usages)
await test_keys(k1!, k2!, usage1, true, false)
})
test('Different usage', async () => {
const k1 = await kdf.ecdh(p1.privateKey, p2.publicKey, usage1)
test_key(k1!, usage1)
const k2 = await kdf.ecdh(p2.privateKey, p1.publicKey, usage2)
test_key(k2!, usage2)
expect(k1!.usages).not.toContainAllValues(k2!.usages)
await test_keys(k1!, k2!, usage1, true, false)
await test_keys(k1!, k2!, usage2, false, false)
})
test('Different context', async () => {
const k1 = await kdf.ecdh(p1.privateKey, p2.publicKey, usage1, 'abc')
test_key(k1!, usage1)
const k2 = await kdf.ecdh(p2.privateKey, p1.publicKey, usage1, 'def')
test_key(k2!, usage1)
expect(k1!.usages).toContainAllValues(k2!.usages)
await test_keys(k1!, k2!, usage1, true, false)
})
})