@li0ard/magma
Version:
Magma cipher implementation in pure TypeScript
49 lines (48 loc) • 2.03 kB
JavaScript
import { BLOCK_SIZE, Magma, sboxes } from "../index.js";
import { ctr, getPadLength } from "@li0ard/gost3413";
import { concatBytes, xor } from "@li0ard/gost3413/dist/utils.js";
/** Magma `CNT` (not `CTR`, but similar) mode */
const cnt = (encrypter, data, iv) => {
if (iv.length !== BLOCK_SIZE)
throw new Error("Invalid IV size");
const C1 = 0x01010104;
const C2 = 0x01010101;
const encryptedIv = encrypter(iv).reverse();
let n2 = Magma.bytesToU32(encryptedIv.slice(0, 4));
let n1 = Magma.bytesToU32(encryptedIv.slice(4));
const gamma = [];
for (let i = 0; i < (data.length + getPadLength(data.length, BLOCK_SIZE)); i += BLOCK_SIZE) {
n1 = (n1 + C2) % 0x100000000;
n2 = (n2 + C1) % 0xFFFFFFFF;
gamma.push(encrypter(concatBytes(Magma.u32ToBytes(n2), Magma.u32ToBytes(n1)).reverse()));
}
return xor(concatBytes(...gamma), data);
};
/**
* Encrypts data using the Counter (CTR) mode with Magma cipher.
*
* @param key Encryption key
* @param data Data to be encrypted
* @param iv Initialization vector
* @param legacy Enable backward compatibility with old GOST 28147-89
* @param sbox Optional substitution box, defaults to `ID_TC26_GOST_28147_PARAM_Z`
* @returns {Uint8Array}
*/
export const encryptCTR = (key, data, iv, legacy = false, sbox = sboxes.ID_TC26_GOST_28147_PARAM_Z) => {
const cipher = new Magma(legacy ? Magma.reverseKey(key) : key, sbox);
const encrypter = (buf) => (legacy ? cipher.encryptLegacy(buf) : cipher.encryptBlock(buf));
if (legacy)
return cnt(encrypter, data, iv);
return ctr(encrypter, BLOCK_SIZE, data, iv);
};
/**
* Decrypts data using the Counter (CTR) mode with Magma cipher.
*
* @param key Encryption key
* @param data Data to be decrypted
* @param iv Initialization vector
* @param legacy Enable backward compatibility with old GOST 28147-89
* @param sbox Optional substitution box, defaults to `ID_TC26_GOST_28147_PARAM_Z`
* @returns {Uint8Array}
*/
export const decryptCTR = encryptCTR;