63 lines
1.8 KiB
JavaScript
63 lines
1.8 KiB
JavaScript
export class CryptoUtil {
|
|
static algorithm = 'RSASSA-PKCS1-v1_5';
|
|
|
|
static hash = 'SHA-256';
|
|
|
|
static async generateAsymmetricKey() {
|
|
return window.crypto.subtle.generateKey(
|
|
{
|
|
name: CryptoUtil.algorithm,
|
|
hash: CryptoUtil.hash,
|
|
modulusLength: 2048,
|
|
publicExponent: new Uint8Array([1, 0, 1]),
|
|
},
|
|
true,
|
|
['sign', 'verify'],
|
|
);
|
|
}
|
|
|
|
static async sign(content, privateKey) {
|
|
const encoder = new TextEncoder();
|
|
const encoded = encoder.encode(content);
|
|
const signature = await window.crypto.subtle.sign(CryptoUtil.algorithm, privateKey, encoded);
|
|
// Return base64-encoded signature
|
|
return btoa(String.fromCharCode(...new Uint8Array(signature)));
|
|
}
|
|
|
|
static async verify(content, b64publicKey, b64signature) {
|
|
// Convert base64 javascript web key to CryptoKey
|
|
const publicKey = await CryptoUtil.importKey(b64publicKey);
|
|
// Convert base64 signature to an ArrayBuffer
|
|
const signature = Uint8Array.from(atob(b64signature), (c) => c.charCodeAt(0));
|
|
// TODO: make a single TextEncoder instance and reuse it
|
|
const encoder = new TextEncoder();
|
|
const encoded = encoder.encode(content);
|
|
return window.crypto.subtle.verify(CryptoUtil.algorithm, publicKey, signature, encoded);
|
|
}
|
|
|
|
static async exportKey(publicKey) {
|
|
// Store public key as base64 javascript web key
|
|
const jwk = await window.crypto.subtle.exportKey('jwk', publicKey);
|
|
return btoa(JSON.stringify(jwk));
|
|
}
|
|
|
|
static async importKey(b64jwk) {
|
|
// Convert base64 javascript web key to CryptoKey
|
|
const jwk = JSON.parse(atob(b64jwk));
|
|
return window.crypto.subtle.importKey(
|
|
'jwk',
|
|
jwk,
|
|
{
|
|
name: CryptoUtil.algorithm,
|
|
hash: CryptoUtil.hash,
|
|
},
|
|
false,
|
|
['verify'],
|
|
);
|
|
}
|
|
|
|
static randomUUID() {
|
|
return window.crypto.randomUUID();
|
|
}
|
|
}
|