|
| 1 | +import { createCipheriv, createDecipheriv } from 'node:crypto' |
| 2 | +import { ErrorHandler } from '@utils/index' |
| 3 | +import type { TokenEncrypted, EncryptionAlgo, IEncryptionAlgo } from '@interfaces/index' |
| 4 | + |
| 5 | +/** |
| 6 | + * ChaCha20-Poly1305 encryption class |
| 7 | + * Provides encryption and decryption using ChaCha20-Poly1305 algorithm |
| 8 | + */ |
| 9 | +export default class ChaCha20 implements IEncryptionAlgo { |
| 10 | + /** Algorithm name constant */ |
| 11 | + private readonly algorithm = 'chacha20-poly1305' |
| 12 | + |
| 13 | + /** |
| 14 | + * Encrypts data using ChaCha20-Poly1305 |
| 15 | + * @param data - String data to encrypt |
| 16 | + * @param key - 32-byte encryption key |
| 17 | + * @param iv - 12-byte initialization vector |
| 18 | + * @param version - Token version for additional authentication data |
| 19 | + * @returns Object containing encrypted data, IV, and authentication tag |
| 20 | + */ |
| 21 | + encrypt(data: string, key: Buffer, iv: Buffer, version: string): TokenEncrypted { |
| 22 | + const cipher = createCipheriv(this.algorithm, key, iv) |
| 23 | + cipher.setAAD(Buffer.from(`secure-jwt-${version}`, 'utf8'), { plaintextLength: data.length }) |
| 24 | + let encrypted = cipher.update(data, 'utf8', 'hex') |
| 25 | + encrypted += cipher.final('hex') |
| 26 | + const tag = cipher.getAuthTag() |
| 27 | + ErrorHandler.validateAuthTag(tag) |
| 28 | + return { |
| 29 | + encrypted, |
| 30 | + iv: iv.toString('hex'), |
| 31 | + tag: tag.toString('hex') |
| 32 | + } |
| 33 | + } |
| 34 | + |
| 35 | + /** |
| 36 | + * Decrypts data using ChaCha20-Poly1305 |
| 37 | + * @param tokenEncrypted - Object containing encrypted data, IV, and authentication tag |
| 38 | + * @param key - 32-byte decryption key |
| 39 | + * @param version - Token version for additional authentication data |
| 40 | + * @returns Decrypted string data |
| 41 | + */ |
| 42 | + decrypt(tokenEncrypted: TokenEncrypted, key: Buffer, version: string): string { |
| 43 | + const decipher = createDecipheriv(this.algorithm, key, Buffer.from(tokenEncrypted.iv, 'hex')) |
| 44 | + decipher.setAAD(Buffer.from(`secure-jwt-${version}`, 'utf8'), { |
| 45 | + plaintextLength: tokenEncrypted.encrypted.length / 2 |
| 46 | + }) |
| 47 | + decipher.setAuthTag(Buffer.from(tokenEncrypted.tag, 'hex')) |
| 48 | + let decrypted = decipher.update(tokenEncrypted.encrypted, 'hex', 'utf8') |
| 49 | + decrypted += decipher.final('utf8') |
| 50 | + return decrypted |
| 51 | + } |
| 52 | + |
| 53 | + /** |
| 54 | + * Gets the required IV length for ChaCha20-Poly1305 |
| 55 | + * @returns IV length in bytes (12) |
| 56 | + */ |
| 57 | + getIVLength(): number { |
| 58 | + return 12 |
| 59 | + } |
| 60 | + |
| 61 | + /** |
| 62 | + * Gets the algorithm name |
| 63 | + * @returns Algorithm name string |
| 64 | + */ |
| 65 | + getAlgoName(): EncryptionAlgo { |
| 66 | + return this.algorithm |
| 67 | + } |
| 68 | +} |
0 commit comments