Add PwdWrap

This commit is contained in:
2024-05-15 12:14:15 +02:00
parent 267f6737fa
commit 9a0b7b6b44
3 changed files with 106 additions and 0 deletions
+2
View File
@@ -1,5 +1,7 @@
export {PrivateBox} from './asymmetric'
export {SecretBox} from './symmetric'
export {PwdBox} from './pwd'
export {PrivateWrap} from './private-wrap'
export {SecretWrap} from './secret-wrap'
export {PwdWrap} from './pwd-wrap'
+51
View File
@@ -0,0 +1,51 @@
import {Result} from 'result'
import * as misc from 'misc'
import {SecretWrap} from './secret-wrap'
import {pbkdf} from '../pbkdf'
export class PwdWrap {
private constructor(
private readonly secret_wrap: SecretWrap,
private readonly salt: Uint8Array,
) {}
public static async wrap(pwd: string, key_to_wrap: CryptoKey) : Promise<Result<PwdWrap>> {
const salt = crypto.getRandomValues(new Uint8Array(18))
const key = await PwdWrap.get_key(pwd, salt)
const box = await SecretWrap.wrap_key(key, key_to_wrap)
if (box.error()) return Result.error([])
return Result.ok(new PwdWrap(box.unwrap(), salt))
}
public async unwrap(pwd: string) : Promise<Result<CryptoKey>> {
const key = await PwdWrap.get_key(pwd, this.salt)
const unwrapped_key = await this.secret_wrap.unwrap(key)
if (unwrapped_key.error()) return Result.error([])
return Result.ok(unwrapped_key.unwrap())
}
private static async get_key(pwd: string, salt: Uint8Array) : Promise<CryptoKey> {
return pbkdf(pwd, salt, ['wrapKey', 'unwrapKey'])
}
public toString() : string {
const salt = misc.a2b64(this.salt)
const box = this.secret_wrap.toString()
return `${salt}${box}`
}
public static fromString(data: string) : Result<PwdWrap> {
const salt64 = data.slice(0, 24)
const salt = misc.b642a(salt64)
if (salt.error()) return Result.error([])
const box64 = data.slice(24)
const box = SecretWrap.fromString(box64)
if (box.error()) return Result.error([])
return Result.ok(new PwdWrap(box.unwrap(), salt.unwrap()))
}
}
+53
View File
@@ -0,0 +1,53 @@
import {beforeAll, expect, test} from 'bun:test'
import {PwdWrap} from '../../src/boxes'
import * as sym from '../../src/boxes/symmetric'
import * as asym from '../../src/boxes/asymmetric'
let kw_sym!: sym.Key;
let kw_asym!: asym.KeyPair;
beforeAll(async () => {
kw_sym = await sym.SecretBox.gen_key(true)
expect(kw_sym.extractable).toBe(true)
kw_asym = await asym.PrivateBox.gen_keypair(true)
expect(kw_asym[0].extractable).toBe(true)
})
test('base case', async () => {
const pwd = "password"
const testit = async (key: CryptoKey) => {
console.log(`Testing ${key.type} key with usage ${key.usages}`)
const wrapped = (await PwdWrap.wrap(pwd, key)).expect("Should wrap the key")
const unwrapped = (await wrapped.unwrap(pwd)).expect("Should unwrap the key")
expect(unwrapped).toEqual(key)
}
await testit(kw_sym)
await testit(kw_asym[0])
})
test('Fails with wrong password', async () => {
const pwd1 = "AwesomePassword123!"
const pwd2 = "AwesomePassword321!"
expect(pwd1).not.toEqual(pwd2)
const wrapped = (await PwdWrap.wrap(pwd1, kw_sym)).expect("Should wrap the key")
;(await wrapped.unwrap(pwd2)).expect_err("Shouldn't unwrap the key with wrong password")
})
test('toString and fromString are inverses', async () => {
const pwd = "password"
const wrapped = (await PwdWrap.wrap(pwd, kw_sym)).expect("Should wrap the key")
const str = wrapped.toString()
const wrapped2 = PwdWrap.fromString(str).expect("Should unwrap the key")
expect(wrapped2).toEqual(wrapped)
const unwrapped = (await wrapped.unwrap(pwd)).expect("Should unwrap the key")
expect(unwrapped).toEqual(kw_sym)
})