import crypto from 'crypto' ; import { concat as uint8ArrayConcat } from 'uint8arrays/concat' ; import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' ; import type { CreateOptions , AESCipher } from './interface.js' ; export function create ( opts ? ) { const algorithm = opts ?. algorithm ?? 'aes-128-gcm' ; const keyLength = opts ?. keyLength ?? 16 ; const nonceLength = opts ?. nonceLength ?? 12 ; const digest = opts ?. digest ?? 'sha256' ; const saltLength = opts ?. saltLength ?? 16 ; const iterations = opts ?. iterations ?? 32767 ; const algorithmTagLength = opts ?. algorithmTagLength ?? 16 ; async function encryptWithKey ( data , key ) { const nonce = crypto . randomBytes ( nonceLength ) ; const cipher = crypto . createCipheriv ( algorithm , key , nonce ) ; const ciphertext = uint8ArrayConcat ( [ cipher . update ( data ) , cipher . final ( ) ] ) ; return uint8ArrayConcat ( [ nonce , ciphertext , cipher . getAuthTag ( ) ] ) ; } /**
     * Uses the provided password to derive a pbkdf2 key. The key
     * will then be used to encrypt the data.
     */ async function encrypt ( data , password ) { const salt = crypto . randomBytes ( saltLength ) ; if ( typeof password === 'string' ) { password = uint8ArrayFromString ( password ) ; } const key = crypto . pbkdf2Sync ( password , salt , iterations , keyLength , digest ) ; return uint8ArrayConcat ( [ salt , await encryptWithKey ( Uint8Array . from ( data ) , key ) ] ) ; } /**
     * Decrypts the given cipher text with the provided key. The `key` should
     * be a cryptographically safe key and not a plaintext password. To use
     * a plaintext password, use `decrypt`. The options used to create
     * this decryption cipher must be the same as those used to create
     * the encryption cipher.
     */ async function decryptWithKey ( ciphertextAndNonce , key ) { const nonce = ciphertextAndNonce . slice ( 0 , nonceLength ) ; const ciphertext = ciphertextAndNonce . slice ( nonceLength , ciphertextAndNonce . length - algorithmTagLength ) ; const tag = ciphertextAndNonce . slice ( ciphertext . length + nonceLength ) ; const cipher = crypto . createDecipheriv ( algorithm , key , nonce ) ; cipher . setAuthTag ( tag ) ; return uint8ArrayConcat ( [ cipher . update ( ciphertext ) , cipher . final ( ) ] ) ; } param { Uint8Array } data param { string | Uint8Array } password async function decrypt ( data , password ) { const salt = data . slice ( 0 , saltLength ) ; const ciphertextAndNonce = data . slice ( saltLength ) ; if ( typeof password === 'string' ) { password = uint8ArrayFromString ( password ) ; } const key = crypto . pbkdf2Sync ( password , salt , iterations , keyLength , digest ) ; return await decryptWithKey ( ciphertextAndNonce , key ) ; } const cipher = { encrypt , decrypt } ; return cipher ; }