/**
 * Package xchacha20 implements XChaCha20 stream cipher.
 */ import { writeUint32LE } from "@stablelib/binary" ; import { wipe } from "@stablelib/wipe" ; import { streamXOR as chachaStreamXOR } from "@stablelib/chacha" ; const ROUNDS = 20 ; /**
 * Encrypt src with XChaCha20 stream generated for the given 32-byte key and
 * 8-byte (as in original implementation) or 12-byte (as in RFC7539) nonce and
 * write the result into dst and return it.
 *
 * dst and src may be the same, but otherwise must not overlap.
 *
 * Nonce length is set in such a way that given it's generated via a CSPRNG
 * then there's little concern of collision for roughly 2^96 messages while
 * reusing a secret key and not encountering nonce reuse vulnerabilities.
 */ export function streamXOR ( key , nonce , src , dst ) { if ( nonce . length !== 24 ) { throw new Error ( "XChaCha20 nonce must be 24 bytes" ) ; } const subkey = hchacha ( key , nonce . subarray ( 0 , 16 ) , new Uint8Array ( 32 ) ) ; const modifiedNonce = new Uint8Array ( 12 ) ; modifiedNonce . set ( nonce . subarray ( 16 ) , 4 ) ; const result = chachaStreamXOR ( subkey , modifiedNonce , src , dst ) ; wipe ( subkey ) ; return result ; } /**
 * Generate XChaCha20 stream for the given 32-byte key and 12-byte
 * nonce (last 8 bytes of 24 byte nonce prefixed with 4 zero bytes)
 * and write it into dst and return it.
 *
 * Nonces MUST be generated using an CSPRNG to generate a sufficiently
 * random nonce such that a collision is highly unlikely to occur.
 *
 * stream is like streamXOR with all-zero src.
 */ export function stream ( key , nonce , dst ) { wipe ( dst ) ; return streamXOR ( key , nonce , dst , dst ) ; } /**
 * HChaCha is a one-way function used in XChaCha to extend nonce.
 *
 * It takes 32-byte key and 16-byte src and writes 32-byte result
 * into dst and returns it.
 */ export function hchacha ( key , src , dst ) { let j0 = 0x61707865 ; let j1 = 0x3320646e ; let j2 = 0x79622d32 ; let j3 = 0x6b206574 ; let j4 = ( key [ 3 ] << 24 ) | ( key [ 2 ] << 16 ) | ( key [ 1 ] << 8 ) | key [ 0 ] ; let j5 = ( key [ 7 ] << 24 ) | ( key [ 6 ] << 16 ) | ( key [ 5 ] << 8 ) | key [ 4 ] ; let j6 = ( key [ 11 ] << 24 ) | ( key [ 10 ] << 16 ) | ( key [ 9 ] << 8 ) | key [ 8 ] ; let j7 = ( key [ 15 ] << 24 ) | ( key [ 14 ] << 16 ) | ( key [ 13 ] << 8 ) | key [ 12 ] ; let j8 = ( key [ 19 ] << 24 ) | ( key [ 18 ] << 16 ) | ( key [ 17 ] << 8 ) | key [ 16 ] ; let j9 = ( key [ 23 ] << 24 ) | ( key [ 22 ] << 16 ) | ( key [ 21 ] << 8 ) | key [ 20 ] ; let j10 = ( key [ 27 ] << 24 ) | ( key [ 26 ] << 16 ) | ( key [ 25 ] << 8 ) | key [ 24 ] ; let j11 = ( key [ 31 ] << 24 ) | ( key [ 30 ] << 16 ) | ( key [ 29 ] << 8 ) | key [ 28 ] ; let j12 = ( src [ 3 ] << 24 ) | ( src [ 2 ] << 16 ) | ( src [ 1 ] << 8 ) | src [ 0 ] ; let j13 = ( src [ 7 ] << 24 ) | ( src [ 6 ] << 16 ) | ( src [ 5 ] << 8 ) | src [ 4 ] ; let j14 = ( src [ 11 ] << 24 ) | ( src [ 10 ] << 16 ) | ( src [ 9 ] << 8 ) | src [ 8 ] ; let j15 = ( src [ 15 ] << 24 ) | ( src [ 14 ] << 16 ) | ( src [ 13 ] << 8 ) | src [ 12 ] ; let x0 = j0 ; let x1 = j1 ; let x2 = j2 ; let x3 = j3 ; let x4 = j4 ; let x5 = j5 ; let x6 = j6 ; let x7 = j7 ; let x8 = j8 ; let x9 = j9 ; let x10 = j10 ; let x11 = j11 ; let x12 = j12 ; let x13 = j13 ; let x14 = j14 ; let x15 = j15 ; for ( let i = 0 ; i < ROUNDS ; i += 2 ) { x0 = ( x0 + x4 ) | 0 ; x12 ^= x0 ; x12 = ( x12 >>> ( 32 - 16 ) ) | ( x12 << 16 ) ; x8 = ( x8 + x12 ) | 0 ; x4 ^= x8 ; x4 = ( x4 >>> ( 32 - 12 ) ) | ( x4 << 12 ) ; x1 = ( x1 + x5 ) | 0 ; x13 ^= x1 ; x13 = ( x13 >>> ( 32 - 16 ) ) | ( x13 << 16 ) ; x9 = ( x9 + x13 ) | 0 ; x5 ^= x9 ; x5 = ( x5 >>> ( 32 - 12 ) ) | ( x5 << 12 ) ; x2 = ( x2 + x6 ) | 0 ; x14 ^= x2 ; x14 = ( x14 >>> ( 32 - 16 ) ) | ( x14 << 16 ) ; x10 = ( x10 + x14 ) | 0 ; x6 ^= x10 ; x6 = ( x6 >>> ( 32 - 12 ) ) | ( x6 << 12 ) ; x3 = ( x3 + x7 ) | 0 ; x15 ^= x3 ; x15 = ( x15 >>> ( 32 - 16 ) ) | ( x15 << 16 ) ; x11 = ( x11 + x15 ) | 0 ; x7 ^= x11 ; x7 = ( x7 >>> ( 32 - 12 ) ) | ( x7 << 12 ) ; x2 = ( x2 + x6 ) | 0 ; x14 ^= x2 ; x14 = ( x14 >>> ( 32 - 8 ) ) | ( x14 << 8 ) ; x10 = ( x10 + x14 ) | 0 ; x6 ^= x10 ; x6 = ( x6 >>> ( 32 - 7 ) ) | ( x6 << 7 ) ; x3 = ( x3 + x7 ) | 0 ; x15 ^= x3 ; x15 = ( x15 >>> ( 32 - 8 ) ) | ( x15 << 8 ) ; x11 = ( x11 + x15 ) | 0 ; x7 ^= x11 ; x7 = ( x7 >>> ( 32 - 7 ) ) | ( x7 << 7 ) ; x1 = ( x1 + x5 ) | 0 ; x13 ^= x1 ; x13 = ( x13 >>> ( 32 - 8 ) ) | ( x13 << 8 ) ; x9 = ( x9 + x13 ) | 0 ; x5 ^= x9 ; x5 = ( x5 >>> ( 32 - 7 ) ) | ( x5 << 7 ) ; x0 = ( x0 + x4 ) | 0 ; x12 ^= x0 ; x12 = ( x12 >>> ( 32 - 8 ) ) | ( x12 << 8 ) ; x8 = ( x8 + x12 ) | 0 ; x4 ^= x8 ; x4 = ( x4 >>> ( 32 - 7 ) ) | ( x4 << 7 ) ; x0 = ( x0 + x5 ) | 0 ; x15 ^= x0 ; x15 = ( x15 >>> ( 32 - 16 ) ) | ( x15 << 16 ) ; x10 = ( x10 + x15 ) | 0 ; x5 ^= x10 ; x5 = ( x5 >>> ( 32 - 12 ) ) | ( x5 << 12 ) ; x1 = ( x1 + x6 ) | 0 ; x12 ^= x1 ; x12 = ( x12 >>> ( 32 - 16 ) ) | ( x12 << 16 ) ; x11 = ( x11 + x12 ) | 0 ; x6 ^= x11 ; x6 = ( x6 >>> ( 32 - 12 ) ) | ( x6 << 12 ) ; x2 = ( x2 + x7 ) | 0 ; x13 ^= x2 ; x13 = ( x13 >>> ( 32 - 16 ) ) | ( x13 << 16 ) ; x8 = ( x8 + x13 ) | 0 ; x7 ^= x8 ; x7 = ( x7 >>> ( 32 - 12 ) ) | ( x7 << 12 ) ; x3 = ( x3 + x4 ) | 0 ; x14 ^= x3 ; x14 = ( x14 >>> ( 32 - 16 ) ) | ( x14 << 16 ) ; x9 = ( x9 + x14 ) | 0 ; x4 ^= x9 ; x4 = ( x4 >>> ( 32 - 12 ) ) | ( x4 << 12 ) ; x2 = ( x2 + x7 ) | 0 ; x13 ^= x2 ; x13 = ( x13 >>> ( 32 - 8 ) ) | ( x13 << 8 ) ; x8 = ( x8 + x13 ) | 0 ; x7 ^= x8 ; x7 = ( x7 >>> ( 32 - 7 ) ) | ( x7 << 7 ) ; x3 = ( x3 + x4 ) | 0 ; x14 ^= x3 ; x14 = ( x14 >>> ( 32 - 8 ) ) | ( x14 << 8 ) ; x9 = ( x9 + x14 ) | 0 ; x4 ^= x9 ; x4 = ( x4 >>> ( 32 - 7 ) ) | ( x4 << 7 ) ; x1 = ( x1 + x6 ) | 0 ; x12 ^= x1 ; x12 = ( x12 >>> ( 32 - 8 ) ) | ( x12 << 8 ) ; x11 = ( x11 + x12 ) | 0 ; x6 ^= x11 ; x6 = ( x6 >>> ( 32 - 7 ) ) | ( x6 << 7 ) ; x0 = ( x0 + x5 ) | 0 ; x15 ^= x0 ; x15 = ( x15 >>> ( 32 - 8 ) ) | ( x15 << 8 ) ; x10 = ( x10 + x15 ) | 0 ; x5 ^= x10 ; x5 = ( x5 >>> ( 32 - 7 ) ) | ( x5 << 7 ) ; } writeUint32LE ( x0 , dst , 0 ) ; writeUint32LE ( x1 , dst , 4 ) ; writeUint32LE ( x2 , dst , 8 ) ; writeUint32LE ( x3 , dst , 12 ) ; writeUint32LE ( x12 , dst , 16 ) ; writeUint32LE ( x13 , dst , 20 ) ; writeUint32LE ( x14 , dst , 24 ) ; writeUint32LE ( x15 , dst , 28 ) ; return dst ; }