UNPKG

1.7 kBPlain TextView Raw
1import type { Decrypter, Encrypter, EncryptionResult, ProtectedHeader } from './types.js'
2import { bytesToBase64url, encodeBase64url, stringToBytes } from '../util.js'
3import { xchacha20poly1305 } from '@noble/ciphers/chacha'
4import { randomBytes } from '@noble/hashes/utils'
5
6export function xc20pEncrypter(key: Uint8Array): (cleartext: Uint8Array, aad?: Uint8Array) => EncryptionResult {
7 return (cleartext: Uint8Array, aad?: Uint8Array) => {
8 const iv = randomBytes(24)
9 const cipher = xchacha20poly1305(key, iv, aad)
10 const sealed = cipher.encrypt(cleartext)
11 return {
12 ciphertext: sealed.subarray(0, sealed.length - 16),
13 tag: sealed.subarray(sealed.length - 16),
14 iv,
15 }
16 }
17}
18
19export function xc20pDirEncrypter(key: Uint8Array): Encrypter {
20 const xc20pEncrypt = xc20pEncrypter(key)
21 const enc = 'XC20P'
22 const alg = 'dir'
23
24 async function encrypt(
25 cleartext: Uint8Array,
26 protectedHeader: ProtectedHeader = {},
27 aad?: Uint8Array
28 ): Promise<EncryptionResult> {
29 const protHeader = encodeBase64url(JSON.stringify(Object.assign({ alg }, protectedHeader, { enc })))
30 const encodedAad = stringToBytes(aad ? `${protHeader}.${bytesToBase64url(aad)}` : protHeader)
31 return {
32 ...xc20pEncrypt(cleartext, encodedAad),
33 protectedHeader: protHeader,
34 }
35 }
36
37 return { alg, enc, encrypt }
38}
39
40export function xc20pDirDecrypter(key: Uint8Array): Decrypter {
41 async function decrypt(sealed: Uint8Array, iv: Uint8Array, aad?: Uint8Array): Promise<Uint8Array | null> {
42 try {
43 return xchacha20poly1305(key, iv, aad).decrypt(sealed)
44 } catch (error) {
45 return null
46 }
47 }
48
49 return { alg: 'dir', enc: 'XC20P', decrypt }
50}