mirror of
https://github.com/tompro/sattle.git
synced 2026-10-26 01:49:58 +00:00
refactor: isolate passkey wrapping crypto
This commit is contained in:
@@ -16,15 +16,11 @@ const WRAP_KEY_HKDF_INFO = 'sattle-passkey-wrap-v1'
|
||||
|
||||
export const derivePasskeyWrapKey = async (
|
||||
prfOutput: Uint8Array,
|
||||
hkdfSalt: Uint8Array
|
||||
hkdfSalt: Uint8Array,
|
||||
): Promise<CryptoKey> => {
|
||||
const baseKey = await crypto.subtle.importKey(
|
||||
'raw',
|
||||
new Uint8Array(prfOutput),
|
||||
'HKDF',
|
||||
false,
|
||||
['deriveKey']
|
||||
)
|
||||
const baseKey = await crypto.subtle.importKey('raw', new Uint8Array(prfOutput), 'HKDF', false, [
|
||||
'deriveKey',
|
||||
])
|
||||
return crypto.subtle.deriveKey(
|
||||
// the copies pin the TS type to Uint8Array<ArrayBuffer> - hexToBytes
|
||||
// returns Uint8Array<ArrayBufferLike>, which BufferSource rejects
|
||||
@@ -32,33 +28,29 @@ export const derivePasskeyWrapKey = async (
|
||||
name: 'HKDF',
|
||||
hash: 'SHA-256',
|
||||
salt: new Uint8Array(hkdfSalt),
|
||||
info: new Uint8Array(utf8ToBytes(WRAP_KEY_HKDF_INFO))
|
||||
info: new Uint8Array(utf8ToBytes(WRAP_KEY_HKDF_INFO)),
|
||||
},
|
||||
baseKey,
|
||||
{name: 'AES-GCM', length: 256},
|
||||
false,
|
||||
['encrypt', 'decrypt']
|
||||
['encrypt', 'decrypt'],
|
||||
)
|
||||
}
|
||||
|
||||
export const wrapLinkingKeyWithPrf = async (
|
||||
prfOutput: Uint8Array,
|
||||
linkingKey: Uint8Array
|
||||
linkingKey: Uint8Array,
|
||||
): Promise<PasskeyWrap> => {
|
||||
const hkdfSalt = crypto.getRandomValues(new Uint8Array(16))
|
||||
const iv = crypto.getRandomValues(new Uint8Array(12))
|
||||
const wrapKey = await derivePasskeyWrapKey(prfOutput, hkdfSalt)
|
||||
const ciphertext = new Uint8Array(
|
||||
await crypto.subtle.encrypt(
|
||||
{name: 'AES-GCM', iv},
|
||||
wrapKey,
|
||||
new Uint8Array(linkingKey)
|
||||
)
|
||||
await crypto.subtle.encrypt({name: 'AES-GCM', iv}, wrapKey, new Uint8Array(linkingKey)),
|
||||
)
|
||||
return {
|
||||
hkdfSalt: bytesToHex(hkdfSalt),
|
||||
iv: bytesToHex(iv),
|
||||
wrappedKey: bytesToHex(ciphertext)
|
||||
wrappedKey: bytesToHex(ciphertext),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,16 +58,13 @@ export const wrapLinkingKeyWithPrf = async (
|
||||
// i.e. a different passkey than the one that created the slot
|
||||
export const unwrapLinkingKeyWithPrf = async (
|
||||
prfOutput: Uint8Array,
|
||||
wrap: PasskeyWrap
|
||||
wrap: PasskeyWrap,
|
||||
): Promise<Uint8Array> => {
|
||||
const wrapKey = await derivePasskeyWrapKey(
|
||||
prfOutput,
|
||||
hexToBytes(wrap.hkdfSalt)
|
||||
)
|
||||
const wrapKey = await derivePasskeyWrapKey(prfOutput, hexToBytes(wrap.hkdfSalt))
|
||||
const plaintext = await crypto.subtle.decrypt(
|
||||
{name: 'AES-GCM', iv: new Uint8Array(hexToBytes(wrap.iv))},
|
||||
wrapKey,
|
||||
new Uint8Array(hexToBytes(wrap.wrappedKey))
|
||||
new Uint8Array(hexToBytes(wrap.wrappedKey)),
|
||||
)
|
||||
return new Uint8Array(plaintext)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user