This commit is contained in:
Pascal Perrenoud
2024-07-27 13:35:17 +02:00
parent 5cc375bd5a
commit 81ec3e9ed0
7 changed files with 364 additions and 390 deletions
+69 -71
View File
@@ -4,80 +4,78 @@ import {a2b64, b642a} from 'misc'
const log = logger('crypto:secret-wrap')
export class SecretWrap {
constructor(
private readonly cipher: Uint8Array,
private readonly algorithm: KeyAlgorithm,
private readonly usages: KeyUsage[],
private readonly type: "raw" | "pkcs8",
private readonly iv: Uint8Array,
) {}
constructor(
private readonly cipher: Uint8Array,
private readonly algorithm: KeyAlgorithm,
private readonly usages: KeyUsage[],
private readonly type: 'raw' | 'pkcs8',
private readonly iv: Uint8Array
) {}
public static gen_key(extractable : boolean = true) : Promise<CryptoKey> {
log.trace("generate key")
return crypto.subtle.generateKey(
{
name: "AES-GCM",
length: 256,
},
extractable,
["wrapKey", "unwrapKey"],
)
}
public static gen_key(extractable: boolean = true): Promise<CryptoKey> {
log.trace('generate key')
return crypto.subtle.generateKey(
{
name: 'AES-GCM',
length: 256
},
extractable,
['wrapKey', 'unwrapKey']
)
}
private static format(type: KeyType) : "raw" | "pkcs8" {
switch (type) {
case "private": return "pkcs8"
case "secret": return "raw"
default: throw "Don't wrap public keys please..."
}
private static format(type: KeyType): 'raw' | 'pkcs8' {
switch (type) {
case 'private':
return 'pkcs8'
case 'secret':
return 'raw'
default:
throw "Don't wrap public keys please..."
}
}
public static async encrypt(data: CryptoKey, key: CryptoKey) : Promise<SecretWrap> {
log.trace("encrypt")
const format = this.format(data.type)
const iv = crypto.getRandomValues(new Uint8Array(12))
const box = await crypto.subtle.wrapKey(
format,
data,
key,
{
name: "AES-GCM",
iv,
},
)
return new SecretWrap(new Uint8Array(box), data.algorithm, data.usages, format, iv)
}
public async decrypt(key: CryptoKey) : Promise<CryptoKey> {
log.trace("decrypt")
return crypto.subtle.unwrapKey(
this.type,
this.cipher,
key,
{
name: "AES-GCM",
iv: this.iv,
},
this.algorithm,
true,
this.usages
)
}
public static async encrypt(data: CryptoKey, key: CryptoKey): Promise<SecretWrap> {
log.trace('encrypt')
const format = this.format(data.type)
const iv = crypto.getRandomValues(new Uint8Array(12))
const box = await crypto.subtle.wrapKey(format, data, key, {
name: 'AES-GCM',
iv
})
return new SecretWrap(new Uint8Array(box), data.algorithm, data.usages, format, iv)
}
public async decrypt(key: CryptoKey): Promise<CryptoKey> {
log.trace('decrypt')
return crypto.subtle.unwrapKey(
this.type,
this.cipher,
key,
{
name: 'AES-GCM',
iv: this.iv
},
this.algorithm,
true,
this.usages
)
}
public toString() : string {
log.trace("toString")
return JSON.stringify({
cipher: a2b64(this.cipher),
iv: a2b64(this.iv),
algorithm: this.algorithm,
usages: this.usages,
type: this.type,
})
}
public static fromString(data: string) : SecretWrap {
log.trace("fromString")
const obj = JSON.parse(data)
const cipher = b642a(obj.cipher).expect("Failed to decode cipher")
const iv = b642a(obj.iv).expect("Failed to decode IV")
return new SecretWrap(cipher, obj.algorithm, obj.usages, obj.type, iv)
}
public toString(): string {
log.trace('toString')
return JSON.stringify({
cipher: a2b64(this.cipher),
iv: a2b64(this.iv),
algorithm: this.algorithm,
usages: this.usages,
type: this.type
})
}
public static fromString(data: string): SecretWrap {
log.trace('fromString')
const obj = JSON.parse(data)
const cipher = b642a(obj.cipher).expect('Failed to decode cipher')
const iv = b642a(obj.iv).expect('Failed to decode IV')
return new SecretWrap(cipher, obj.algorithm, obj.usages, obj.type, iv)
}
}