185 lines
6.1 KiB
TypeScript
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)
|
|
})
|
|
})
|