UNPKG

@li0ard/kalyna

Version:

Kalyna (DSTU 7624:2014) cipher implementation in pure TypeScript

72 lines (71 loc) 2.94 kB
import { concatBytes, equalBytes, numberToBytesLE, xor } from "@li0ard/gost3413/dist/utils.js"; import { ctr } from "../index.js"; import { gf2mMul } from "../utils.js"; /** * Compute GMAC * @param cipherClass Initialized cipher class * @param authData Data to be authenticated * @param cipherData Ciphertext to be authenticated (Only for GMAC) * @param q MAC size */ export const gmac = (cipherClass, authData, cipherData = new Uint8Array(), q = 16) => { const blockSize = cipherClass.blockSize; const H = cipherClass.encrypt(new Uint8Array(blockSize)); let B = new Uint8Array(blockSize); let i = 0; while (i < authData.length) { const blockSizeToProcess = Math.min(blockSize, authData.length - i); const block = new Uint8Array(blockSize); for (let j = 0; j < blockSizeToProcess; j++) block[j] = authData[i + j]; if (blockSizeToProcess < blockSize) block[blockSizeToProcess] = 0x80; for (let j = 0; j < blockSize; j++) B[j] ^= block[j]; B = gf2mMul(blockSize, B, H); i += blockSize; } i = 0; while (i < cipherData.length) { const blockSizeToProcess = Math.min(blockSize, cipherData.length - i); const block = new Uint8Array(blockSize); for (let j = 0; j < blockSizeToProcess; j++) block[j] = cipherData[i + j]; if (blockSizeToProcess < blockSize) block[blockSizeToProcess] = 0x80; for (let j = 0; j < blockSize; j++) B[j] ^= block[j]; B = gf2mMul(blockSize, B, H); i += blockSize; } B = xor(B, concatBytes(numberToBytesLE(authData.length * 8, blockSize / 2), numberToBytesLE(cipherData.length * 8, blockSize / 2))); // B = gf2mMul(blockSize, B, H); return cipherClass.encrypt(B).slice(0, q); }; /** * Encrypts data using Galois/Counter Mode (GCM) mode * @param cipherClass Initialized cipher class * @param plainData Data to be encrypted and authenticated * @param iv Initialization vector * @param authData Additional data to be authenticated * @param q MAC size */ export const encryptGCM = (cipherClass, plainData, iv, authData = new Uint8Array(), q = 16) => { const enc = ctr(cipherClass, plainData, iv); return concatBytes(enc, gmac(cipherClass, authData, enc, q)); }; /** * Decrypts data using Galois/Counter Mode (GCM) mode * @param cipherClass Initialized cipher class * @param plainData Data to be decrypted and authenticated * @param iv Initialization vector * @param authData Additional data to be authenticated * @param q MAC size */ export const decryptGCM = (cipherClass, encryptedData, iv, authData = new Uint8Array(), q = 16) => { const enc = encryptedData.slice(0, -q); const hC = gmac(cipherClass, authData, enc, q); if (!equalBytes(encryptedData.slice(-q), hC)) throw new Error("Invalid MAC"); return ctr(cipherClass, enc, iv); };