Allow to add context on key derivations

This commit is contained in:
2024-09-11 22:43:52 +02:00
parent 11801b81f5
commit 7aef4bed50
5 changed files with 45 additions and 31 deletions
+19 -5
View File
@@ -13,7 +13,7 @@ export enum DHusage {
wrap
}
export async function hkdf(key: Uint8Array, usage: Usage): Promise<CryptoKey> {
export async function hkdf(key: Uint8Array, usage: Usage, context?: string): Promise<CryptoKey> {
log.trace('HKDF')
log.trace(`usage : ${usage}`)
@@ -53,7 +53,7 @@ export async function hkdf(key: Uint8Array, usage: Usage): Promise<CryptoKey> {
throw 'Unknown usage for HDKF'
}
}
const info = new TextEncoder().encode(info_txt)
const info = new TextEncoder().encode(info_txt + '-' + (context ?? 'key'))
return await crypto.subtle.deriveKey(
{
@@ -87,15 +87,29 @@ export async function pbkdf(salt: Uint8Array, password: string): Promise<Uint8Ar
return new Uint8Array(buffer)
}
export async function ecdh(privkey: CryptoKey, pubkey: CryptoKey, usage: DHusage): Promise<CryptoKey> {
export async function ecdh(privkey: CryptoKey, pubkey: CryptoKey, usage: DHusage, context?: string): Promise<CryptoKey> {
log.trace('ecdh')
const outputUsage: KeyUsage[] = usage === DHusage.box ? ['encrypt', 'decrypt'] : ['wrapKey', 'unwrapKey']
return await crypto.subtle.deriveKey(
const seed_bits = await crypto.subtle.deriveBits(
{
name: consts.ECDH.name,
public: pubkey
},
privkey,
256
)
const seed = await crypto.subtle.importKey('raw', seed_bits, 'HKDF', false, ['deriveKey'])
const outputUsage: KeyUsage[] = usage === DHusage.box ? ['encrypt', 'decrypt'] : ['wrapKey', 'unwrapKey']
return await crypto.subtle.deriveKey(
{
name: 'HKDF',
hash: 'SHA-512',
salt: new Uint8Array(16),
info: new TextEncoder().encode('ECDH-' + (context ?? 'key'))
},
seed,
{
name: consts.ENCRYPTION,
length: 256
+5 -5
View File
@@ -14,19 +14,19 @@ export default class PrivateBox {
public static async gen(extractable: boolean = true): Promise<CryptoKeyPair> {
log.trace('generate keypair')
return await crypto.subtle.generateKey(consts.ECDH, extractable, ['deriveKey']) as CryptoKeyPair
return await crypto.subtle.generateKey(consts.ECDH, extractable, ['deriveBits']) as CryptoKeyPair
}
public static async encrypt(data: Uint8Array, pubkey: CryptoKey): Promise<PrivateBox> {
public static async encrypt(data: Uint8Array, pubkey: CryptoKey, context?: string): Promise<PrivateBox> {
log.trace('encrypt')
const tmp_pair = await PrivateBox.gen(false)
const key = await ecdh(tmp_pair.privateKey, pubkey, DHusage.box)
const key = await ecdh(tmp_pair.privateKey, pubkey, DHusage.box, context) // TODO : null
const box = await SecretBox.encrypt(data, key)
return new this(tmp_pair.publicKey, box)
}
public async decrypt(privkey: CryptoKey): Promise<Uint8Array | null> {
public async decrypt(privkey: CryptoKey, context?: string): Promise<Uint8Array | null> {
log.trace('decrypt')
const key = await ecdh(privkey, this.pubkey, DHusage.box)
const key = await ecdh(privkey, this.pubkey, DHusage.box, context) // TODO : null
return await this.box.decrypt(key)
}
+5 -5
View File
@@ -14,19 +14,19 @@ export default class PrivateWrap {
public static async gen(extractable: boolean = true): Promise<CryptoKeyPair> {
log.trace('generate keypair')
return await crypto.subtle.generateKey(consts.ECDH, extractable, ['deriveKey']) as CryptoKeyPair
return await crypto.subtle.generateKey(consts.ECDH, extractable, ['deriveBits']) as CryptoKeyPair
}
public static async wrap(data: CryptoKey, pubkey: CryptoKey): Promise<PrivateWrap> {
public static async wrap(data: CryptoKey, pubkey: CryptoKey, context?: string): Promise<PrivateWrap> {
log.trace('wrap')
const tmp_keypair = await PrivateWrap.gen()
const kd = await ecdh(tmp_keypair.privateKey, pubkey, DHusage.wrap)
const kd = await ecdh(tmp_keypair.privateKey, pubkey, DHusage.wrap, context) // TODO : null
const box = await SecretWrap.wrap(data, kd)
return new this(box, tmp_keypair.publicKey)
}
public async unwrap(privkey: CryptoKey): Promise<CryptoKey | null> {
public async unwrap(privkey: CryptoKey, context?: string): Promise<CryptoKey | null> {
log.trace('unwrap')
const kd = await ecdh(privkey, this.pubkey, DHusage.wrap)
const kd = await ecdh(privkey, this.pubkey, DHusage.wrap, context) // TODO : null
return await this.box.unwrap(kd)
}
+8 -8
View File
@@ -11,21 +11,21 @@ export default class PwdBox {
private readonly salt: Uint8Array
) {}
private static async derive(pwd: string, salt: Uint8Array): Promise<CryptoKey> {
const k = await pbkdf(salt, pwd)
return await hkdf(k, Usage.box) as CryptoKey
private static async derive(pwd: string, salt: Uint8Array, context?: string): Promise<CryptoKey> {
const k = await pbkdf(salt, pwd) // TODO : null
return await hkdf(k, Usage.box, context) as CryptoKey // TODO : null
}
public static async encrypt(data: Uint8Array, pwd: string): Promise<PwdBox> {
public static async encrypt(data: Uint8Array, pwd: string, context?: string): Promise<PwdBox> {
log.trace('encrypt')
const salt = crypto.getRandomValues(new Uint8Array(16))
const k = await PwdBox.derive(pwd, salt)
const box = await SecretBox.encrypt(data, k)
const k = await PwdBox.derive(pwd, salt, context) // TODO : null
const box = await SecretBox.encrypt(data, k) // TODO : null
return new PwdBox(box, salt)
}
public async decrypt(pwd: string): Promise<Uint8Array | null> {
public async decrypt(pwd: string, context?: string): Promise<Uint8Array | null> {
log.trace('decrypt')
const k = await PwdBox.derive(pwd, this.salt)
const k = await PwdBox.derive(pwd, this.salt, context) // TODO : null
return await this.box.decrypt(k)
}
+8 -8
View File
@@ -11,21 +11,21 @@ export default class PwdWrap {
private readonly salt: Uint8Array
) {}
private static async derive(pwd: string, salt: Uint8Array): Promise<CryptoKey> {
const k = await pbkdf(salt, pwd)
return await hkdf(k, Usage.wrap) as CryptoKey
private static async derive(pwd: string, salt: Uint8Array, context?: string): Promise<CryptoKey> {
const k = await pbkdf(salt, pwd) // TODO : null
return await hkdf(k, Usage.wrap, context) as CryptoKey // TODO : null
}
public static async wrap(data: CryptoKey, pwd: string): Promise<PwdWrap> {
public static async wrap(data: CryptoKey, pwd: string, context?: string): Promise<PwdWrap> {
log.trace('wrap')
const salt = crypto.getRandomValues(new Uint8Array(16))
const k = await PwdWrap.derive(pwd, salt)
const box = await SecretWrap.wrap(data, k)
const k = await PwdWrap.derive(pwd, salt, context) // TODO : null
const box = await SecretWrap.wrap(data, k) // TODO : null
return new PwdWrap(box, salt)
}
public async unwrap(pwd: string): Promise<CryptoKey | null> {
public async unwrap(pwd: string, context?: string): Promise<CryptoKey | null> {
log.trace('unwrap')
const k = await PwdWrap.derive(pwd, this.salt)
const k = await PwdWrap.derive(pwd, this.salt, context) // TODO : null
return await this.box.unwrap(k)
}