🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

mima-kit

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mima-kit - npm Package Compare versions

Comparing version
0.0.16
to
0.0.17
+206
dist/chunk/cipher/blockCipher/aes.js
import { KitError, U8 } from '../../core/utils';
import { createCipher } from '../../core/cipher';
// * Constants
const SBox = new Uint8Array([0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]);
const InvSBox = new Uint8Array([0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D]);
const ROUND = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36];
// * Functions
function GFMultiply(a, b) {
let p = 0;
if (b === 1) {
return a;
}
for (let i = 0; i < 8; i++) {
if (b & 1) {
p ^= a;
}
const carry = a & 0x80;
a <<= 1;
if (carry) {
a ^= 0x1B; // 0x1B 是不可约多项式 x^8 + x^4 + x^3 + x + 1 的低 8 位
}
b >>= 1;
}
return p & 0xFF;
}
function KeyExpansion(K, Nr) {
const Nk = K.byteLength >> 2;
const W = new Uint8Array((Nr + 1) << 4);
W.set(K);
let current = 0;
for (let i = Nk; i < (Nr + 1) << 2; i++) {
const i_1 = (i - 1) << 2;
const temp = W.slice(i_1, i_1 + 4);
if (i % Nk === 0) {
const t0 = temp[0];
temp[0] = SBox[temp[1]] ^ ROUND[current];
temp[1] = SBox[temp[2]];
temp[2] = SBox[temp[3]];
temp[3] = SBox[t0];
current++;
}
else if (Nk > 6 && i % Nk === 4) {
temp[0] = SBox[temp[0]];
temp[1] = SBox[temp[1]];
temp[2] = SBox[temp[2]];
temp[3] = SBox[temp[3]];
}
const i_Nk = (i - Nk) << 2;
const Wi_NK = W.subarray(i_Nk, i_Nk + 4);
for (let j = 0; j < 4; j++) {
temp[j] ^= Wi_NK[j];
}
W.set(temp, i << 2);
}
return W;
}
// * AES Algorithm
function Cipher(M, W, Nr) {
if (M.byteLength !== 16) {
throw new KitError(`AES block must be 16 byte`);
}
const S = new U8(M.slice(0));
const AddRoundKey = (W) => {
for (let i = 0; i < S.byteLength; i++) {
S[i] ^= W[i];
}
};
const SubBytes = () => {
for (let i = 0; i < S.byteLength; i++) {
S[i] = SBox[S[i]];
}
};
const ShiftRows = () => {
const S1 = S[1];
S[1] = S[5];
S[5] = S[9];
S[9] = S[13];
S[13] = S1;
const S2 = S[2];
const S6 = S[6];
S[2] = S[10];
S[6] = S[14];
S[10] = S2;
S[14] = S6;
const S15 = S[15];
S[15] = S[11];
S[11] = S[7];
S[7] = S[3];
S[3] = S15;
};
const MixColumn = () => {
for (let i = 0; i < 4; i++) {
const s0 = S[(i << 2)];
const s1 = S[(i << 2) + 1];
const s2 = S[(i << 2) + 2];
const s3 = S[(i << 2) + 3];
const t0 = GFMultiply(s0, 0x02) ^ GFMultiply(s1, 0x03) ^ GFMultiply(s2, 0x01) ^ GFMultiply(s3, 0x01);
const t1 = GFMultiply(s0, 0x01) ^ GFMultiply(s1, 0x02) ^ GFMultiply(s2, 0x03) ^ GFMultiply(s3, 0x01);
const t2 = GFMultiply(s0, 0x01) ^ GFMultiply(s1, 0x01) ^ GFMultiply(s2, 0x02) ^ GFMultiply(s3, 0x03);
const t3 = GFMultiply(s0, 0x03) ^ GFMultiply(s1, 0x01) ^ GFMultiply(s2, 0x01) ^ GFMultiply(s3, 0x02);
S[(i << 2)] = t0;
S[(i << 2) + 1] = t1;
S[(i << 2) + 2] = t2;
S[(i << 2) + 3] = t3;
}
};
AddRoundKey(W.subarray(0, 16));
for (let i = 1; i < Nr; i++) {
SubBytes();
ShiftRows();
MixColumn();
AddRoundKey(W.subarray(i << 4, (i + 1) << 4));
}
SubBytes();
ShiftRows();
AddRoundKey(W.subarray(W.length - 16, W.length));
return S;
}
function InvCipher(M, W, Nr) {
if (M.byteLength !== 16) {
throw new KitError(`AES block must be 16 byte`);
}
const S = new U8(M.slice(0));
const AddRoundKey = (W) => {
for (let i = 0; i < S.byteLength; i++) {
S[i] ^= W[i];
}
};
const InvSubBytes = () => {
for (let i = 0; i < S.byteLength; i++) {
S[i] = InvSBox[S[i]];
}
};
const InvShiftRows = () => {
const S13 = S[13];
S[13] = S[9];
S[9] = S[5];
S[5] = S[1];
S[1] = S13;
const S2 = S[2];
const S6 = S[6];
S[2] = S[10];
S[6] = S[14];
S[10] = S2;
S[14] = S6;
const S3 = S[3];
S[3] = S[7];
S[7] = S[11];
S[11] = S[15];
S[15] = S3;
};
const InvMixColumn = () => {
for (let i = 0; i < 4; i++) {
const s0 = S[(i << 2)];
const s1 = S[(i << 2) + 1];
const s2 = S[(i << 2) + 2];
const s3 = S[(i << 2) + 3];
const t0 = GFMultiply(s0, 0x0E) ^ GFMultiply(s1, 0x0B) ^ GFMultiply(s2, 0x0D) ^ GFMultiply(s3, 0x09);
const t1 = GFMultiply(s0, 0x09) ^ GFMultiply(s1, 0x0E) ^ GFMultiply(s2, 0x0B) ^ GFMultiply(s3, 0x0D);
const t2 = GFMultiply(s0, 0x0D) ^ GFMultiply(s1, 0x09) ^ GFMultiply(s2, 0x0E) ^ GFMultiply(s3, 0x0B);
const t3 = GFMultiply(s0, 0x0B) ^ GFMultiply(s1, 0x0D) ^ GFMultiply(s2, 0x09) ^ GFMultiply(s3, 0x0E);
S[(i << 2)] = t0;
S[(i << 2) + 1] = t1;
S[(i << 2) + 2] = t2;
S[(i << 2) + 3] = t3;
}
};
AddRoundKey(W.subarray(W.length - 16, W.length));
for (let i = Nr - 1; i > 0; i--) {
InvShiftRows();
InvSubBytes();
AddRoundKey(W.subarray(i << 4, (i + 1) << 4));
InvMixColumn();
}
InvShiftRows();
InvSubBytes();
AddRoundKey(W.subarray(0, 16));
return S;
}
function _aes(K, b) {
if (K.byteLength !== b >> 3) {
throw new KitError(`AES key must be ${b >> 3} byte`);
}
const Nr = b === 128 ? 10 : (b === 192 ? 12 : 14);
const W = KeyExpansion(K, Nr);
return {
encrypt: (M) => Cipher(M, W, Nr),
decrypt: (C) => InvCipher(C, W, Nr),
};
}
/**
* 高级加密标准 (AES) 分组密码算法
*
* Advanced Encryption Standard (AES) block cipher algorithm
*
* @param {128 | 192 | 256} b - 密钥长度 / Key size (bit)
*/
export function aes(b) {
return createCipher((K) => _aes(K, b), {
ALGORITHM: `AES-${b}`,
BLOCK_SIZE: 16,
KEY_SIZE: b >> 3,
MIN_KEY_SIZE: b >> 3,
MAX_KEY_SIZE: b >> 3,
});
}
import { createCipher } from '../../core/cipher';
import { KitError, U8, genBitMask, resizeBuffer, rotateL, rotateR } from '../../core/utils';
// const Eul = [0xB7, 0xE1, 0x51, 0x62, 0x8A, 0xED, 0x2A, 0x6A, 0xBF, 0x71, 0x58, 0x80, 0x9C, 0xF4, 0xF3, 0xC7, 0x62, 0xE7, 0x16, 0x0F, 0x38, 0xB4, 0xDA, 0x56, 0xA7, 0x84, 0xD9, 0x04, 0x51, 0x90, 0xCF, 0xEF]
// const Phi = [0x9E, 0x37, 0x79, 0xB9, 0x7F, 0x4A, 0x7C, 0x15, 0xF3, 0x9C, 0xC0, 0x60, 0x5C, 0xED, 0xC8, 0x34, 0x10, 0x82, 0x27, 0x6B, 0xF3, 0xA2, 0x72, 0x51, 0xF8, 0x6C, 0x6A, 0x11, 0xD0, 0xC1, 0x8E, 0x95]
// const P = Eul{0,...,w-1} - 2) | 1
// const Q = Phi{0,...,w-1} - 2) | 1
// * Functions
function _setup(key, word_size, round, mask) {
const word_bit = BigInt(word_size);
const word_byte = word_size >> 3;
const P = (0xb7e151628aed2a6abf7158809cf4f3c7n >> (128n - word_bit)) | 1n;
const Q = (0x9e3779b97f4a7c15f39cc0605cedc835n >> (128n - word_bit)) | 1n;
// Break the key into w-bit words
const c = Math.ceil((key.length || 1) / word_byte);
const L = resizeBuffer(key, c * word_byte);
const LV = L.view(word_byte);
// Initialize key-independent pseudorandom S array
const t = (round + 1) << 1;
const S = new U8(t * word_byte);
const SV = S.view(word_byte);
// S[0] = P
let prv = P;
SV.set(0, prv, true);
for (let i = 1; i < t; i++) {
// S[i] = S[i-1] + Q
prv = (prv + Q) & mask;
SV.set(i, prv, true);
}
// The main key scheduling loop
let i = 0;
let j = 0;
let A = 0n;
let B = 0n;
const v = 3 * Math.max(c, t);
for (let k = 0; k < v; k++) {
// A = S[i] = (S[i] + A + B) <<< 3
const S = SV.get(i, true);
A = rotateL(word_bit, S + A + B, 3n, mask);
SV.set(i, A, true);
// B = L[j] = (L[j] + A + B) <<< (A + B)
const L = LV.get(j, true);
B = rotateL(word_bit, L + A + B, A + B, mask);
LV.set(j, B, true);
// i = (i + 1) mod t
i = (i + 1) % t;
// j = (j + 1) mod c
j = (j + 1) % c;
}
return S;
}
function _encrypt(M, S, word_size, round, mask) {
if (M.byteLength !== word_size >> 2) {
throw new KitError(`ARC5-${word_size}/${round} block must be ${word_size >> 3} byte`);
}
const word_bit = BigInt(word_size);
const word_byte = word_size >> 3;
const MV = U8.from(M).view(word_byte);
const SV = U8.from(S).view(word_byte);
// A = M[0] + S[0], B = M[1] + S[1]
let A = MV.get(0, true) + SV.get(0, true);
let B = MV.get(1, true) + SV.get(1, true);
A &= mask;
B &= mask;
for (let i = 1; i <= round; i++) {
// A = ((A ^ B) <<< B) + S[2 * i]
A = rotateL(word_bit, A ^ B, B, mask);
A += SV.get(i << 1, true);
A &= mask;
// B = ((B ^ A) <<< A) + S[2 * i + 1]
B = rotateL(word_bit, B ^ A, A, mask);
B += SV.get((i << 1) + 1, true);
B &= mask;
}
return U8.fromBI(B << word_bit | A, word_byte << 1, true);
}
function _decrypt(C, S, word_size, round, mask) {
if (C.byteLength !== word_size >> 2) {
throw new KitError(`ARC5-${word_size}/${round} block must be ${word_size >> 3} byte`);
}
const word_bit = BigInt(word_size);
const word_byte = word_size >> 3;
const CV = U8.from(C).view(word_byte);
const SV = U8.from(S).view(word_byte);
// A = C[0], B = C[1]
let A = CV.get(0, true);
let B = CV.get(1, true);
for (let i = round; i > 0; i--) {
// B = ((B - S[2 * i + 1]) >>> A) ^ A
const S1 = SV.get((i << 1) + 1, true);
B = rotateR(word_bit, B - S1, A, mask);
B = B ^ A;
B &= mask;
// A = ((A - S[2 * i]) >>> B) ^ B
const S0 = SV.get(i << 1, true);
A = rotateR(word_bit, A - S0, B, mask);
A = A ^ B;
A &= mask;
}
// A = A - S[0], B = B - S[1]
A = A - SV.get(0, true);
A &= mask;
B = B - SV.get(1, true);
B &= mask;
return U8.fromBI(B << word_bit | A, word_byte << 1, true);
}
// * ARC5 Algorithm
function _arc5(K, WORD_SIZE, round) {
const mask = genBitMask(WORD_SIZE);
const S = _setup(K, WORD_SIZE, round, mask);
const encrypt = (M) => _encrypt(M, S, WORD_SIZE, round, mask);
const decrypt = (C) => _decrypt(C, S, WORD_SIZE, round, mask);
return { encrypt, decrypt };
}
/**
* ARC5 分组加密算法 / block cipher algorithm
*
* ```ts
* const spec8 = arc5(8, 8) // ARC5-8/8
* const spec16 = arc5(16, 12) // ARC5-16/12
* const spec32 = arc5(32, 16) // ARC5-32/16 (default)
* const spec64 = arc5(64, 20) // ARC5-64/20
* const spec128 = arc5(128, 24) // ARC5-128/24
* ```
*
* @param {16 | 32 | 64} WORD_SIZE - 工作字长 / Word size (default: 32 bit)
* @param {number} round - 轮数 / Rounds (default: 16)
*/
export function arc5(WORD_SIZE = 32, round = 16) {
if (round <= 0 || round > 255) {
throw new KitError('ARC5 round must be between 1 and 255');
}
return createCipher((K) => _arc5(K, WORD_SIZE, round), {
ALGORITHM: `ARC5-${WORD_SIZE}/${round}`,
BLOCK_SIZE: WORD_SIZE >> 2,
KEY_SIZE: 16,
MIN_KEY_SIZE: 1,
MAX_KEY_SIZE: 255,
});
}
import { createCipher } from '../../core/cipher';
import { KitError, U8 } from '../../core/utils';
// * Constants
const SBox1 = new Uint8Array([0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]);
const SBox2 = new Uint8Array([0xE2, 0x4E, 0x54, 0xFC, 0x94, 0xC2, 0x4A, 0xCC, 0x62, 0x0D, 0x6A, 0x46, 0x3C, 0x4D, 0x8B, 0xD1, 0x5E, 0xFA, 0x64, 0xCB, 0xB4, 0x97, 0xBE, 0x2B, 0xBC, 0x77, 0x2E, 0x03, 0xD3, 0x19, 0x59, 0xC1, 0x1D, 0x06, 0x41, 0x6B, 0x55, 0xF0, 0x99, 0x69, 0xEA, 0x9C, 0x18, 0xAE, 0x63, 0xDF, 0xE7, 0xBB, 0x00, 0x73, 0x66, 0xFB, 0x96, 0x4C, 0x85, 0xE4, 0x3A, 0x09, 0x45, 0xAA, 0x0F, 0xEE, 0x10, 0xEB, 0x2D, 0x7F, 0xF4, 0x29, 0xAC, 0xCF, 0xAD, 0x91, 0x8D, 0x78, 0xC8, 0x95, 0xF9, 0x2F, 0xCE, 0xCD, 0x08, 0x7A, 0x88, 0x38, 0x5C, 0x83, 0x2A, 0x28, 0x47, 0xDB, 0xB8, 0xC7, 0x93, 0xA4, 0x12, 0x53, 0xFF, 0x87, 0x0E, 0x31, 0x36, 0x21, 0x58, 0x48, 0x01, 0x8E, 0x37, 0x74, 0x32, 0xCA, 0xE9, 0xB1, 0xB7, 0xAB, 0x0C, 0xD7, 0xC4, 0x56, 0x42, 0x26, 0x07, 0x98, 0x60, 0xD9, 0xB6, 0xB9, 0x11, 0x40, 0xEC, 0x20, 0x8C, 0xBD, 0xA0, 0xC9, 0x84, 0x04, 0x49, 0x23, 0xF1, 0x4F, 0x50, 0x1F, 0x13, 0xDC, 0xD8, 0xC0, 0x9E, 0x57, 0xE3, 0xC3, 0x7B, 0x65, 0x3B, 0x02, 0x8F, 0x3E, 0xE8, 0x25, 0x92, 0xE5, 0x15, 0xDD, 0xFD, 0x17, 0xA9, 0xBF, 0xD4, 0x9A, 0x7E, 0xC5, 0x39, 0x67, 0xFE, 0x76, 0x9D, 0x43, 0xA7, 0xE1, 0xD0, 0xF5, 0x68, 0xF2, 0x1B, 0x34, 0x70, 0x05, 0xA3, 0x8A, 0xD5, 0x79, 0x86, 0xA8, 0x30, 0xC6, 0x51, 0x4B, 0x1E, 0xA6, 0x27, 0xF6, 0x35, 0xD2, 0x6E, 0x24, 0x16, 0x82, 0x5F, 0xDA, 0xE6, 0x75, 0xA2, 0xEF, 0x2C, 0xB2, 0x1C, 0x9F, 0x5D, 0x6F, 0x80, 0x0A, 0x72, 0x44, 0x9B, 0x6C, 0x90, 0x0B, 0x5B, 0x33, 0x7D, 0x5A, 0x52, 0xF3, 0x61, 0xA1, 0xF7, 0xB0, 0xD6, 0x3F, 0x7C, 0x6D, 0xED, 0x14, 0xE0, 0xA5, 0x3D, 0x22, 0xB3, 0xF8, 0x89, 0xDE, 0x71, 0x1A, 0xAF, 0xBA, 0xB5, 0x81]);
const SBox3 = new Uint8Array([0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D]);
const SBox4 = new Uint8Array([0x30, 0x68, 0x99, 0x1B, 0x87, 0xB9, 0x21, 0x78, 0x50, 0x39, 0xDB, 0xE1, 0x72, 0x09, 0x62, 0x3C, 0x3E, 0x7E, 0x5E, 0x8E, 0xF1, 0xA0, 0xCC, 0xA3, 0x2A, 0x1D, 0xFB, 0xB6, 0xD6, 0x20, 0xC4, 0x8D, 0x81, 0x65, 0xF5, 0x89, 0xCB, 0x9D, 0x77, 0xC6, 0x57, 0x43, 0x56, 0x17, 0xD4, 0x40, 0x1A, 0x4D, 0xC0, 0x63, 0x6C, 0xE3, 0xB7, 0xC8, 0x64, 0x6A, 0x53, 0xAA, 0x38, 0x98, 0x0C, 0xF4, 0x9B, 0xED, 0x7F, 0x22, 0x76, 0xAF, 0xDD, 0x3A, 0x0B, 0x58, 0x67, 0x88, 0x06, 0xC3, 0x35, 0x0D, 0x01, 0x8B, 0x8C, 0xC2, 0xE6, 0x5F, 0x02, 0x24, 0x75, 0x93, 0x66, 0x1E, 0xE5, 0xE2, 0x54, 0xD8, 0x10, 0xCE, 0x7A, 0xE8, 0x08, 0x2C, 0x12, 0x97, 0x32, 0xAB, 0xB4, 0x27, 0x0A, 0x23, 0xDF, 0xEF, 0xCA, 0xD9, 0xB8, 0xFA, 0xDC, 0x31, 0x6B, 0xD1, 0xAD, 0x19, 0x49, 0xBD, 0x51, 0x96, 0xEE, 0xE4, 0xA8, 0x41, 0xDA, 0xFF, 0xCD, 0x55, 0x86, 0x36, 0xBE, 0x61, 0x52, 0xF8, 0xBB, 0x0E, 0x82, 0x48, 0x69, 0x9A, 0xE0, 0x47, 0x9E, 0x5C, 0x04, 0x4B, 0x34, 0x15, 0x79, 0x26, 0xA7, 0xDE, 0x29, 0xAE, 0x92, 0xD7, 0x84, 0xE9, 0xD2, 0xBA, 0x5D, 0xF3, 0xC5, 0xB0, 0xBF, 0xA4, 0x3B, 0x71, 0x44, 0x46, 0x2B, 0xFC, 0xEB, 0x6F, 0xD5, 0xF6, 0x14, 0xFE, 0x7C, 0x70, 0x5A, 0x7D, 0xFD, 0x2F, 0x18, 0x83, 0x16, 0xA5, 0x91, 0x1F, 0x05, 0x95, 0x74, 0xA9, 0xC1, 0x5B, 0x4A, 0x85, 0x6D, 0x13, 0x07, 0x4F, 0x4E, 0x45, 0xB2, 0x0F, 0xC9, 0x1C, 0xA6, 0xBC, 0xEC, 0x73, 0x90, 0x7B, 0xCF, 0x59, 0x8F, 0xA1, 0xF9, 0x2D, 0xF2, 0xB1, 0x00, 0x94, 0x37, 0x9F, 0xD0, 0x2E, 0x9C, 0x6E, 0x28, 0x3F, 0x80, 0xF0, 0x3D, 0xD3, 0x25, 0x8A, 0xB5, 0xE7, 0x42, 0xB3, 0xC7, 0xEA, 0xF7, 0x4C, 0x11, 0x33, 0x03, 0xA2, 0xAC, 0x60]);
const C1 = new Uint8Array([0x51, 0x7C, 0xC1, 0xB7, 0x27, 0x22, 0x0A, 0x94, 0xFE, 0x13, 0xAB, 0xE8, 0xFA, 0x9A, 0x6E, 0xE0]);
const C2 = new Uint8Array([0x6D, 0xB1, 0x4A, 0xCC, 0x9E, 0x21, 0xC8, 0x20, 0xFF, 0x28, 0xB1, 0xD5, 0xEF, 0x5D, 0xE2, 0xB0]);
const C3 = new Uint8Array([0xDB, 0x92, 0x37, 0x1D, 0x21, 0x26, 0xE9, 0x70, 0x03, 0x24, 0x97, 0x75, 0x04, 0xE8, 0xC9, 0x0E]);
// * Functions
function RL128(x, n) {
const x_byte = x.length;
const x_bit = x_byte << 3;
// 规范化移位数
const shift = n % x_bit;
if (shift === 0) {
return x.slice(0);
}
// 计算字节和位移
const byte_shift = shift >> 3;
const bit_shift = shift % 8;
const result = new U8(x.length);
for (let i = 0; i < x_byte; i++) {
const current = x[i];
const next = x[(i + 1) % x_byte];
result[i] = (current << bit_shift) | (next >> (8 - bit_shift));
}
// 处理字节移位
if (byte_shift > 0) {
const temp = new Uint8Array(result);
for (let i = 0; i < x_byte; i++) {
result[i] = temp[(i + byte_shift) % x_byte];
}
}
return result;
}
function RR128(x, n) {
const x_byte = x.length;
const x_bit = x_byte << 3;
// 规范化移位数
const shift = n % x_bit;
if (shift === 0) {
return x.slice(0);
}
// 计算字节和位移
const byte_shift = shift >> 3;
const bit_shift = shift % 8;
const result = new U8(x.length);
for (let i = 0; i < x_byte; i++) {
const current = x[i];
const next = x[(i - 1 + x_byte) % x_byte];
result[i] = (current >> bit_shift) | (next << (8 - bit_shift));
}
// 处理字节移位
if (byte_shift > 0) {
const temp = new Uint8Array(result);
for (let i = 0; i < x_byte; i++) {
result[i] = temp[(i - byte_shift + x_byte) % x_byte];
}
}
return result;
}
function XOR(x, y) {
return x.map((_, i) => x[i] ^ y[i]);
}
function FO(D, RK) {
return A(SL1(XOR(D, RK)));
}
function FE(D, RK) {
return A(SL2(XOR(D, RK)));
}
function SL1(x) {
const y = new Uint8Array(16);
// y0 = SB1(x0), y1 = SB2(x1), y2 = SB3(x2), y3 = SB4(x3),
// y4 = SB1(x4), y5 = SB2(x5), y6 = SB3(x6), y7 = SB4(x7),
// y8 = SB1(x8), y9 = SB2(x9), y10 = SB3(x10), y11 = SB4(x11),
// y12 = SB1(x12), y13 = SB2(x13), y14 = SB3(x14), y15 = SB4(x15).
y[0] = SBox1[x[0]];
y[1] = SBox2[x[1]];
y[2] = SBox3[x[2]];
y[3] = SBox4[x[3]];
y[4] = SBox1[x[4]];
y[5] = SBox2[x[5]];
y[6] = SBox3[x[6]];
y[7] = SBox4[x[7]];
y[8] = SBox1[x[8]];
y[9] = SBox2[x[9]];
y[10] = SBox3[x[10]];
y[11] = SBox4[x[11]];
y[12] = SBox1[x[12]];
y[13] = SBox2[x[13]];
y[14] = SBox3[x[14]];
y[15] = SBox4[x[15]];
return y;
}
function SL2(x) {
const y = new Uint8Array(16);
// y0 = SB3(x0), y1 = SB4(x1), y2 = SB1(x2), y3 = SB2(x3),
// y4 = SB3(x4), y5 = SB4(x5), y6 = SB1(x6), y7 = SB2(x7),
// y8 = SB3(x8), y9 = SB4(x9), y10 = SB1(x10), y11 = SB2(x11),
// y12 = SB3(x12), y13 = SB4(x13), y14 = SB1(x14), y15 = SB2(x15).
y[0] = SBox3[x[0]];
y[1] = SBox4[x[1]];
y[2] = SBox1[x[2]];
y[3] = SBox2[x[3]];
y[4] = SBox3[x[4]];
y[5] = SBox4[x[5]];
y[6] = SBox1[x[6]];
y[7] = SBox2[x[7]];
y[8] = SBox3[x[8]];
y[9] = SBox4[x[9]];
y[10] = SBox1[x[10]];
y[11] = SBox2[x[11]];
y[12] = SBox3[x[12]];
y[13] = SBox4[x[13]];
y[14] = SBox1[x[14]];
y[15] = SBox2[x[15]];
return y;
}
function A(x) {
const y = new Uint8Array(16);
// y0 = x3 ^ x4 ^ x6 ^ x8 ^ x9 ^ x13 ^ x14
// y1 = x2 ^ x5 ^ x7 ^ x8 ^ x9 ^ x12 ^ x15
// y2 = x1 ^ x4 ^ x6 ^ x10 ^ x11 ^ x12 ^ x15
// y3 = x0 ^ x5 ^ x7 ^ x10 ^ x11 ^ x13 ^ x14
// y4 = x0 ^ x2 ^ x5 ^ x8 ^ x11 ^ x14 ^ x15
// y5 = x1 ^ x3 ^ x4 ^ x9 ^ x10 ^ x14 ^ x15
// y6 = x0 ^ x2 ^ x7 ^ x9 ^ x10 ^ x12 ^ x13
// y7 = x1 ^ x3 ^ x6 ^ x8 ^ x11 ^ x12 ^ x13
// y8 = x0 ^ x1 ^ x4 ^ x7 ^ x10 ^ x13 ^ x15
// y9 = x0 ^ x1 ^ x5 ^ x6 ^ x11 ^ x12 ^ x14
// y10 = x2 ^ x3 ^ x5 ^ x6 ^ x8 ^ x13 ^ x15
// y11 = x2 ^ x3 ^ x4 ^ x7 ^ x9 ^ x12 ^ x14
// y12 = x1 ^ x2 ^ x6 ^ x7 ^ x9 ^ x11 ^ x12
// y13 = x0 ^ x3 ^ x6 ^ x7 ^ x8 ^ x10 ^ x13
// y14 = x0 ^ x3 ^ x4 ^ x5 ^ x9 ^ x11 ^ x14
// y15 = x1 ^ x2 ^ x4 ^ x5 ^ x8 ^ x10 ^ x15
y[0] = x[3] ^ x[4] ^ x[6] ^ x[8] ^ x[9] ^ x[13] ^ x[14];
y[1] = x[2] ^ x[5] ^ x[7] ^ x[8] ^ x[9] ^ x[12] ^ x[15];
y[2] = x[1] ^ x[4] ^ x[6] ^ x[10] ^ x[11] ^ x[12] ^ x[15];
y[3] = x[0] ^ x[5] ^ x[7] ^ x[10] ^ x[11] ^ x[13] ^ x[14];
y[4] = x[0] ^ x[2] ^ x[5] ^ x[8] ^ x[11] ^ x[14] ^ x[15];
y[5] = x[1] ^ x[3] ^ x[4] ^ x[9] ^ x[10] ^ x[14] ^ x[15];
y[6] = x[0] ^ x[2] ^ x[7] ^ x[9] ^ x[10] ^ x[12] ^ x[13];
y[7] = x[1] ^ x[3] ^ x[6] ^ x[8] ^ x[11] ^ x[12] ^ x[13];
y[8] = x[0] ^ x[1] ^ x[4] ^ x[7] ^ x[10] ^ x[13] ^ x[15];
y[9] = x[0] ^ x[1] ^ x[5] ^ x[6] ^ x[11] ^ x[12] ^ x[14];
y[10] = x[2] ^ x[3] ^ x[5] ^ x[6] ^ x[8] ^ x[13] ^ x[15];
y[11] = x[2] ^ x[3] ^ x[4] ^ x[7] ^ x[9] ^ x[12] ^ x[14];
y[12] = x[1] ^ x[2] ^ x[6] ^ x[7] ^ x[9] ^ x[11] ^ x[12];
y[13] = x[0] ^ x[3] ^ x[6] ^ x[7] ^ x[8] ^ x[10] ^ x[13];
y[14] = x[0] ^ x[3] ^ x[4] ^ x[5] ^ x[9] ^ x[11] ^ x[14];
y[15] = x[1] ^ x[2] ^ x[4] ^ x[5] ^ x[8] ^ x[10] ^ x[15];
return y;
}
function KeyScheduling(K, round) {
const _K = new Uint8Array(32);
_K.set(K);
K = _K;
const KL = new Uint8Array(16);
const KR = new Uint8Array(16);
KL.set(K.subarray(0, 16));
KR.set(K.subarray(16, 32));
let CK1, CK2, CK3;
switch (round) {
case 12:
CK1 = C1;
CK2 = C2;
CK3 = C3;
break;
case 14:
CK1 = C2;
CK2 = C3;
CK3 = C1;
break;
case 16:
CK1 = C3;
CK2 = C1;
CK3 = C2;
break;
}
const W0 = new Uint8Array(16);
const W1 = new Uint8Array(16);
const W2 = new Uint8Array(16);
const W3 = new Uint8Array(16);
W0.set(KL);
W1.set(FO(W0, CK1));
W1.forEach((_, i) => W1[i] ^= KR[i]);
W2.set(FE(W1, CK2));
W2.forEach((_, i) => W2[i] ^= W0[i]);
W3.set(FO(W2, CK3));
W3.forEach((_, i) => W3[i] ^= W1[i]);
const EK = computeEK([W0, W1, W2, W3], round);
const DK = computeDK(EK, round);
return { EK, DK };
}
function computeEK(W, round) {
const [W0, W1, W2, W3] = W;
// ek1 = W0 ^ (W1 >>> 19)
// ek2 = W1 ^ (W2 >>> 19)
// ek3 = W2 ^ (W3 >>> 19)
// ek4 = W3 ^ (W0 >>> 19)
// ek5 = W0 ^ (W1 >>> 31)
// ek6 = W1 ^ (W2 >>> 31)
// ek7 = W2 ^ (W3 >>> 31)
// ek8 = W3 ^ (W0 >>> 31)
// ek9 = W0 ^ (W1 <<< 61)
// ek10 = W1 ^ (W2 <<< 61)
// ek11 = W2 ^ (W3 <<< 61)
// ek12 = W3 ^ (W0 <<< 61)
// ek13 = W0 ^ (W1 <<< 31)
// ek14 = W1 ^ (W2 <<< 31)
// ek15 = W2 ^ (W3 <<< 31)
// ek16 = W3 ^ (W0 <<< 31)
// ek17 = W0 ^ (W1 <<< 19)
const ek01 = XOR(RR128(W1, 19), W0);
const ek02 = XOR(RR128(W2, 19), W1);
const ek03 = XOR(RR128(W3, 19), W2);
const ek04 = XOR(RR128(W0, 19), W3);
const ek05 = XOR(RR128(W1, 31), W0);
const ek06 = XOR(RR128(W2, 31), W1);
const ek07 = XOR(RR128(W3, 31), W2);
const ek08 = XOR(RR128(W0, 31), W3);
const ek09 = XOR(RL128(W1, 61), W0);
const ek10 = XOR(RL128(W2, 61), W1);
const ek11 = XOR(RL128(W3, 61), W2);
const ek12 = XOR(RL128(W0, 61), W3);
const ek13 = XOR(RL128(W1, 31), W0);
if (round === 12) {
return [ek01, ek02, ek03, ek04, ek05, ek06, ek07, ek08, ek09, ek10, ek11, ek12, ek13];
}
const ek14 = XOR(RL128(W2, 31), W1);
const ek15 = XOR(RL128(W3, 31), W2);
if (round === 14) {
return [ek01, ek02, ek03, ek04, ek05, ek06, ek07, ek08, ek09, ek10, ek11, ek12, ek13, ek14, ek15];
}
const ek16 = XOR(RL128(W0, 31), W3);
const ek17 = XOR(RL128(W1, 19), W0);
return [ek01, ek02, ek03, ek04, ek05, ek06, ek07, ek08, ek09, ek10, ek11, ek12, ek13, ek14, ek15, ek16, ek17];
}
function computeDK(EK, round) {
const DK = Array.from({ length: EK.length });
// dk1 = ek{ n + 1 },
// dk2 = A(ek{ n }),
// dk3 = A(ek{ n- 1}),
// ...,
// dk{ n }= A(ek2),
// dk{ n + 1 }= ek1.
DK[0] = EK[round];
let j = round - 1;
for (let i = 1; i < round; i++) {
DK[i] = A(EK[j--]);
}
DK[round] = EK[0];
return DK;
}
// * ARIA Algorithm
function _aria(K, b) {
if (K.byteLength !== b >> 3) {
throw new KitError(`Aria-${b} key must be ${b >> 3} byte`);
}
/**
* - 128-bit key: 12 rounds
* - 192-bit key: 14 rounds
* - 256-bit key: 16 rounds
*/
const round = b === 128 ? 12 : (b === 192 ? 14 : 16);
const { EK, DK } = KeyScheduling(K, round);
const cipher = (M, RK) => {
if (M.byteLength !== 16) {
throw new KitError('ARIA block must be 16 byte');
}
let P = M;
let i = 0;
while (i < round - 2) {
P = FO(P, RK[i++]);
P = FE(P, RK[i++]);
}
P = FO(P, RK[i++]);
P = SL2(XOR(P, RK[i++]));
P = XOR(P, RK[i++]);
return new U8(P);
};
return {
encrypt: (M) => cipher(M, EK),
decrypt: (C) => cipher(C, DK),
};
}
/**
* ARIA 分组密码算法 / block cipher algorithm
*
* @param {128 | 192 | 256} b - 密钥长度 / Key size (bit)
*/
export function aria(b) {
return createCipher((K) => _aria(K, b), {
ALGORITHM: `ARIA-${b}`,
BLOCK_SIZE: 16,
KEY_SIZE: b >> 3,
MIN_KEY_SIZE: 16,
MAX_KEY_SIZE: 32,
});
}
import { createCipher } from '../../core/cipher';
import { KitError, U8 } from '../../core/utils';
// * Blowfish Algorithm
function _blowfish(key) {
if (key.length < 4 || key.length > 56) {
throw new KitError(`Blowfish key must be between 4 and 56 byte`);
}
const P = new Uint32Array([0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, 0x9216D5D9, 0x8979FB1B]);
const S = [
new Uint32Array([0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A]),
new Uint32Array([0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7]),
new Uint32Array([0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0]),
new Uint32Array([0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6]),
];
function F(x) {
let r = 0;
r += S[0][(x >>> 24) & 0xFF];
r += S[1][(x >>> 16) & 0xFF];
r ^= S[2][(x >>> 8) & 0xFF];
r += S[3][(x >>> 0) & 0xFF];
return r;
}
const _encrypt = (l, r) => {
for (let i = 0; i < 16; i++) {
l ^= P[i];
r ^= F(l);
[l, r] = [r, l];
}
l ^= P[16];
r ^= P[17];
return [r, l];
};
const _decrypt = (l, r) => {
for (let i = 17; i > 1; i--) {
l ^= P[i];
r ^= F(l);
[l, r] = [r, l];
}
l ^= P[1];
r ^= P[0];
return [r, l];
};
// init
(() => {
let p = 0;
for (let i = 0; i < 18; i++) {
let k = 0;
for (let j = 0; j < 4; j++) {
k = (k << 8) | key[p];
p = (p + 1) % key.length;
}
P[i] ^= k;
}
let l = 0;
let r = 0;
for (let i = 0; i < 18; i += 2) {
[l, r] = _encrypt(l, r);
P[i] = l;
P[i + 1] = r;
}
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 256; j += 2) {
[l, r] = _encrypt(l, r);
S[i][j] = l;
S[i][j + 1] = r;
}
}
})();
return {
encrypt: (plaintext) => {
if (plaintext.length !== 8) {
throw new KitError(`Blowfish block must be 8 byte`);
}
const c = U8.from(plaintext.slice(0));
const c_view = new DataView(c.buffer);
let c0 = c_view.getUint32(0, false);
let c1 = c_view.getUint32(4, false);
[c0, c1] = _encrypt(c0, c1);
c_view.setUint32(0, c0, false);
c_view.setUint32(4, c1, false);
return c;
},
decrypt: (ciphertext) => {
if (ciphertext.length !== 8) {
throw new KitError(`Blowfish block must be 8 byte`);
}
const p = U8.from(ciphertext.slice(0));
const p_view = new DataView(p.buffer);
let p0 = p_view.getUint32(0, false);
let p1 = p_view.getUint32(4, false);
[p0, p1] = _decrypt(p0, p1);
p_view.setUint32(0, p0, false);
p_view.setUint32(4, p1, false);
return p;
},
};
}
/**
* Blowfish 分组密码算法 / block cipher algorithm
*/
export const blowfish = createCipher(_blowfish, {
ALGORITHM: 'Blowfish',
BLOCK_SIZE: 8,
KEY_SIZE: 16,
MIN_KEY_SIZE: 4,
MAX_KEY_SIZE: 56,
});
import { createCipher } from '../../core/cipher';
import { KitError, U8, rotateL32, rotateR32 } from '../../core/utils';
// * Constants
const SBox1_1110 = new Uint32Array([0x70707000, 0x82828200, 0x2C2C2C00, 0xECECEC00, 0xB3B3B300, 0x27272700, 0xC0C0C000, 0xE5E5E500, 0xE4E4E400, 0x85858500, 0x57575700, 0x35353500, 0xEAEAEA00, 0x0C0C0C00, 0xAEAEAE00, 0x41414100, 0x23232300, 0xEFEFEF00, 0x6B6B6B00, 0x93939300, 0x45454500, 0x19191900, 0xA5A5A500, 0x21212100, 0xEDEDED00, 0x0E0E0E00, 0x4F4F4F00, 0x4E4E4E00, 0x1D1D1D00, 0x65656500, 0x92929200, 0xBDBDBD00, 0x86868600, 0xB8B8B800, 0xAFAFAF00, 0x8F8F8F00, 0x7C7C7C00, 0xEBEBEB00, 0x1F1F1F00, 0xCECECE00, 0x3E3E3E00, 0x30303000, 0xDCDCDC00, 0x5F5F5F00, 0x5E5E5E00, 0xC5C5C500, 0x0B0B0B00, 0x1A1A1A00, 0xA6A6A600, 0xE1E1E100, 0x39393900, 0xCACACA00, 0xD5D5D500, 0x47474700, 0x5D5D5D00, 0x3D3D3D00, 0xD9D9D900, 0x01010100, 0x5A5A5A00, 0xD6D6D600, 0x51515100, 0x56565600, 0x6C6C6C00, 0x4D4D4D00, 0x8B8B8B00, 0x0D0D0D00, 0x9A9A9A00, 0x66666600, 0xFBFBFB00, 0xCCCCCC00, 0xB0B0B000, 0x2D2D2D00, 0x74747400, 0x12121200, 0x2B2B2B00, 0x20202000, 0xF0F0F000, 0xB1B1B100, 0x84848400, 0x99999900, 0xDFDFDF00, 0x4C4C4C00, 0xCBCBCB00, 0xC2C2C200, 0x34343400, 0x7E7E7E00, 0x76767600, 0x05050500, 0x6D6D6D00, 0xB7B7B700, 0xA9A9A900, 0x31313100, 0xD1D1D100, 0x17171700, 0x04040400, 0xD7D7D700, 0x14141400, 0x58585800, 0x3A3A3A00, 0x61616100, 0xDEDEDE00, 0x1B1B1B00, 0x11111100, 0x1C1C1C00, 0x32323200, 0x0F0F0F00, 0x9C9C9C00, 0x16161600, 0x53535300, 0x18181800, 0xF2F2F200, 0x22222200, 0xFEFEFE00, 0x44444400, 0xCFCFCF00, 0xB2B2B200, 0xC3C3C300, 0xB5B5B500, 0x7A7A7A00, 0x91919100, 0x24242400, 0x08080800, 0xE8E8E800, 0xA8A8A800, 0x60606000, 0xFCFCFC00, 0x69696900, 0x50505000, 0xAAAAAA00, 0xD0D0D000, 0xA0A0A000, 0x7D7D7D00, 0xA1A1A100, 0x89898900, 0x62626200, 0x97979700, 0x54545400, 0x5B5B5B00, 0x1E1E1E00, 0x95959500, 0xE0E0E000, 0xFFFFFF00, 0x64646400, 0xD2D2D200, 0x10101000, 0xC4C4C400, 0x00000000, 0x48484800, 0xA3A3A300, 0xF7F7F700, 0x75757500, 0xDBDBDB00, 0x8A8A8A00, 0x03030300, 0xE6E6E600, 0xDADADA00, 0x09090900, 0x3F3F3F00, 0xDDDDDD00, 0x94949400, 0x87878700, 0x5C5C5C00, 0x83838300, 0x02020200, 0xCDCDCD00, 0x4A4A4A00, 0x90909000, 0x33333300, 0x73737300, 0x67676700, 0xF6F6F600, 0xF3F3F300, 0x9D9D9D00, 0x7F7F7F00, 0xBFBFBF00, 0xE2E2E200, 0x52525200, 0x9B9B9B00, 0xD8D8D800, 0x26262600, 0xC8C8C800, 0x37373700, 0xC6C6C600, 0x3B3B3B00, 0x81818100, 0x96969600, 0x6F6F6F00, 0x4B4B4B00, 0x13131300, 0xBEBEBE00, 0x63636300, 0x2E2E2E00, 0xE9E9E900, 0x79797900, 0xA7A7A700, 0x8C8C8C00, 0x9F9F9F00, 0x6E6E6E00, 0xBCBCBC00, 0x8E8E8E00, 0x29292900, 0xF5F5F500, 0xF9F9F900, 0xB6B6B600, 0x2F2F2F00, 0xFDFDFD00, 0xB4B4B400, 0x59595900, 0x78787800, 0x98989800, 0x06060600, 0x6A6A6A00, 0xE7E7E700, 0x46464600, 0x71717100, 0xBABABA00, 0xD4D4D400, 0x25252500, 0xABABAB00, 0x42424200, 0x88888800, 0xA2A2A200, 0x8D8D8D00, 0xFAFAFA00, 0x72727200, 0x07070700, 0xB9B9B900, 0x55555500, 0xF8F8F800, 0xEEEEEE00, 0xACACAC00, 0x0A0A0A00, 0x36363600, 0x49494900, 0x2A2A2A00, 0x68686800, 0x3C3C3C00, 0x38383800, 0xF1F1F100, 0xA4A4A400, 0x40404000, 0x28282800, 0xD3D3D300, 0x7B7B7B00, 0xBBBBBB00, 0xC9C9C900, 0x43434300, 0xC1C1C100, 0x15151500, 0xE3E3E300, 0xADADAD00, 0xF4F4F400, 0x77777700, 0xC7C7C700, 0x80808000, 0x9E9E9E00]);
const SBox4_4404 = new Uint32Array([0x70700070, 0x2C2C002C, 0xB3B300B3, 0xC0C000C0, 0xE4E400E4, 0x57570057, 0xEAEA00EA, 0xAEAE00AE, 0x23230023, 0x6B6B006B, 0x45450045, 0xA5A500A5, 0xEDED00ED, 0x4F4F004F, 0x1D1D001D, 0x92920092, 0x86860086, 0xAFAF00AF, 0x7C7C007C, 0x1F1F001F, 0x3E3E003E, 0xDCDC00DC, 0x5E5E005E, 0x0B0B000B, 0xA6A600A6, 0x39390039, 0xD5D500D5, 0x5D5D005D, 0xD9D900D9, 0x5A5A005A, 0x51510051, 0x6C6C006C, 0x8B8B008B, 0x9A9A009A, 0xFBFB00FB, 0xB0B000B0, 0x74740074, 0x2B2B002B, 0xF0F000F0, 0x84840084, 0xDFDF00DF, 0xCBCB00CB, 0x34340034, 0x76760076, 0x6D6D006D, 0xA9A900A9, 0xD1D100D1, 0x04040004, 0x14140014, 0x3A3A003A, 0xDEDE00DE, 0x11110011, 0x32320032, 0x9C9C009C, 0x53530053, 0xF2F200F2, 0xFEFE00FE, 0xCFCF00CF, 0xC3C300C3, 0x7A7A007A, 0x24240024, 0xE8E800E8, 0x60600060, 0x69690069, 0xAAAA00AA, 0xA0A000A0, 0xA1A100A1, 0x62620062, 0x54540054, 0x1E1E001E, 0xE0E000E0, 0x64640064, 0x10100010, 0x00000000, 0xA3A300A3, 0x75750075, 0x8A8A008A, 0xE6E600E6, 0x09090009, 0xDDDD00DD, 0x87870087, 0x83830083, 0xCDCD00CD, 0x90900090, 0x73730073, 0xF6F600F6, 0x9D9D009D, 0xBFBF00BF, 0x52520052, 0xD8D800D8, 0xC8C800C8, 0xC6C600C6, 0x81810081, 0x6F6F006F, 0x13130013, 0x63630063, 0xE9E900E9, 0xA7A700A7, 0x9F9F009F, 0xBCBC00BC, 0x29290029, 0xF9F900F9, 0x2F2F002F, 0xB4B400B4, 0x78780078, 0x06060006, 0xE7E700E7, 0x71710071, 0xD4D400D4, 0xABAB00AB, 0x88880088, 0x8D8D008D, 0x72720072, 0xB9B900B9, 0xF8F800F8, 0xACAC00AC, 0x36360036, 0x2A2A002A, 0x3C3C003C, 0xF1F100F1, 0x40400040, 0xD3D300D3, 0xBBBB00BB, 0x43430043, 0x15150015, 0xADAD00AD, 0x77770077, 0x80800080, 0x82820082, 0xECEC00EC, 0x27270027, 0xE5E500E5, 0x85850085, 0x35350035, 0x0C0C000C, 0x41410041, 0xEFEF00EF, 0x93930093, 0x19190019, 0x21210021, 0x0E0E000E, 0x4E4E004E, 0x65650065, 0xBDBD00BD, 0xB8B800B8, 0x8F8F008F, 0xEBEB00EB, 0xCECE00CE, 0x30300030, 0x5F5F005F, 0xC5C500C5, 0x1A1A001A, 0xE1E100E1, 0xCACA00CA, 0x47470047, 0x3D3D003D, 0x01010001, 0xD6D600D6, 0x56560056, 0x4D4D004D, 0x0D0D000D, 0x66660066, 0xCCCC00CC, 0x2D2D002D, 0x12120012, 0x20200020, 0xB1B100B1, 0x99990099, 0x4C4C004C, 0xC2C200C2, 0x7E7E007E, 0x05050005, 0xB7B700B7, 0x31310031, 0x17170017, 0xD7D700D7, 0x58580058, 0x61610061, 0x1B1B001B, 0x1C1C001C, 0x0F0F000F, 0x16160016, 0x18180018, 0x22220022, 0x44440044, 0xB2B200B2, 0xB5B500B5, 0x91910091, 0x08080008, 0xA8A800A8, 0xFCFC00FC, 0x50500050, 0xD0D000D0, 0x7D7D007D, 0x89890089, 0x97970097, 0x5B5B005B, 0x95950095, 0xFFFF00FF, 0xD2D200D2, 0xC4C400C4, 0x48480048, 0xF7F700F7, 0xDBDB00DB, 0x03030003, 0xDADA00DA, 0x3F3F003F, 0x94940094, 0x5C5C005C, 0x02020002, 0x4A4A004A, 0x33330033, 0x67670067, 0xF3F300F3, 0x7F7F007F, 0xE2E200E2, 0x9B9B009B, 0x26260026, 0x37370037, 0x3B3B003B, 0x96960096, 0x4B4B004B, 0xBEBE00BE, 0x2E2E002E, 0x79790079, 0x8C8C008C, 0x6E6E006E, 0x8E8E008E, 0xF5F500F5, 0xB6B600B6, 0xFDFD00FD, 0x59590059, 0x98980098, 0x6A6A006A, 0x46460046, 0xBABA00BA, 0x25250025, 0x42420042, 0xA2A200A2, 0xFAFA00FA, 0x07070007, 0x55550055, 0xEEEE00EE, 0x0A0A000A, 0x49490049, 0x68680068, 0x38380038, 0xA4A400A4, 0x28280028, 0x7B7B007B, 0xC9C900C9, 0xC1C100C1, 0xE3E300E3, 0xF4F400F4, 0xC7C700C7, 0x9E9E009E]);
const SBox2_0222 = new Uint32Array([0x00E0E0E0, 0x00050505, 0x00585858, 0x00D9D9D9, 0x00676767, 0x004E4E4E, 0x00818181, 0x00CBCBCB, 0x00C9C9C9, 0x000B0B0B, 0x00AEAEAE, 0x006A6A6A, 0x00D5D5D5, 0x00181818, 0x005D5D5D, 0x00828282, 0x00464646, 0x00DFDFDF, 0x00D6D6D6, 0x00272727, 0x008A8A8A, 0x00323232, 0x004B4B4B, 0x00424242, 0x00DBDBDB, 0x001C1C1C, 0x009E9E9E, 0x009C9C9C, 0x003A3A3A, 0x00CACACA, 0x00252525, 0x007B7B7B, 0x000D0D0D, 0x00717171, 0x005F5F5F, 0x001F1F1F, 0x00F8F8F8, 0x00D7D7D7, 0x003E3E3E, 0x009D9D9D, 0x007C7C7C, 0x00606060, 0x00B9B9B9, 0x00BEBEBE, 0x00BCBCBC, 0x008B8B8B, 0x00161616, 0x00343434, 0x004D4D4D, 0x00C3C3C3, 0x00727272, 0x00959595, 0x00ABABAB, 0x008E8E8E, 0x00BABABA, 0x007A7A7A, 0x00B3B3B3, 0x00020202, 0x00B4B4B4, 0x00ADADAD, 0x00A2A2A2, 0x00ACACAC, 0x00D8D8D8, 0x009A9A9A, 0x00171717, 0x001A1A1A, 0x00353535, 0x00CCCCCC, 0x00F7F7F7, 0x00999999, 0x00616161, 0x005A5A5A, 0x00E8E8E8, 0x00242424, 0x00565656, 0x00404040, 0x00E1E1E1, 0x00636363, 0x00090909, 0x00333333, 0x00BFBFBF, 0x00989898, 0x00979797, 0x00858585, 0x00686868, 0x00FCFCFC, 0x00ECECEC, 0x000A0A0A, 0x00DADADA, 0x006F6F6F, 0x00535353, 0x00626262, 0x00A3A3A3, 0x002E2E2E, 0x00080808, 0x00AFAFAF, 0x00282828, 0x00B0B0B0, 0x00747474, 0x00C2C2C2, 0x00BDBDBD, 0x00363636, 0x00222222, 0x00383838, 0x00646464, 0x001E1E1E, 0x00393939, 0x002C2C2C, 0x00A6A6A6, 0x00303030, 0x00E5E5E5, 0x00444444, 0x00FDFDFD, 0x00888888, 0x009F9F9F, 0x00656565, 0x00878787, 0x006B6B6B, 0x00F4F4F4, 0x00232323, 0x00484848, 0x00101010, 0x00D1D1D1, 0x00515151, 0x00C0C0C0, 0x00F9F9F9, 0x00D2D2D2, 0x00A0A0A0, 0x00555555, 0x00A1A1A1, 0x00414141, 0x00FAFAFA, 0x00434343, 0x00131313, 0x00C4C4C4, 0x002F2F2F, 0x00A8A8A8, 0x00B6B6B6, 0x003C3C3C, 0x002B2B2B, 0x00C1C1C1, 0x00FFFFFF, 0x00C8C8C8, 0x00A5A5A5, 0x00202020, 0x00898989, 0x00000000, 0x00909090, 0x00474747, 0x00EFEFEF, 0x00EAEAEA, 0x00B7B7B7, 0x00151515, 0x00060606, 0x00CDCDCD, 0x00B5B5B5, 0x00121212, 0x007E7E7E, 0x00BBBBBB, 0x00292929, 0x000F0F0F, 0x00B8B8B8, 0x00070707, 0x00040404, 0x009B9B9B, 0x00949494, 0x00212121, 0x00666666, 0x00E6E6E6, 0x00CECECE, 0x00EDEDED, 0x00E7E7E7, 0x003B3B3B, 0x00FEFEFE, 0x007F7F7F, 0x00C5C5C5, 0x00A4A4A4, 0x00373737, 0x00B1B1B1, 0x004C4C4C, 0x00919191, 0x006E6E6E, 0x008D8D8D, 0x00767676, 0x00030303, 0x002D2D2D, 0x00DEDEDE, 0x00969696, 0x00262626, 0x007D7D7D, 0x00C6C6C6, 0x005C5C5C, 0x00D3D3D3, 0x00F2F2F2, 0x004F4F4F, 0x00191919, 0x003F3F3F, 0x00DCDCDC, 0x00797979, 0x001D1D1D, 0x00525252, 0x00EBEBEB, 0x00F3F3F3, 0x006D6D6D, 0x005E5E5E, 0x00FBFBFB, 0x00696969, 0x00B2B2B2, 0x00F0F0F0, 0x00313131, 0x000C0C0C, 0x00D4D4D4, 0x00CFCFCF, 0x008C8C8C, 0x00E2E2E2, 0x00757575, 0x00A9A9A9, 0x004A4A4A, 0x00575757, 0x00848484, 0x00111111, 0x00454545, 0x001B1B1B, 0x00F5F5F5, 0x00E4E4E4, 0x000E0E0E, 0x00737373, 0x00AAAAAA, 0x00F1F1F1, 0x00DDDDDD, 0x00595959, 0x00141414, 0x006C6C6C, 0x00929292, 0x00545454, 0x00D0D0D0, 0x00787878, 0x00707070, 0x00E3E3E3, 0x00494949, 0x00808080, 0x00505050, 0x00A7A7A7, 0x00F6F6F6, 0x00777777, 0x00939393, 0x00868686, 0x00838383, 0x002A2A2A, 0x00C7C7C7, 0x005B5B5B, 0x00E9E9E9, 0x00EEEEEE, 0x008F8F8F, 0x00010101, 0x003D3D3D]);
const SBox3_3033 = new Uint32Array([0x38003838, 0x41004141, 0x16001616, 0x76007676, 0xD900D9D9, 0x93009393, 0x60006060, 0xF200F2F2, 0x72007272, 0xC200C2C2, 0xAB00ABAB, 0x9A009A9A, 0x75007575, 0x06000606, 0x57005757, 0xA000A0A0, 0x91009191, 0xF700F7F7, 0xB500B5B5, 0xC900C9C9, 0xA200A2A2, 0x8C008C8C, 0xD200D2D2, 0x90009090, 0xF600F6F6, 0x07000707, 0xA700A7A7, 0x27002727, 0x8E008E8E, 0xB200B2B2, 0x49004949, 0xDE00DEDE, 0x43004343, 0x5C005C5C, 0xD700D7D7, 0xC700C7C7, 0x3E003E3E, 0xF500F5F5, 0x8F008F8F, 0x67006767, 0x1F001F1F, 0x18001818, 0x6E006E6E, 0xAF00AFAF, 0x2F002F2F, 0xE200E2E2, 0x85008585, 0x0D000D0D, 0x53005353, 0xF000F0F0, 0x9C009C9C, 0x65006565, 0xEA00EAEA, 0xA300A3A3, 0xAE00AEAE, 0x9E009E9E, 0xEC00ECEC, 0x80008080, 0x2D002D2D, 0x6B006B6B, 0xA800A8A8, 0x2B002B2B, 0x36003636, 0xA600A6A6, 0xC500C5C5, 0x86008686, 0x4D004D4D, 0x33003333, 0xFD00FDFD, 0x66006666, 0x58005858, 0x96009696, 0x3A003A3A, 0x09000909, 0x95009595, 0x10001010, 0x78007878, 0xD800D8D8, 0x42004242, 0xCC00CCCC, 0xEF00EFEF, 0x26002626, 0xE500E5E5, 0x61006161, 0x1A001A1A, 0x3F003F3F, 0x3B003B3B, 0x82008282, 0xB600B6B6, 0xDB00DBDB, 0xD400D4D4, 0x98009898, 0xE800E8E8, 0x8B008B8B, 0x02000202, 0xEB00EBEB, 0x0A000A0A, 0x2C002C2C, 0x1D001D1D, 0xB000B0B0, 0x6F006F6F, 0x8D008D8D, 0x88008888, 0x0E000E0E, 0x19001919, 0x87008787, 0x4E004E4E, 0x0B000B0B, 0xA900A9A9, 0x0C000C0C, 0x79007979, 0x11001111, 0x7F007F7F, 0x22002222, 0xE700E7E7, 0x59005959, 0xE100E1E1, 0xDA00DADA, 0x3D003D3D, 0xC800C8C8, 0x12001212, 0x04000404, 0x74007474, 0x54005454, 0x30003030, 0x7E007E7E, 0xB400B4B4, 0x28002828, 0x55005555, 0x68006868, 0x50005050, 0xBE00BEBE, 0xD000D0D0, 0xC400C4C4, 0x31003131, 0xCB00CBCB, 0x2A002A2A, 0xAD00ADAD, 0x0F000F0F, 0xCA00CACA, 0x70007070, 0xFF00FFFF, 0x32003232, 0x69006969, 0x08000808, 0x62006262, 0x00000000, 0x24002424, 0xD100D1D1, 0xFB00FBFB, 0xBA00BABA, 0xED00EDED, 0x45004545, 0x81008181, 0x73007373, 0x6D006D6D, 0x84008484, 0x9F009F9F, 0xEE00EEEE, 0x4A004A4A, 0xC300C3C3, 0x2E002E2E, 0xC100C1C1, 0x01000101, 0xE600E6E6, 0x25002525, 0x48004848, 0x99009999, 0xB900B9B9, 0xB300B3B3, 0x7B007B7B, 0xF900F9F9, 0xCE00CECE, 0xBF00BFBF, 0xDF00DFDF, 0x71007171, 0x29002929, 0xCD00CDCD, 0x6C006C6C, 0x13001313, 0x64006464, 0x9B009B9B, 0x63006363, 0x9D009D9D, 0xC000C0C0, 0x4B004B4B, 0xB700B7B7, 0xA500A5A5, 0x89008989, 0x5F005F5F, 0xB100B1B1, 0x17001717, 0xF400F4F4, 0xBC00BCBC, 0xD300D3D3, 0x46004646, 0xCF00CFCF, 0x37003737, 0x5E005E5E, 0x47004747, 0x94009494, 0xFA00FAFA, 0xFC00FCFC, 0x5B005B5B, 0x97009797, 0xFE00FEFE, 0x5A005A5A, 0xAC00ACAC, 0x3C003C3C, 0x4C004C4C, 0x03000303, 0x35003535, 0xF300F3F3, 0x23002323, 0xB800B8B8, 0x5D005D5D, 0x6A006A6A, 0x92009292, 0xD500D5D5, 0x21002121, 0x44004444, 0x51005151, 0xC600C6C6, 0x7D007D7D, 0x39003939, 0x83008383, 0xDC00DCDC, 0xAA00AAAA, 0x7C007C7C, 0x77007777, 0x56005656, 0x05000505, 0x1B001B1B, 0xA400A4A4, 0x15001515, 0x34003434, 0x1E001E1E, 0x1C001C1C, 0xF800F8F8, 0x52005252, 0x20002020, 0x14001414, 0xE900E9E9, 0xBD00BDBD, 0xDD00DDDD, 0xE400E4E4, 0xA100A1A1, 0xE000E0E0, 0x8A008A8A, 0xF100F1F1, 0xD600D6D6, 0x7A007A7A, 0xBB00BBBB, 0xE300E3E3, 0x40004040, 0x4F004F4F]);
const SIGMA = new Uint32Array([0xA09E667F, 0x3BCC908B, 0xB67AE858, 0x4CAA73B2, 0xC6EF372F, 0xE94F82BE, 0x54FF53A5, 0xF1D36F1C, 0x10E527FA, 0xDE682D1D, 0xB05688C2, 0xB3E6C1FD]);
// * Functions
function ROTL128(s, bit) {
const n = 32 - bit;
const t = s[3] << bit | s[0] >>> n;
s[0] = s[0] << bit | s[1] >>> n;
s[1] = s[1] << bit | s[2] >>> n;
s[2] = s[2] << bit | s[3] >>> n;
s[3] = t;
}
function Camellia_Feistel(sh, sl, kh, kl) {
const t0 = sh[0] ^ kh;
const t1 = sh[1] ^ kl;
const t3 = SBox1_1110[0xFF & (t0 >> 24)]
^ SBox2_0222[0xFF & (t0 >> 16)]
^ SBox3_3033[0xFF & (t0 >> 8)]
^ SBox4_4404[0xFF & (t0)];
const t2 = t3
^ SBox1_1110[0xFF & (t1)]
^ SBox4_4404[0xFF & (t1 >> 8)]
^ SBox3_3033[0xFF & (t1 >> 16)]
^ SBox2_0222[0xFF & (t1 >> 24)];
sl[0] ^= t2;
sl[1] ^= t2 ^ rotateR32(t3, 8);
}
// * Camellia Algorithm
function KeySchedule(K) {
const KView = new DataView(K.buffer);
const k = K.length === 16 ? new Uint32Array(52) : new Uint32Array(68);
const s = new Uint32Array(4);
const sh = s.subarray(0, 2);
const sl = s.subarray(2, 4);
/* Map the key to the keyTable */
switch (K.length) {
case 16:
mapKey128(KView, s, k);
break;
case 24:
mapKey192(KView, s, k);
break;
case 32:
mapKey256(KView, s, k);
break;
}
/* Use the Feistel routine to scramble the key material */
Camellia_Feistel(sh, sl, SIGMA[0], SIGMA[1]);
Camellia_Feistel(sl, sh, SIGMA[2], SIGMA[3]);
s[0] ^= k[0];
s[1] ^= k[1];
s[2] ^= k[2];
s[3] ^= k[3];
Camellia_Feistel(sh, sl, SIGMA[4], SIGMA[5]);
Camellia_Feistel(sl, sh, SIGMA[6], SIGMA[7]);
/* Fill the keyTable. Requires many block rotations. */
switch (K.length) {
case 16:
setup128(s, k);
break;
case 24:
case 32:
setup256(s, k);
break;
}
return k;
}
function mapKey128(KView, s, k) {
s[0] = k[0] = KView.getUint32(0, false);
s[1] = k[1] = KView.getUint32(4, false);
s[2] = k[2] = KView.getUint32(8, false);
s[3] = k[3] = KView.getUint32(12, false);
}
function mapKey192(KView, s, k) {
mapKey128(KView, s, k);
s[0] = k[8] = KView.getUint32(16, false);
s[1] = k[9] = KView.getUint32(20, false);
s[2] = k[10] = ~s[0];
s[3] = k[11] = ~s[1];
s[0] ^= k[0];
s[1] ^= k[1];
s[2] ^= k[2];
s[3] ^= k[3];
}
function mapKey256(KView, s, k) {
mapKey192(KView, s, k);
s[0] = k[8] = KView.getUint32(16, false);
s[1] = k[9] = KView.getUint32(20, false);
s[2] = k[10] = KView.getUint32(24, false);
s[3] = k[11] = KView.getUint32(28, false);
s[0] ^= k[0];
s[1] ^= k[1];
s[2] ^= k[2];
s[3] ^= k[3];
}
function setup128(s, k) {
k[4] = s[0];
k[5] = s[1];
k[6] = s[2];
k[7] = s[3];
ROTL128(s, 15); /* KA <<< 15 */
k[12] = s[0];
k[13] = s[1];
k[14] = s[2];
k[15] = s[3];
ROTL128(s, 15); /* KA <<< 30 */
k[16] = s[0];
k[17] = s[1];
k[18] = s[2];
k[19] = s[3];
ROTL128(s, 15); /* KA <<< 45 */
k[24] = s[0];
k[25] = s[1];
ROTL128(s, 15); /* KA <<< 60 */
k[28] = s[0];
k[29] = s[1];
k[30] = s[2];
k[31] = s[3];
[s[0], s[1], s[2], s[3]] = [s[1], s[2], s[3], s[0]];
ROTL128(s, 2); /* KA <<< 94 */
k[40] = s[0];
k[41] = s[1];
k[42] = s[2];
k[43] = s[3];
ROTL128(s, 17); /* KA <<<111 */
k[48] = s[0];
k[49] = s[1];
k[50] = s[2];
k[51] = s[3];
s[0] = k[0];
s[1] = k[1];
s[2] = k[2];
s[3] = k[3];
ROTL128(s, 15); /* KL <<< 15 */
k[8] = s[0];
k[9] = s[1];
k[10] = s[2];
k[11] = s[3];
ROTL128(s, 30); /* KL <<< 45 */
k[20] = s[0];
k[21] = s[1];
k[22] = s[2];
k[23] = s[3];
ROTL128(s, 15); /* KL <<< 60 */
k[26] = s[2];
k[27] = s[3];
ROTL128(s, 17); /* KL <<< 77 */
k[32] = s[0];
k[33] = s[1];
k[34] = s[2];
k[35] = s[3];
ROTL128(s, 17); /* KL <<< 94 */
k[36] = s[0];
k[37] = s[1];
k[38] = s[2];
k[39] = s[3];
ROTL128(s, 17); /* KL <<<111 */
k[44] = s[0];
k[45] = s[1];
k[46] = s[2];
k[47] = s[3];
}
function setup256(s, k) {
const sh = s.subarray(0, 2);
const sl = s.subarray(2, 4);
k[12] = s[0];
k[13] = s[1];
k[14] = s[2];
k[15] = s[3];
s[0] ^= k[8];
s[1] ^= k[9];
s[2] ^= k[10];
s[3] ^= k[11];
Camellia_Feistel(sh, sl, SIGMA[8], SIGMA[9]);
Camellia_Feistel(sl, sh, SIGMA[10], SIGMA[11]);
k[4] = s[0];
k[5] = s[1];
k[6] = s[2];
k[7] = s[3];
ROTL128(s, 30); /* KB <<< 30 */
k[20] = s[0];
k[21] = s[1];
k[22] = s[2];
k[23] = s[3];
ROTL128(s, 30); /* KB <<< 60 */
k[40] = s[0];
k[41] = s[1];
k[42] = s[2];
k[43] = s[3];
[s[0], s[1], s[2], s[3]] = [s[1], s[2], s[3], s[0]];
ROTL128(s, 19); /* KB <<<111 */
k[64] = s[0];
k[65] = s[1];
k[66] = s[2];
k[67] = s[3];
s[0] = k[8];
s[1] = k[9];
s[2] = k[10];
s[3] = k[11];
ROTL128(s, 15); /* KR <<< 15 */
k[8] = s[0];
k[9] = s[1];
k[10] = s[2];
k[11] = s[3];
ROTL128(s, 15); /* KR <<< 30 */
k[16] = s[0];
k[17] = s[1];
k[18] = s[2];
k[19] = s[3];
ROTL128(s, 30); /* KR <<< 60 */
k[36] = s[0];
k[37] = s[1];
k[38] = s[2];
k[39] = s[3];
[s[0], s[1], s[2], s[3]] = [s[1], s[2], s[3], s[0]];
ROTL128(s, 2); /* KR <<< 94 */
k[52] = s[0];
k[53] = s[1];
k[54] = s[2];
k[55] = s[3];
s[0] = k[12];
s[1] = k[13];
s[2] = k[14];
s[3] = k[15];
ROTL128(s, 15); /* KA <<< 15 */
k[12] = s[0];
k[13] = s[1];
k[14] = s[2];
k[15] = s[3];
ROTL128(s, 30); /* KA <<< 45 */
k[28] = s[0];
k[29] = s[1];
k[30] = s[2];
k[31] = s[3];
/* KA <<< 77 */
k[48] = s[1];
k[49] = s[2];
k[50] = s[3];
k[51] = s[0];
[s[0], s[1], s[2], s[3]] = [s[1], s[2], s[3], s[0]];
ROTL128(s, 17); /* KA <<< 94 */
k[56] = s[0];
k[57] = s[1];
k[58] = s[2];
k[59] = s[3];
s[0] = k[0];
s[1] = k[1];
s[2] = k[2];
s[3] = k[3];
[s[0], s[1], s[2], s[3]] = [s[1], s[2], s[3], s[0]];
ROTL128(s, 13); /* KL <<< 45 */
k[24] = s[0];
k[25] = s[1];
k[26] = s[2];
k[27] = s[3];
ROTL128(s, 15); /* KL <<< 60 */
k[32] = s[0];
k[33] = s[1];
k[34] = s[2];
k[35] = s[3];
ROTL128(s, 17); /* KL <<< 77 */
k[44] = s[0];
k[45] = s[1];
k[46] = s[2];
k[47] = s[3];
[s[0], s[1], s[2], s[3]] = [s[1], s[2], s[3], s[0]];
ROTL128(s, 2); /* KL <<<111 */
k[60] = s[0];
k[61] = s[1];
k[62] = s[2];
k[63] = s[3];
}
function _encrypt128(M, k) {
const C = M.slice(0);
const CView = new DataView(C.buffer);
const s = new Uint32Array(4);
const sh = s.subarray(0, 2);
const sl = s.subarray(2, 4);
s[0] = k[0] ^ CView.getUint32(0, false);
s[1] = k[1] ^ CView.getUint32(4, false);
s[2] = k[2] ^ CView.getUint32(8, false);
s[3] = k[3] ^ CView.getUint32(12, false);
// GR 1
Camellia_Feistel(sh, sl, k[4], k[5]);
Camellia_Feistel(sl, sh, k[6], k[7]);
Camellia_Feistel(sh, sl, k[8], k[9]);
Camellia_Feistel(sl, sh, k[10], k[11]);
Camellia_Feistel(sh, sl, k[12], k[13]);
Camellia_Feistel(sl, sh, k[14], k[15]);
s[1] ^= rotateL32(s[0] & k[16], 1);
s[2] ^= s[3] | k[19];
s[0] ^= s[1] | k[17];
s[3] ^= rotateL32(s[2] & k[18], 1);
// GR 2
Camellia_Feistel(sh, sl, k[20], k[21]);
Camellia_Feistel(sl, sh, k[22], k[23]);
Camellia_Feistel(sh, sl, k[24], k[25]);
Camellia_Feistel(sl, sh, k[26], k[27]);
Camellia_Feistel(sh, sl, k[28], k[29]);
Camellia_Feistel(sl, sh, k[30], k[31]);
s[1] ^= rotateL32(s[0] & k[32], 1);
s[2] ^= s[3] | k[35];
s[0] ^= s[1] | k[33];
s[3] ^= rotateL32(s[2] & k[34], 1);
// GR 3
Camellia_Feistel(sh, sl, k[36], k[37]);
Camellia_Feistel(sl, sh, k[38], k[39]);
Camellia_Feistel(sh, sl, k[40], k[41]);
Camellia_Feistel(sl, sh, k[42], k[43]);
Camellia_Feistel(sh, sl, k[44], k[45]);
Camellia_Feistel(sl, sh, k[46], k[47]);
s[2] ^= k[48];
s[3] ^= k[49];
s[0] ^= k[50];
s[1] ^= k[51];
CView.setUint32(0, s[2], false);
CView.setUint32(4, s[3], false);
CView.setUint32(8, s[0], false);
CView.setUint32(12, s[1], false);
return C;
}
function _encrypt256(M, k) {
const C = M.slice(0);
const CView = new DataView(C.buffer);
const s = new Uint32Array(4);
const sh = s.subarray(0, 2);
const sl = s.subarray(2, 4);
s[0] = k[0] ^ CView.getUint32(0, false);
s[1] = k[1] ^ CView.getUint32(4, false);
s[2] = k[2] ^ CView.getUint32(8, false);
s[3] = k[3] ^ CView.getUint32(12, false);
// GR 1
Camellia_Feistel(sh, sl, k[4], k[5]);
Camellia_Feistel(sl, sh, k[6], k[7]);
Camellia_Feistel(sh, sl, k[8], k[9]);
Camellia_Feistel(sl, sh, k[10], k[11]);
Camellia_Feistel(sh, sl, k[12], k[13]);
Camellia_Feistel(sl, sh, k[14], k[15]);
s[1] ^= rotateL32(s[0] & k[16], 1);
s[2] ^= s[3] | k[19];
s[0] ^= s[1] | k[17];
s[3] ^= rotateL32(s[2] & k[18], 1);
// GR 2
Camellia_Feistel(sh, sl, k[20], k[21]);
Camellia_Feistel(sl, sh, k[22], k[23]);
Camellia_Feistel(sh, sl, k[24], k[25]);
Camellia_Feistel(sl, sh, k[26], k[27]);
Camellia_Feistel(sh, sl, k[28], k[29]);
Camellia_Feistel(sl, sh, k[30], k[31]);
s[1] ^= rotateL32(s[0] & k[32], 1);
s[2] ^= s[3] | k[35];
s[0] ^= s[1] | k[33];
s[3] ^= rotateL32(s[2] & k[34], 1);
// GR 3
Camellia_Feistel(sh, sl, k[36], k[37]);
Camellia_Feistel(sl, sh, k[38], k[39]);
Camellia_Feistel(sh, sl, k[40], k[41]);
Camellia_Feistel(sl, sh, k[42], k[43]);
Camellia_Feistel(sh, sl, k[44], k[45]);
Camellia_Feistel(sl, sh, k[46], k[47]);
s[1] ^= rotateL32(s[0] & k[48], 1);
s[2] ^= s[3] | k[51];
s[0] ^= s[1] | k[49];
s[3] ^= rotateL32(s[2] & k[50], 1);
// GR 4
Camellia_Feistel(sh, sl, k[52], k[53]);
Camellia_Feistel(sl, sh, k[54], k[55]);
Camellia_Feistel(sh, sl, k[56], k[57]);
Camellia_Feistel(sl, sh, k[58], k[59]);
Camellia_Feistel(sh, sl, k[60], k[61]);
Camellia_Feistel(sl, sh, k[62], k[63]);
s[2] ^= k[64];
s[3] ^= k[65];
s[0] ^= k[66];
s[1] ^= k[67];
CView.setUint32(0, s[2], false);
CView.setUint32(4, s[3], false);
CView.setUint32(8, s[0], false);
CView.setUint32(12, s[1], false);
return C;
}
function _decrypt128(C, k) {
const M = C.slice(0);
const MView = new DataView(M.buffer);
const s = new Uint32Array(4);
const sh = s.subarray(0, 2);
const sl = s.subarray(2, 4);
s[0] = k[48] ^ MView.getUint32(0, false);
s[1] = k[49] ^ MView.getUint32(4, false);
s[2] = k[50] ^ MView.getUint32(8, false);
s[3] = k[51] ^ MView.getUint32(12, false);
// GR1
Camellia_Feistel(sh, sl, k[46], k[47]);
Camellia_Feistel(sl, sh, k[44], k[45]);
Camellia_Feistel(sh, sl, k[42], k[43]);
Camellia_Feistel(sl, sh, k[40], k[41]);
Camellia_Feistel(sh, sl, k[38], k[39]);
Camellia_Feistel(sl, sh, k[36], k[37]);
s[1] ^= rotateL32(s[0] & k[34], 1);
s[2] ^= s[3] | k[33];
s[0] ^= s[1] | k[35];
s[3] ^= rotateL32(s[2] & k[32], 1);
// GR2
Camellia_Feistel(sh, sl, k[30], k[31]);
Camellia_Feistel(sl, sh, k[28], k[29]);
Camellia_Feistel(sh, sl, k[26], k[27]);
Camellia_Feistel(sl, sh, k[24], k[25]);
Camellia_Feistel(sh, sl, k[22], k[23]);
Camellia_Feistel(sl, sh, k[20], k[21]);
s[1] ^= rotateL32(s[0] & k[18], 1);
s[2] ^= s[3] | k[17];
s[0] ^= s[1] | k[19];
s[3] ^= rotateL32(s[2] & k[16], 1);
// GR3
Camellia_Feistel(sh, sl, k[14], k[15]);
Camellia_Feistel(sl, sh, k[12], k[13]);
Camellia_Feistel(sh, sl, k[10], k[11]);
Camellia_Feistel(sl, sh, k[8], k[9]);
Camellia_Feistel(sh, sl, k[6], k[7]);
Camellia_Feistel(sl, sh, k[4], k[5]);
s[2] ^= k[0];
s[3] ^= k[1];
s[0] ^= k[2];
s[1] ^= k[3];
MView.setUint32(0, s[2], false);
MView.setUint32(4, s[3], false);
MView.setUint32(8, s[0], false);
MView.setUint32(12, s[1], false);
return M;
}
function _decrypt256(C, k) {
const M = C.slice(0);
const MView = new DataView(M.buffer);
const s = new Uint32Array(4);
const sh = s.subarray(0, 2);
const sl = s.subarray(2, 4);
s[0] = k[64] ^ MView.getUint32(0, false);
s[1] = k[65] ^ MView.getUint32(4, false);
s[2] = k[66] ^ MView.getUint32(8, false);
s[3] = k[67] ^ MView.getUint32(12, false);
// GR1
Camellia_Feistel(sh, sl, k[62], k[63]);
Camellia_Feistel(sl, sh, k[60], k[61]);
Camellia_Feistel(sh, sl, k[58], k[59]);
Camellia_Feistel(sl, sh, k[56], k[57]);
Camellia_Feistel(sh, sl, k[54], k[55]);
Camellia_Feistel(sl, sh, k[52], k[53]);
s[1] ^= rotateL32(s[0] & k[50], 1);
s[2] ^= s[3] | k[49];
s[0] ^= s[1] | k[51];
s[3] ^= rotateL32(s[2] & k[48], 1);
// GR2
Camellia_Feistel(sh, sl, k[46], k[47]);
Camellia_Feistel(sl, sh, k[44], k[45]);
Camellia_Feistel(sh, sl, k[42], k[43]);
Camellia_Feistel(sl, sh, k[40], k[41]);
Camellia_Feistel(sh, sl, k[38], k[39]);
Camellia_Feistel(sl, sh, k[36], k[37]);
s[1] ^= rotateL32(s[0] & k[34], 1);
s[2] ^= s[3] | k[33];
s[0] ^= s[1] | k[35];
s[3] ^= rotateL32(s[2] & k[32], 1);
// GR3
Camellia_Feistel(sh, sl, k[30], k[31]);
Camellia_Feistel(sl, sh, k[28], k[29]);
Camellia_Feistel(sh, sl, k[26], k[27]);
Camellia_Feistel(sl, sh, k[24], k[25]);
Camellia_Feistel(sh, sl, k[22], k[23]);
Camellia_Feistel(sl, sh, k[20], k[21]);
s[1] ^= rotateL32(s[0] & k[18], 1);
s[2] ^= s[3] | k[17];
s[0] ^= s[1] | k[19];
s[3] ^= rotateL32(s[2] & k[16], 1);
// GR4
Camellia_Feistel(sh, sl, k[14], k[15]);
Camellia_Feistel(sl, sh, k[12], k[13]);
Camellia_Feistel(sh, sl, k[10], k[11]);
Camellia_Feistel(sl, sh, k[8], k[9]);
Camellia_Feistel(sh, sl, k[6], k[7]);
Camellia_Feistel(sl, sh, k[4], k[5]);
s[2] ^= k[0];
s[3] ^= k[1];
s[0] ^= k[2];
s[1] ^= k[3];
MView.setUint32(0, s[2], false);
MView.setUint32(4, s[3], false);
MView.setUint32(8, s[0], false);
MView.setUint32(12, s[1], false);
return M;
}
function cipher(M, k, _cipher) {
if (M.length !== 16) {
throw new KitError('Camellia block must be 16 byte');
}
return new U8(_cipher(M, k));
}
function _camellia(key, b) {
if (key.length !== b >>> 3) {
throw new KitError(`Camellia-${b} key must be ${b >>> 3} byte`);
}
const K = KeySchedule(key);
const encrypt = b === 128
? (M) => cipher(M, K, _encrypt128)
: (M) => cipher(M, K, _encrypt256);
const decrypt = b === 128
? (C) => cipher(C, K, _decrypt128)
: (C) => cipher(C, K, _decrypt256);
return { encrypt, decrypt };
}
/**
* Camellia 分组密码算法 / block cipher algorithm
*
* @param {128 | 192 | 256} b - 密钥长度 / Key size (bit)
*/
export function camellia(b) {
return createCipher((K) => _camellia(K, b), {
ALGORITHM: `Camellia-${b}`,
BLOCK_SIZE: 16,
KEY_SIZE: b >>> 3,
MIN_KEY_SIZE: b >>> 3,
MAX_KEY_SIZE: b >>> 3,
});
}
import { KitError, U8 } from '../../core/utils';
import { createCipher } from '../../core/cipher';
// * Constants
const IP = [58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7].map(value => 64 - value);
const FP = [40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25].map(value => 64 - value);
const E = [32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1].map(value => 32 - value);
const PC1 = [57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4].map(value => 64 - value);
const PC2 = [14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32].map(value => 56 - value);
const P = [16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25].map(value => 32 - value);
const KEY_SHIFT = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1];
const S1 = [14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13];
const S2 = [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9];
const S3 = [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12];
const S4 = [7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14];
const S5 = [2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3];
const S6 = [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13];
const S7 = [4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12];
const S8 = [13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11];
// * Functions
function permute(input, table) {
let output = 0n;
for (let i = 0; i < table.length; i++) {
output = output << 1n;
output |= ((input >> BigInt(table[i])) & 0x1n);
}
return output;
}
function substitute(input) {
const s = [S1, S2, S3, S4, S5, S6, S7, S8];
let output = 0n;
for (let i = 0; i < 8; i++) {
const word = Number((input >> BigInt(6 * (7 - i))) & 0x3fn);
const x = (word >> 1) & 0xF;
const y = (word >> 4) & 0b10 | (word & 0b1);
const offset = x + (y << 4);
output = (output << 4n) | BigInt(s[i][offset]);
}
return output;
}
function generateKeys(key) {
const k = permute(key.reduce((acc, cur) => (acc << 8n) | BigInt(cur), 0n), PC1);
const key_set = new Uint8Array(16 * 6);
let l = 0xfffffffn & (k >> 28n);
let r = 0xfffffffn & (k);
for (let i = 0; i < 16; i++) {
l = ((l << BigInt(KEY_SHIFT[i])) | (l >> 28n - BigInt(KEY_SHIFT[i]))) & 0xfffffffn;
r = ((r << BigInt(KEY_SHIFT[i])) | (r >> 28n - BigInt(KEY_SHIFT[i]))) & 0xfffffffn;
const kr = permute((l << 28n) | r, PC2);
const offset = i * 6;
key_set[offset + 0] = Number(0xffn & (kr >> 40n));
key_set[offset + 1] = Number(0xffn & (kr >> 32n));
key_set[offset + 2] = Number(0xffn & (kr >> 24n));
key_set[offset + 3] = Number(0xffn & (kr >> 16n));
key_set[offset + 4] = Number(0xffn & (kr >> 8n));
key_set[offset + 5] = Number(0xffn & (kr));
}
return key_set;
}
function reverseKeys(keys) {
const key_set = new Uint8Array(keys.byteLength);
for (let i = 0; i < 16; i++) {
const offset = keys.byteLength - i * 6;
key_set.set(keys.subarray(offset - 6, offset), i * 6);
}
return key_set;
}
function isEqual(a, b) {
if (a.byteLength !== b.byteLength) {
return false;
}
for (let i = 0; i < a.byteLength; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
// * DES
function Cipher(M, K) {
const m = permute(M.reduce((acc, cur) => acc << 8n | BigInt(cur), 0n), IP);
let l = 0xffffffffn & (m >> 32n);
let r = 0xffffffffn & (m);
for (let i = 0; i < 16; i++) {
const offset = i * 6;
const k = K.subarray(offset, offset + 6).reduce((acc, cur) => (acc << 8n) | BigInt(cur), 0n);
const l_next = r;
r = permute(r, E) ^ k;
r = substitute(r);
r = permute(r, P) ^ l;
l = l_next;
}
return permute((r << 32n) | l, FP);
}
function _des(K) {
const key_set = generateKeys(K);
const inv_key_set = reverseKeys(key_set);
return {
encrypt: (M) => {
const C = new U8(8);
const view = new DataView(C.buffer);
view.setBigUint64(0, Cipher(M, key_set), false);
return C;
},
decrypt: (C) => {
const M = new U8(8);
const view = new DataView(M.buffer);
view.setBigUint64(0, Cipher(C, inv_key_set), false);
return M;
},
};
}
function _t_des(K, l) {
if (K.byteLength !== l >> 3) {
throw new KitError(`3DES key must be ${l >> 3} byte`);
}
const K1 = K.subarray(0, 8);
const K2 = K.subarray(8, 16);
const K3 = l === 128 ? K1 : K.subarray(16, 24);
if (isEqual(K1, K2) || (l === 192 && (isEqual(K1, K3) || isEqual(K2, K3)))) {
console.warn('mima-kit: Weak key detected in 3DES');
}
const d1 = _des(K1);
const d2 = _des(K2);
const d3 = _des(K3);
return {
encrypt: (M) => d3.encrypt(d2.decrypt(d1.encrypt(M))),
decrypt: (C) => d1.decrypt(d2.encrypt(d3.decrypt(C))),
};
}
/**
* Data Encryption Standard (DES) block cipher algorithm
*
* 数据加密标准(DES)分组密码算法
*/
export const des = createCipher(_des, {
ALGORITHM: 'DES',
BLOCK_SIZE: 8,
KEY_SIZE: 8,
MIN_KEY_SIZE: 8,
MAX_KEY_SIZE: 8,
});
/**
* Triple Data Encryption Standard (3DES) block cipher algorithm
*
* 三重数据加密标准(3DES)分组密码算法
*
* @param {128 | 192} l - 密钥长度 / Key Size (bit)
*/
export function t_des(l) {
return createCipher((K) => _t_des(K, l), {
ALGORITHM: '3DES',
BLOCK_SIZE: 8,
KEY_SIZE: l >> 3,
MIN_KEY_SIZE: l >> 3,
MAX_KEY_SIZE: l >> 3,
});
}
import { KitError, U8, rotateL32 } from '../../core/utils';
import { createCipher } from '../../core/cipher';
// * Constants
const SBox = new Uint8Array([0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05, 0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, 0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62, 0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6, 0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8, 0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35, 0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0x78, 0x87, 0xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52, 0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E, 0xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5, 0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1, 0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55, 0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3, 0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60, 0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F, 0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F, 0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 0x51, 0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F, 0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8, 0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD, 0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0, 0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96, 0x77, 0x7E, 0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84, 0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20, 0x79, 0xEE, 0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48]);
const CK = new Uint32Array([0x00070E15, 0x1C232A31, 0x383F464D, 0x545B6269, 0x70777E85, 0x8C939AA1, 0xA8AFB6BD, 0xC4CBD2D9, 0xE0E7EEF5, 0xFC030A11, 0x181F262D, 0x343B4249, 0x50575E65, 0x6C737A81, 0x888F969D, 0xA4ABB2B9, 0xC0C7CED5, 0xDCE3EAF1, 0xF8FF060D, 0x141B2229, 0x30373E45, 0x4C535A61, 0x686F767D, 0x848B9299, 0xA0A7AEB5, 0xBCC3CAD1, 0xD8DFE6ED, 0xF4FB0209, 0x10171E25, 0x2C333A41, 0x484F565D, 0x646B7279]);
// * Functions
/**
* 非线性变换函数 `τ`.
*
* Nonlinear transformation function `τ`.
*
* @param {number} A - 工作字 / word
*/
function tau(A) {
return SBox[A >> 24 & 0xFF] << 24 | SBox[A >> 16 & 0xFF] << 16 | SBox[A >> 8 & 0xFF] << 8 | SBox[A & 0xFF];
}
/**
* 合成置换函数 `T`, 由非线性变换函数 `τ` 和线性变换函数 `L` 组成.
*
* Synthetic permutation function `T`, composed of function `τ` and function `L`.
*
* @param {number} A - 工作字 / word
*/
function T(A) {
const B = tau(A);
return B ^ rotateL32(B, 2) ^ rotateL32(B, 10) ^ rotateL32(B, 18) ^ rotateL32(B, 24);
}
/**
* 合成置换函数 `T1`, 由非线性变换函数 `τ` 和线性变换函数 `L1` 组成.
*
* Synthetic permutation function `T1`, composed of function `τ` and function `L1`.
*
* @param {number} A - 工作字 / word
*/
function T1(A) {
const B = tau(A);
return B ^ rotateL32(B, 13) ^ rotateL32(B, 23);
}
/**
* 密钥扩展函数 / Key expansion function
*/
function expandKey(key) {
if (key.length !== 16) {
throw new KitError('SM4 key must be 16 byte');
}
const KView = new DataView(key.buffer);
let K0 = 0xA3B1BAC6 ^ KView.getUint32(0, false);
let K1 = 0x56AA3350 ^ KView.getUint32(4, false);
let K2 = 0x677D9197 ^ KView.getUint32(8, false);
let K3 = 0xB27022DC ^ KView.getUint32(12, false);
const rk = new Uint32Array(32);
for (let i = 0; i < 32; i++) {
rk[i] = K0 ^ T1(K1 ^ K2 ^ K3 ^ CK[i]);
K0 = K1;
K1 = K2;
K2 = K3;
K3 = rk[i];
}
return rk;
}
/**
* 轮函数 `F` / Round function `F`
*
* @param {number} X0 - 工作字 / word
* @param {number} X1 - 工作字 / word
* @param {number} X2 - 工作字 / word
* @param {number} X3 - 工作字 / word
* @param {number} rk - 轮密钥 / round key
*/
function F(X0, X1, X2, X3, rk) {
return X0 ^ T(X1 ^ X2 ^ X3 ^ rk);
}
// * SM4 Algorithm
/**
* @param {Uint8Array} M - 输入块 / input block
* @param {Uint32Array} rk - 轮密钥 / round keys
*/
function cipher(M, rk) {
if (M.length !== 16) {
throw new KitError('SM4 block must be 16 byte');
}
const MView = new DataView(M.buffer, M.byteOffset);
let X0 = MView.getUint32(0, false);
let X1 = MView.getUint32(4, false);
let X2 = MView.getUint32(8, false);
let X3 = MView.getUint32(12, false);
let X_;
for (let i = 0; i < 32; i++) {
X_ = F(X0, X1, X2, X3, rk[i]);
X0 = X1;
X1 = X2;
X2 = X3;
X3 = X_;
}
const R = new U8(16);
const RView = new DataView(R.buffer);
RView.setUint32(0, X3, false);
RView.setUint32(4, X2, false);
RView.setUint32(8, X1, false);
RView.setUint32(12, X0, false);
return R;
}
function _sm4(K) {
const rk = expandKey(K);
const rkReversed = rk.toReversed();
return {
encrypt: (M) => cipher(M, rk),
decrypt: (M) => cipher(M, rkReversed),
};
}
/**
* SM4 分组密码算法 / block cipher algorithm
*/
export const sm4 = createCipher(_sm4, {
ALGORITHM: 'SM4',
BLOCK_SIZE: 16,
KEY_SIZE: 16,
MIN_KEY_SIZE: 16,
MAX_KEY_SIZE: 16,
});
import { PKCS7_PAD, createCipher } from '../../core/cipher';
import { KitError, U8 } from '../../core/utils';
// * Constants
const DELTA = 0x9E3779B9;
// * Tiny Encryption Algorithm (TEA)
function _tea(K, round) {
if (K.length !== 16) {
throw new KitError('TEA key must be 16 byte');
}
const K32 = new Uint32Array(K.buffer);
const sum_delta = (DELTA * round) & 0xFFFFFFFF;
const encrypt = (M) => {
if (M.length !== 8) {
throw new KitError('TEA block must be 8 byte');
}
const C = U8.from(M.slice(0));
const C32 = new Uint32Array(C.buffer);
let sum = 0;
for (let i = 0; i < round; i++) {
sum += DELTA;
C32[0] += ((C32[1] << 4) + K32[0]) ^ (C32[1] + sum) ^ ((C32[1] >>> 5) + K32[1]);
C32[1] += ((C32[0] << 4) + K32[2]) ^ (C32[0] + sum) ^ ((C32[0] >>> 5) + K32[3]);
}
return C;
};
const decrypt = (C) => {
if (C.length !== 8) {
throw new KitError('TEA block must be 8 byte');
}
const M = U8.from(C.slice(0));
const M32 = new Uint32Array(M.buffer);
let sum = sum_delta;
for (let i = 0; i < round; i++) {
M32[1] -= ((M32[0] << 4) + K32[2]) ^ (M32[0] + sum) ^ ((M32[0] >>> 5) + K32[3]);
M32[0] -= ((M32[1] << 4) + K32[0]) ^ (M32[1] + sum) ^ ((M32[1] >>> 5) + K32[1]);
sum -= DELTA;
}
return M;
};
return { encrypt, decrypt };
}
function _xtea(K, round) {
if (K.length !== 16) {
throw new KitError('XTEA key must be 16 byte');
}
const K32 = new Uint32Array(K.buffer);
const sum_delta = (DELTA * round) & 0xFFFFFFFF;
const encrypt = (M) => {
if (M.length !== 8) {
throw new KitError('XTEA block must be 8 byte');
}
const C = U8.from(M.slice(0));
const C32 = new Uint32Array(C.buffer);
let sum = 0;
for (let i = 0; i < round; i++) {
C32[0] += (C32[1] << 4 ^ C32[1] >>> 5) + C32[1] ^ sum + K32[sum & 3];
sum += DELTA;
C32[1] += (C32[0] << 4 ^ C32[0] >>> 5) + C32[0] ^ sum + K32[(sum >>> 11) & 3];
}
return C;
};
const decrypt = (C) => {
if (C.length !== 8) {
throw new KitError('XTEA block must be 8 byte');
}
const M = U8.from(C.slice(0));
const M32 = new Uint32Array(M.buffer);
let sum = sum_delta;
for (let i = 0; i < round; i++) {
M32[1] -= ((M32[0] << 4 ^ M32[0] >>> 5) + M32[0]) ^ (sum + K32[(sum >>> 11) & 3]);
sum -= DELTA;
M32[0] -= ((M32[1] << 4 ^ M32[1] >>> 5) + M32[1]) ^ (sum + K32[sum & 3]);
}
return M;
};
return { encrypt, decrypt };
}
function _xxtea(K, padding, round) {
if (K.length !== 16) {
throw new KitError('XXTEA key must be 16 byte');
}
const K32 = new Uint32Array(K.buffer);
const encrypt = (M) => {
const C = U8.from(padding(M, 4));
if (C.length < 8 || C.length % 4 !== 0) {
throw new KitError('XXTEA block must be a multiple of 4 byte (at least 8 byte)');
}
const C32 = new Uint32Array(C.buffer);
const n = C32.length;
let _round = round || (6 + 52 / n) >>> 0;
let sum = 0;
let y;
let z = C32[n - 1];
let p;
while (_round-- > 0) {
sum += DELTA;
const e = (sum >>> 2) & 3;
for (p = 0; p < n - 1; p++) {
y = C32[p + 1];
z = C32[p] += (((z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4)) ^ ((sum ^ y) + (K32[(p & 3) ^ e] ^ z)));
}
y = C32[0];
z = C32[n - 1] += (((z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4)) ^ ((sum ^ y) + (K32[(p & 3) ^ e] ^ z)));
}
return C;
};
const decrypt = (C) => {
if (C.length % 4 !== 0) {
throw new KitError('Decryption error');
}
const M = U8.from(C.slice(0));
const M32 = new Uint32Array(M.buffer);
const n = M32.length;
let _round = round || (6 + 52 / n) >>> 0;
let sum = (DELTA * _round) & 0xFFFFFFFF;
let y = M32[0];
let z;
let p;
while (_round-- > 0) {
const e = (sum >>> 2) & 3;
for (p = n - 1; p > 0; p--) {
z = M32[p - 1];
y = M32[p] -= (((z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4)) ^ ((sum ^ y) + (K32[(p & 3) ^ e] ^ z)));
}
z = M32[n - 1];
y = M32[0] -= (((z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4)) ^ ((sum ^ y) + (K32[(p & 3) ^ e] ^ z)));
sum -= DELTA;
}
return padding(M);
};
return { encrypt, decrypt };
}
/**
* 微型加密算法 (TEA) 分组密码算法
*
* Tiny Encryption Algorithm (TEA) block cipher algorithm
*
* @param {number} round - 轮数 / Rounds (default: 32)
*/
export function tea(round = 32) {
if (round <= 0) {
throw new KitError('TEA round must be a positive number');
}
return createCipher((K) => _tea(K, round), {
ALGORITHM: 'TEA',
BLOCK_SIZE: 8,
KEY_SIZE: 16,
MIN_KEY_SIZE: 16,
MAX_KEY_SIZE: 16,
});
}
/**
* 扩展微型加密算法 (XTEA) 分组密码算法
*
* eXtended Tiny Encryption Algorithm (XTEA) block cipher algorithm
*
* @param {number} round - 轮数 / Rounds (default: 32)
*/
export function xtea(round = 32) {
if (round <= 0) {
throw new KitError('XTEA round must be a positive number');
}
return createCipher((K) => _xtea(K, round), {
ALGORITHM: 'XTEA',
BLOCK_SIZE: 8,
KEY_SIZE: 16,
MIN_KEY_SIZE: 16,
MAX_KEY_SIZE: 16,
});
}
/**
* 纠正块 TEA (XXTEA) 分组密码算法
*
* Corrected Block TEA (XXTEA) block cipher algorithm
*
* @param {Padding} [config.padding] - 填充方式 / Padding method (default: PKCS7)
* @param {number} [config.round] - 轮数 / Rounds (default: undefined)
* @param {number} [config.BLOCK_SIZE] - 分组大小 / Block size (default: 16)
*/
export function xxtea(config) {
const { BLOCK_SIZE = 16, padding = PKCS7_PAD, round, } = config ?? {};
if (BLOCK_SIZE < 8 || BLOCK_SIZE % 4 !== 0) {
throw new KitError('XXTEA block size must be a multiple of 4 byte (at least 8 byte)');
}
return createCipher((K) => _xxtea(K, padding, round), {
ALGORITHM: 'XXTEA',
BLOCK_SIZE,
KEY_SIZE: 16,
MIN_KEY_SIZE: 16,
MAX_KEY_SIZE: 16,
});
}
import { createCipher } from '../../core/cipher';
import { KitError, U8, rotateL32, rotateR32 } from '../../core/utils';
// * Constants
const P0 = new Uint8Array([0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0]);
const P1 = new Uint8Array([0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91]);
const P = [P0, P1];
const P_00 = 1;
const P_01 = 0;
const P_02 = 0;
const P_03 = P_01 ^ 1;
const P_04 = 1;
const P_10 = 0;
const P_11 = 0;
const P_12 = 1;
const P_13 = P_11 ^ 1;
const P_14 = 0;
const P_20 = 1;
const P_21 = 1;
const P_22 = 0;
const P_23 = P_21 ^ 1;
const P_24 = 0;
const P_30 = 0;
const P_31 = 1;
const P_32 = 1;
const P_33 = P_31 ^ 1;
const P_34 = 1;
const GF256_FDBK_2 = 0x169 >> 1;
const GF256_FDBK_4 = 0x169 >> 2;
const RS_GF_FDBK = 0x14D;
const MDS = [
new Uint32Array(256),
new Uint32Array(256),
new Uint32Array(256),
new Uint32Array(256),
];
// * Functions
const LFSR1 = (x) => (x >> 1) ^ ((x & 0x01) !== 0 ? GF256_FDBK_2 : 0);
const LFSR2 = (x) => (x >> 2) ^ ((x & 0x02) !== 0 ? GF256_FDBK_2 : 0) ^ ((x & 0x01) !== 0 ? GF256_FDBK_4 : 0);
const Mx_X = (x) => x ^ LFSR2(x);
const Mx_Y = (x) => x ^ LFSR1(x) ^ LFSR2(x);
(function initMDS() {
// precompute the MDS matrix
const m1 = new Uint32Array(2);
const mX = new Uint32Array(2);
const mY = new Uint32Array(2);
for (let i = 0; i < 256; i++) {
const j0 = P[0][i] & 0xFF;
m1[0] = j0;
mX[0] = Mx_X(j0) & 0xFF;
mY[0] = Mx_Y(j0) & 0xFF;
const j1 = P[1][i] & 0xFF;
m1[1] = j1;
mX[1] = Mx_X(j1) & 0xFF;
mY[1] = Mx_Y(j1) & 0xFF;
MDS[0][i]
= (m1[P_00] << 0)
| (mX[P_00] << 8)
| (mY[P_00] << 16)
| (mY[P_00] << 24);
MDS[1][i]
= (mY[P_10] << 0)
| (mY[P_10] << 8)
| (mX[P_10] << 16)
| (m1[P_10] << 24);
MDS[2][i]
= (mX[P_20] << 0)
| (mY[P_20] << 8)
| (m1[P_20] << 16)
| (mY[P_20] << 24);
MDS[3][i]
= (mX[P_30] << 0)
| (m1[P_30] << 8)
| (mY[P_30] << 16)
| (mX[P_30] << 24);
}
})();
const b0 = (x) => x & 0xFF;
const b1 = (x) => (x >>> 8) & 0xFF;
const b2 = (x) => (x >>> 16) & 0xFF;
const b3 = (x) => (x >>> 24) & 0xFF;
function chooseB(x, N) {
switch (N & 3) {
case 0: return b0(x);
case 1: return b1(x);
case 2: return b2(x);
case 3: return b3(x);
default: return 0;
}
}
function RS_REM(x) {
const b = (x >>> 24) & 0xFF;
const g2 = ((b << 1) ^ ((b & 0x80) !== 0 ? RS_GF_FDBK : 0)) & 0xFF;
const g3 = (b >>> 1) ^ ((b & 0x01) !== 0 ? (RS_GF_FDBK >>> 1) : 0) ^ g2;
return (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b;
}
function RS_MDS_Encode(k0, k1) {
for (let i = 0; i < 4; i++) {
k1 = RS_REM(k1);
}
k1 ^= k0;
for (let i = 0; i < 4; i++) {
k1 = RS_REM(k1);
}
return k1;
}
function F32(K64SigByte, x, k32) {
let lB0 = b0(x);
let lB1 = b1(x);
let lB2 = b2(x);
let lB3 = b3(x);
const k0 = k32[0] || 0;
const k1 = k32[1] || 0;
const k2 = k32[2] || 0;
const k3 = k32[3] || 0;
let result = 0;
let K64LSB = K64SigByte & 0x3;
if (K64LSB === 1) {
result
= MDS[0][P[P_01][lB0] & 0xFF ^ b0(k0)]
^ MDS[1][P[P_11][lB1] & 0xFF ^ b1(k0)]
^ MDS[2][P[P_21][lB2] & 0xFF ^ b2(k0)]
^ MDS[3][P[P_31][lB3] & 0xFF ^ b3(k0)];
return result;
}
if (K64LSB === 0) {
lB0 = P[P_04][lB0] & 0xFF ^ b0(k3);
lB1 = P[P_14][lB1] & 0xFF ^ b1(k3);
lB2 = P[P_24][lB2] & 0xFF ^ b2(k3);
lB3 = P[P_34][lB3] & 0xFF ^ b3(k3);
K64LSB = 3;
}
if (K64LSB === 3) {
lB0 = P[P_03][lB0] & 0xFF ^ b0(k2);
lB1 = P[P_13][lB1] & 0xFF ^ b1(k2);
lB2 = P[P_23][lB2] & 0xFF ^ b2(k2);
lB3 = P[P_33][lB3] & 0xFF ^ b3(k2);
K64LSB = 2;
}
if (K64LSB === 2) {
result
= MDS[0][P[P_01][P[P_02][lB0] & 0xFF ^ b0(k1)] & 0xFF ^ b0(k0)]
^ MDS[1][P[P_11][P[P_12][lB1] & 0xFF ^ b1(k1)] & 0xFF ^ b1(k0)]
^ MDS[2][P[P_21][P[P_22][lB2] & 0xFF ^ b2(k1)] & 0xFF ^ b2(k0)]
^ MDS[3][P[P_31][P[P_32][lB3] & 0xFF ^ b3(k1)] & 0xFF ^ b3(k0)];
return result;
}
return 0;
}
function Fe32(SBox, x, R) {
const result = SBox[0x000 + 2 * chooseB(x, R + 0) + 0]
^ SBox[0x000 + 2 * chooseB(x, R + 1) + 1]
^ SBox[0x200 + 2 * chooseB(x, R + 2) + 0]
^ SBox[0x200 + 2 * chooseB(x, R + 3) + 1];
return result;
}
// * Blowfish Algorithm
function initKeySchedule(K) {
const K32 = new Uint32Array(K.buffer, K.byteOffset);
const K32e = new Uint32Array([K32[0], K32[2], K32[4], K32[6]]);
const K32o = new Uint32Array([K32[1], K32[3], K32[5], K32[7]]);
const K64Count = K32.length >> 1;
// compute S-box keys using (12, 8) Reed-Solomon code over GF(256)
const SBoxKeys = new Uint32Array(4);
for (let i = 0; i < 4; i++) {
const j = K64Count - 1 - i;
SBoxKeys[j] = RS_MDS_Encode(K32e[i], K32o[i]);
}
// compute the round decryption subkeys for PHT. these same subkeys
// will be used in encryption but will be applied in reverse order.
let q = 0;
const Subkeys = new Uint32Array(40);
for (let i = 0; i < 20; i++) {
let A = F32(K64Count, q, K32e);
let B = F32(K64Count, q + 0x01010101, K32o);
B = rotateL32(B, 8);
A += B;
Subkeys[2 * i] = A;
A += B;
Subkeys[2 * i + 1] = rotateL32(A, 9);
q += 0x02020202;
}
// fully expand the table for speed
const k0 = SBoxKeys[0];
const k1 = SBoxKeys[1];
const k2 = SBoxKeys[2];
const k3 = SBoxKeys[3];
const SBox = new Uint32Array(4 * 256);
for (let i = 0; i < 256; i++) {
let lb0 = i;
let lb1 = i;
let lb2 = i;
let lb3 = i;
let K64CountLSB = K64Count & 3;
if (K64CountLSB === 1) {
SBox[0x000 + 2 * i + 0] = MDS[0][P[P_01][lb0] & 0xFF ^ b0(k0)];
SBox[0x000 + 2 * i + 1] = MDS[1][P[P_11][lb1] & 0xFF ^ b1(k0)];
SBox[0x200 + 2 * i + 0] = MDS[2][P[P_21][lb2] & 0xFF ^ b2(k0)];
SBox[0x200 + 2 * i + 1] = MDS[3][P[P_31][lb3] & 0xFF ^ b3(k0)];
continue;
}
if (K64CountLSB === 0) {
lb0 = P[P_04][lb0] & 0xFF ^ b0(k3);
lb1 = P[P_14][lb1] & 0xFF ^ b1(k3);
lb2 = P[P_24][lb2] & 0xFF ^ b2(k3);
lb3 = P[P_34][lb3] & 0xFF ^ b3(k3);
K64CountLSB = 3;
}
if (K64CountLSB === 3) {
lb0 = P[P_03][lb0] & 0xFF ^ b0(k2);
lb1 = P[P_13][lb1] & 0xFF ^ b1(k2);
lb2 = P[P_23][lb2] & 0xFF ^ b2(k2);
lb3 = P[P_33][lb3] & 0xFF ^ b3(k2);
K64CountLSB = 2;
}
if (K64CountLSB === 2) {
SBox[0x000 + 2 * i + 0]
= MDS[0][P[P_01][P[P_02][lb0] & 0xFF ^ b0(k1)] & 0xFF ^ b0(k0)];
SBox[0x000 + 2 * i + 1]
= MDS[1][P[P_11][P[P_12][lb1] & 0xFF ^ b1(k1)] & 0xFF ^ b1(k0)];
SBox[0x200 + 2 * i + 0]
= MDS[2][P[P_21][P[P_22][lb2] & 0xFF ^ b2(k1)] & 0xFF ^ b2(k0)];
SBox[0x200 + 2 * i + 1]
= MDS[3][P[P_31][P[P_32][lb3] & 0xFF ^ b3(k1)] & 0xFF ^ b3(k0)];
}
}
return { Subkeys, SBox };
}
function _twofish(K, b) {
if (K.byteLength !== b >> 3) {
throw new KitError(`Twofish key must be ${b >> 3} byte`);
}
const { Subkeys, SBox } = initKeySchedule(K);
const encrypt = (M) => {
if (M.byteLength !== 16) {
throw new KitError('Twofish block must be 16 byte');
}
const M32 = new Uint32Array(M.buffer, M.byteOffset);
// input whitening
let x0 = M32[0] ^ Subkeys[0];
let x1 = M32[1] ^ Subkeys[1];
let x2 = M32[2] ^ Subkeys[2];
let x3 = M32[3] ^ Subkeys[3];
let k = 8;
// 16 rounds of encryption
for (let i = 0; i < 16; i += 2) {
let t0 = Fe32(SBox, x0, 0);
let t1 = Fe32(SBox, x1, 3);
x2 ^= t0 + t1 + Subkeys[k++];
x2 = rotateR32(x2, 1);
x3 = rotateL32(x3, 1);
x3 ^= t0 + 2 * t1 + Subkeys[k++];
t0 = Fe32(SBox, x2, 0);
t1 = Fe32(SBox, x3, 3);
x0 ^= t0 + t1 + Subkeys[k++];
x0 = rotateR32(x0, 1);
x1 = rotateL32(x1, 1);
x1 ^= t0 + 2 * t1 + Subkeys[k++];
}
// output whitening
x2 ^= Subkeys[4];
x3 ^= Subkeys[5];
x0 ^= Subkeys[6];
x1 ^= Subkeys[7];
return new U8(new Uint32Array([x2, x3, x0, x1]).buffer);
};
const decrypt = (C) => {
if (C.byteLength !== 16) {
throw new KitError('Twofish block must be 16 byte');
}
const M32 = new Uint32Array(C.buffer, C.byteOffset);
// input whitening
let x2 = M32[0] ^ Subkeys[4];
let x3 = M32[1] ^ Subkeys[5];
let x0 = M32[2] ^ Subkeys[6];
let x1 = M32[3] ^ Subkeys[7];
let k = 39;
// 16 rounds of decryption
for (let i = 0; i < 16; i += 2) {
let t0 = Fe32(SBox, x2, 0);
let t1 = Fe32(SBox, x3, 3);
x1 ^= t0 + 2 * t1 + Subkeys[k--];
x1 = rotateR32(x1, 1);
x0 = rotateL32(x0, 1);
x0 ^= t0 + t1 + Subkeys[k--];
t0 = Fe32(SBox, x0, 0);
t1 = Fe32(SBox, x1, 3);
x3 ^= t0 + 2 * t1 + Subkeys[k--];
x3 = rotateR32(x3, 1);
x2 = rotateL32(x2, 1);
x2 ^= t0 + t1 + Subkeys[k--];
}
// output whitening
x0 ^= Subkeys[0];
x1 ^= Subkeys[1];
x2 ^= Subkeys[2];
x3 ^= Subkeys[3];
return new U8(new Uint32Array([x0, x1, x2, x3]).buffer);
};
return { encrypt, decrypt };
}
/**
* Twofish 分组密码算法 / block cipher algorithm
*
* @param {128 | 192 | 256} b - 密钥长度 / Key size (bit)
*/
export function twofish(b) {
return createCipher((K) => _twofish(K, b), {
ALGORITHM: 'Twofish',
BLOCK_SIZE: 16,
KEY_SIZE: b >> 3,
MIN_KEY_SIZE: b >> 3,
MAX_KEY_SIZE: b >> 3,
});
}
import { cbc, createCipher } from '../../core/cipher';
import { BIPoint, Fp, FpEC, U8Point } from '../../core/ec';
import { KitError, U8, genBitMask, genRandomBI, getBIBits, joinBuffer, mod, modInverse } from '../../core/utils';
import { x963kdf } from '../../core/kdf';
import { aes } from '../blockCipher/aes';
import { sha256 } from '../../hash/sha256';
import { hmac } from '../../hash/hmac';
// * Functions
/**
* 定义 ECIES 配置
*
* Define ECIES Configuration
*
* @param {IVBlockCipher} [config.cipher] - 分组密码算法 / Block Cipher Algorithm (default: AES-256-GCM)
* @param {KeyHash} [config.mac] - 密钥哈希函数 / Key Hash Function (default: HMAC-SHA-256)
* @param {KDF} [config.kdf] - 密钥派生函数 / Key Derivation Function (default: ANSI-X9.63-KDF with SHA-256)
* @param {Uint8Array} [config.S1] - 附加数据1 / Additional Data 1 (default: empty)
* @param {Uint8Array} [config.S2] - 附加数据2 / Additional Data 2 (default: empty)
* @param {Uint8Array} [config.iv] - 初始化向量 / Initialization Vector (default: Uint8Array(cipher.BLOCK_SIZE))
*/
export function defineECIES(config) {
config = config ?? {};
const { cipher = cbc(aes(256)), mac = hmac(sha256), kdf = x963kdf(sha256), S1 = new Uint8Array(0), S2 = new Uint8Array(0), iv = new Uint8Array(cipher.BLOCK_SIZE), } = config;
return { cipher, mac, kdf, S1, S2, iv };
}
// * EC Algorithms
/**
* 素域椭圆曲线密码学组件
*
* Prime Field Elliptic Curve Cryptography Components
*/
export function FpECC(curve) {
const { p, a, b, G, n, h } = curve;
const p_bit = getBIBits(p);
const p_byte = (p_bit + 7) >> 3;
const n_bit = getBIBits(n);
const n_mask = genBitMask(n_bit);
const { addPoint, mulPoint } = FpEC(curve);
const { plus, multiply, root } = Fp(p);
const isLegalPK = (p_key) => {
const { Q } = p_key;
// P != O
if (Q.isInfinity) {
return false;
}
// P(x, y) ∈ E
const P = BIPoint(Q);
const { x, y } = P;
if (x < 0n || x >= p || y < 0n || y >= p) {
return false;
}
if (curve.type === 'Weierstrass') {
// y^2 = x^3 + ax + b
const l = multiply(y, y);
const r = plus(multiply(x, x, x), multiply(a, x), b);
if (l !== r) {
return false;
}
// nP = O
const nP = mulPoint(P, n);
return nP.isInfinity;
}
if (curve.type === 'Montgomery') {
// By^2 = x^3 + Ax^2 + x
const l = multiply(b, y, y);
const r = plus(multiply(x, x, x), multiply(a, x, x), x);
if (l !== r) {
return false;
}
// nP = O
const nP = mulPoint(P, n);
return nP.isInfinity;
}
// unknown curve type
else {
return false;
}
};
const isLegalSK = (s_key) => {
const d = typeof s_key.d === 'bigint' ? s_key.d : U8.from(s_key.d).toBI();
if (d < 0n || d >= p) {
return false;
}
return !mulPoint(G, d).isInfinity;
};
const PointToU8 = (point, compress = false) => {
if (point.isInfinity) {
return new U8([0x00]);
}
const { x, y } = U8Point(point, p_byte);
const sign_y = y[y.length - 1] & 1;
const PC = new U8([compress ? 0x02 | sign_y : 0x04]);
const X1 = x;
const Y1 = compress ? new U8() : y;
return joinBuffer(PC, X1, Y1);
};
const U8ToPoint = (buffer) => {
const point_buffer = U8.from(buffer);
const PC = point_buffer[0];
if (PC === 0x00) {
if (point_buffer.length !== 1) {
throw new KitError('Invalid Point');
}
return U8Point();
}
if (PC !== 0x02 && PC !== 0x03 && PC !== 0x04) {
throw new KitError('Invalid Point');
}
// 无压缩
if (PC === 0x04) {
if (point_buffer.length !== (p_byte << 1) + 1) {
throw new KitError('Invalid Point');
}
const x = point_buffer.slice(1, p_byte + 1);
const y = point_buffer.slice(p_byte + 1);
return { isInfinity: false, x, y };
}
// 解压缩
else {
if (point_buffer.length !== p_byte + 1) {
throw new KitError('Invalid Point');
}
const x_buffer = point_buffer.slice(1);
const x = x_buffer.toBI();
const sign_y = BigInt(PC & 1);
if (curve.type === 'Weierstrass') {
let y = 0n;
y = plus(multiply(x, x, x), multiply(a, x), b);
y = root(y);
y = (y & 1n) === sign_y ? y : p - y;
return U8Point({ isInfinity: false, x: x_buffer, y }, p_byte);
}
else if (curve.type === 'Montgomery') {
let y = 0n;
y = plus(multiply(x, x, x), multiply(a, x, x), x);
y = root(y / b);
y = (y & 1n) === sign_y ? y : p - y;
return U8Point({ isInfinity: false, x: x_buffer, y }, p_byte);
}
else {
throw new KitError('Unknown curve type');
}
}
};
function gen(type = 'key_pair', s_key) {
if (type === 'key_pair') {
// private key
const { buffer, result: d } = genRandomBI(n, p_byte);
// public key
const _ = mulPoint(G, d);
const Q = U8Point(_, p_byte);
return { Q, d: buffer };
}
else if (type === 'private_key') {
return { d: genRandomBI(n, p_byte).buffer };
}
else if (type === 'public_key') {
const d_buffer = typeof s_key.d === 'bigint' ? U8.fromBI(s_key.d) : U8.from(s_key.d);
const d = typeof s_key.d === 'bigint' ? s_key.d : d_buffer.toBI();
if (d === 0n) {
throw new KitError('Invalid private key');
}
const _ = mulPoint(G, d);
const Q = U8Point(_, p_byte);
return { Q, d: d_buffer };
}
}
// Key agreement
const ecdh = (s_key, p_key) => {
if (!isLegalPK(p_key)) {
throw new KitError('Invalid public key');
}
if (!isLegalSK(s_key)) {
throw new KitError('Invalid private key');
}
const Q = p_key.Q;
const d = s_key.d;
const S = mulPoint(Q, d);
if (S.isInfinity) {
throw new KitError('the result of ECDH is the point at infinity');
}
return U8Point(S, p_byte);
};
const eccdh = (s_key, p_key) => {
if (!isLegalPK(p_key)) {
throw new KitError('Invalid public key');
}
if (!isLegalSK(s_key)) {
throw new KitError('Invalid private key');
}
const Q = p_key.Q;
const d = typeof s_key.d === 'bigint' ? s_key.d : U8.from(s_key.d).toBI();
const S = mulPoint(Q, d * h);
if (S.isInfinity) {
throw new KitError('the result of ECCDH is the point at infinity');
}
return U8Point(S, p_byte);
};
const ecmqv = (u1, u2, v1, v2) => {
if (!isLegalPK(v1) || !isLegalPK(v2)) {
throw new KitError('Invalid public key');
}
const ceilLog2n = n_bit;
const L = 1n << BigInt(Math.ceil(ceilLog2n / 2));
const u1d = typeof u1.d === 'bigint' ? u1.d : U8.from(u1.d).toBI();
const u2d = typeof u2.d === 'bigint' ? u2.d : U8.from(u2.d).toBI();
const u2Qx = typeof u2.Q.x === 'bigint' ? u2.Q.x : U8.from(u2.Q.x).toBI();
const v2Qx = typeof v2.Q.x === 'bigint' ? v2.Q.x : U8.from(v2.Q.x).toBI();
const Q2u = mod(u2Qx, L) + L;
const Q2v = mod(v2Qx, L) + L;
const s = mod(u2d + Q2u * u1d, n);
const P = mulPoint(addPoint(v2.Q, mulPoint(v1.Q, Q2v)), s * h);
if (P.isInfinity) {
throw new KitError('Public key not available');
}
return U8Point(P, p_byte);
};
// Digital signature
const ecdsa = (hash = sha256) => {
const sign = (s_key, M) => {
const d = typeof s_key.d === 'bigint' ? s_key.d : U8.from(s_key.d).toBI();
let r = 0n;
let s = 0n;
let z = hash(M).toBI();
while (z > n_mask) {
z = z >> 1n;
}
do {
const K = gen();
const k = K.d.toBI();
const x1 = K.Q.x.toBI();
r = mod(x1, n);
if (r === 0n)
continue;
s = modInverse(k, n) * mod(z + r * d, n);
s = mod(s, n);
} while (s === 0n);
const r_buffer = U8.fromBI(r);
const s_buffer = U8.fromBI(s);
return { r: r_buffer, s: s_buffer };
};
const verify = (p_key, M, signature) => {
const { Q } = p_key;
const r = typeof signature.r === 'bigint' ? signature.r : U8.from(signature.r).toBI();
const s = typeof signature.s === 'bigint' ? signature.s : U8.from(signature.s).toBI();
if (r <= 0n || r >= n || s <= 0n || s >= n) {
return false;
}
let z = hash(M).toBI();
while (z > n_mask) {
z = z >> 1n;
}
const w = modInverse(s, n);
const u1 = mod(z * w, n);
const u2 = mod(r * w, n);
const P = addPoint(mulPoint(G, u1), mulPoint(Q, u2));
const v = mod(P.x, n);
return v === r;
};
return { sign, verify };
};
// Integrated encryption scheme
const ecies = (config) => {
const { cipher, mac, kdf, S1, S2, iv } = defineECIES(config);
const encrypt = (p_key, M) => {
if (!isLegalPK(p_key)) {
throw new KitError('Invalid public key');
}
let s_key;
let deriveShare;
do {
s_key = gen();
deriveShare = ecdh(s_key, p_key);
} while (deriveShare.isInfinity);
const Z = deriveShare.x;
const K = kdf((cipher.KEY_SIZE + mac.KEY_SIZE) << 3, joinBuffer(Z, S1));
const KE = K.slice(0, cipher.KEY_SIZE);
const KM = K.slice(cipher.KEY_SIZE, cipher.KEY_SIZE + mac.KEY_SIZE);
const _cipher = cipher(KE, iv);
const R = { Q: s_key.Q };
const C = _cipher.encrypt(M);
const D = mac(KM, joinBuffer(C, S2));
return { R, C, D };
};
const decrypt = (s_key, CT) => {
const { R, C, D } = CT;
// 密钥派生
const deriveShare = ecdh(s_key, R);
if (deriveShare.isInfinity) {
throw new KitError('ECIES Decryption failed');
}
const Z = deriveShare.x;
const K = kdf((cipher.KEY_SIZE + mac.KEY_SIZE) << 3, joinBuffer(Z, S1));
const KE = K.slice(0, cipher.KEY_SIZE);
const KM = K.slice(cipher.KEY_SIZE, cipher.KEY_SIZE + mac.KEY_SIZE);
const _cipher = cipher(KE, iv);
// 校验
if (mac(KM, joinBuffer(C, S2)).some((v, i) => v !== D[i])) {
throw new KitError('ECIES Decryption failed');
}
const M = _cipher.decrypt(C);
// 解密
return new U8(M);
};
return { encrypt, decrypt };
};
return {
utils: {
addPoint,
mulPoint,
isLegalPK,
isLegalSK,
PointToU8,
U8ToPoint,
},
gen,
dh: ecdh,
cdh: eccdh,
mqv: ecmqv,
dsa: ecdsa,
ies: ecies,
};
}
// * Algorithms for Test
/**
* ! 此加密算法仅用于测试 ECIES
* ! This encryption algorithm is only used for testing ECIES
*/
export const es_xor = createCipher((K) => {
const encrypt = (M) => new U8(M.map((v, i) => v ^ K[i]));
const decrypt = (C) => new U8(C.map((v, i) => v ^ K[i]));
return { encrypt, decrypt };
}, {
ALGORITHM: 'ES-XOR',
BLOCK_SIZE: 20,
KEY_SIZE: 20,
MIN_KEY_SIZE: 20,
MAX_KEY_SIZE: 20,
});
import { ASN1 } from '../../core/asn1';
import { Counter, KitError, U8, getBIBits, joinBuffer } from '../../core/utils';
import { sha256 } from '../../hash/sha256';
import { rsa } from './rsa';
/**
* PKCS#1 v2.2 的 掩码生成函数 MGF1
*
* Mask Generation Function MGF1 of PKCS#1 v2.2
*/
export function mgf1(hash) {
return (mdfSeed, maskLen) => {
const T = [];
const C = new Counter(joinBuffer(mdfSeed, new Uint8Array(4)));
for (let i = 0; i < maskLen; i += hash.DIGEST_SIZE) {
T.push(hash(C));
C.inc(mdfSeed.length);
}
return joinBuffer(...T).slice(0, maskLen);
};
}
// * Encryption Scheme
/**
* 最优非对称加密填充的 RSA 加密方案 (OAEP)
*
* RSA Encryption Scheme with Optimal Asymmetric Encryption Padding (OAEP)
*
* @param {RSAPublicKey | RSAPrivateKey} key - RSA 公钥或私钥 / RSA public or private key
* @param {Hash} [hash] - 散列函数 / Hash function (default: SHA-256)
* @param {MGF} [mgf] - 掩码生成函数 / Mask generation function (default: MGF1)
* @param {Uint8Array} [label] - 标签 / Label (default: empty)
*/
export function pkcs1_es_oaep(key, hash = sha256, mgf = mgf1(hash), label = new Uint8Array()) {
const k = (getBIBits(key.n) + 7) >> 3;
const hLen = hash.DIGEST_SIZE;
const MAX_MESSAGE_LENGTH = k - 2 * hLen - 2;
if (MAX_MESSAGE_LENGTH <= 0) {
throw new KitError('Invalid key or hash function');
}
const _rsa = rsa(key);
const lHash = hash(label);
const encrypt = (M) => {
const mLen = M.length;
if (mLen > MAX_MESSAGE_LENGTH) {
throw new KitError('Message too long');
}
// DB = lHash || PS || 0x01 || M
const PS = new U8(MAX_MESSAGE_LENGTH - mLen);
const DB = joinBuffer(lHash, PS, new U8([0x01]), M);
// EM = 0x00 || maskedSeed || maskedDB
const seed = new U8(hLen);
crypto.getRandomValues(seed);
const dbMask = mgf(seed, DB.length);
const maskedDB = DB.map((v, i) => v ^ dbMask[i]);
const seedMask = mgf(maskedDB, hLen);
const maskedSeed = seed.map((v, i) => v ^ seedMask[i]);
const EM = joinBuffer(new U8([0x00]), maskedSeed, maskedDB);
return U8.fromBI(_rsa.encrypt(EM), k);
};
const decrypt = (C) => {
if (k !== C.length) {
throw new KitError('Decryption error');
}
const EM = U8.fromBI(_rsa.decrypt(C), k);
if (EM[0] !== 0x00) {
throw new KitError('Decryption error');
}
const maskedSeed = EM.subarray(1, hLen + 1);
const maskedDB = EM.subarray(hLen + 1);
const seedMask = mgf(maskedDB, hLen);
const seed = maskedSeed.map((v, i) => v ^ seedMask[i]);
const dbMask = mgf(seed, maskedDB.length);
const DB = maskedDB.map((v, i) => v ^ dbMask[i]);
const lHash_ = DB.subarray(0, hLen);
if (lHash.some((v, i) => v !== lHash_[i])) {
throw new KitError('Decryption error');
}
const PS = DB.subarray(hLen);
const mOffset = PS.findIndex(v => v === 0x01);
if (mOffset === -1) {
throw new KitError('Decryption error');
}
if (PS.subarray(0, mOffset).some(v => v !== 0x00)) {
throw new KitError('Decryption error');
}
const M = PS.slice(mOffset + 1);
return M;
};
return { encrypt, decrypt };
}
/**
* RSA 加密方案 (PKCS#1 v1.5)
*
* RSA Encryption Scheme (PKCS#1 v1.5)
*
* @param {RSAPublicKey | RSAPrivateKey} key - RSA 公钥或私钥 / RSA public or private key
*/
export function pkcs1_es_1_5(key) {
const k = (getBIBits(key.n) + 7) >> 3;
const MAX_MESSAGE_LENGTH = k - 11;
if (MAX_MESSAGE_LENGTH <= 0) {
throw new KitError('Invalid key');
}
const _rsa = rsa(key);
const encrypt = (M) => {
if (M.length > MAX_MESSAGE_LENGTH) {
throw new KitError('Message is too long');
}
const PS = new Uint8Array(k - M.length - 3);
do {
crypto.getRandomValues(PS);
} while (PS.includes(0x00));
const EM = joinBuffer(new U8([0x00, 0x02]), PS, new U8([0x00]), M);
return U8.fromBI(_rsa.encrypt(EM), k);
};
const decrypt = (C) => {
if (C.length !== k) {
throw new KitError('Decryption error');
}
const EM = U8.fromBI(_rsa.decrypt(C), k);
if (EM[0] !== 0x00 || EM[1] !== 0x02) {
throw new KitError('Decryption error');
}
const SeparatorIndex = EM.subarray(2).findIndex(v => v === 0x00);
if (SeparatorIndex === -1) {
throw new KitError('Decryption error');
}
const M = EM.slice(SeparatorIndex + 3);
return M;
};
return { encrypt, decrypt };
}
// * Signature Scheme with Appendix
/**
* 基于 概率签名方案 的 RSA 附录签名方案 (PSS)
*
* RSA Signature Scheme with Appendix - Probabilistic Signature Scheme (PSS)
*
* @param {RSAPublicKey | RSAPrivateKey} key - RSA 公钥或私钥 / RSA public or private key
* @param {Hash} [hash] - 散列函数 / Hash function (default: SHA-256)
* @param {MGF} [mgf] - 掩码生成函数 / Mask generation function (default: MGF1)
* @param {number} [sLen] - 盐长度 / Salt length (default: hash.DIGEST_SIZE)
*/
export function pkcs1_ssa_pss(key, hash = sha256, mgf = mgf1(hash), sLen = hash.DIGEST_SIZE) {
const modBits = getBIBits(key.n);
const k = (modBits + 7) >> 3;
const emLen = (modBits + 6) >> 3;
const emsa = emsa_pss(hash, mgf, sLen);
const _rsa = rsa(key);
const sign = (M) => {
const EM = emsa.encode(M, modBits - 1);
const S = _rsa.sign(EM);
return U8.fromBI(S, k);
};
const verify = (M, S) => {
if (S.length !== k) {
return false;
}
const EM = U8.fromBI(_rsa.verify(S), emLen);
return emsa.verify(M, EM, modBits - 1);
};
return { sign, verify };
}
/**
* RSA 附录签名方案 (PKCS#1 v1.5)
*
* RSA Signature Scheme with Appendix (PKCS#1 v1.5)
*
* @param {RSAPublicKey | RSAPrivateKey} key - RSA 公钥或私钥 / RSA public or private key
* @param {Hash} [hash] - 散列函数 / Hash function (default: SHA-256)
*/
export function pkcs1_ssa_1_5(key, hash = sha256) {
const modBits = getBIBits(key.n);
const k = (modBits + 7) >> 3;
const _rsa = rsa(key);
const sign = (M) => {
const EM = emsa_1_5(M, k, hash);
const S = _rsa.sign(EM);
return U8.fromBI(S, k);
};
const verify = (M, S) => {
if (S.length !== k) {
return false;
}
const EM = U8.fromBI(_rsa.verify(S), k);
const EM2 = emsa_1_5(M, k, hash);
return EM.every((v, i) => v === EM2[i]);
};
return { sign, verify };
}
// * Encoding Method for Signatures with Appendix
function emsa_pss(hash = sha256, mgf = mgf1(hash), sLen = hash.DIGEST_SIZE) {
const hLen = hash.DIGEST_SIZE;
const encode = (M, emBits) => {
const mHash = hash(M);
const emLen = (emBits + 7) >> 3;
if (emLen < hLen + sLen + 2) {
throw new KitError('Encoding error');
}
const salt = new U8(sLen);
crypto.getRandomValues(salt);
const M2 = joinBuffer(new U8(8), mHash, salt);
const H = hash(M2);
const PS = new U8(emLen - sLen - hLen - 2);
const DB = joinBuffer(PS, new U8([0x01]), salt);
const dbMask = mgf(H, DB.length);
const maskedDB = DB.map((v, i) => v ^ dbMask[i]);
const bitMask = 0xFF >> (emLen << 3) - emBits;
maskedDB[0] &= bitMask;
const EM = joinBuffer(maskedDB, H, new U8([0xBC]));
return EM;
};
const verify = (M, EM, emBits) => {
const mHash = hash(M);
const emLen = (emBits + 7) >> 3;
if (emLen !== EM.length || emLen < hLen + sLen + 2) {
return false;
}
if (EM[emLen - 1] !== 0xBC) {
return false;
}
const maskedDB = EM.subarray(0, emLen - hLen - 1);
const H = EM.subarray(maskedDB.length, emLen - 1);
const bitMask = 0xFF >> (emLen << 3) - emBits;
if (maskedDB[0] > bitMask) {
return false;
}
const dbMask = mgf(H, maskedDB.length);
const DB = maskedDB.map((v, i) => v ^ dbMask[i]);
DB[0] &= bitMask;
const PS = DB.subarray(0, DB.length - sLen - 1);
if (PS.some(v => v !== 0x00)) {
return false;
}
if (DB[PS.length] !== 0x01) {
return false;
}
const salt = DB.subarray(PS.length + 1);
const M2 = joinBuffer(new U8(8), mHash, salt);
const H2 = hash(M2);
return H2.every((v, i) => v === H[i]);
};
return { encode, verify };
}
function emsa_1_5(M, emLen, hash = sha256) {
const H = hash(M);
const digestAlgorithm = ASN1.SEQUENCE([
ASN1.OBJECT_IDENTIFIER(hash.OID),
ASN1.NULL(),
]);
const digest = ASN1.OCTET_STRING(H);
const DigestInfo = ASN1.SEQUENCE([
digestAlgorithm,
digest,
]);
const T = DigestInfo;
const psLen = emLen - T.length - 3;
if (psLen < 8) {
throw new KitError('intended encoded message length too short');
}
const PS = new U8(psLen).fill(0xFF);
const EM = joinBuffer(new U8([0x00, 0x01]), PS, new U8([0x00]), T);
return EM;
}
import { genPrime } from '../../core/prime';
import { KitError, U8, gcd, lcm, mod, modInverse, modPow } from '../../core/utils';
// * RSA Algorithm
/**
* RSA 加密原语
*
* RSA encryption primitive
*/
function encryptionPrimitive(key, M) {
const { n, e } = key;
if (e === undefined || n === undefined) {
throw new KitError('Invalid public key');
}
M = typeof M === 'bigint' ? M : U8.from(M).toBI();
if (M >= n) {
throw new KitError('Message representative out of range');
}
return modPow(M, e, n);
}
/**
* RSA 解密原语
*
* RSA decryption primitive
*/
function decryptionPrimitive(key, C) {
const { n, d } = key;
if (d === undefined || n === undefined) {
throw new KitError('Invalid private key');
}
C = typeof C === 'bigint' ? C : U8.from(C).toBI();
if (C >= n) {
throw new KitError('Ciphertext representative out of range');
}
return modPow(C, d, n);
}
/**
* RSA 签名原语
*
* RSA signature primitive
*/
function signaturePrimitive(key, M) {
const { n, d } = key;
if (d === undefined || n === undefined) {
throw new KitError('Invalid private key');
}
M = typeof M === 'bigint' ? M : U8.from(M).toBI();
if (M >= n) {
throw new KitError('Message representative out of range');
}
return modPow(M, d, n);
}
/**
* RSA 验证原语
*
* RSA verification primitive
*/
function verificationPrimitive(key, S) {
const { n, e } = key;
if (e === undefined || n === undefined) {
throw new KitError('Invalid public key');
}
S = typeof S === 'bigint' ? S : U8.from(S).toBI();
if (S >= n) {
throw new KitError('Signature is too long');
}
return modPow(S, e, n);
}
/**
* RSA 密钥生成
*
* RSA key generation
*
* @param {number} b - RSA 私钥长度 / RSA private key length (bit)
* @param {RandomPrimeGenerator} rpg - 随机素数生成器 / Random prime generator
*/
function genKey(b, rpg = genPrime) {
const p = rpg(b >> 1);
const q = rpg(b >> 1);
const n = p * q;
const λ = lcm(p - 1n, q - 1n);
// public key
const e = 65537n;
if (gcd(e, λ) !== 1n) {
throw new KitError('Invalid public exponent');
}
// private key
const d = modInverse(e, λ);
const dP = mod(d, p - 1n);
const dQ = mod(d, q - 1n);
const qInv = modInverse(q, p);
const privateKey = { n, e, d, p, q, dP, dQ, qInv };
return privateKey;
}
function fromKey(key) {
const encrypt = (M) => encryptionPrimitive(key, M);
const decrypt = (C) => decryptionPrimitive(key, C);
const sign = (M) => signaturePrimitive(key, M);
const verify = (S) => verificationPrimitive(key, S);
return {
...key,
encrypt,
decrypt,
sign,
verify,
};
}
export function rsa(b, rpg = genPrime) {
if (typeof b === 'number') {
return fromKey(genKey(b, rpg));
}
return fromKey(b);
}
import { sm2p256v1 } from '../../core/ecParams';
import { x963kdf } from '../../core/kdf';
import { sm3 } from '../../hash/sm3';
import { KitError, U8, genBitMask, getBIBits, joinBuffer, mod, modInverse } from '../../core/utils';
import { FpECC } from './ecc';
/**
* SM2 椭圆曲线公钥密码算法
*
* Public Key Cryptography Algorithm SM2 Based on Elliptic Curves
*
* @param {FpECParams} curve - 椭圆曲线参数 / Elliptic Curve Parameters (default: sm2p256v1)
*/
export function sm2(curve = sm2p256v1) {
const { p, a, b, G, n, h } = curve;
const p_bit = getBIBits(p);
const p_byte = (p_bit + 7) >> 3;
const ecc = FpECC(curve);
const { addPoint, mulPoint } = ecc.utils;
const a_buffer = U8.fromBI(a);
const b_buffer = U8.fromBI(b);
const Gx_buffer = U8.fromBI(G.x);
const Gy_buffer = U8.fromBI(G.y);
const gen = ecc.gen;
const isLegalPK = ecc.utils.isLegalPK;
const PointToU8 = ecc.utils.PointToU8;
const U8ToPoint = ecc.utils.U8ToPoint;
const di = (id, key, hash = sm3) => {
const ent = id.length << 3;
if (ent > 0xFFFF) {
throw new KitError('ID长度超过了最大限制');
}
const ENT = new Uint8Array([ent >> 8, ent & 0xFF]);
const a = a_buffer;
const b = b_buffer;
const Gx = Gx_buffer;
const Gy = Gy_buffer;
const Ax = typeof key.Q.x === 'bigint' ? U8.fromBI(key.Q.x) : U8.from(key.Q.x);
const Ay = typeof key.Q.y === 'bigint' ? U8.fromBI(key.Q.y) : U8.from(key.Q.y);
const ZA = hash(joinBuffer(ENT, id, a, b, Gx, Gy, Ax, Ay));
return ZA;
};
const w = Math.ceil(getBIBits(n) / 2) - 1;
const w_mask = genBitMask(w);
const dh = (KA, KX, KB, KY, ZA = new Uint8Array(), ZB = new Uint8Array()) => {
if (isLegalPK(KB) === false || isLegalPK(KY) === false) {
throw new KitError('非法的公钥');
}
const KA_d = typeof KA.d === 'bigint' ? KA.d : U8.from(KA.d).toBI();
const KX_d = typeof KX.d === 'bigint' ? KX.d : U8.from(KX.d).toBI();
const KX_Q_x = typeof KX.Q.x === 'bigint' ? KX.Q.x : U8.from(KX.Q.x).toBI();
const KY_Q_x = typeof KY.Q.x === 'bigint' ? KY.Q.x : U8.from(KY.Q.x).toBI();
const x1 = (1n << BigInt(w)) + (KX_Q_x & w_mask);
const x2 = (1n << BigInt(w)) + (KY_Q_x & w_mask);
const t = mod(KA_d + KX_d * x1, n);
const V = mulPoint(addPoint(KB.Q, mulPoint(KY.Q, x2)), h * t);
if (V.isInfinity) {
throw new KitError('协商失败');
}
const xu = U8.fromBI(V.x);
const yu = U8.fromBI(V.y);
return joinBuffer(xu, yu, ZA, ZB);
};
const dsa = (hash = sm3) => {
if (hash.DIGEST_SIZE !== 32) {
throw new KitError('不支持的哈希算法');
}
const sign = (Z, key, M) => {
const dA = typeof key.d === 'bigint' ? key.d : U8.from(key.d).toBI();
let r = 0n;
let s = 0n;
const e = hash(joinBuffer(Z, M)).toBI();
do {
const k = gen('private_key').d.toBI();
const p = mulPoint(G, k);
r = mod(e + p.x, n);
if (r === 0n || r + k === n) {
continue;
}
const numerator = mod(k - r * dA, n);
const denominator = modInverse(1n + dA, n);
s = mod(numerator * denominator, n);
if (s === 0n) {
continue;
}
break;
} while (1);
const r_buffer = new U8(p_byte);
const s_buffer = new U8(p_byte);
r_buffer.set(U8.fromBI(r));
s_buffer.set(U8.fromBI(s));
return { r: r_buffer, s: s_buffer };
};
const verify = (Z, key, M, S) => {
const PA = key.Q;
const r = typeof S.r === 'bigint' ? S.r : U8.from(S.r).toBI();
const s = typeof S.s === 'bigint' ? S.s : U8.from(S.s).toBI();
if (r <= 0n || r >= n || s <= 0n || s >= n) {
return false;
}
const e = hash(joinBuffer(Z, M)).toBI();
const t = mod(r + s, n);
if (t === 0n) {
return false;
}
const p = addPoint(mulPoint(G, s), mulPoint(PA, t));
const R = mod(e + p.x, n);
return R === r;
};
return { sign, verify };
};
const es = (hash = sm3, kdf = x963kdf(sm3), order = 'c1c3c2') => {
const encrypt = (p_key, M) => {
const C1 = gen();
const S = mulPoint(p_key.Q, h);
if (S.isInfinity) {
throw new KitError('加密失败');
}
const { x, y } = mulPoint(p_key.Q, C1.d);
const x2 = U8.fromBI(x);
const y2 = U8.fromBI(y);
const ikm = joinBuffer(x2, y2);
const C2 = kdf(M.length << 3, ikm);
C2.forEach((_, i) => C2[i] ^= M[i]);
const C3 = hash(joinBuffer(x2, M, y2));
if (order === 'c1c2c3') {
return joinBuffer(PointToU8(C1.Q), C2, C3);
}
else {
return joinBuffer(PointToU8(C1.Q), C3, C2);
}
};
const decrypt = (s_key, C) => {
const C1_Length = (p_byte << 1) + 1;
const C3_Length = hash.DIGEST_SIZE;
const C2_Length = C.length - C1_Length - C3_Length;
const C1 = U8ToPoint(C.subarray(0, C1_Length));
const S = mulPoint(C1, h);
if (S.isInfinity) {
throw new KitError('解密失败');
}
const { x, y } = mulPoint(C1, s_key.d);
const x2 = U8.fromBI(x);
const y2 = U8.fromBI(y);
const ikm = joinBuffer(x2, y2);
const t = kdf(C2_Length << 3, ikm);
let C2;
let C3;
if (order === 'c1c2c3') {
C2 = C.subarray(C1_Length, C1_Length + C2_Length);
C3 = C.subarray(C1_Length + C2_Length);
}
else {
C3 = C.subarray(C1_Length, C1_Length + C3_Length);
C2 = C.subarray(C1_Length + C3_Length);
}
const M = t.map((_, i) => t[i] ^ C2[i]);
const u = hash(joinBuffer(x2, M, y2));
u.forEach((_, i) => {
if (u[i] !== C3[i]) {
throw new KitError('解密失败');
}
});
return M;
};
return { encrypt, decrypt };
};
return {
utils: ecc.utils,
gen,
di,
es,
dh,
dsa,
};
}
import { Fp } from '../../core/ec';
import { curve25519, curve448 } from '../../core/ecParams';
import { KitError, U8, genRandomBI, getBIBits } from '../../core/utils';
// * X25519 & X448 Algorithms
function cSwap(swap, x_2, x_3) {
const mask = -swap;
const dummy = mask & (x_2 ^ x_3);
x_2 ^= dummy;
x_3 ^= dummy;
return [x_2, x_3];
}
/** 蒙哥马利梯子算法 / Montgomery Ladder Algorithm */
function ladder(k, u, p, a24, bit) {
const { plus, subtract, pow, multiply } = Fp(p);
let x_2 = 1n;
let z_2 = 0n;
let x_3 = u;
let z_3 = 1n;
let swap = 0n;
const bit_array = k.toString(2).padStart(bit, '0').split('').map(BigInt);
for (const bit of bit_array) {
swap ^= bit;
[x_2, x_3] = cSwap(swap, x_2, x_3);
[z_2, z_3] = cSwap(swap, z_2, z_3);
swap = bit;
const A = plus(x_2, z_2);
const AA = pow(A, 2n);
const B = subtract(x_2, z_2);
const BB = pow(B, 2n);
const E = subtract(AA, BB);
const C = plus(x_3, z_3);
const D = subtract(x_3, z_3);
const DA = multiply(D, A);
const CB = multiply(C, B);
x_3 = pow(plus(DA, CB), 2n);
z_3 = multiply(u, pow(subtract(DA, CB), 2n));
x_2 = multiply(AA, BB);
z_2 = multiply(E, plus(AA, multiply(E, a24)));
}
[x_2, x_3] = cSwap(swap, x_2, x_3);
[z_2, z_3] = cSwap(swap, z_2, z_3);
return multiply(x_2, pow(z_2, p - 2n));
}
/** x25519 椭圆曲线算法 / Elliptic Curve Algorithm */
export const x25519 = (() => {
const { p, G, n } = curve25519;
const p_bit = getBIBits(p);
const p_byte = (p_bit + 7) >> 3;
const a24 = 121665n;
const Gx = typeof G.x === 'bigint' ? G.x : U8.from(G.x).toBI();
function clamp(d) {
d = d & 0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8n;
d = d | 0x4000000000000000000000000000000000000000000000000000000000000000n;
return d;
}
function gen(type = 'key_pair', s_key) {
if (type === 'key_pair') {
// private key
const t = genRandomBI(n, p_byte);
const d_buffer = t.buffer;
const d = t.result;
// public key
const x = ladder(clamp(d), Gx, p, a24, 255);
const Q = U8.fromBI(x, p_byte);
return { Q, d: d_buffer };
}
else if (type === 'private_key') {
return { d: genRandomBI(n, p_byte).buffer };
}
else if (type === 'public_key') {
const d_buffer = typeof s_key.d === 'bigint' ? U8.fromBI(s_key.d) : U8.from(s_key.d);
const d = typeof s_key.d === 'bigint' ? s_key.d : d_buffer.toBI();
if (d === 0n) {
throw new KitError('Invalid private key');
}
const x = ladder(clamp(d), Gx, p, a24, 255);
const Q = U8.fromBI(x, p_byte);
return { Q, d: d_buffer };
}
}
const ecdh = (s_key, p_key) => {
const u = typeof p_key.Q === 'bigint' ? p_key.Q : U8.from(p_key.Q).toBI();
const k = typeof s_key.d === 'bigint' ? s_key.d : U8.from(s_key.d).toBI();
const x = ladder(clamp(k), u, p, a24, 255);
return U8.fromBI(x, p_byte);
};
return { gen, dh: ecdh };
})();
/** x448 椭圆曲线算法 / Elliptic Curve Algorithm */
export const x448 = (() => {
const { p, G, n } = curve448;
const p_bit = getBIBits(p);
const p_byte = (p_bit + 7) >> 3;
const a24 = 39081n;
const Gx = typeof G.x === 'bigint' ? G.x : U8.from(G.x).toBI();
function clamp(d) {
d = d & 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcn;
d = d | 0x8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n;
return d;
}
function gen(type = 'key_pair', s_key) {
if (type === 'key_pair') {
// private key
const t = genRandomBI(n, p_byte);
const d_buffer = t.buffer;
const d = t.result;
// public key
const x = ladder(clamp(d), Gx, p, a24, 448);
const Q = U8.fromBI(x, p_byte);
return { Q, d: d_buffer };
}
else if (type === 'private_key') {
return { d: genRandomBI(n, p_byte).buffer };
}
else if (type === 'public_key') {
const d_buffer = typeof s_key.d === 'bigint' ? U8.fromBI(s_key.d) : U8.from(s_key.d);
const d = typeof s_key.d === 'bigint' ? s_key.d : d_buffer.toBI();
if (d === 0n) {
throw new KitError('Invalid private key');
}
const x = ladder(clamp(d), Gx, p, a24, 448);
const Q = U8.fromBI(x, p_byte);
return { Q, d: d_buffer };
}
}
const ecdh = (s_key, p_key) => {
const u = typeof p_key.Q === 'bigint' ? p_key.Q : U8.from(p_key.Q).toBI();
const k = typeof s_key.d === 'bigint' ? s_key.d : U8.from(s_key.d).toBI();
const x = ladder(clamp(k), u, p, a24, 448);
return U8.fromBI(x, p_byte);
};
return { gen, dh: ecdh };
})();
import { createCipher } from '../../core/cipher';
import { KitError, U8 } from '../../core/utils';
// * Functions
function KSA(K) {
const SBox = new Uint8Array(256);
SBox.forEach((_, i) => SBox[i] = i);
let j = 0;
for (let i = 0; i < 256; i++) {
j = (j + SBox[i] + K[i % K.byteLength]) % 256;
[SBox[i], SBox[j]] = [SBox[j], SBox[i]];
}
return SBox;
}
// * RC4 Algorithm
function cipher(M, SBox) {
SBox = SBox.slice(0);
const result = new U8(M.byteLength);
let i = 0;
let j = 0;
M.forEach((_, k) => {
i = (i + 1) % 256;
j = (j + SBox[i]) % 256;
[SBox[i], SBox[j]] = [SBox[j], SBox[i]];
result[k] = M[k] ^ SBox[(SBox[i] + SBox[j]) % 256];
});
return result;
}
function _arc4(K) {
if (K.byteLength < 5 || K.byteLength > 256) {
throw new KitError(`RC4 key must be between 5 and 256 byte`);
}
const SBox = KSA(K);
return {
encrypt: (M) => cipher(M, SBox),
decrypt: (M) => cipher(M, SBox),
};
}
/**
* ARC4 流密码 / stream cipher
*/
export const arc4 = createCipher(_arc4, {
ALGORITHM: `ARC4`,
KEY_SIZE: 16,
MIN_KEY_SIZE: 5,
MAX_KEY_SIZE: 256,
});
import { createCipher } from '../../core/cipher';
import { KitError, U8, resizeBuffer, rotateL32 } from '../../core/utils';
// * Constants
const A = new Uint32Array([0x4D34D34D, 0xD34D34D3, 0x34D34D34, 0x4D34D34D, 0xD34D34D3, 0x34D34D34, 0x4D34D34D, 0xD34D34D3]);
// * Rabbit Algorithm
function _rabbit(key, iv) {
if (key.length !== 16) {
throw new KitError('Rabbit key must be 16 byte');
}
// 内部状态
let carray = 0;
const X = new Uint8Array(32);
const C = new Uint8Array(32);
const X32 = new Uint32Array(X.buffer);
const C32 = new Uint32Array(C.buffer);
const nextState = (skipExtract = false) => {
// Counter System
for (let i = 0; i < 8; i++) {
const T = C32[i] + A[i] + carray;
C32[i] = T | 0;
carray = T > 0xFFFFFFFF ? 1 : 0;
}
// G
const G = new Uint32Array(8);
for (let i = 0; i < 8; i++) {
const T = (BigInt(X32[i]) + BigInt(C32[i])) & 0xffffffffn;
const S = T * T;
G[i] = Number((S ^ (S >> 32n)) & 0xffffffffn);
}
// Next State
X32[0] = 0xFFFFFFFF & (G[0] + rotateL32(G[7], 16) + rotateL32(G[6], 16));
X32[1] = 0xFFFFFFFF & (G[1] + rotateL32(G[0], 8) + G[7]);
X32[2] = 0xFFFFFFFF & (G[2] + rotateL32(G[1], 16) + rotateL32(G[0], 16));
X32[3] = 0xFFFFFFFF & (G[3] + rotateL32(G[2], 8) + G[1]);
X32[4] = 0xFFFFFFFF & (G[4] + rotateL32(G[3], 16) + rotateL32(G[2], 16));
X32[5] = 0xFFFFFFFF & (G[5] + rotateL32(G[4], 8) + G[3]);
X32[6] = 0xFFFFFFFF & (G[6] + rotateL32(G[5], 16) + rotateL32(G[4], 16));
X32[7] = 0xFFFFFFFF & (G[7] + rotateL32(G[6], 8) + G[5]);
if (skipExtract) {
return new Uint8Array();
}
// Extract Output
const S = new Uint32Array(4);
S[0] = X32[0] ^ (X32[5] >>> 16) ^ (X32[3] << 16);
S[1] = X32[2] ^ (X32[7] >>> 16) ^ (X32[5] << 16);
S[2] = X32[4] ^ (X32[1] >>> 16) ^ (X32[7] << 16);
S[3] = X32[6] ^ (X32[3] >>> 16) ^ (X32[1] << 16);
return new Uint8Array(S.buffer);
};
// 初始化
(() => {
// 配置密钥
const K16 = new Uint16Array(key.buffer);
for (let i = 0; i < 8; i++) {
if ((i & 1) === 0) {
const KH = K16[(i + 1) % 8];
const KL = K16[i];
X32[i] = (KH << 16) | KL;
const CH = K16[(i + 4) % 8];
const CL = K16[(i + 5) % 8];
C32[i] = (CH << 16) | CL;
}
else {
const KH = K16[(i + 5) % 8];
const KL = K16[(i + 4) % 8];
X32[i] = (KH << 16) | KL;
const CH = K16[i];
const CL = K16[(i + 1) % 8];
C32[i] = (CH << 16) | CL;
}
}
for (let i = 0; i < 4; i++) {
nextState(true);
}
for (let i = 0; i < 8; i++) {
C32[i] ^= X32[(i + 4) % 8];
}
// 配置 IV
if (iv.length === 8) {
const iv32 = new Uint32Array(iv.buffer);
const iv16 = new Uint16Array(iv.buffer);
C32[0] ^= iv32[0];
C32[1] ^= (iv16[3] << 16) | iv16[1];
C32[2] ^= iv32[1];
C32[3] ^= (iv16[2] << 16) | iv16[0];
C32[4] ^= iv32[0];
C32[5] ^= (iv16[3] << 16) | iv16[1];
C32[6] ^= iv32[1];
C32[7] ^= (iv16[2] << 16) | iv16[0];
for (let i = 0; i < 4; i++) {
nextState(true);
}
}
else if (iv.length !== 0 && iv.length !== 8) {
throw new KitError('Rabbit iv must be 8 byte');
}
})();
// 密钥流
let S = nextState();
let current = 1;
const squeeze = (count) => {
if (current >= count) {
return S;
}
S = resizeBuffer(S, count << 4);
while (current < count) {
S.set(nextState(), current << 4);
current++;
}
return S;
};
const cipher = (M) => {
const BLOCK_TOTAL = Math.ceil(M.length >> 4) || 1;
S = squeeze(BLOCK_TOTAL);
return new U8(M.map((_, i) => _ ^ S[i]));
};
return {
encrypt: (M) => cipher(M),
decrypt: (C) => cipher(C),
};
}
/**
* Rabbit 流密码 / stream cipher
*/
export const rabbit = createCipher(_rabbit, {
ALGORITHM: 'rabbit',
KEY_SIZE: 16,
MIN_KEY_SIZE: 16,
MAX_KEY_SIZE: 16,
IV_SIZE: 8,
MIN_IV_SIZE: 0,
MAX_IV_SIZE: 8,
});
import { createCipher } from '../../core/cipher';
import { Counter, KitError, U8, resizeBuffer, rotateL32 } from '../../core/utils';
// * Functions
function QR(a, b, c, d) {
b ^= rotateL32(a + d, 7);
c ^= rotateL32(b + a, 9);
d ^= rotateL32(c + b, 13);
a ^= rotateL32(d + c, 18);
return [a, b, c, d];
}
function hash(x, rounds = 20) {
// to word
const X = new Uint32Array(x.buffer);
const W = X.slice(0);
// main loop
for (let i = 0; i < rounds; i += 2) {
// ODD Rounds
[W[0], W[4], W[8], W[12]] = QR(W[0], W[4], W[8], W[12]);
[W[5], W[9], W[13], W[1]] = QR(W[5], W[9], W[13], W[1]);
[W[10], W[14], W[2], W[6]] = QR(W[10], W[14], W[2], W[6]);
[W[15], W[3], W[7], W[11]] = QR(W[15], W[3], W[7], W[11]);
// EVEN Rounds
[W[0], W[1], W[2], W[3]] = QR(W[0], W[1], W[2], W[3]);
[W[5], W[6], W[7], W[4]] = QR(W[5], W[6], W[7], W[4]);
[W[10], W[11], W[8], W[9]] = QR(W[10], W[11], W[8], W[9]);
[W[15], W[12], W[13], W[14]] = QR(W[15], W[12], W[13], W[14]);
}
// mix
const Z = new U8(64);
const Z32 = new Uint32Array(Z.buffer);
for (let i = 0; i < 16; i++) {
Z32[i] = X[i] + W[i];
}
return Z;
}
function expand(K, iv) {
if (iv.byteLength !== 8) {
throw new KitError(`Salsa20 iv must be 8 byte`);
}
const S = new Counter(64);
const S32 = new Uint32Array(S.buffer);
const K32 = new Uint32Array(K.buffer);
const N32 = new Uint32Array(iv.buffer);
switch (K.byteLength) {
case 16: // use tau
S32[0] = 0x61707865;
S32[1] = K32[0];
S32[2] = K32[1];
S32[3] = K32[2];
S32[4] = K32[3];
S32[5] = 0x3120646E;
S32[6] = N32[0];
S32[7] = N32[1];
S32[10] = 0x79622D36;
S32[11] = K32[0];
S32[12] = K32[1];
S32[13] = K32[2];
S32[14] = K32[3];
S32[15] = 0x6B206574;
break;
case 32: // use sigma
S32[0] = 0x61707865;
S32[1] = K32[0];
S32[2] = K32[1];
S32[3] = K32[2];
S32[4] = K32[3];
S32[5] = 0x3320646E;
S32[6] = N32[0];
S32[7] = N32[1];
S32[10] = 0x79622D32;
S32[11] = K32[4];
S32[12] = K32[5];
S32[13] = K32[6];
S32[14] = K32[7];
S32[15] = 0x6B206574;
break;
default:
throw new KitError(`Salsa20 key must be 16 or 32 byte`);
}
return S;
}
// * Salsa20 Algorithm
function _salsa20(key, iv) {
/** Counter Block */
const E = expand(key, iv);
/** Presudo Random Byte Stream */
let S = hash(E);
let current = 1;
const cipher = (M) => {
const R = U8.from(M);
const BLOCK_TOTAL = (R.length >> 6) + 1;
if (current > BLOCK_TOTAL) {
return R.map((byte, i) => byte ^ S[i]);
}
// Squeeze
S = resizeBuffer(S, BLOCK_TOTAL << 6);
while (BLOCK_TOTAL > current) {
E.inc(32, 8, true);
S.set(hash(E), current << 6);
current++;
}
return R.map((byte, i) => byte ^ S[i]);
};
return {
encrypt: (M) => cipher(M),
decrypt: (C) => cipher(C),
};
}
/**
* Salsa20 流密码 / Stream Cipher
*/
export const salsa20 = createCipher(_salsa20, {
ALGORITHM: 'Salsa20',
KEY_SIZE: 32,
MIN_KEY_SIZE: 16,
MAX_KEY_SIZE: 32,
IV_SIZE: 8,
MIN_IV_SIZE: 8,
MAX_IV_SIZE: 8,
});
import { KitError, U8, rotateL32, wrap } from '../../core/utils';
// * Constants
const S0 = new Uint8Array([0x3E, 0x72, 0x5B, 0x47, 0xCA, 0xE0, 0x00, 0x33, 0x04, 0xD1, 0x54, 0x98, 0x09, 0xB9, 0x6D, 0xCB, 0x7B, 0x1B, 0xF9, 0x32, 0xAF, 0x9D, 0x6A, 0xA5, 0xB8, 0x2D, 0xFC, 0x1D, 0x08, 0x53, 0x03, 0x90, 0x4D, 0x4E, 0x84, 0x99, 0xE4, 0xCE, 0xD9, 0x91, 0xDD, 0xB6, 0x85, 0x48, 0x8B, 0x29, 0x6E, 0xAC, 0xCD, 0xC1, 0xF8, 0x1E, 0x73, 0x43, 0x69, 0xC6, 0xB5, 0xBD, 0xFD, 0x39, 0x63, 0x20, 0xD4, 0x38, 0x76, 0x7D, 0xB2, 0xA7, 0xCF, 0xED, 0x57, 0xC5, 0xF3, 0x2C, 0xBB, 0x14, 0x21, 0x06, 0x55, 0x9B, 0xE3, 0xEF, 0x5E, 0x31, 0x4F, 0x7F, 0x5A, 0xA4, 0x0D, 0x82, 0x51, 0x49, 0x5F, 0xBA, 0x58, 0x1C, 0x4A, 0x16, 0xD5, 0x17, 0xA8, 0x92, 0x24, 0x1F, 0x8C, 0xFF, 0xD8, 0xAE, 0x2E, 0x01, 0xD3, 0xAD, 0x3B, 0x4B, 0xDA, 0x46, 0xEB, 0xC9, 0xDE, 0x9A, 0x8F, 0x87, 0xD7, 0x3A, 0x80, 0x6F, 0x2F, 0xC8, 0xB1, 0xB4, 0x37, 0xF7, 0x0A, 0x22, 0x13, 0x28, 0x7C, 0xCC, 0x3C, 0x89, 0xC7, 0xC3, 0x96, 0x56, 0x07, 0xBF, 0x7E, 0xF0, 0x0B, 0x2B, 0x97, 0x52, 0x35, 0x41, 0x79, 0x61, 0xA6, 0x4C, 0x10, 0xFE, 0xBC, 0x26, 0x95, 0x88, 0x8A, 0xB0, 0xA3, 0xFB, 0xC0, 0x18, 0x94, 0xF2, 0xE1, 0xE5, 0xE9, 0x5D, 0xD0, 0xDC, 0x11, 0x66, 0x64, 0x5C, 0xEC, 0x59, 0x42, 0x75, 0x12, 0xF5, 0x74, 0x9C, 0xAA, 0x23, 0x0E, 0x86, 0xAB, 0xBE, 0x2A, 0x02, 0xE7, 0x67, 0xE6, 0x44, 0xA2, 0x6C, 0xC2, 0x93, 0x9F, 0xF1, 0xF6, 0xFA, 0x36, 0xD2, 0x50, 0x68, 0x9E, 0x62, 0x71, 0x15, 0x3D, 0xD6, 0x40, 0xC4, 0xE2, 0x0F, 0x8E, 0x83, 0x77, 0x6B, 0x25, 0x05, 0x3F, 0x0C, 0x30, 0xEA, 0x70, 0xB7, 0xA1, 0xE8, 0xA9, 0x65, 0x8D, 0x27, 0x1A, 0xDB, 0x81, 0xB3, 0xA0, 0xF4, 0x45, 0x7A, 0x19, 0xDF, 0xEE, 0x78, 0x34, 0x60]);
const S1 = new Uint8Array([0x55, 0xC2, 0x63, 0x71, 0x3B, 0xC8, 0x47, 0x86, 0x9F, 0x3C, 0xDA, 0x5B, 0x29, 0xAA, 0xFD, 0x77, 0x8C, 0xC5, 0x94, 0x0C, 0xA6, 0x1A, 0x13, 0x00, 0xE3, 0xA8, 0x16, 0x72, 0x40, 0xF9, 0xF8, 0x42, 0x44, 0x26, 0x68, 0x96, 0x81, 0xD9, 0x45, 0x3E, 0x10, 0x76, 0xC6, 0xA7, 0x8B, 0x39, 0x43, 0xE1, 0x3A, 0xB5, 0x56, 0x2A, 0xC0, 0x6D, 0xB3, 0x05, 0x22, 0x66, 0xBF, 0xDC, 0x0B, 0xFA, 0x62, 0x48, 0xDD, 0x20, 0x11, 0x06, 0x36, 0xC9, 0xC1, 0xCF, 0xF6, 0x27, 0x52, 0xBB, 0x69, 0xF5, 0xD4, 0x87, 0x7F, 0x84, 0x4C, 0xD2, 0x9C, 0x57, 0xA4, 0xBC, 0x4F, 0x9A, 0xDF, 0xFE, 0xD6, 0x8D, 0x7A, 0xEB, 0x2B, 0x53, 0xD8, 0x5C, 0xA1, 0x14, 0x17, 0xFB, 0x23, 0xD5, 0x7D, 0x30, 0x67, 0x73, 0x08, 0x09, 0xEE, 0xB7, 0x70, 0x3F, 0x61, 0xB2, 0x19, 0x8E, 0x4E, 0xE5, 0x4B, 0x93, 0x8F, 0x5D, 0xDB, 0xA9, 0xAD, 0xF1, 0xAE, 0x2E, 0xCB, 0x0D, 0xFC, 0xF4, 0x2D, 0x46, 0x6E, 0x1D, 0x97, 0xE8, 0xD1, 0xE9, 0x4D, 0x37, 0xA5, 0x75, 0x5E, 0x83, 0x9E, 0xAB, 0x82, 0x9D, 0xB9, 0x1C, 0xE0, 0xCD, 0x49, 0x89, 0x01, 0xB6, 0xBD, 0x58, 0x24, 0xA2, 0x5F, 0x38, 0x78, 0x99, 0x15, 0x90, 0x50, 0xB8, 0x95, 0xE4, 0xD0, 0x91, 0xC7, 0xCE, 0xED, 0x0F, 0xB4, 0x6F, 0xA0, 0xCC, 0xF0, 0x02, 0x4A, 0x79, 0xC3, 0xDE, 0xA3, 0xEF, 0xEA, 0x51, 0xE6, 0x6B, 0x18, 0xEC, 0x1B, 0x2C, 0x80, 0xF7, 0x74, 0xE7, 0xFF, 0x21, 0x5A, 0x6A, 0x54, 0x1E, 0x41, 0x31, 0x92, 0x35, 0xC4, 0x33, 0x07, 0x0A, 0xBA, 0x7E, 0x0E, 0x34, 0x88, 0xB1, 0x98, 0x7C, 0xF3, 0x3D, 0x60, 0x6C, 0x7B, 0xCA, 0xD3, 0x1F, 0x32, 0x65, 0x04, 0x28, 0x64, 0xBE, 0x85, 0x9B, 0x2F, 0x59, 0x8A, 0xD7, 0xB0, 0x25, 0xAC, 0xAF, 0x12, 0x03, 0xE2, 0xF2]);
const D = new Uint16Array([0x44D7, 0x26BC, 0x626B, 0x135E, 0x5789, 0x35E2, 0x7135, 0x09AF, 0x4D78, 0x2F13, 0x6BC4, 0x1AF1, 0x5E26, 0x3C4D, 0x789A, 0x47AC]);
// * Functions
function mulPow2n(v, n) {
return ((v << n | v >>> (31 - n)) & 0x7FFFFFFF);
}
function addMod31(a, b) {
const c = a + b;
return (c & 0x7FFFFFFF) + (c >>> 31);
}
const L1 = (X) => X ^ rotateL32(X, 2) ^ rotateL32(X, 10) ^ rotateL32(X, 18) ^ rotateL32(X, 24);
const L2 = (X) => X ^ rotateL32(X, 8) ^ rotateL32(X, 14) ^ rotateL32(X, 22) ^ rotateL32(X, 30);
function BR(S, X) {
X[0] = (S[15] & 0x7FFF8000) << 1 | S[14] & 0xFFFF;
X[1] = (S[11] & 0x0000FFFF) << 16 | S[9] >>> 15;
X[2] = (S[7] & 0x0000FFFF) << 16 | S[5] >>> 15;
X[3] = (S[2] & 0x0000FFFF) << 16 | S[0] >>> 15;
}
function F(X0, X1, X2, R) {
const W = (X0 ^ R[0]) + R[1];
const W1 = (R[0] + X1) & 0xFFFFFFFF;
const W2 = R[1] ^ X2;
const r0 = L1((W1 << 16) | (W2 >>> 16));
R[0] = S0[r0 >>> 24] << 24 | S1[(r0 >>> 16) & 0xFF] << 16 | S0[(r0 >>> 8) & 0xFF] << 8 | S1[r0 & 0xFF];
const r1 = L2((W2 << 16) | (W1 >>> 16));
R[1] = S0[r1 >>> 24] << 24 | S1[(r1 >>> 16) & 0xFF] << 16 | S0[(r1 >>> 8) & 0xFF] << 8 | S1[r1 & 0xFF];
return W;
}
/**
* 线性反馈移位寄存器有两种运行模式:初始化模式和工作模式,当输入 `u` 时为初始化模式,否则为工作模式
*
* @param {Uint32Array} S - 线性反馈移位寄存器(LFSR)
* @param {number} u - 初始化模式下的输入
*/
function next(S, u) {
let s16, v;
s16 = S[0];
v = mulPow2n(S[0], 8);
s16 = addMod31(s16, v);
v = mulPow2n(S[4], 20);
s16 = addMod31(s16, v);
v = mulPow2n(S[10], 21);
s16 = addMod31(s16, v);
v = mulPow2n(S[13], 17);
s16 = addMod31(s16, v);
v = mulPow2n(S[15], 15);
s16 = addMod31(s16, v);
s16 = u ? addMod31(s16, u) : s16;
s16 = s16 || 0x7FFFFFFF;
for (let i = 0; i < 15; i++) {
S[i] = S[i + 1];
}
S[15] = s16;
}
// * ZUC Algorithm (presudo-random generator)
/**
* 3GPP ZUC 算法用于生成密钥流,每次调用返回一个 32 位的密钥流.
*
* 3GPP ZUC algorithm is used to generate a key stream, each call returns a 32-bit key stream.
*
* ```ts
* const K = new Uint8Array(16)
* const iv = new Uint8Array(16)
* const prg = zuc(K, iv)
* prg() // 32-bit number
* ```
*/
export function zuc(K, iv) {
if (K.byteLength !== 16) {
throw new KitError('ZUC requires a key of 16 bytes');
}
if (iv.byteLength !== 16) {
throw new KitError('ZUC requires an IV of 16 bytes');
}
const LFSR = new Uint32Array(16);
const X = new Uint32Array(4);
const R = new Uint32Array(2);
(function init() {
for (let i = 0; i < 16; i++) {
LFSR[i] = K[i] << 23 | D[i] << 8 | iv[i];
}
for (let i = 0; i < 32; i++) {
BR(LFSR, X);
const W = F(X[0], X[1], X[2], R);
next(LFSR, W >>> 1);
}
BR(LFSR, X);
F(X[0], X[1], X[2], R);
next(LFSR);
})();
return () => {
BR(LFSR, X);
const W = F(X[0], X[1], X[2], R) ^ X[3];
next(LFSR);
return W;
};
}
// * EEA3 & EIA3
function createEEA_IV(count, bearer, direction) {
const iv = new Uint8Array(16);
iv.set(count, 0);
iv[4] = bearer << 3 | direction << 2;
iv.set(iv.subarray(0, 5), 8);
return iv;
}
function createEIA_IV(count, bearer, direction) {
const iv = new Uint8Array(16);
iv.set(count, 0);
iv[4] = bearer << 3;
iv.set(iv.subarray(0, 5), 8);
iv[8] ^= direction << 7;
iv[14] ^= direction << 7;
return iv;
}
function getWord(Z, bit_offset) {
const ti = bit_offset % 8;
const byte_offset = bit_offset >>> 3;
const W = ti === 0
? Z.getUint32(byte_offset, false)
: Z.getUint32(byte_offset, false) << ti | Z.getUint32(byte_offset + 4, false) >>> (32 - ti);
return W & 0xFFFFFFFF;
}
/**
* 3GPP ZUC 加密算法 / Encryption algorithm
*/
export const eea3 = wrap((param) => {
const { BEARER, DIRECTION, KEY, M } = param;
let { COUNTER, LENGTH } = param;
// 转换参数
COUNTER = typeof COUNTER === 'number' ? new Uint8Array([COUNTER >> 24, COUNTER >> 16, COUNTER >> 8, COUNTER]) : COUNTER;
// 生成密钥流
LENGTH = M.byteLength << 3;
const WORD_COUNT = (LENGTH + 31) >> 5;
const EEA_KeyStream = new Uint8Array(WORD_COUNT << 2);
const KSView = new DataView(EEA_KeyStream.buffer);
const EEA_IV = createEEA_IV(COUNTER, BEARER, DIRECTION);
const prg = zuc(KEY, EEA_IV);
for (let i = 0; i < WORD_COUNT; i++) {
KSView.setUint32(i << 2, prg(), false);
}
// 加密
return new U8(M.map((_, i) => _ ^ EEA_KeyStream[i]));
}, {
ALGORITHM: 'ZUC-EEA3',
KEY_SIZE: 16,
});
/**
* 3GPP ZUC 完整性算法 / Integrity algorithm
*/
export const eia3 = wrap((param) => {
const { BEARER, DIRECTION, KEY, M } = param;
let { COUNTER, LENGTH } = param;
// 转换参数
COUNTER = typeof COUNTER === 'number' ? new Uint8Array([COUNTER >> 24, COUNTER >> 16, COUNTER >> 8, COUNTER]) : COUNTER;
// 生成密钥流
const N = LENGTH + 64;
const WORD_COUNT = N + 31 >> 5;
const EIA_KeyStream = new Uint8Array(WORD_COUNT << 2);
const KSView = new DataView(EIA_KeyStream.buffer);
const EIA_IV = createEIA_IV(COUNTER, BEARER, DIRECTION);
const prg = zuc(KEY, EIA_IV);
for (let i = 0; i < WORD_COUNT; i++) {
KSView.setUint32(i << 2, prg(), false);
}
// 计算 MAC
let t = 0;
for (let i = 0; i < LENGTH; i++) {
const bit = M[i >>> 3] & (1 << (7 - (i % 8)));
if (bit) {
t ^= getWord(KSView, i);
}
}
t ^= getWord(KSView, LENGTH);
t ^= KSView.getUint32(EIA_KeyStream.byteLength - 4);
return new U8([t >> 24, t >> 16, t >> 8, t]);
}, {
ALGORITHM: 'ZUC-EIA3',
KEY_SIZE: 16,
});
import { U8 } from './utils';
export const ASN1 = {
// 0x04
OCTET_STRING: (value) => {
const buffer = new U8(value.length + 2);
buffer.set([0x04, value.length], 0);
buffer.set(value, 2);
return buffer;
},
// 0x05
NULL: () => new U8([0x05, 0x00]),
// 0x06
OBJECT_IDENTIFIER: (id = '') => {
const node = id.split('.').map(Number);
const buffer = [];
buffer.push(node[0] * 40 + node[1]);
for (let i = 2; i < node.length; i++) {
let n = node[i];
if (n < 128) {
buffer.push(n);
}
else {
const bytes = [n & 0x7F];
n >>= 7;
while (n > 0) {
bytes.unshift((n & 0x7F) | 0x80);
n >>= 7;
}
buffer.push(...bytes);
}
}
return new U8([0x06, buffer.length, ...buffer]);
},
// 0x30
SEQUENCE: (value) => {
const length = value.reduce((sum, v) => sum + v.length, 0);
const buffer = new U8(length + 2);
buffer.set([0x30, length], 0);
let offset = 2;
for (const v of value) {
buffer.set(v, offset);
offset += v.length;
}
return buffer;
},
};
import { Counter, KitError, U8, joinBuffer, wrap } from './utils';
export function createCipher(algorithm, description) {
return wrap((key, iv) => wrap(algorithm(key, iv), description), description);
}
export function createPadding(doPad, unPad, description) {
return wrap((M, BLOCK_SIZE) => (typeof BLOCK_SIZE === 'number'
? doPad(M, BLOCK_SIZE)
: unPad(M)), description);
}
// * 填充方案
/** PKCS7 填充方案 / Padding Scheme */
export const PKCS7_PAD = createPadding((M, BLOCK_SIZE) => {
const pad = BLOCK_SIZE - M.length % BLOCK_SIZE;
return joinBuffer(M, new Uint8Array(pad).fill(pad));
}, (P) => {
const pad = P[P.length - 1];
return new U8(P.slice(0, P.length - pad));
}, { ALGORITHM: 'PKCS#7' });
/** ISO/IEC 7816 填充方案 / Padding Scheme */
export const ISO7816_PAD = createPadding((M, BLOCK_SIZE) => {
const BLOCK_TOTAL = Math.ceil((M.length + 1) / BLOCK_SIZE);
const P = new U8(BLOCK_TOTAL * BLOCK_SIZE);
P.set(M);
P[M.length] = 0x80;
return P;
}, (P) => {
let i = P.length - 1;
while (P[i] === 0x80) {
i = i - 1;
if (i < 0) {
console.warn('This message may not be ISO/IEC 7816-4 padded');
return new U8();
}
}
return new U8(P.slice(0, i + 1));
}, { ALGORITHM: 'ISO/IEC 7816-4' });
/** ANSI X9.23 填充方案 / Padding Scheme */
export const X923_PAD = createPadding((M, BLOCK_SIZE) => {
const BLOCK_TOTAL = Math.ceil((M.length + 1) / BLOCK_SIZE);
const P = new U8(BLOCK_TOTAL * BLOCK_SIZE);
P.set(M);
P[P.length - 1] = P.length - M.length;
return P;
}, (P) => {
const pad = P[P.length - 1];
return new U8(P.slice(0, P.length - pad));
}, { ALGORITHM: 'ANSI X9.23' });
/** Zero 零填充方案 / Padding Scheme */
export const ZERO_PAD = createPadding((M, BLOCK_SIZE) => {
const pad = BLOCK_SIZE - M.length % BLOCK_SIZE;
return joinBuffer(M, new Uint8Array(pad));
}, (P) => {
let i = P.length - 1;
while (P[i] === 0) {
i = i - 1;
if (i < 0) {
return new U8();
}
}
return new U8(P.slice(0, i + 1));
}, { ALGORITHM: 'Zero Padding' });
/** 无填充 / No Padding */
export const NO_PAD = createPadding((M) => new U8(M.slice(0)), (P) => new U8(P.slice(0)), { ALGORITHM: 'No Padding' });
/** 电子密码本模式 / Electronic Code Book Mode */
export const ecb = wrap((cipher, padding = PKCS7_PAD) => {
const info = {
ALGORITHM: `ECB-${cipher.ALGORITHM}`,
PADDING: padding,
BLOCK_SIZE: cipher.BLOCK_SIZE,
KEY_SIZE: cipher.KEY_SIZE,
MIN_KEY_SIZE: cipher.MIN_KEY_SIZE,
MAX_KEY_SIZE: cipher.MAX_KEY_SIZE,
IV_SIZE: 0,
MIN_IV_SIZE: 0,
MAX_IV_SIZE: 0,
};
const suite = (K) => {
const { BLOCK_SIZE } = cipher;
const c = cipher(K);
const encrypt = (M) => {
const P = padding(M, BLOCK_SIZE);
const C = new U8(P.length);
for (let i = 0; i < P.length;) {
const offset = i;
const B = P.subarray(i, i += BLOCK_SIZE);
C.set(c.encrypt(B), offset);
}
return C;
};
const decrypt = (C) => {
if (C.length % BLOCK_SIZE !== 0) {
throw new KitError('Decryption error');
}
const P = new U8(C.length);
for (let i = 0; i < C.length;) {
const offset = i;
const B = C.subarray(i, i += BLOCK_SIZE);
P.set(c.decrypt(B), offset);
}
return padding(P);
};
return wrap({ encrypt, decrypt }, info);
};
return wrap(suite, info);
}, { ALGORITHM: 'ECB' });
/** 密码块链接模式 / Cipher Block Chaining Mode */
export const cbc = wrap((cipher, padding = PKCS7_PAD) => {
const info = {
ALGORITHM: `CBC-${cipher.ALGORITHM}`,
PADDING: padding,
BLOCK_SIZE: cipher.BLOCK_SIZE,
KEY_SIZE: cipher.KEY_SIZE,
MIN_KEY_SIZE: cipher.MIN_KEY_SIZE,
MAX_KEY_SIZE: cipher.MAX_KEY_SIZE,
IV_SIZE: cipher.BLOCK_SIZE,
MIN_IV_SIZE: cipher.BLOCK_SIZE,
MAX_IV_SIZE: cipher.BLOCK_SIZE,
};
const suite = (K, iv) => {
// iv 检查
const { BLOCK_SIZE } = cipher;
if (iv.length !== BLOCK_SIZE) {
throw new KitError(`${info.ALGORITHM} iv must be ${BLOCK_SIZE} byte`);
}
const c = cipher(K);
const encrypt = (M) => {
const P = padding(M, BLOCK_SIZE);
const C = new U8(P.length);
let prev = iv.slice(0);
for (let i = 0; i < P.length;) {
const offset = i;
const B = P.subarray(i, i += BLOCK_SIZE);
prev.forEach((_, i) => prev[i] ^= B[i]);
prev = c.encrypt(prev);
C.set(prev, offset);
}
return C;
};
const decrypt = (C) => {
if (C.length % BLOCK_SIZE !== 0) {
throw new KitError('Decryption error');
}
const P = new U8(C.length);
let prev = iv;
for (let i = 0; i < C.length;) {
const offset = i;
const B = C.slice(i, i += BLOCK_SIZE);
c.decrypt(B).forEach((_, i) => prev[i] ^= _);
P.set(prev, offset);
prev = B;
}
return padding(P);
};
return wrap({ encrypt, decrypt }, info);
};
return wrap(suite, info);
}, { ALGORITHM: 'CBC' });
/** 传播密码块链接模式 / Propagating Cipher Block Chaining Mode */
export const pcbc = wrap((cipher, padding = PKCS7_PAD) => {
const info = {
ALGORITHM: `PCBC-${cipher.ALGORITHM}`,
PADDING: padding,
BLOCK_SIZE: cipher.BLOCK_SIZE,
KEY_SIZE: cipher.KEY_SIZE,
MIN_KEY_SIZE: cipher.MIN_KEY_SIZE,
MAX_KEY_SIZE: cipher.MAX_KEY_SIZE,
IV_SIZE: cipher.BLOCK_SIZE,
MIN_IV_SIZE: cipher.BLOCK_SIZE,
MAX_IV_SIZE: cipher.BLOCK_SIZE,
};
const suite = (K, IV) => {
// iv 检查
const { BLOCK_SIZE } = cipher;
if (IV.length !== BLOCK_SIZE) {
throw new KitError(`${info.ALGORITHM} iv must be ${BLOCK_SIZE} byte`);
}
const c = cipher(K);
const encrypt = (M) => {
const P = padding(M, BLOCK_SIZE);
const C = new U8(P.length);
const prev = IV.slice(0);
for (let i = 0; i < P.length;) {
const offset = i;
const B = P.subarray(i, i += BLOCK_SIZE);
prev.forEach((_, i) => prev[i] ^= B[i]);
const _C = c.encrypt(prev);
C.set(_C, offset);
prev.forEach((_, i) => prev[i] = _C[i] ^ B[i]);
}
return C;
};
const decrypt = (C) => {
if (C.length % BLOCK_SIZE !== 0) {
throw new KitError('Decryption error');
}
const P = new U8(C.length);
const prev = IV.slice(0);
for (let i = 0; i < C.length;) {
const offset = i;
const B = C.slice(i, i += BLOCK_SIZE);
const _P = c.decrypt(B);
_P.forEach((_, i) => _P[i] ^= prev[i]);
P.set(_P, offset);
B.forEach((_, i) => prev[i] = B[i] ^ _P[i]);
}
return padding(P);
};
return wrap({ encrypt, decrypt }, info);
};
return wrap(suite, info);
}, { ALGORITHM: 'PCBC' });
/** 密码反馈模式 / Cipher Feedback Mode */
export const cfb = wrap((cipher, padding = PKCS7_PAD) => {
const info = {
ALGORITHM: `CFB-${cipher.ALGORITHM}`,
PADDING: padding,
BLOCK_SIZE: cipher.BLOCK_SIZE,
KEY_SIZE: cipher.KEY_SIZE,
MIN_KEY_SIZE: cipher.MIN_KEY_SIZE,
MAX_KEY_SIZE: cipher.MAX_KEY_SIZE,
IV_SIZE: cipher.BLOCK_SIZE,
MIN_IV_SIZE: cipher.BLOCK_SIZE,
MAX_IV_SIZE: cipher.BLOCK_SIZE,
};
const suite = (K, iv) => {
// iv 检查
const { BLOCK_SIZE } = cipher;
if (iv.length !== BLOCK_SIZE) {
throw new KitError(`${info.ALGORITHM} iv must be ${BLOCK_SIZE} byte`);
}
const c = cipher(K);
const encrypt = (M) => {
const P = padding(M, BLOCK_SIZE);
const C = new U8(P.length);
let prev = iv;
for (let i = 0; i < P.length;) {
const offset = i;
const B = P.subarray(i, i += BLOCK_SIZE);
prev = c.encrypt(prev);
prev.forEach((_, i) => prev[i] ^= B[i]);
C.set(prev.subarray(0, B.length), offset);
}
return C;
};
const decrypt = (C) => {
const P = new U8(C.length);
let prev = iv;
for (let i = 0; i < C.length;) {
const offset = i;
const B = C.subarray(i, i += BLOCK_SIZE);
prev = c.encrypt(prev);
B.forEach((_, i) => prev[i] ^= B[i]);
P.set(prev.subarray(0, B.length), offset);
prev = B;
}
return padding(P);
};
return wrap({ encrypt, decrypt }, info);
};
return wrap(suite, info);
}, { ALGORITHM: 'CFB' });
/** 输出反馈模式 / Output Feedback Mode */
export const ofb = wrap((cipher, padding = PKCS7_PAD) => {
const info = {
ALGORITHM: `OFB-${cipher.ALGORITHM}`,
PADDING: padding,
BLOCK_SIZE: cipher.BLOCK_SIZE,
KEY_SIZE: cipher.KEY_SIZE,
MIN_KEY_SIZE: cipher.MIN_KEY_SIZE,
MAX_KEY_SIZE: cipher.MAX_KEY_SIZE,
IV_SIZE: cipher.BLOCK_SIZE,
MIN_IV_SIZE: cipher.BLOCK_SIZE,
MAX_IV_SIZE: cipher.BLOCK_SIZE,
};
const suite = (K, iv) => {
// iv 检查
const { BLOCK_SIZE } = cipher;
if (iv.length !== BLOCK_SIZE) {
throw new KitError(`${info.ALGORITHM} iv must be ${BLOCK_SIZE} byte`);
}
const c = cipher(K);
let prev = c.encrypt(iv);
let S = prev;
let SByte = BLOCK_SIZE;
const squeeze = (TByte) => {
if (SByte > TByte) {
return S;
}
const buffer = [S];
while (SByte < TByte) {
prev = c.encrypt(prev);
buffer.push(prev);
SByte += BLOCK_SIZE;
}
S = joinBuffer(...buffer);
return S;
};
const encrypt = (M) => {
const P = padding(M, BLOCK_SIZE);
S = squeeze(P.length);
return P.map((_, i) => _ ^ S[i]);
};
const decrypt = (C) => {
S = squeeze(C.length);
return padding(C.map((_, i) => _ ^ S[i]));
};
return wrap({ encrypt, decrypt }, info);
};
return wrap(suite, info);
}, { ALGORITHM: 'OFB' });
/** 计数器模式 / Counter Mode */
export const ctr = wrap((cipher, padding = PKCS7_PAD) => {
const info = {
ALGORITHM: `CTR-${cipher.ALGORITHM}`,
PADDING: padding,
BLOCK_SIZE: cipher.BLOCK_SIZE,
KEY_SIZE: cipher.KEY_SIZE,
MIN_KEY_SIZE: cipher.MIN_KEY_SIZE,
MAX_KEY_SIZE: cipher.MAX_KEY_SIZE,
IV_SIZE: cipher.BLOCK_SIZE,
MIN_IV_SIZE: cipher.BLOCK_SIZE,
MAX_IV_SIZE: cipher.BLOCK_SIZE,
};
const suite = (K, iv) => {
// iv 检查
const { BLOCK_SIZE } = cipher;
if (iv.length !== BLOCK_SIZE) {
throw new KitError(`{info.ALGORITHM} iv must be ${BLOCK_SIZE} byte`);
}
const c = cipher(K);
const counter = new Counter(iv.slice());
let S = new U8();
let SByte = 0;
const squeeze = (TByte) => {
if (SByte > TByte) {
return S;
}
const buffer = [S];
while (SByte < TByte) {
buffer.push(c.encrypt(counter));
counter.inc();
SByte += BLOCK_SIZE;
}
S = joinBuffer(...buffer);
return S;
};
const encrypt = (M) => {
const P = padding(M, BLOCK_SIZE);
S = squeeze(P.length);
return P.map((_, i) => _ ^ S[i]);
};
const decrypt = (C) => {
S = squeeze(C.length);
return padding(C.map((_, i) => _ ^ S[i]));
};
return wrap({ encrypt, decrypt }, info);
};
return wrap(suite, info);
}, { ALGORITHM: 'CTR' });
function GF128Mul(X, Y) {
// R: E1000000000000000000000000000000
const RH = 0xe1n << 56n;
const YView = new DataView(Y.buffer);
let VH = YView.getBigUint64(0, false);
let VL = YView.getBigUint64(8, false);
let ZH = 0n;
let ZL = 0n;
for (let i = 0; i < 16; i++) {
const x = X[i];
for (let j = 7; j >= 0; j--) {
if ((x >> j) & 1) {
ZH ^= VH;
ZL ^= VL;
}
const carry = VL & 1n;
VL = (VH << 63n) | (VL >> 1n);
VL = VL & 0xffffffffffffffffn;
VH = (VH >> 1n);
if (carry) {
VH ^= RH;
}
}
}
const Z = new U8(16);
const ZView = new DataView(Z.buffer);
ZView.setBigUint64(0, ZH, false);
ZView.setBigUint64(8, ZL, false);
return Z;
}
function GHASH(H, A, C) {
const A_BLOCK_TOTAL = Math.ceil(A.length / 16);
const C_BLOCK_TOTAL = Math.ceil(C.length / 16);
const D = new Uint8Array((A_BLOCK_TOTAL + C_BLOCK_TOTAL + 1) * 16);
const view = new DataView(D.buffer);
D.set(A);
D.set(C, A_BLOCK_TOTAL * 16);
view.setBigUint64(D.length - 16, BigInt(A.length << 3), false);
view.setBigUint64(D.length - 8, BigInt(C.length << 3), false);
let X = new U8(16);
for (let i = 0; i < D.length; i += 16) {
const B = D.subarray(i, i + 16);
X.forEach((_, i) => X[i] ^= B[i]);
X = GF128Mul(H, X);
}
return X;
}
/** 伽罗瓦计数器模式 / Galois Counter Mode */
export const gcm = wrap((cipher, padding = PKCS7_PAD, tag_size = 16) => {
const { BLOCK_SIZE } = cipher;
if (BLOCK_SIZE !== 16) {
throw new KitError('GCM cipher block must be 128 bit');
}
const info = {
ALGORITHM: `GCM-${cipher.ALGORITHM}`,
PADDING: padding,
BLOCK_SIZE: cipher.BLOCK_SIZE,
KEY_SIZE: cipher.KEY_SIZE,
MIN_KEY_SIZE: cipher.MIN_KEY_SIZE,
MAX_KEY_SIZE: cipher.MAX_KEY_SIZE,
IV_SIZE: 12,
MIN_IV_SIZE: 0,
MAX_IV_SIZE: Infinity,
AUTH_TAG_SIZE: tag_size,
};
const suite = (K, iv) => {
const c = cipher(K);
const H = c.encrypt(new Uint8Array(BLOCK_SIZE));
let IV = new Counter(16);
if (iv.length === 12) {
IV.set(iv);
IV[15] = 1;
}
else {
IV = new Counter(GHASH(H, new Uint8Array(), iv.slice(0)));
}
let S = c.encrypt(IV);
let SByte = 0;
const squeeze = (TByte) => {
if (SByte > TByte) {
return S;
}
const buffer = [S];
while (SByte < TByte) {
IV.inc();
buffer.push(c.encrypt(IV));
SByte += BLOCK_SIZE;
}
S = joinBuffer(...buffer);
return S;
};
const encrypt = (M) => {
const P = padding(M, BLOCK_SIZE);
S = squeeze(P.length);
return P.map((_, i) => _ ^ S[i + BLOCK_SIZE]);
};
const decrypt = (C) => {
S = squeeze(C.length);
return padding(C.map((_, i) => _ ^ S[i + BLOCK_SIZE]));
};
const sign = (C, A = new Uint8Array()) => {
const T = GHASH(H, A, C);
T.forEach((_, i) => T[i] ^= S[i]);
return T.slice(0, tag_size);
};
const verify = (T, C, A) => {
if (T.length !== tag_size) {
return false;
}
const T1 = sign(C, A);
return T.every((_, i) => _ === T1[i]);
};
return wrap({ encrypt, decrypt, sign, verify }, info);
};
return wrap(suite, info);
}, {
ALGORITHM: 'GCM',
IV_SIZE: 12,
});
import { KitError, U8, wrap } from './utils';
function createCodec(parse, stringify, format) {
function codec(input) {
if (typeof input === 'string') {
return parse(input);
}
else {
return stringify(input);
}
}
return wrap(codec, { FORMAT: format });
}
function UTF8ToU8(input) {
/**
* 尝试使用 TextEncoder 编码
* 否则使用自定义编码器
*/
try {
const buffer = new TextEncoder().encode(input);
return U8.from(buffer);
}
/** provided by xingluo233 */
catch {
const buffer = [];
for (let i = 0; i < input.length; i++) {
const char_code = input.codePointAt(i);
if (char_code === undefined) {
continue;
}
else if (char_code < 0x80) {
buffer.push(char_code);
}
else if (char_code < 0x800) {
buffer.push(0xC0 | (char_code >> 6));
buffer.push(0x80 | (char_code & 0x3F));
}
else if (char_code < 0x10000) {
buffer.push(0xE0 | (char_code >> 12));
buffer.push(0x80 | ((char_code >> 6) & 0x3F));
buffer.push(0x80 | (char_code & 0x3F));
}
else if (char_code < 0x110000) {
buffer.push(0xF0 | (char_code >> 18));
buffer.push(0x80 | ((char_code >> 12) & 0x3F));
buffer.push(0x80 | ((char_code >> 6) & 0x3F));
buffer.push(0x80 | (char_code & 0x3F));
i++;
}
}
return U8.from(buffer);
}
}
function U8ToUTF8(input) {
/**
* 尝试使用 TextDecoder 解码
* 否则使用自定义解码器
*/
try {
return new TextDecoder().decode(input);
}
/** provided by xingluo233 */
catch {
const str = [];
let i = 0;
while (i < input.length) {
const byte1 = input[i++];
if (byte1 < 0x80) {
str.push(String.fromCharCode(byte1));
}
else if (byte1 >= 0xC0 && byte1 < 0xE0) {
const byte2 = input[i++];
const char_code = ((byte1 & 0x1F) << 6) | (byte2 & 0x3F);
str.push(String.fromCharCode(char_code));
}
else if (byte1 >= 0xE0 && byte1 < 0xF0) {
const byte2 = input[i++];
const byte3 = input[i++];
const char_code = ((byte1 & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | (byte3 & 0x3F);
str.push(String.fromCharCode(char_code));
}
else if (byte1 >= 0xF0 && byte1 < 0xF8) {
const byte2 = input[i++];
const byte3 = input[i++];
const byte4 = input[i++];
const char_code = ((byte1 & 0x07) << 18) | ((byte2 & 0x3F) << 12) | ((byte3 & 0x3F) << 6) | (byte4 & 0x3F);
str.push(String.fromCodePoint(char_code));
}
else {
console.warn('Included an invalid UTF-8 byte');
}
}
return str.join('');
}
}
/** UTF-8 编解码器 / Codec */
export const UTF8 = createCodec(UTF8ToU8, U8ToUTF8, 'utf-8');
function HEXToU8(input) {
const arr = input.match(/[\da-f]{2}/gi);
if (arr == null) {
return new U8();
}
return new U8(arr.map(h => Number.parseInt(h, 16)));
}
function U8ToHEX(input) {
let result = '';
for (let i = 0; i < input.length; i++) {
result += input[i].toString(16).padStart(2, '0');
}
return result;
}
/** hex 编解码器 / Codec */
export const HEX = createCodec(HEXToU8, U8ToHEX, 'hex');
function B64ToU8(input) {
return B64CommonParse(input);
}
function U8ToB64(input) {
return B64CommonStringify(input, false);
}
/** base64 编解码器 / Codec */
export const B64 = createCodec(B64ToU8, U8ToB64, 'base64');
function B64URLToU8(input) {
return B64CommonParse(input);
}
function U8ToB64URL(input) {
return B64(input).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}
/** base64url 编解码器 / Codec */
export const B64URL = createCodec(B64URLToU8, U8ToB64URL, 'base64url');
/**
* provided by xingluo233
*
* B64CommonParse can parse B64 or B64url string to Uint8Array
*
* B64CommonParse 可以将 B64 或者 B64url 字符串解析为 Uint8Array
*
* @param {string} input - B64 或 B64url 字符串
* @param {boolean} url - 是否是 B64url 字符串
*/
function B64CommonParse(input) {
const map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
input = input
.replace(/-/g, '+')
.replace(/_/g, '/')
.replace(/[^A-Z0-9+/]/gi, '');
const length = input.length * 0.75;
const result = new U8(length);
let i = 0;
let j = 0;
while (i < input.length) {
const a = map.indexOf(input.charAt(i++));
const b = map.indexOf(input.charAt(i++));
const c = map.indexOf(input.charAt(i++));
const d = map.indexOf(input.charAt(i++));
const combined = (a << 18) | (b << 12) | (c << 6) | d;
result[j++] = (combined >> 16) & 0xFF;
result[j++] = (combined >> 8) & 0xFF;
result[j++] = combined & 0xFF;
}
return result;
}
/**
* B64CommonStringify can stringify Uint8Array to B64 or B64url string
*
* B64CommonStringify 可以将 Uint8Array 编码为 B64 或 B64url 字符串
*
* @param {Uint8Array} input - Uint8Array
* @param {boolean} url - 是否是 B64url 字符串
*/
function B64CommonStringify(input, url) {
let map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
map += url ? '-_' : '+/';
let result = '';
let i;
for (i = 0; i < input.length - 2; i += 3) {
result += map[input[i] >> 2];
result += map[((input[i] & 3) << 4) | (input[i + 1] >> 4)];
result += map[((input[i + 1] & 15) << 2) | (input[i + 2] >> 6)];
result += map[input[i + 2] & 63];
}
if (i === input.length - 2) {
result += map[input[i] >> 2];
result += map[((input[i] & 3) << 4) | (input[i + 1] >> 4)];
result += map[(input[i + 1] & 15) << 2];
result += url ? '' : '=';
}
else if (i === input.length - 1) {
result += map[input[i] >> 2];
result += map[(input[i] & 3) << 4];
result += url ? '' : '==';
}
return result;
}
function TheB32Codec(args) {
// 使用默认配置处理 B32 编解码
const RFC4648_B32_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
if (typeof args === 'string') {
const input = args.toUpperCase().replace(/[^A-Z2-7]/g, '');
return B32CommonParse(input, RFC4648_B32_MAP);
}
else if (args instanceof Uint8Array) {
return B32CommonStringify(args, RFC4648_B32_MAP, false);
}
// 创建 B32 变体
const { variant = 'rfc4648', padding = false } = args;
if (variant === 'rfc4648') {
function B32ToU8(input) {
input = input.toUpperCase().replace(/[^A-Z2-7]/g, '');
return B32CommonParse(input, RFC4648_B32_MAP);
}
function U8ToB32(input) {
return B32CommonStringify(input, RFC4648_B32_MAP, padding);
}
return createCodec(B32ToU8, U8ToB32, 'base32');
}
else if (variant === 'rfc4648-hex') {
const RFC4648_B32_HEX_MAP = '0123456789ABCDEFGHIJKLMNOPQRSTUV';
function B32HexToU8(input) {
input = input.toUpperCase().replace(/[^0-9A-V]/g, '');
return B32CommonParse(input, RFC4648_B32_HEX_MAP);
}
function U8ToB32Hex(input) {
return B32CommonStringify(input, RFC4648_B32_HEX_MAP, padding);
}
return createCodec(B32HexToU8, U8ToB32Hex, 'base32-hex');
}
else if (variant === 'crockford') {
const RFC4648_B32_CROCKFORD_MAP = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
function B32CrockfordToU8(input) {
input = input
.toUpperCase()
.replace(/O/g, '0')
.replace(/[IL]/g, '1')
.replace(/[^0-9A-HJKMNP-TV-Z]/g, '');
return B32CommonParse(input, RFC4648_B32_CROCKFORD_MAP);
}
function U8ToB32Crockford(input) {
return B32CommonStringify(input, RFC4648_B32_CROCKFORD_MAP, padding);
}
return createCodec(B32CrockfordToU8, U8ToB32Crockford, 'base32-crockford');
}
}
/** base32 编解码器 / Codec */
export const B32 = wrap(TheB32Codec, { FORMAT: 'base32' });
/**
* B32CommonParse can parse B32 string to Uint8Array
*
* B32CommonParse 可以将 B32 字符串解析为 Uint8Array
*
* @param {string} input - B32 或 B32url 字符串
* @param {string} map - 字符表
*/
function B32CommonParse(input, map) {
const length = input.length * 0.625;
const result = new U8(length);
let i = 0;
let j = 0;
while (i < input.length) {
const a = map.indexOf(input.charAt(i++));
const b = map.indexOf(input.charAt(i++));
const c = map.indexOf(input.charAt(i++));
const d = map.indexOf(input.charAt(i++));
const e = map.indexOf(input.charAt(i++));
const f = map.indexOf(input.charAt(i++));
const g = map.indexOf(input.charAt(i++));
const h = map.indexOf(input.charAt(i++));
result[j++] = (a << 3) | (b >> 2);
result[j++] = ((b & 0b11) << 6) | (c << 1) | (d >> 4);
result[j++] = ((d & 0b1111) << 4) | (e >> 1);
result[j++] = ((e & 0b1) << 7) | (f << 2) | (g >> 3);
result[j++] = ((g & 0b111) << 5) | h;
}
return result;
}
/**
* B32CommonStringify can stringify Uint8Array to B32 string
*
* B32CommonStringify 可以将 Uint8Array 编码为 B32 字符串
*
* @param {Uint8Array} input - Uint8Array
* @param {string} map - 字符表
* @param {boolean} pad - 是否填充
*/
function B32CommonStringify(input, map, pad) {
let result = '';
let i;
for (i = 0; i < input.length - 4; i += 5) {
const E0 = input[i];
const E1 = input[i + 1];
const E2 = input[i + 2];
const E3 = input[i + 3];
const E4 = input[i + 4];
result += map[E0 >> 3];
result += map[((E0 & 0b111) << 2) | (E1 >> 6)];
result += map[(E1 >> 1) & 0b11111];
result += map[((E1 & 0b1) << 4) | (E2 >> 4)];
result += map[((E2 & 0b1111) << 1) | (E3 >> 7)];
result += map[(E3 >> 2) & 0b11111];
result += map[((E3 & 0b11) << 3) | (E4 >> 5)];
result += map[E4 & 0b11111];
}
if (i === input.length - 4) {
const E0 = input[i];
const E1 = input[i + 1];
const E2 = input[i + 2];
const E3 = input[i + 3];
result += map[E0 >> 3];
result += map[((E0 & 0b111) << 2) | (E1 >> 6)];
result += map[(E1 >> 1) & 0b11111];
result += map[((E1 & 0b1) << 4) | (E2 >> 4)];
result += map[((E2 & 0b1111) << 1) | (E3 >> 7)];
result += map[(E3 >> 2) & 0b11111];
result += map[((E3 & 0b11) << 3)];
result += pad ? '=' : '';
}
else if (i === input.length - 3) {
const E0 = input[i];
const E1 = input[i + 1];
const E2 = input[i + 2];
result += map[E0 >> 3];
result += map[((E0 & 0b111) << 2) | (E1 >> 6)];
result += map[(E1 >> 1) & 0b11111];
result += map[((E1 & 0b1) << 4) | (E2 >> 4)];
result += map[(E2 & 0b1111) << 1];
result += pad ? '===' : '';
}
else if (i === input.length - 2) {
const E0 = input[i];
const E1 = input[i + 1];
result += map[E0 >> 3];
result += map[((E0 & 0b111) << 2) | (E1 >> 6)];
result += map[(E1 >> 1) & 0b11111];
result += map[(E1 & 0b1) << 4];
result += pad ? '====' : '';
}
else if (i === input.length - 1) {
const E0 = input[i];
result += map[E0 >> 3];
result += map[(E0 & 0b111) << 2];
result += pad ? '======' : '';
}
return result;
}
function CSVToU8(input) {
const coreValueMap = new Map();
coreValueMap.set('富强', 0);
coreValueMap.set('民主', 1);
coreValueMap.set('文明', 2);
coreValueMap.set('和谐', 3);
coreValueMap.set('自由', 4);
coreValueMap.set('平等', 5);
coreValueMap.set('公正', 6);
coreValueMap.set('法治', 7);
coreValueMap.set('爱国', 8);
coreValueMap.set('敬业', 9);
coreValueMap.set('诚信', 10);
coreValueMap.set('友善', 11);
const from = (value) => {
const nibble = coreValueMap.get(value);
if (nibble === undefined) {
throw new KitError('你竟然在社会主义核心价值观里夹带私货!');
}
return nibble;
};
const coreValues = input.match(/(\S){2}/g);
if (coreValues == null) {
return new U8();
}
let h = 0;
let l = 0;
let count = 0;
const result = [];
for (let i = 0; i < coreValues.length; i++) {
const isHigh = count % 2 === 0;
let nibble = from(coreValues[i]);
if (nibble === 10 || nibble === 11) {
i++;
if (i === coreValues.length) {
throw new KitError('你的社会主义核心价值观破碎了!');
}
nibble = nibble === 10
? 10 + from(coreValues[i])
: 6 + from(coreValues[i]);
}
if (isHigh) {
h = nibble;
}
else {
l = nibble;
}
if (!isHigh) {
result.push(((h << 4) | l) & 0xFF);
}
count++;
}
return new U8(result);
}
function U8ToCSV(input) {
const rand = () => Math.random() >= 0.5;
const map = ['富强', '民主', '文明', '和谐', '自由', '平等', '公正', '法治', '爱国', '敬业', '诚信', '友善'];
let result = '';
input.forEach((byte) => {
const h = (byte >> 4) & 0xF;
const l = byte & 0xF;
if (h < 10) {
result += map[h];
}
else if (rand()) {
result += map[11] + map[h - 6];
}
else {
result += map[11] + map[h - 6];
}
if (l < 10) {
result += map[l];
}
else if (rand()) {
result += map[10] + map[l - 10];
}
else {
result += map[11] + map[l - 6];
}
});
return result;
}
/** 社会主义核心价值观编解码器 / Core Socialist Values Codec */
export const CSV = createCodec(CSVToU8, U8ToCSV, 'core-socialist-values');
import { U8, mod, modInverse, modPow, modPrimeSquare } from './utils';
// * FpEC Components
/**
* 将椭圆曲线点转换为 U8 格式
*
* Convert EC Point to U8 Format
*/
export function U8Point(point, byte) {
if (!point) {
return { isInfinity: true, x: new U8(), y: new U8() };
}
const isInfinity = point.isInfinity;
const x = typeof point.x === 'bigint'
? U8.fromBI(point.x, byte)
: U8.from(point.x);
const y = typeof point.y === 'bigint'
? U8.fromBI(point.y, byte)
: U8.from(point.y);
return { isInfinity, x, y };
}
/**
* 将椭圆曲线点转换为 bigint 格式
*
* Convert EC Point to bigint Format
*/
export function BIPoint(point) {
if (!point) {
return { isInfinity: true, x: 0n, y: 0n };
}
const isInfinity = point.isInfinity;
const x = typeof point.x === 'bigint'
? point.x
: U8.from(point.x).toBI();
const y = typeof point.y === 'bigint'
? point.y
: U8.from(point.y).toBI();
return { isInfinity, x, y };
}
/**
* 蒙哥马利梯子点乘法
*
* Montgomery Ladder Point Multiplication
*
* @param addPoint 素域椭圆曲线点加法函数 / Prime Field EC Point Addition Function
* @param {FpECPoint} P 椭圆曲线点 / EC Point
* @param {bigint | Uint8Array} k 标量 / Scalar
*/
function LadderMultiply(addPoint, P, k) {
k = typeof k === 'bigint' ? k : U8.from(k).toBI();
let R0 = BIPoint();
let R1 = BIPoint(P);
// MSb -> LSb
const bit_array = k.toString(2).split('');
for (const bit of bit_array) {
if (bit === '1') {
R0 = addPoint(R0, R1);
R1 = addPoint(R1, R1);
}
else {
R1 = addPoint(R0, R1);
R0 = addPoint(R0, R0);
}
}
return R0;
}
/** 素域运算 / Prime Field Operations */
export function Fp(p) {
const _mod = (a) => mod(a, p);
const inverse = (a) => modInverse(a, p);
const root = (a) => modPrimeSquare(a, p);
const pow = (a, b) => modPow(a, b, p);
const plus = (...args) => args.reduce((acc, cur) => _mod(acc + cur));
const multiply = (...args) => args.reduce((acc, cur) => _mod(acc * cur));
const subtract = (a, ...args) => {
const b = args.map(v => _mod(p - v));
return plus(a, ...b);
};
const divide = (a, b) => multiply(a, inverse(b));
return {
plus,
multiply,
subtract,
divide,
mod: _mod,
pow,
inverse,
root,
};
}
/**
* 素域椭圆曲线运算
*
* Prime Field Elliptic Curve Operations
*/
export function FpEC(curve) {
switch (curve.type) {
case 'Weierstrass':
return FpWEC(curve);
case 'Montgomery':
return FpMEC(curve);
case 'TwistedEdwards':
return FpTEC(curve);
}
}
/**
* 素域 Weierstrass 椭圆曲线运算
*
* Prime Field Weierstrass Elliptic Curve Operations
*/
export function FpWEC(curve) {
const { p, a } = curve;
const { plus, multiply, subtract, divide } = Fp(p);
const addPoint = (A, B) => {
// O + P = P
if (A.isInfinity) {
return BIPoint(B);
}
if (B.isInfinity) {
return BIPoint(A);
}
let [x1, y1] = [A.x, A.y];
let [x2, y2] = [B.x, B.y];
x1 = typeof x1 === 'bigint' ? x1 : U8.from(x1).toBI();
y1 = typeof y1 === 'bigint' ? y1 : U8.from(y1).toBI();
x2 = typeof x2 === 'bigint' ? x2 : U8.from(x2).toBI();
y2 = typeof y2 === 'bigint' ? y2 : U8.from(y2).toBI();
// P + (-P) = O
if (x1 === x2 && y1 !== y2) {
return BIPoint();
}
let λ = 0n;
// P1 + P2
if (x1 !== x2) {
// λ = (y2 - y1) / (x2 - x1)
const numerator = subtract(y2, y1);
const denominator = subtract(x2, x1);
λ = divide(numerator, denominator);
}
// P1 + P1
else {
// λ = (3 * x1 * x1 + a) / 2 * y1
const numerator = plus(multiply(3n, x1, x1), a);
const denominator = multiply(2n, y1);
λ = divide(numerator, denominator);
}
// x3 = λ * λ - x1 - x2
const x3 = subtract(multiply(λ, λ), x1, x2);
// y3 = λ * (x1 - x3) - y1
const y3 = subtract(multiply(λ, subtract(x1, x3)), y1);
return { isInfinity: false, x: x3, y: y3 };
};
const mulPoint = (P, k) => LadderMultiply(addPoint, P, k);
return { addPoint, mulPoint };
}
/**
* 素域 Montgomery 椭圆曲线运算
*
* Prime Field Montgomery Elliptic Curve Operations
*/
export function FpMEC(curve) {
const { p, a, b } = curve;
const { plus, multiply, subtract, divide } = Fp(p);
const addPoint = (A, B) => {
// O + P = P
if (A.isInfinity) {
return BIPoint(B);
}
if (B.isInfinity) {
return BIPoint(A);
}
let [x1, y1] = [A.x, A.y];
let [x2, y2] = [B.x, B.y];
x1 = typeof x1 === 'bigint' ? x1 : U8.from(x1).toBI();
y1 = typeof y1 === 'bigint' ? y1 : U8.from(y1).toBI();
x2 = typeof x2 === 'bigint' ? x2 : U8.from(x2).toBI();
y2 = typeof y2 === 'bigint' ? y2 : U8.from(y2).toBI();
// P + (-P) = O
if (x1 === x2 && y1 !== y2) {
return BIPoint();
}
let λ = 0n;
// P1 + P2
if (x1 !== x2) {
// λ = (y2 - y1) / (x2 - x1)
const numerator = subtract(y2, y1);
const denominator = subtract(x2, x1);
λ = divide(numerator, denominator);
}
// P1 + P1
else {
// λ = (3 * x1 * x1 + 2 * a * x1 + 1) / 2 * b * y1
const numerator = plus(multiply(3n, x1, x1), multiply(2n, a, x1), 1n);
const denominator = multiply(2n, b, y1);
λ = divide(numerator, denominator);
}
// x3 = b * λ * λ - a - x1 - x2
const x3 = subtract(multiply(λ, λ, b), a, x1, x2);
// y3 = (2 x1 + x2 + a) * λ - b * λ * λ * λ - y1
const y3 = subtract(multiply(2n * x1 + x2 + a, λ), multiply(λ, λ, λ, b), y1);
return { isInfinity: false, x: x3, y: y3 };
};
const mulPoint = (P, k) => LadderMultiply(addPoint, P, k);
return { addPoint, mulPoint };
}
/**
* 素域 Twisted Edwards 椭圆曲线运算
*
* Prime Field Twisted Edwards Elliptic Curve Operations
*/
// eslint-disable-next-line unused-imports/no-unused-vars
export function FpTEC(curve) {
// TODO
return {};
}
// * Prime Filed Elliptic Curve Interfaces
// * SM2 Prime Curve
/**
* 256 位素域上的 SM2 曲线
*
* SM2 curve over a 256 bit prime field
*/
export const sm2p256v1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffffn,
a: 0xfffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffcn,
b: 0x28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93n,
G: {
isInfinity: false,
x: 0x32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7n,
y: 0xbc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0n,
},
n: 0xfffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123n,
h: 1n,
});
// * SEC-1 Prime Curves
/**
* 112 位素域上的 SECG/WTLS 曲线
*
* SECG/WTLS curve over a 112 bit prime field
*
* @alias secp112r1
* @alias wtls6
*/
export const secp112r1 = Object.freeze({
type: 'Weierstrass',
p: 0xdb7c2abf62e35e668076bead208bn,
a: 0xdb7c2abf62e35e668076bead2088n,
b: 0x659ef8ba043916eede8911702b22n,
G: {
isInfinity: false,
x: 0x09487239995a5ee76b55f9c2f098n,
y: 0xa89ce5af8724c0a23e0e0ff77500n,
},
n: 0xdb7c2abf62e35e7628dfac6561c5n,
h: 1n,
});
/**
* 112 位素域上的 SECG 曲线
*
* SECG curve over a 112 bit prime field
*/
export const secp112r2 = Object.freeze({
type: 'Weierstrass',
p: 0xdb7c2abf62e35e668076bead208bn,
a: 0x6127c24c05f38a0aaaf65c0ef02cn,
b: 0x51def1815db5ed74fcc34c85d709n,
G: {
isInfinity: false,
x: 0x4ba30ab5e892b4e1649dd0928643n,
y: 0xadcd46f5882e3747def36e956e97n,
},
n: 0x36df0aafd8b8d7597ca10520d04bn,
h: 4n,
});
/**
* 128 位素域上的 SECG 曲线
*
* SECG curve over a 128 bit prime field
*/
export const secp128r1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffdffffffffffffffffffffffffn,
a: 0xfffffffdfffffffffffffffffffffffcn,
b: 0xe87579c11079f43dd824993c2cee5ed3n,
G: {
isInfinity: false,
x: 0x161ff7528b899b2d0c28607ca52c5b86n,
y: 0xcf5ac8395bafeb13c02da292dded7a83n,
},
n: 0xfffffffe0000000075a30d1b9038a115n,
h: 1n,
});
/**
* 128 位素域上的 SECG 曲线
*
* SECG curve over a 128 bit prime field
*/
export const secp128r2 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffdffffffffffffffffffffffffn,
a: 0xd6031998d1b3bbfebf59cc9bbff9aee1n,
b: 0x5eeefca380d02919dc2c6558bb6d8a5dn,
G: {
isInfinity: false,
x: 0x7b6aa5d85e572983e6fb32a7cdebc140n,
y: 0x27b6916a894d3aee7106fe805fc34b44n,
},
n: 0x3fffffff7fffffffbe0024720613b5a3n,
h: 4n,
});
/**
* 160 位素域上的 SECG 曲线
*
* SECG curve over a 160 bit prime field
*/
export const secp160k1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffffffffffffffffffffffffffeffffac73n,
a: 0n,
b: 7n,
G: {
isInfinity: false,
x: 0x3b4c382ce37aa192a4019e763036f4f5dd4d7ebbn,
y: 0x938cf935318fdced6bc28286531733c3f03c4feen,
},
n: 0x0100000000000000000001b8fa16dfab9aca16b6b3n,
h: 1n,
});
/**
* 160 位素域上的 SECG/WTLS 曲线
*
* SECG/WTLS curve over a 160 bit prime field
*
* @alias secp160r1
* @alias wtls7
*/
export const secp160r1 = Object.freeze({
type: 'Weierstrass',
p: 0xffffffffffffffffffffffffffffffff7fffffffn,
a: 0xffffffffffffffffffffffffffffffff7ffffffcn,
b: 0x1c97befc54bd7a8b65acf89f81d4d4adc565fa45n,
G: {
isInfinity: false,
x: 0x4a96b5688ef573284664698968c38bb913cbfc82n,
y: 0x23a628553168947d59dcc912042351377ac5fb32n,
},
n: 0x0100000000000000000001f4c8f927aed3ca752257n,
h: 1n,
});
/**
* 160 位素域上的 SECG 曲线
*
* SECG curve over a 160 bit prime field
*/
export const secp160r2 = Object.freeze({
type: 'Weierstrass',
p: 0xffffffffffffffffffffffffffffffff7fffffffn,
a: 0xffffffffffffffffffffffffffffffff7ffffffcn,
b: 0xb4e134d3fb59eb8bab57274904664d5af50388ban,
G: {
isInfinity: false,
x: 0x52dcb034293a117e1f4ff11b30f7199d3144ce6dn,
y: 0xfeaffef2e331f296e071fa0df9982cfea7d43f2en,
},
n: 0x0100000000000000000000351ee786a818f3a1a16bn,
h: 1n,
});
/**
* 192 位素域上的 SECG 曲线
*
* SECG curve over a 192 bit prime field
*/
export const secp192k1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffffffffffffffffffffffffffffffffffeffffee37n,
a: 0x000000000000000000000000000000000000000000000000n,
b: 0x000000000000000000000000000000000000000000000003n,
G: {
isInfinity: false,
x: 0xdb4ff10ec057e9ae26b07d0280b7f4341da5d1b1eae06c7dn,
y: 0x9b2f2f6d9c5628a7844163d015be86344082aa88d95e2f9dn,
},
n: 0xfffffffffffffffffffffffe26f2fc170f69466a74defd8dn,
h: 1n,
});
/**
* 192 位素域上的 NIST/X9.62/SECG 曲线
*
* NIST/X9.62/SECG curve over a 192 bit prime field
*
* @alias p192
* @alias prime192v1
* @alias secp192r1
*/
export const secp192r1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffffffffffffffffffffffffffeffffffffffffffffn,
a: 0xfffffffffffffffffffffffffffffffefffffffffffffffcn,
b: 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1n,
G: {
isInfinity: false,
x: 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012n,
y: 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811n,
},
n: 0xffffffffffffffffffffffff99def836146bc9b1b4d22831n,
h: 1n,
});
/**
* 224 位素域上的 SECG 曲线
*
* SECG curve over a 224 bit prime field
*/
export const secp224k1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffffffffffffffffffffffffffffffffffffffffffeffffe56dn,
a: 0x00000000000000000000000000000000000000000000000000000000n,
b: 0x00000000000000000000000000000000000000000000000000000005n,
G: {
isInfinity: false,
x: 0xa1455b334df099df30fc28a169a467e9e47075a90f7e650eb6b7a45cn,
y: 0x7e089fed7fba344282cafbd6f7e319f7c0b0bd59e2ca4bdb556d61a5n,
},
n: 0x010000000000000000000000000001dce8d2ec6184caf0a971769fb1f7n,
h: 1n,
});
/**
* 224 位素域上的 NIST/SECG 曲线
*
* NIST/SECG curve over a 224 bit prime field
*
* @alias p224
* @alias secp224r1
*/
export const secp224r1 = Object.freeze({
type: 'Weierstrass',
p: 0xffffffffffffffffffffffffffffffff000000000000000000000001n,
a: 0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffen,
b: 0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4n,
G: {
isInfinity: false,
x: 0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21n,
y: 0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34n,
},
n: 0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3dn,
h: 1n,
});
/**
* 256 位素域上的 SECG 曲线
*
* SECG curve over a 256 bit prime field
*/
export const secp256k1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn,
a: 0x0000000000000000000000000000000000000000000000000000000000000000n,
b: 0x0000000000000000000000000000000000000000000000000000000000000007n,
G: {
isInfinity: false,
x: 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798n,
y: 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8n,
},
n: 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n,
h: 1n,
});
/**
* 256 位素域上的 NIST/X9.62/SECG 曲线
*
* NIST/X9.62/SECG curve over a 256 bit prime field
*
* @alias p256
* @alias prime256v1
* @alias secp256r1
*/
export const secp256r1 = Object.freeze({
type: 'Weierstrass',
p: 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffffn,
a: 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffcn,
b: 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604bn,
G: {
isInfinity: false,
x: 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296n,
y: 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5n,
},
n: 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551n,
h: 1n,
});
/**
* 384 位素域上的 NIST/SECG 曲线
*
* NIST/SECG curve over a 384 bit prime field
*
* @alias p384
* @alias secp384r1
*/
export const secp384r1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffffn,
a: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffcn,
b: 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aefn,
G: {
isInfinity: false,
x: 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7n,
y: 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5fn,
},
n: 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973n,
h: 1n,
});
/**
* 521 位素域上的 NIST/SECG 曲线
*
* NIST/SECG curve over a 521 bit prime field
*
* @alias p521
* @alias secp521r1
*/
export const secp521r1 = Object.freeze({
type: 'Weierstrass',
p: 0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
a: 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcn,
b: 0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00n,
G: {
isInfinity: false,
x: 0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66n,
y: 0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650n,
},
n: 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409n,
h: 1n,
});
// * SEC-1 Binary Curves
export const sect163k1 = Object.freeze({
m: 163,
f: (x) => x ** 163n + x ** 7n + x ** 6n + x ** 3n + 1n,
a: 0x1n,
b: 0x1n,
G: {
isInfinity: false,
x: 0x02fe13c0537bbc11acaa07d793de4e6d5e5c94eee8n,
y: 0x0289070fb05d38ff58321f2e800536d538ccdaa3d9n,
},
n: 0x04000000000000000000020108a2e0cc0d99f8a5efn,
h: 2n,
});
// * X9.63 Prime Curves
/**
* 192 位素域上的 NIST/X9.62/SECG 曲线
*
* NIST/X9.62/SECG curve over a 192 bit prime field
*
* @alias p192
* @alias prime192v1
* @alias secp192r1
*/
export const prime192v1 = secp192r1;
/**
* 256 位素域上的 NIST/X9.62/SECG 曲线
*
* NIST/X9.62/SECG curve over a 256 bit prime field
*
* @alias p256
* @alias prime256v1
* @alias secp256r1
*/
export const prime256v1 = secp256r1;
// * NIST Prime Curves
/**
* 192 位素域上的 NIST/X9.62/SECG 曲线
*
* NIST/X9.62/SECG curve over a 192 bit prime field
*
* @alias p192
* @alias prime192v1
* @alias secp192r1
*/
export const p192 = secp192r1;
/**
* 224 位素域上的 NIST/SECG 曲线
*
* NIST/SECG curve over a 224 bit prime field
*
* @alias p224
* @alias secp224r1
*/
export const p224 = secp224r1;
/**
* 256 位素域上的 SECG 曲线
*
* SECG curve over a 256 bit prime field
*
* @alias p256
* @alias prime256v1
* @alias secp256r1
*/
export const p256 = secp256r1;
/**
* 384 位素域上的 NIST/SECG 曲线
*
* NIST/SECG curve over a 384 bit prime field
*
* @alias p384
* @alias secp384r1
*/
export const p384 = secp384r1;
/**
* 521 位素域上的 NIST/SECG 曲线
*
* NIST/SECG curve over a 521 bit prime field
*
* @alias p521
* @alias secp521r1
*/
export const p521 = secp521r1;
/**
* NIST W-25519 是与 Curve25519 同构的 Weierstrass 曲线
*
* NIST W-25519 is a Weierstrass curve isomorphic to Curve25519
*/
export const w25519 = Object.freeze({
type: 'Weierstrass',
p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
a: 0x2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa984914a144n,
b: 0x7b425ed097b425ed097b425ed097b425ed097b425ed097b4260b5e9c7710c864n,
G: {
isInfinity: false,
x: 0x2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaad245an,
y: 0x5f51e65e475f794b1fe122d388b72eb36dc2b28192839e4dd6163a5d81312c14n,
},
n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,
h: 8n,
});
/**
* NIST W-448 是与 Curve448 同构的 Weierstrass 曲线
*
* NISt W-448 is a Weierstrass curve isomorphic to Curve448
*/
export const w448 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
a: 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9fffffffffffffffffffffffffffffffffffffffffffffffe1a76d41fn,
b: 0x5ed097b425ed097b425ed097b425ed097b425ed097b425ed097b425e71c71c71c71c71c71c71c71c71c71c71c71c71c71c72c87b7cc69f70n,
G: {
isInfinity: false,
x: 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000000000000000000000000000000000000000000000000000cb91n,
y: 0x7d235d1295f5b1f66c98ab6e58326fcecbae5d34f55545d060f75dc28df3f6edb8027e2346430d211312c4b150677af76fd7223d457b5b1an,
},
n: 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3n,
h: 4n,
});
/**
* 素域 p^255 - 19 上的 NIST Montgomery 曲线
*
* NIST Montgomery curve over a prime field p^255 - 19
*/
export const curve25519 = Object.freeze({
type: 'Montgomery',
p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
a: 486662n,
b: 1n,
G: {
isInfinity: false,
x: 9n,
y: 0x5f51e65e475f794b1fe122d388b72eb36dc2b28192839e4dd6163a5d81312c14n,
},
n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,
h: 8n,
});
/**
* 素域 p^448 - 2^224 - 1 上的 NIST Montgomery 曲线
*
* NIST Montgomery curve over a prime field p^448 - 2^224 - 1
*/
export const curve448 = Object.freeze({
type: 'Montgomery',
p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
a: 156326n,
b: 1n,
G: {
isInfinity: false,
x: 5n,
y: 0x7d235d1295f5b1f66c98ab6e58326fcecbae5d34f55545d060f75dc28df3f6edb8027e2346430d211312c4b150677af76fd7223d457b5b1an,
},
n: 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3n,
h: 4n,
});
/**
* ed25519 是与 Curve25519 同构的 Twisted Edwards 曲线
*
* ed25519 is a Twisted Edwards curve isomorphic to Curve25519
*/
export const ed25519 = Object.freeze({
type: 'TwistedEdwards',
p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
a: -1n,
d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,
G: {
isInfinity: false,
x: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,
y: 0x6666666666666666666666666666666666666666666666666666666666666658n,
},
n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,
h: 8n,
});
/**
* ed448 是与 Curve448 同构的 Twisted Edwards 曲线
*
* ed448 is a Twisted Edwards curve isomorphic to Curve448
*/
export const ed448 = Object.freeze({
type: 'TwistedEdwards',
p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
a: 1n,
d: -39081n,
G: {
isInfinity: false,
x: 0x4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05en,
y: 0x693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14n,
},
n: 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3n,
h: 4n,
});
// * Brainpool Prime Curves
/**
* 160 位素域上的 RFC 5639 曲线
*
* RFC 5639 curve over a 160 bit prime field
*/
export const bp160r1 = Object.freeze({
type: 'Weierstrass',
p: 0xe95e4a5f737059dc60dfc7ad95b3d8139515620fn,
a: 0x340e7be2a280eb74e2be61bada745d97e8f7c300n,
b: 0x1e589a8595423412134faa2dbdec95c8d8675e58n,
G: {
isInfinity: false,
x: 0xbed5af16ea3f6a4f62938c4631eb5af7bdbcdbc3n,
y: 0x1667cb477a1a8ec338f94741669c976316da6321n,
},
n: 0xe95e4a5f737059dc60df5991d45029409e60fc09n,
h: 1n,
});
/**
* 192 位素域上的 RFC 5639 曲线
*
* RFC 5639 curve over a 192 bit prime field
*/
export const bp192r1 = Object.freeze({
type: 'Weierstrass',
p: 0xc302f41d932a36cda7a3463093d18db78fce476de1a86297n,
a: 0x6a91174076b1e0e19c39c031fe8685c1cae040e5c69a28efn,
b: 0x469a28ef7c28cca3dc721d044f4496bcca7ef4146fbf25c9n,
G: {
isInfinity: false,
x: 0xc0a0647eaab6a48753b033c56cb0f0900a2f5c4853375fd6n,
y: 0x14b690866abd5bb88b5f4828c1490002e6773fa2fa299b8fn,
},
n: 0xc302f41d932a36cda7a3462f9e9e916b5be8f1029ac4acc1n,
h: 1n,
});
/**
* 224 位素域上的 RFC 5639 曲线
*
* RFC 5639 curve over a 224 bit prime field
*/
export const bp224r1 = Object.freeze({
type: 'Weierstrass',
p: 0xd7c134aa264366862a18302575d1d787b09f075797da89f57ec8c0ffn,
a: 0x68a5e62ca9ce6c1c299803a6c1530b514e182ad8b0042a59cad29f43n,
b: 0x2580f63ccfe44138870713b1a92369e33e2135d266dbb372386c400bn,
G: {
isInfinity: false,
x: 0x0d9029ad2c7e5cf4340823b2a87dc68c9e4ce3174c1e6efdee12c07dn,
y: 0x58aa56f772c0726f24c6b89e4ecdac24354b9e99caa3f6d3761402cdn,
},
n: 0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939fn,
h: 1n,
});
/**
* 256 位素域上的 RFC 5639 曲线
*
* RFC 5639 curve over a 256 bit prime field
*/
export const bp256r1 = Object.freeze({
type: 'Weierstrass',
p: 0xa9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5377n,
a: 0x7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9n,
b: 0x26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6n,
G: {
isInfinity: false,
x: 0x8bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262n,
y: 0x547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f046997n,
},
n: 0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7n,
h: 1n,
});
/**
* 320 位素域上的 RFC 5639 曲线
*
* RFC 5639 curve over a 320 bit prime field
*/
export const bp320r1 = Object.freeze({
type: 'Weierstrass',
p: 0xd35e472036bc4fb7e13c785ed201e065f98fcfa6f6f40def4f92b9ec7893ec28fcd412b1f1b32e27n,
a: 0x3ee30b568fbab0f883ccebd46d3f3bb8a2a73513f5eb79da66190eb085ffa9f492f375a97d860eb4n,
b: 0x520883949dfdbc42d3ad198640688a6fe13f41349554b49acc31dccd884539816f5eb4ac8fb1f1a6n,
G: {
isInfinity: false,
x: 0x43bd7e9afb53d8b85289bcc48ee5bfe6f20137d10a087eb6e7871e2a10a599c710af8d0d39e20611n,
y: 0x14fdd05545ec1cc8ab4093247f77275e0743ffed117182eaa9c77877aaac6ac7d35245d1692e8ee1n,
},
n: 0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59311n,
h: 1n,
});
/**
* 384 位素域上的 RFC 5639 曲线
*
* RFC 5639 curve over a 384 bit prime field
*/
export const bp384r1 = Object.freeze({
type: 'Weierstrass',
p: 0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123acd3a729901d1a71874700133107ec53n,
a: 0x7bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f8aa5814a503ad4eb04a8c7dd22ce2826n,
b: 0x04a8c7dd22ce28268b39b55416f0447c2fb77de107dcd2a62e880ea53eeb62d57cb4390295dbc9943ab78696fa504c11n,
G: {
isInfinity: false,
x: 0x1d1c64f068cf45ffa2a63a81b7c13f6b8847a3e77ef14fe3db7fcafe0cbd10e8e826e03436d646aaef87b2e247d4af1en,
y: 0x8abe1d7520f9c2a45cb1eb8e95cfd55262b70b29feec5864e19c054ff99129280e4646217791811142820341263c5315n,
},
n: 0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e9046565n,
h: 1n,
});
/**
* 512 位素域上的 RFC 5639 曲线
*
* RFC 5639 curve over a 512 bit prime field
*/
export const bp512r1 = Object.freeze({
type: 'Weierstrass',
p: 0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca703308717d4d9b009bc66842aecda12ae6a380e62881ff2f2d82c68528aa6056583a48f3n,
a: 0x7830a3318b603b89e2327145ac234cc594cbdd8d3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94can,
b: 0x3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94cadc083e67984050b75ebae5dd2809bd638016f723n,
G: {
isInfinity: false,
x: 0x81aee4bdd82ed9645a21322e9c4c6a9385ed9f70b5d916c1b43b62eef4d0098eff3b1f78e2d0d48d50d1687b93b97d5f7c6d5047406a5e688b352209bcb9f822n,
y: 0x7dde385d566332ecc0eabfa9cf7822fdf209f70024a57b1aa000c55b881f8111b2dcde494a5f485e5bca4bd88a2763aed1ca2b2fa8f0540678cd1e0f3ad80892n,
},
n: 0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90069n,
h: 1n,
});
import { wrap } from './utils';
/**
* 散列算法包装器,
* 提供散列算法描述, 以实现 `HMAC` 等拓展算法.
*
* Hash algorithm wrapper,
* provide hash algorithm description to implement extended algorithms such as `HMAC`.
*
* @param {Digest} digest - 摘要函数 / digest function
* @param {HashDescription} description - 算法描述 / algorithm description
*
* ```ts
* const digest: Digest = (M: Uint8Array): U8 => { ... }
* const description: HashDescription = { ... }
* const hash = createHash(digest, description)
* ```
*/
export const createHash = (digest, description) => wrap(digest, description);
/**
* 元组散列算法包装器
*
* Tuple hash algorithm wrapper
*
* @param {TupleDigest} digest - 元组摘要函数 / tuple digest function
* @param {TupleHashDescription} description - 算法描述 / algorithm description
*
* ```ts
* const digest: TupleDigest = (M: Uint8Array[]): U8 => { ... }
* const description: TupleHashDescription = { ... }
* const hash = createTupleHash(digest, description)
* ```
*/
export const createTupleHash = (digest, description) => wrap(digest, description);
export const createKeyHash = (digest, description) => wrap(digest, description);
import { Counter, joinBuffer } from './utils';
/**
* ANSI-X9.63 Key Derivation Function
*
* ANSI-X9.63 密钥派生函数
*/
export function x963kdf(hash) {
const d_bit = hash.DIGEST_SIZE << 3;
return (k_bit, ikm, info = new Uint8Array(0)) => {
/** Output Keying Material */
const okm = [];
const counter = new Counter([0, 0, 0, 1]);
for (let okm_bit = 0; okm_bit < k_bit; okm_bit += d_bit) {
const data = joinBuffer(ikm, counter, info);
okm.push(hash(data));
counter.inc();
}
return joinBuffer(...okm).slice(0, k_bit >> 3);
};
}
/**
* HMAC-based Key Derivation Function (HKDF), please combine `hmac` and `hash` externally to control the behavior of calling `hmac` inside the function.
*
* 基于 HMAC 的密钥派生函数 (HKDF), 请在外部组合 `hmac` 和 `hash` 函数, 以控制在函数内部调用 `hmac` 时的行为.
*/
export function hkdf(k_hash, salt = new Uint8Array(k_hash.DIGEST_SIZE)) {
const d_bit = k_hash.DIGEST_SIZE << 3;
return (k_bit, ikm, info = new Uint8Array(0)) => {
/** Pseudo-Random Key */
const prk = k_hash(salt, ikm);
/** Output Keying Material */
const okm = [];
const counter = new Uint8Array([1]);
let prv = new Uint8Array(0);
for (let okm_bit = 0; okm_bit < k_bit; okm_bit += d_bit) {
prv = k_hash(prk, joinBuffer(prv, info, counter));
okm.push(prv);
counter[0]++;
}
return joinBuffer(...okm).slice(0, k_bit >> 3);
};
}
/**
* Password-Based Key Derivation Function 2 (PBKDF2), please combine `hmac` and `hash` externally to control the behavior of calling `hmac` inside the function.
* Also, PBKDF2 does not use the `info` parameter, if provided, it will be ignored.
*
* PBKDF2 密码基础密钥派生函数 (PBKDF2), 请在外部组合 `hmac` 和 `hash` 函数, 以控制在函数内部调用 `hmac` 时的行为.
* 同时, PBKDF2 不使用 `info` 参数, 如果提供 `info`, 将被忽略.
*/
export function pbkdf2(k_hash, salt = new Uint8Array(k_hash.DIGEST_SIZE), iterations = 1000) {
const d_bit = k_hash.DIGEST_SIZE << 3;
return (k_bit, ikm) => {
ikm = joinBuffer(ikm);
/** Output Keying Material */
const okm = [];
let T;
let U;
const counter = new Counter([0, 0, 0, 1]);
for (let okm_bit = 0; okm_bit < k_bit; okm_bit += d_bit) {
T = new Uint8Array(k_hash.DIGEST_SIZE);
U = joinBuffer(salt, counter);
for (let i = 0; i < iterations; i++) {
U = k_hash(ikm, U);
T.forEach((_, j) => T[j] ^= U[j]);
}
okm.push(T);
counter.inc();
}
return joinBuffer(...okm).slice(0, k_bit >> 3);
};
}
import { U8, modPow } from './utils';
// * Constants
/** deterministic >= 1 - 0.5^t */
const T = 40;
const LOW_PRIMES = [2n, 3n, 5n, 7n, 11n, 13n, 17n, 19n, 23n, 29n, 31n, 37n, 41n, 43n, 47n, 53n, 59n, 61n, 67n, 71n, 73n, 79n, 83n, 89n, 97n, 101n, 103n, 107n, 109n, 113n, 127n, 131n, 137n, 139n, 149n, 151n, 157n, 163n, 167n, 173n, 179n, 181n, 191n, 193n, 197n, 199n, 211n, 223n, 227n, 229n, 233n, 239n, 241n, 251n, 257n, 263n, 269n, 271n, 277n, 281n, 283n, 293n, 307n, 311n, 313n, 317n, 331n, 337n, 347n, 349n, 353n, 359n, 367n, 373n, 379n, 383n, 389n, 397n, 401n, 409n, 419n, 421n, 431n, 433n, 439n, 443n, 449n, 457n, 461n, 463n, 467n, 479n, 487n, 491n, 499n, 503n, 509n, 521n, 523n, 541n, 547n, 557n, 563n, 569n, 571n, 577n, 587n, 593n, 599n, 601n, 607n, 613n, 617n, 619n, 631n, 641n, 643n, 647n, 653n, 659n, 661n, 673n, 677n, 683n, 691n, 701n, 709n, 719n, 727n, 733n, 739n, 743n, 751n, 757n, 761n, 769n, 773n, 787n, 797n, 809n, 811n, 821n, 823n, 827n, 829n, 839n, 853n, 857n, 859n, 863n, 877n, 881n, 883n, 887n, 907n, 911n, 919n, 929n, 937n, 941n, 947n, 953n, 967n, 971n, 977n, 983n, 991n, 997n];
const LOW_PRIMES_LIMIT = (1n << 26n) / LOW_PRIMES[LOW_PRIMES.length - 1];
// * Functions
/** Miller-Rabin 素性测试 / Primality Test */
function MillerRabin(n, t) {
const n_1 = n - 1n;
let s = 0n;
let d = n_1;
while ((d & 1n) === 0n) {
d >>= 1n;
s++;
}
t = (t + 1) >> 1;
if (t > LOW_PRIMES.length)
t = LOW_PRIMES.length;
const tested = [2n];
for (let i = 0; i < t; ++i) {
// Pick bases at random
let base;
do {
base = LOW_PRIMES[Math.floor(Math.random() * LOW_PRIMES.length)];
} while (tested.includes(base));
tested.push(base);
if (StrongPseudoPrime(n, n_1, s, d, base) === false) {
return false;
}
}
return true;
}
/**
* 根据费马小定理: `base^(n-1) ≡ 1 (mod n)` 时 `n` 可能是素数,
* 通过将 `n-1` 分解为 `2^s * d` 优化计算
*
* According to Fermat's Little Theorem: `base^(n-1) ≡ 1 (mod n)` when `n` may be a prime,
* optimize the calculation by decomposing `n-1` into `2^s * d`
*
* @param {bigint} n - 待测试的数
* @param {bigint} n_1 - n - 1
* @param {bigint} s - n - 1 = 2^s * d
* @param {bigint} d - n - 1 = 2^s * d
* @param {bigint} base - 测试基数
*/
function StrongPseudoPrime(n, n_1, s, d, base) {
let x = modPow(base, d, n);
if (x === 1n || x === n_1)
return true;
let y = 0n;
for (let i = 1; i < s; i++) {
y = modPow(x, 2n, n);
if (y === 1n && x !== 1n && x !== n_1)
return false;
x = y;
}
return y === 1n;
}
/**
* 高级素性测试: 确定性 >= 1-.5^t
*
* Advanced primality test: deterministic >= 1-.5^t
*/
function _isProbablePrime(n, t = T) {
// 低素数倍数
for (let i = 1; i < LOW_PRIMES.length;) {
let m = LOW_PRIMES[i];
let j = i + 1;
while (j < LOW_PRIMES.length && m < LOW_PRIMES_LIMIT) {
m *= LOW_PRIMES[j++];
}
m = n % m;
while (i < j) {
if (m % LOW_PRIMES[i++] === 0n)
return false;
}
}
return MillerRabin(n, t);
}
function genPrimeCandidate(buffer) {
crypto.getRandomValues(buffer);
buffer[0] |= 0x80;
let n = buffer.toBI() | 1n;
const n_mod_6 = n % 6n;
if (n_mod_6 !== 1n && n_mod_6 !== 5n)
n += 4n;
return n;
}
/** 随机素数生成器 / Random Prime Generator */
export const genPrime = (b) => {
const buffer = new U8(b >> 3);
let n;
do {
n = genPrimeCandidate(buffer);
} while (!_isProbablePrime(n));
return n;
};
/**
* 素性测试: 确定性 >= 1-.5^t
*
* Primality test: deterministic >= 1-.5^t
*
* @param {bigint} n - 待测试的数 / Number to be tested
* @param {number} t - 测试轮数 / Number of tests
*/
export function isProbablePrime(n, t = T) {
if (t <= 0)
return false;
// 偶数
if ((n & 1n) === 0n)
return false;
// 六倍原理
const n_mod_6 = n % 6n;
if (n_mod_6 !== 1n && n_mod_6 !== 5n)
return false;
// 小素数
if (n <= LOW_PRIMES[LOW_PRIMES.length - 1])
return LOW_PRIMES.includes(n);
return _isProbablePrime(n, t);
}
// * Math utility functions
/** 32-bit 循环左移 */
export function rotateL32(x, n) {
x >>>= 0;
n %= 32;
x = (x << n) | (x >>> (32 - n));
return x >>> 0;
}
/** 32-bit 循环右移 */
export function rotateR32(x, n) {
x >>>= 0;
n %= 32;
x = (x >>> n) | (x << (32 - n));
return x >>> 0;
}
/**
* 位循环左移 / Rotate Left
*
* @param {number} bit - 位数 / bit
* @param {number | bigint} x - 数值 / value
* @param {number | bigint} n - 位移 / shift
* @param {bigint} [mask] - 位掩码 / bit mask
*/
export function rotateL(bit, x, n, mask) {
bit = BigInt(bit);
mask ??= genBitMask(bit);
x = BigInt(x);
n = BigInt(n);
x &= mask;
n %= bit;
x = (x << n) | (x >> (bit - n));
return x & mask;
}
/**
* 位循环右移 / Rotate Right
*
* @param {number} bit - 位数 / bit
* @param {number | bigint} x - 数值 / value
* @param {number | bigint} n - 位移 / shift
* @param {bigint} [mask] - 位掩码 / bit mask
*/
export function rotateR(bit, x, n, mask) {
bit = BigInt(bit);
mask ??= genBitMask(bit);
x = BigInt(x);
n = BigInt(n);
x &= mask;
n %= bit;
x = (x >> n) | (x << (bit - n));
return x & mask;
}
/** 生成随机大整数 / Generate Random BigInt */
export function genRandomBI(max, byte) {
let result = 0n;
// 生成随机数
const buffer = new U8(byte);
do {
crypto.getRandomValues(buffer);
result = buffer.toBI();
} while (result >= max);
return { buffer, result };
}
/**
* 获取大整数的比特长度
*
* Get the bit length of a BigInt
*/
export function getBIBits(n) {
let bit = 0;
while (n > 0) {
bit++;
n >>= 1n;
}
return bit;
}
/**
* 生成位掩码 / Generate Bit Mask
*
* @param {number} w - 位数 / bit
*
* ```ts
* const mask = genBitMask(8) // 0xFFn
* ```
*/
export function genBitMask(w) {
w = BigInt(w);
let mask = 0x0n;
for (let i = 0; i < w; i++) {
mask = (mask << 1n) | 1n;
}
return mask;
}
/**
* 扩展欧几里得算法
*
* Extended Euclidean Algorithm
*
* - gcd: 最大公约数 / greatest common divisor
* - a_inv: a 的模逆 / modular inverse of a
* - b_inv: b 的模逆 / modular inverse of b
*/
export function extendedEuclidean(a, b) {
let [s0, s1, t0, t1, r0, r1] = [1n, 0n, 0n, 1n, a, b];
if (b === 0n) {
return {
gcd: a,
a_inv: 1n,
b_inv: 0n,
};
}
while (r1 !== 0n) {
const q = r0 / r1;
[r0, r1] = [r1, r0 - q * r1];
[s0, s1] = [s1, s0 - q * s1];
[t0, t1] = [t1, t0 - q * t1];
}
return {
gcd: r0,
a_inv: s0,
b_inv: t0,
};
}
/**
* 勒让德符号
*
* Legendre Symbol
*/
export function legendreSymbol(a, p) {
return modPow(a, (p - 1n) >> 1n, p);
}
/**
* 托内利-香克斯算法
*
* Tonelli-Shanks Algorithm
*/
export function tonelliShanks(a, p) {
if (legendreSymbol(a, p) !== 1n) {
throw new KitError('There is no square root');
}
if (a === 0n) {
return 0n;
}
if (p === 2n) {
return a;
}
if (p % 4n === 3n) {
return modPow(a, (p + 1n) >> 2n, p);
}
let q = p - 1n;
let s = 0n;
while (mod(q, 2n) === 0n) {
q >>= 1n;
s++;
}
let z = 2n;
while (legendreSymbol(z, p) !== p - 1n) {
z++;
}
let m = s;
let c = modPow(z, q, p);
let t = modPow(a, q, p);
let r = modPow(a, (q + 1n) >> 1n, p);
while (t !== 0n && t !== 1n) {
let t2i = t;
let i = 1n;
for (; i < m; i++) {
t2i = modPow(t2i, 2n, p);
if (t2i === 1n) {
break;
}
}
const b = modPow(c, 1n << (m - i - 1n), p);
m = i;
c = modPow(b, 2n, p);
t = t * c % p;
r = r * b % p;
}
return r;
}
/**
* 最大公约数
*
* Greatest Common Divisor
*/
export function gcd(a, b) {
return extendedEuclidean(a, b).gcd;
}
/**
* 最小公倍数
*
* Least Common Multiple
*/
export function lcm(a, b) {
return a * b / gcd(a, b);
}
/**
* 求模: a mod b
*
* Modulo operation: a mod b
*
* @param {bigint} a - dividend
* @param {bigint} b - divisor
*/
export function mod(a, b) {
const r = a % b;
return r < 0n ? r + b : r;
}
/**
* 模幂运算: x ^ y mod n
*
* Modular exponentiation: x ^ y mod n
*
* @param {bigint} x - base
* @param {bigint} y - exponent
* @param {bigint} n - modulus
*/
export function modPow(x, y, n) {
x %= n;
let r = 1n;
while (y > 0n) {
if (y & 1n)
r = r * x % n;
x = x * x % n;
y >>= 1n;
}
return r;
}
/**
* 模逆运算: e ≡ x ^ -1 (mod n)
*
* Modular inverse operation: e ≡ x ^ -1 (mod n)
*
* @param {bigint} x - base
* @param {bigint} n - modulus
*/
export function modInverse(x, n) {
const { gcd, a_inv: inv } = extendedEuclidean(x, n);
if (gcd !== 1n) {
throw new KitError('Modular inverse does not exist');
}
return mod(inv, n);
}
/**
* 模素平方根运算: n ^ 0.5 (mod p)
*
* Modular prime square operation: n ^ 0.5 (mod p)
*/
export function modPrimeSquare(n, p) {
n = mod(n, p);
return tonelliShanks(n, p);
}
// * Buffer utility functions
/**
* @extends Uint8Array
*/
export class U8 extends Uint8Array {
/**
* 从 U8 中获取一个字 / Get a word from U8
*
* @param {number} word_byte - 字长 / word size
* @param {number} index - 字索引 / word index
* @param {boolean} [little_endian] - 是否为小端序 / little-endian (default: false)
*/
getWord(word_byte, index, little_endian = false) {
const offset = index * word_byte;
const buffer = this.subarray(offset, offset + word_byte);
return little_endian ? buffer.toBI(true) : buffer.toBI();
}
/**
* 将一个字写入 U8 / Set a word to U8
*
* @param {number} word_byte - 字长 / word size
* @param {number} index - 字索引 / word index
* @param {bigint | Uint8Array} word - 字 / word
* @param {boolean} [little_endian] - 是否为小端序 / little-endian (default: false)
*/
setWord(word_byte, index, word, little_endian = false) {
const offset = index * word_byte;
const buffer = typeof word === 'bigint' ? U8.fromBI(word, word_byte) : word;
this.set(little_endian ? buffer.toReversed() : buffer, offset);
}
/**
* U8 视图 / U8 view
*
* @param {number} word_byte - 字长 / word size
*/
view(word_byte) {
const length = Math.floor(this.length / word_byte);
const get = (index, little_endian = false) => this.getWord(word_byte, index, little_endian);
const set = (index, word, little_endian = false) => this.setWord(word_byte, index, word, little_endian);
return { get, set, length };
}
/**
* 将 U8 编码为字符串 / stringify U8 to encoded string
*/
to(codec) {
return codec(this);
}
/**
* 将 U8 转换为 BigInt / Convert U8 to BigInt
*
* @param {boolean} [little_endian] - 是否为小端序 / little-endian (default: false)
*/
toBI(little_endian = false) {
const buffer = little_endian ? this.toReversed() : this;
let bigint = 0n;
buffer.forEach(byte => bigint = (bigint << 8n) | BigInt(byte));
return bigint;
}
/**
* Convert U8 to Uint8Array
*
* 将 U8 转换为 Uint8Array
*/
toUint8Array() {
return new Uint8Array(this);
}
/**
* Convert string to U8
*
* 将 字符串 转换为 U8
*/
static fromString(input, codec) {
return codec(input);
}
/**
* Convert BigInt to U8
*
* 将 BigInt 转换为 U8
*/
static fromBI(bigint, length, little_endian = false) {
length = length || (getBIBits(bigint) + 7) >> 3;
const buffer = new U8(length);
if (little_endian) {
for (let i = 0; i < buffer.length; i++) {
buffer[i] = Number(bigint & 0xffn);
bigint >>= 8n;
}
}
else {
for (let i = buffer.length - 1; i >= 0; i--) {
buffer[i] = Number(bigint & 0xffn);
bigint >>= 8n;
}
}
return buffer;
}
static from(arrayLike, mapfn, thisArg) {
return new U8(super.from(arrayLike, mapfn, thisArg));
}
filter(predicate, thisArg) {
return new U8(super.filter(predicate, thisArg));
}
map(callbackfn, thisArg) {
return new U8(super.map(callbackfn, thisArg));
}
static of(...items) {
return new U8(super.of(...items));
}
toReversed() {
return super.reverse();
}
toSorted(compareFn) {
return super.sort(compareFn);
}
reverse() {
return super.reverse();
}
slice(start, end) {
return new U8(super.slice(start, end));
}
subarray(begin, end) {
return new U8(super.subarray(begin, end));
}
with(index, value) {
return new U8(super.with(index, value));
}
}
/**
* Merging multiple ArrayBuffers
*
* 合并多个 ArrayBuffer
*/
export function joinBuffer(...buffers) {
const byteTotal = buffers.reduce((acc, cur) => acc + cur.byteLength, 0);
const result = new U8(byteTotal);
let offset = 0;
for (const buffer of buffers) {
result.set(new U8(buffer), offset);
offset += buffer.byteLength;
}
return result;
}
/**
* resize ArrayBuffer
*
* 调整 ArrayBuffer 大小
*
* @param {ArrayBuffer} buffer
* @param {number} size - byte
*/
export function resizeBuffer(buffer, size) {
const B = new U8(size);
B.set(new U8(buffer));
return B;
}
const nibbleReverseMap = [0x0n, 0x8n, 0x4n, 0xcn, 0x2n, 0xan, 0x6n, 0xen, 0x1n, 0x9n, 0x5n, 0xdn, 0x3n, 0xbn, 0x7n, 0xfn];
/**
* 快速翻转字节位序 / Fast Reverse Byte's Bit Order
*
* @param {number} byte - 字节 / byte
*/
export function reverseBit(byte) {
byte &= 0xFF;
const b_h = nibbleReverseMap[byte >> 4];
const b_l = nibbleReverseMap[byte & 0xF];
return (b_l << 4n) | b_h;
}
export class Counter extends U8 {
/**
* @param {number} offset - 计数器偏移 / counter offset
* @param {number} length - 计数器长度 / counter length
*/
inc(offset, length, little_endian = false) {
// 如果不提供偏移,则默认计数器从 0 开始
offset = offset || 0;
if (offset < 0 || offset >= this.length) {
throw new KitError('Invalid counter offset');
}
// 如果不提供长度,则默认计数器长度为剩余长度
length = length || this.length - offset;
if (length < 0 || offset + length > this.length) {
throw new KitError('Invalid counter length');
}
if (little_endian) {
for (let i = offset; i < offset + length; i++) {
if (this[i] < 0xFF) {
this[i] += 1;
break;
}
this[i] = 0;
}
}
else {
for (let i = offset + length - 1; i >= offset; i--) {
if (this[i] < 0xFF) {
this[i] += 1;
break;
}
this[i] = 0;
}
}
}
}
// * Other utility functions
export function wrap(...args) {
if (args.length === 0) {
return {};
}
// @ts-expect-error Object assign
return Object.assign(...args);
}
export class KitError extends Error {
constructor(message) {
super(message);
this.name = 'mima-kit Error';
}
}
import { createKeyHash } from '../core/hash';
import { joinBuffer } from '../core/utils';
function _hmac(hash, K, M) {
const { BLOCK_SIZE } = hash;
const K0 = new Uint8Array(BLOCK_SIZE);
K0.set(K.length > BLOCK_SIZE ? hash(K) : K);
const iPad = K0.map(byte => (byte ^ 0x36));
const oPad = K0.map(byte => (byte ^ 0x5C));
const innerBuffer = hash(joinBuffer(iPad, M));
const outerBuffer = hash(joinBuffer(oPad, innerBuffer));
return outerBuffer;
}
/**
* FIPS.198-1: 散列消息认证码 (HMAC).
* 如果 `d_size` 大于散列算法的摘要大小, 则回退到散列算法的摘要大小.
*
* FIPS.198-1: The Keyed-Hash Message Authentication Code (HMAC).
* If `d_size` is larger than the hash algorithm's digest size, fallback to the hash algorithm's digest size.
*
* @param {Hash} hash - 散列算法 / hash algorithm
* @param {number} [d_size] - 摘要大小 (bit) / digest size (bit)
* @param {number} [k_size] - 推荐密钥大小 (bit) / recommended key size (bit)
*/
export function hmac(hash, d_size, k_size) {
const { ALGORITHM, BLOCK_SIZE, DIGEST_SIZE } = hash;
d_size = d_size ? Math.min(d_size >> 3, DIGEST_SIZE) : DIGEST_SIZE;
k_size = k_size ? k_size >> 3 : DIGEST_SIZE;
const description = {
ALGORITHM: `HMAC-${ALGORITHM}-${d_size << 3}`,
BLOCK_SIZE,
DIGEST_SIZE: d_size,
KEY_SIZE: k_size,
};
return createKeyHash((K, M) => _hmac(hash, K, M).slice(0, d_size), description);
}
import { createHash } from '../core/hash';
import { joinBuffer } from '../core/utils';
import { turboshake128, turboshake256 } from './turboSHAKE';
function lengthEncode(x) {
const S = [];
while (x > 0) {
S.unshift(x & 0xFF);
x >>= 8;
}
S.push(S.length);
return new Uint8Array(S);
}
/**
* KangarooTwelve
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} C - 自定义参数 / Customization
* @param {typeof turboshake128} SHAKE - TurboSHAKE 函数 / Function
* @param {number} cv - 中间压缩值长度 / Compressed Value Size (bit)
*/
function kt(d, C, SHAKE, cv) {
return (M) => {
const length_encode = lengthEncode(C.length);
const S = joinBuffer(M, C, length_encode);
if (S.length <= 8192) {
return SHAKE(d, 0x07)(S);
}
else {
// KangarooTwelve hopping
const FinalNode = [];
FinalNode.push(S.slice(0, 8192));
FinalNode.push(new Uint8Array([0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]));
let offset = 8192;
let num_block = 0;
while (offset < S.length) {
const CV = SHAKE(cv, 0x0B)(S.slice(offset, offset += 8192));
FinalNode.push(CV);
num_block++;
}
FinalNode.push(lengthEncode(num_block));
FinalNode.push(new Uint8Array([0xFF, 0xFF]));
return SHAKE(d, 0x06)(joinBuffer(...FinalNode));
}
};
}
/**
* KangarooTwelve 128
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} [C] - 自定义参数 / Customization
*/
export function kt128(d, C = new Uint8Array()) {
return createHash(kt(d, C, turboshake128, 256), {
ALGORITHM: `KangarooTwelve128/${d}`,
BLOCK_SIZE: 8192,
DIGEST_SIZE: d >> 3,
});
}
/**
* KangarooTwelve 256
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} [C] - 自定义参数 / Customization
*/
export function kt256(d, C = new Uint8Array()) {
return createHash(kt(d, C, turboshake256, 512), {
ALGORITHM: `KangarooTwelve256/${d}`,
BLOCK_SIZE: 8192,
DIGEST_SIZE: d >> 3,
});
}
import { KitError, U8, genBitMask, joinBuffer, rotateL } from '../core/utils';
// * Constants
/**
* ρ(A) 位移表 / Shift Table
*/
const R = [
[0n, 36n, 3n, 41n, 18n],
[1n, 44n, 10n, 45n, 2n],
[62n, 6n, 43n, 15n, 61n],
[28n, 55n, 25n, 21n, 56n],
[27n, 20n, 39n, 8n, 14n],
];
/**
* https://datatracker.ietf.org/doc/draft-irtf-cfrg-kangarootwelve/
*/
const RC12 = [
0x000000008000808bn,
0x800000000000008bn,
0x8000000000008089n,
0x8000000000008003n,
0x8000000000008002n,
0x8000000000000080n,
0x000000000000800an,
0x800000008000000an,
0x8000000080008081n,
0x8000000000008080n,
0x0000000080000001n,
0x8000000080008008n,
];
/**
* `RCGen(6, 24)`
*/
const RC24 = [
0x0000000000000001n,
0x0000000000008082n,
0x800000000000808an,
0x8000000080008000n,
0x000000000000808bn,
0x0000000080000001n,
0x8000000080008081n,
0x8000000000008009n,
0x000000000000008an,
0x0000000000000088n,
0x0000000080008009n,
0x000000008000000an,
0x000000008000808bn,
0x800000000000008bn,
0x8000000000008089n,
0x8000000000008003n,
0x8000000000008002n,
0x8000000000000080n,
0x000000000000800an,
0x800000008000000an,
0x8000000080008081n,
0x8000000000008080n,
0x0000000080000001n,
0x8000000080008008n,
];
const mask64 = genBitMask(64);
const rotateL64 = (x, n) => rotateL(64, x, n, mask64);
// * Keccak Utils
/**
* RC Table Generation Function
*
* @param {number} l - log2(w)
* @param {number} [nr] - 轮数
*/
export function RCGen(l = 6, nr = 24) {
const RCTable = [];
for (let ir = 0; ir < nr; ir++) {
let RC = 0n;
for (let j = 0; j <= l; j++) {
const t = j + 7 * ir;
// rc(t)
let rc;
if (t % 255 === 0) {
rc = 1n;
}
else {
let R = 0x80n;
for (let i = 1; i <= t % 255; i++) {
const b = R & 1n;
R ^= (b << 8n) | (b << 4n) | (b << 3n) | (b << 2n);
R >>= 1n;
}
rc = R >> 7n;
}
// RC[2^j - 1] = rc(j + 7ir)
RC |= (rc << BigInt(2 ** j - 1));
}
RCTable.push(RC);
}
return RCTable;
}
/**
* @param {number} w - 工作字长度 / Word Size
*/
export function RGen(w) {
w = BigInt(w);
const R = [
[0n, 36n, 3n, 105n, 210n],
[1n, 300n, 10n, 45n, 66n],
[190n, 6n, 171n, 15n, 253n],
[28n, 276n, 120n, 136n, 55n],
[91n, 276n, 210n, 66n, 253n],
];
return R.map(x => x.map(y => y % w));
}
/**
* create a 5x5 `State Array`
*
* 创建一个 5x5 `状态矩阵`
*/
function createStateArray() {
return Array.from({ length: 5 }).map(() => new BigUint64Array(5));
}
/**
* Converting `State` to `State Arrays`
*
* 将 `状态` 转换为 `状态矩阵`
*/
function toStateArray(S) {
const A = createStateArray();
const view = new DataView(S.buffer);
for (let x = 0; x < 5; x++) {
for (let y = 0; y < 5; y++) {
A[x][y] = view.getBigUint64((y * 5 + x) << 3, true);
}
}
return A;
}
/**
* Converting `State Arrays` to `State`
*
* 将 `状态矩阵` 转换为 `状态`
*/
function toState(A) {
const S = new Uint8Array(200);
const view = new DataView(S.buffer);
for (let x = 0; x < 5; x++) {
for (let y = 0; y < 5; y++) {
view.setBigUint64((y * 5 + x) << 3, A[x][y], true);
}
}
return S;
}
// * Mapping Function
/** Algorithm 1: θ(A) */
function theta(A) {
const C = new BigUint64Array(5);
const D = new BigUint64Array(5);
for (let x = 0; x < 5; x++) {
C[x] = A[x][0] ^ A[x][1] ^ A[x][2] ^ A[x][3] ^ A[x][4];
}
for (let x = 0; x < 5; x++) {
D[x] = C[(x + 4) % 5] ^ rotateL64(C[(x + 1) % 5], 1n);
for (let y = 0; y < 5; y++) {
A[x][y] = A[x][y] ^ D[x];
}
}
return A;
}
/** Algorithm 2: ρ(A) */
// eslint-disable-next-line unused-imports/no-unused-vars
function rho(A) {
const _A = createStateArray();
for (let x = 0; x < 5; x++) {
for (let y = 0; y < 5; y++) {
_A[x][y] = rotateL64(A[x][y], R[x][y]);
}
}
return _A;
}
/** Algorithm 3: π(A) */
// eslint-disable-next-line unused-imports/no-unused-vars
function pi(A) {
const _A = createStateArray();
for (let x = 0; x < 5; x++) {
for (let y = 0; y < 5; y++) {
_A[x][y] = A[(x + 3 * y) % 5][x];
}
}
return _A;
}
/**
* Combining π(ρ(A))
*
* 合并执行 π(ρ(A))
*/
function rhoPi(A) {
const _A = createStateArray();
for (let x = 0; x < 5; x++) {
for (let y = 0; y < 5; y++) {
_A[y][(2 * x + 3 * y) % 5] = rotateL64(A[x][y], R[x][y]);
}
}
return _A;
}
/** Algorithm 4: χ(A) */
function chi(A) {
const _A = createStateArray();
for (let x = 0; x < 5; x++) {
for (let y = 0; y < 5; y++) {
_A[x][y] = A[x][y] ^ ((~A[(x + 1) % 5][y]) & A[(x + 2) % 5][y]);
}
}
return _A;
}
/** Algorithm 6: ι(A, ir) */
function iota(A, RC) {
A[0][0] = A[0][0] ^ RC;
return A;
}
/**
* `Keccak-p[1600, nr]` 置换函数 / Permutate Function
*
* @param {number} [nr] - 轮数 / Rounds (default: 24)
*/
export function keccak_p_1600(nr = 24) {
// b = 1600
const bByte = 200;
const l = 6;
// 当轮数非默认的情况下,重新生成 RC
let RC;
if (nr === 12) {
RC = RC12;
}
else if (nr === 24) {
RC = RC24;
}
else {
RC = RCGen(l, nr);
}
return (S) => {
if (S.byteLength !== bByte) {
throw new KitError('Invalid state size');
}
let A = toStateArray(S);
for (let i = 0; i < nr; i++) {
A = iota(chi(rhoPi(theta(A))), RC[i]);
}
return new U8(toState(A));
};
}
/**
* `SPONGE` & `Keccak-p[1600]`
*
* @param {number} r_byte - 处理速率 / Rate
* @param {number} d_byte - 输出长度 / Digest Size
* @param {SpongePadding} pad - 填充函数 / Padding Function
* @param {Keccak_p} f - Keccak-p 置换函数 / Permutate Function
*/
export function sponge_1600(r_byte, d_byte, pad, f = keccak_p_1600()) {
return (M) => {
// * 填充
const P = pad(M);
// * 吸收
let S = new Uint8Array(200);
let i = 0;
while (i < P.byteLength) {
const Pi = P.slice(i, i += r_byte);
S.forEach((byte, index) => S[index] = byte ^ Pi[index]);
S = f(S);
}
// * 挤出
const z = [S.slice(0, r_byte)];
let z_byte = r_byte;
while (z_byte < d_byte) {
S = f(S);
z.push(S.slice(0, r_byte));
z_byte += r_byte;
}
// * 截断输出
return joinBuffer(...z).slice(0, d_byte);
};
}
import { createHash } from '../core/hash';
import { U8, rotateL32 } from '../core/utils';
// * Constants
/**
* 轮常量列表 K 由 64 个 32 位无符号整数组成, 使用 1 到 64 的正弦函数生成.
*
* The round constants K is a list of 64 32-bit unsigned integers,
* generated by the sine function from 1 to 64.
*
* ```ts
* const K: number[] = []
* for (let i = 0; i < 64; i++) {
* K[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) >>> 0
* }
* ```
*/
const K = new Uint32Array([0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE, 0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501, 0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE, 0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821, 0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA, 0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8, 0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED, 0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A, 0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C, 0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70, 0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05, 0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665, 0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039, 0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1, 0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1, 0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391]);
// * Function
function FF(a, b, c, d, m, s, k) {
const n = a + ((b & c) | (~b & d)) + m + k;
return rotateL32(n, s) + b;
}
function GG(a, b, c, d, m, s, k) {
const n = a + ((b & d) | (c & ~d)) + m + k;
return rotateL32(n, s) + b;
}
function HH(a, b, c, d, m, s, k) {
const n = a + (b ^ c ^ d) + m + k;
return rotateL32(n, s) + b;
}
function II(a, b, c, d, m, s, k) {
const n = a + (c ^ (b | ~d)) + m + k;
return rotateL32(n, s) + b;
}
// * Algorithm
function digest(message) {
// * 初始化
const state = new Uint32Array([0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476]);
const m_byte = message.length;
const m_bit = BigInt(m_byte) << 3n;
const block_size = 64;
// ceil((M_BYTE + 9) / 64)
const block_total = (m_byte + 9 + 63) >> 6;
// * 填充
const p = new U8(block_total * block_size);
p.set(message);
// appending the bit '1' to the message
p[m_byte] = 0x80;
// appending length
const p_view = new DataView(p.buffer);
p_view.setBigUint64(p.length - 8, m_bit, true);
// * 分块处理
for (let offset = 0; offset < p.length;) {
// 获取分块
const current_buffer = p.subarray(offset, offset += block_size).buffer;
// 准备状态字
const A = state[0];
const B = state[1];
const C = state[2];
const D = state[3];
let a = A;
let b = B;
let c = C;
let d = D;
// 划分词典
const M = new Uint32Array(current_buffer);
/* Round 1 */
a = FF(a, b, c, d, M[0], 7, K[0]);
d = FF(d, a, b, c, M[1], 12, K[1]);
c = FF(c, d, a, b, M[2], 17, K[2]);
b = FF(b, c, d, a, M[3], 22, K[3]);
a = FF(a, b, c, d, M[4], 7, K[4]);
d = FF(d, a, b, c, M[5], 12, K[5]);
c = FF(c, d, a, b, M[6], 17, K[6]);
b = FF(b, c, d, a, M[7], 22, K[7]);
a = FF(a, b, c, d, M[8], 7, K[8]);
d = FF(d, a, b, c, M[9], 12, K[9]);
c = FF(c, d, a, b, M[10], 17, K[10]);
b = FF(b, c, d, a, M[11], 22, K[11]);
a = FF(a, b, c, d, M[12], 7, K[12]);
d = FF(d, a, b, c, M[13], 12, K[13]);
c = FF(c, d, a, b, M[14], 17, K[14]);
b = FF(b, c, d, a, M[15], 22, K[15]);
/* Round 2 */
a = GG(a, b, c, d, M[1], 5, K[16]);
d = GG(d, a, b, c, M[6], 9, K[17]);
c = GG(c, d, a, b, M[11], 14, K[18]);
b = GG(b, c, d, a, M[0], 20, K[19]);
a = GG(a, b, c, d, M[5], 5, K[20]);
d = GG(d, a, b, c, M[10], 9, K[21]);
c = GG(c, d, a, b, M[15], 14, K[22]);
b = GG(b, c, d, a, M[4], 20, K[23]);
a = GG(a, b, c, d, M[9], 5, K[24]);
d = GG(d, a, b, c, M[14], 9, K[25]);
c = GG(c, d, a, b, M[3], 14, K[26]);
b = GG(b, c, d, a, M[8], 20, K[27]);
a = GG(a, b, c, d, M[13], 5, K[28]);
d = GG(d, a, b, c, M[2], 9, K[29]);
c = GG(c, d, a, b, M[7], 14, K[30]);
b = GG(b, c, d, a, M[12], 20, K[31]);
/* Round 3 */
a = HH(a, b, c, d, M[5], 4, K[32]);
d = HH(d, a, b, c, M[8], 11, K[33]);
c = HH(c, d, a, b, M[11], 16, K[34]);
b = HH(b, c, d, a, M[14], 23, K[35]);
a = HH(a, b, c, d, M[1], 4, K[36]);
d = HH(d, a, b, c, M[4], 11, K[37]);
c = HH(c, d, a, b, M[7], 16, K[38]);
b = HH(b, c, d, a, M[10], 23, K[39]);
a = HH(a, b, c, d, M[13], 4, K[40]);
d = HH(d, a, b, c, M[0], 11, K[41]);
c = HH(c, d, a, b, M[3], 16, K[42]);
b = HH(b, c, d, a, M[6], 23, K[43]);
a = HH(a, b, c, d, M[9], 4, K[44]);
d = HH(d, a, b, c, M[12], 11, K[45]);
c = HH(c, d, a, b, M[15], 16, K[46]);
b = HH(b, c, d, a, M[2], 23, K[47]);
/* Round 4 */
a = II(a, b, c, d, M[0], 6, K[48]);
d = II(d, a, b, c, M[7], 10, K[49]);
c = II(c, d, a, b, M[14], 15, K[50]);
b = II(b, c, d, a, M[5], 21, K[51]);
a = II(a, b, c, d, M[12], 6, K[52]);
d = II(d, a, b, c, M[3], 10, K[53]);
c = II(c, d, a, b, M[10], 15, K[54]);
b = II(b, c, d, a, M[1], 21, K[55]);
a = II(a, b, c, d, M[8], 6, K[56]);
d = II(d, a, b, c, M[15], 10, K[57]);
c = II(c, d, a, b, M[6], 15, K[58]);
b = II(b, c, d, a, M[13], 21, K[59]);
a = II(a, b, c, d, M[4], 6, K[60]);
d = II(d, a, b, c, M[11], 10, K[61]);
c = II(c, d, a, b, M[2], 15, K[62]);
b = II(b, c, d, a, M[9], 21, K[63]);
// 更新状态字
state[0] = A + a;
state[1] = B + b;
state[2] = C + c;
state[3] = D + d;
}
// * 返回状态
return new U8(state.buffer);
}
export const md5 = createHash(digest, {
ALGORITHM: 'MD5',
BLOCK_SIZE: 64,
DIGEST_SIZE: 16,
OID: '1.2.840.113549.2.5',
});
import { createHash } from '../core/hash';
import { U8, rotateL32 } from '../core/utils';
// * Constants
function K(t) {
if (t < 20)
return 0x5A827999;
if (t < 40)
return 0x6ED9EBA1;
if (t < 60)
return 0x8F1BBCDC;
return 0xCA62C1D6;
}
// * Function
const Ch = (x, y, z) => (x & y) ^ ((~x) & z);
const Parity = (x, y, z) => x ^ y ^ z;
const Maj = (x, y, z) => (x & y) ^ (x & z) ^ (y & z);
function ft(x, y, z, t) {
if (t < 20)
return Ch(x, y, z);
if (t < 40)
return Parity(x, y, z);
if (t < 60)
return Maj(x, y, z);
return Parity(x, y, z);
}
// * Algorithm
function digest(message) {
// * 初始化
const state = new U8(20);
const state_view = state.view(4);
state_view.set(0, 0x67452301n);
state_view.set(1, 0xefcdab89n);
state_view.set(2, 0x98badcfen);
state_view.set(3, 0x10325476n);
state_view.set(4, 0xc3d2e1f0n);
const m_byte = message.length;
const m_bit = BigInt(m_byte) << 3n;
const block_size = 64;
// ceil((M_BYTE + 9) / 64)
const block_total = (m_byte + 9 + 63) >> 6;
// * 填充
const p = new U8(block_total * block_size);
p.set(message);
// appending the bit '1' to the message
p[m_byte] = 0x80;
// appending length
const p_view = new DataView(p.buffer);
p_view.setBigUint64(p.length - 8, m_bit);
// * 分块处理
for (let offset = 0; offset < p.length; offset += block_size) {
/** B(n) = p[offset:offset + block_size] */
// 准备状态字
const H0 = Number(state_view.get(0));
const H1 = Number(state_view.get(1));
const H2 = Number(state_view.get(2));
const H3 = Number(state_view.get(3));
const H4 = Number(state_view.get(4));
let a = H0;
let b = H1;
let c = H2;
let d = H3;
let e = H4;
// 合并执行 扩展 & 压缩
const W = new Uint32Array(80);
for (let i = 0; i < 80; i++) {
// 扩展
if (i < 16)
// W[i] = B(n)[i]
W[i] = p_view.getUint32(offset + (i << 2));
else
W[i] = rotateL32(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1);
// 压缩
const T = rotateL32(a, 5) + ft(b, c, d, i) + K(i) + e + W[i];
e = d;
d = c;
c = rotateL32(b, 30);
b = a;
a = T;
}
// 更新状态字
state_view.set(0, BigInt(H0 + a));
state_view.set(1, BigInt(H1 + b));
state_view.set(2, BigInt(H2 + c));
state_view.set(3, BigInt(H3 + d));
state_view.set(4, BigInt(H4 + e));
}
// * 返回状态
return state;
}
export const sha1 = createHash(digest, {
ALGORITHM: 'SHA-1',
BLOCK_SIZE: 64,
DIGEST_SIZE: 20,
OID: '1.3.14.3.2.26',
});
import { createHash } from '../core/hash';
import { U8, rotateR32 } from '../core/utils';
// * Constants
const K = new Uint32Array([0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2]);
// * Function
const Ch = (x, y, z) => (x & y) ^ ((~x) & z);
const Maj = (x, y, z) => (x & y) ^ (x & z) ^ (y & z);
const Sigma0 = (x) => rotateR32(x, 2) ^ rotateR32(x, 13) ^ rotateR32(x, 22);
const Sigma1 = (x) => rotateR32(x, 6) ^ rotateR32(x, 11) ^ rotateR32(x, 25);
const sigma0 = (x) => rotateR32(x, 7) ^ rotateR32(x, 18) ^ (x >>> 3);
const sigma1 = (x) => rotateR32(x, 17) ^ rotateR32(x, 19) ^ (x >>> 10);
// * Algorithm
function digest(state, message) {
// * 初始化
state = state.slice(0);
const state_view = state.view(4);
const m_byte = message.length;
const m_bit = BigInt(m_byte) << 3n;
const block_size = 64;
// ceil((m_byte + 9) / 64)
const block_total = (m_byte + 9 + 63) >> 6;
// * 填充
const p = new U8(block_total * block_size);
p.set(message);
// appending the bit '1' to the message
p[m_byte] = 0x80;
// appending length
const p_view = new DataView(p.buffer);
p_view.setBigUint64(p.length - 8, m_bit);
// * 分块处理
for (let offset = 0; offset < p.length; offset += block_size) {
/** B(n) = p[offset:offset + block_size] */
// 准备状态字
const h0 = Number(state_view.get(0));
const h1 = Number(state_view.get(1));
const h2 = Number(state_view.get(2));
const h3 = Number(state_view.get(3));
const h4 = Number(state_view.get(4));
const h5 = Number(state_view.get(5));
const h6 = Number(state_view.get(6));
const h7 = Number(state_view.get(7));
let a = h0;
let b = h1;
let c = h2;
let d = h3;
let e = h4;
let f = h5;
let g = h6;
let h = h7;
// 合并执行 扩展 & 压缩
const W = new Uint32Array(64);
for (let i = 0; i < W.length; i++) {
// 扩展
if (i < 16)
// W[i] = B(n)[i]
W[i] = p_view.getUint32(offset + (i << 2));
else
W[i] = sigma1(W[i - 2]) + W[i - 7] + sigma0(W[i - 15]) + W[i - 16];
// 压缩
const T1 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];
const T2 = Sigma0(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
}
// 更新状态字
state_view.set(0, BigInt(h0 + a));
state_view.set(1, BigInt(h1 + b));
state_view.set(2, BigInt(h2 + c));
state_view.set(3, BigInt(h3 + d));
state_view.set(4, BigInt(h4 + e));
state_view.set(5, BigInt(h5 + f));
state_view.set(6, BigInt(h6 + g));
state_view.set(7, BigInt(h7 + h));
}
// * 返回状态
return state;
}
function sha224Digest(M) {
// * 初始化 SHA-224 状态
const state = new U8(32);
const state_view = state.view(4);
state_view.set(0, 0xc1059ed8n);
state_view.set(1, 0x367cd507n);
state_view.set(2, 0x3070dd17n);
state_view.set(3, 0xf70e5939n);
state_view.set(4, 0xffc00b31n);
state_view.set(5, 0x68581511n);
state_view.set(6, 0x64f98fa7n);
state_view.set(7, 0xbefa4fa4n);
return digest(state, M).slice(0, 28);
}
function sha256Digest(M) {
// * 初始化 SHA-256 状态
const state = new U8(32);
const state_view = state.view(4);
state_view.set(0, 0x6a09e667n);
state_view.set(1, 0xbb67ae85n);
state_view.set(2, 0x3c6ef372n);
state_view.set(3, 0xa54ff53an);
state_view.set(4, 0x510e527fn);
state_view.set(5, 0x9b05688cn);
state_view.set(6, 0x1f83d9abn);
state_view.set(7, 0x5be0cd19n);
return digest(state, M);
}
export const sha224 = createHash(sha224Digest, {
ALGORITHM: 'SHA-224',
BLOCK_SIZE: 64,
DIGEST_SIZE: 28,
OID: '2.16.840.1.101.3.4.2.4',
});
export const sha256 = createHash(sha256Digest, {
ALGORITHM: 'SHA-256',
BLOCK_SIZE: 64,
DIGEST_SIZE: 32,
OID: '2.16.840.1.101.3.4.2.1',
});
import { createHash } from '../core/hash';
import { sponge_1600 } from './keccak1600';
/**
* `SHA3` 填充函数 / Padding Function
*
* ```ts
* M || 01 || 10*1
* ```
*
* @param {number} r_byte - 处理速率 / Rate
*/
const sha3Padding = (r_byte) => {
return (M) => {
const sig_byte = M.length;
const pad_byte = r_byte - (sig_byte % r_byte);
const P = new Uint8Array(sig_byte + pad_byte);
P.set(M);
if (pad_byte === 1) {
P[sig_byte] = 0x86;
}
P[sig_byte] = 0x06;
P[P.length - 1] |= 0x80;
return P;
};
};
/**
* `SHAKE` 填充函数 / Padding Function
*
* ```ts
* M || 1111 || 10*1
* ```
*
* @param {number} r_byte - 处理速率 / Rate
*/
const shakePadding = (r_byte) => {
return (M) => {
const sig_byte = M.length;
const pad_byte = r_byte - (sig_byte % r_byte);
const P = new Uint8Array(sig_byte + pad_byte);
P.set(M);
if (pad_byte === 1) {
P[sig_byte] = 0x9F;
}
P[sig_byte] = 0x1F;
P[P.length - 1] |= 0x80;
return P;
};
};
// * SHA3 Function Specification
/**
* @param {number} c - 安全容量 / Capacity (bit)
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Sha3Padding} padding - 填充函数 / Padding Function
*/
export function Keccak_c(c, d, padding) {
const r = 1600 - c;
const rByte = r >> 3;
const pad = padding(rByte);
return (M) => sponge_1600(rByte, d >> 3, pad)(M);
}
export const sha3_224 = createHash((M) => Keccak_c(448, 224, sha3Padding)(M), {
ALGORITHM: 'SHA3-224',
BLOCK_SIZE: 144,
DIGEST_SIZE: 28,
OID: '2.16.840.1.101.3.4.2.7',
});
export const sha3_256 = createHash((M) => Keccak_c(512, 256, sha3Padding)(M), {
ALGORITHM: 'SHA3-256',
BLOCK_SIZE: 136,
DIGEST_SIZE: 32,
OID: '2.16.840.1.101.3.4.2.8',
});
export const sha3_384 = createHash((M) => Keccak_c(768, 384, sha3Padding)(M), {
ALGORITHM: 'SHA3-384',
BLOCK_SIZE: 104,
DIGEST_SIZE: 48,
OID: '2.16.840.1.101.3.4.2.9',
});
export const sha3_512 = createHash((M) => Keccak_c(1024, 512, sha3Padding)(M), {
ALGORITHM: 'SHA3-512',
BLOCK_SIZE: 72,
DIGEST_SIZE: 64,
OID: '2.16.840.1.101.3.4.2.10',
});
/**
* @param {number} d - 输出长度 / Digest Size (bit)
*/
export function shake128(d) {
return createHash((M) => Keccak_c(256, d, shakePadding)(M), {
ALGORITHM: `SHAKE128/${d}`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
});
}
/**
* @param {number} d - 输出长度 / Digest Size (bit)
*/
export function shake256(d) {
return createHash((M) => Keccak_c(512, d, shakePadding)(M), {
ALGORITHM: `SHAKE256/${d}`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
});
}
import { UTF8 } from '../core/codec';
import { KitError, joinBuffer } from '../core/utils';
import { createHash, createKeyHash, createTupleHash } from '../core/hash';
import { Keccak_c, shake128, shake256 } from './sha3';
// * Encode and Padding Function
/**
* SP.800-185 2.3.1:
*
* 左侧整数编码 / left_encode
*
* Inspired by https://github.com/paulmillr/noble-hashes
*
* ```ts
* leftEncode(0) // Uint8Array(2) [ 1, 0 ]
* leftEncode(18446744073709551615n) // Uint8Array(9) [ 8, 255, 255, 255, 255, 255, 255, 255, 255 ]
* ```
*
* @param {number} x - 输入 / input
*/
function leftEncode(x) {
const result = [];
do {
result.unshift(x & 0xFF);
x = x >> 8;
} while (x > 0);
result.unshift(result.length);
return Uint8Array.from(result);
}
/**
* SP.800-185 2.3.1:
*
* 右侧整数编码 / right_encode
*
* Inspired by https://github.com/paulmillr/noble-hashes
*
* ```ts
* rightEncode(0) // Uint8Array(2) [ 0, 1 ]
* rightEncode(18446744073709551615n) // Uint8Array(9) [ 255, 255, 255, 255, 255, 255, 255, 255, 8 ]
* ```
*
* @param {number | bigint} x - 输入 / input
*/
function rightEncode(x) {
const result = [];
do {
result.unshift(x & 0xFF);
x = x >> 8;
} while (x > 0);
result.push(result.length);
return Uint8Array.from(result);
}
/**
* SP.800-185 2.3.2:
*
* 字符编码 / encode_string
*
* 与规范文档不同, 这个实现不会进行串接操作, 而是返回一个数组, 串接操作在外部进行. 详细见 `bytepad` 函数.
*
* Unlike the specification document, this implementation does not perform concatenation operations, but returns an array, and the concatenation operation is performed externally. See `bytepad` function for details.
*
* ```ts
* encodeString(K) // [left_encode(len(K)), K]
* ```
*
* @param {string | Uint8Array} input - 输入 / input
*/
function encodeString(input) {
input = typeof input === 'string' ? UTF8(input) : input;
return [leftEncode(input.byteLength << 3), input];
}
/**
* SP.800-185 2.3.3:
*
* 在算法中 `bytePad` 涉及很多串接操作, 但对 `Javascript` 实现来说, 每次串接都意味着创建 `Uint8Array` 进行合并. 频繁地创建 `Uint8Array` 有可能导致性能问题.
* 这是一个优化后的实现. 将输入 `X` 改为数组, 最后也返回数组, 将合并操作移动到外部.
*
* The `bytePad` is used by many algorithms which involves many concatenation operations, but for `Javascript` implementation, each concatenation means creating a `Uint8Array` for merging. Frequent creation of `Uint8Array` may cause performance issues.
* This is an optimized implementation. The input `X` is changed to an array, and the final return is also an array. The merge operation is moved to the outside.
*
*
* ```ts
* bytepad(X, w) = left_encode(w) || X0 || ... || Xn || 0^z
* ```
*
* @param {Uint8Array} X - 输入数组 / input array
* @param {number} w - 字节倍数 / byte multiple
*/
function bytepad(X, w) {
if (w <= 0) {
throw new KitError('w must be greater than 0');
}
// 使用 leftEncode 函数编码 w
const left_encoded_w = leftEncode(w);
// z = left_encode(w) || X0 || ... || Xn
// 计算 z 的有效字节长度总和, 用于计算填充零字节的数量
let z_byte = left_encoded_w.length;
X.forEach(x => z_byte += x.length);
// 计算需要填充的零字节的数量
const zero_byte = w - z_byte % w;
X.unshift(left_encoded_w);
X.push(new Uint8Array(zero_byte));
return X;
}
/**
* `cSHAKE` 填充函数 / Padding Function
*
* ```ts
* M || 00 || 10*1
* ```
*
* @param {number} r_byte - 处理速率 / Rate
*/
const cshakePadding = (r_byte) => {
return (M) => {
const sig_byte = M.length;
const pad_byte = r_byte - (sig_byte % r_byte);
const P = new Uint8Array(sig_byte + pad_byte);
P.set(M);
if (pad_byte === 1) {
P[sig_byte] = 0x84;
}
P[sig_byte] = 0x04;
P[P.length - 1] |= 0x80;
return P;
};
};
// * cSHAKE
/**
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} N - 函数名 / Function name
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} c - 安全容量 / capacity (bit)
* @param {number} r_byte - 处理速率 / Rate (byte)
* @param {Hash} SHAKE - SHAKE 函数
*/
function cshake(d, N, S, c, r_byte, SHAKE) {
if (N.byteLength === 0 && S.byteLength === 0) {
return (M) => SHAKE(d)(M);
}
return (M) => {
const P = bytepad([...encodeString(N), ...encodeString(S)], r_byte);
P.push(M);
return Keccak_c(c, d, cshakePadding)(joinBuffer(...P));
};
}
/**
* `cSHAKE128` 是 `SHAKE128` 的可定制变体
*
* `cSHAKE128` is a customizable variant of `SHAKE128`
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} [N] - 函数名 / Function name
* @param {Uint8Array} [S] - 自定义参数 / Customization
*/
export function cshake128(d, N = new Uint8Array(), S = new Uint8Array()) {
return createHash(cshake(d, N, S, 256, 168, shake128), {
ALGORITHM: `cSHAKE128/${d}`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
});
}
/**
* `cSHAKE256` 是 `SHAKE256` 的可定制变体
*
* `cSHAKE256` is a customizable variant of `SHAKE256`
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} [N] - 函数名 / Function name
* @param {Uint8Array} [S] - 自定义参数 / Customization
*/
export function cshake256(d, N = new Uint8Array(), S = new Uint8Array()) {
return createHash(cshake(d, N, S, 512, 136, shake256), {
ALGORITHM: `cSHAKE256/${d}`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
});
}
// * KMAC
/**
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} c - 安全容量 / capacity (bit)
* @param {number} r_byte - 处理速率 / Rate (byte)
* @param {boolean} XOF - 是否为 XOF 模式 / XOF mode
*/
function kmac(d, S, c, r_byte, XOF) {
return (K, M) => {
const X = bytepad([...encodeString('KMAC'), ...encodeString(S)], r_byte);
X.push(...bytepad(encodeString(K), r_byte));
X.push(M);
X.push(rightEncode(XOF ? 0 : d));
return Keccak_c(c, d, cshakePadding)(joinBuffer(...X));
};
}
/**
* Keccak 消息认证码 (KMAC) 算法
* `KMAC128` 是 `KMAC` 的变体, 由 `cSHAKE128` 构建
*
* The Keccak Message Authentication Code (KMAC) algorithm
* `KMAC128` is a variant of `KMAC`, build from `cSHAKE128`
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} k_size - 推荐密钥大小 / Recommended key size (bit)
*/
export function kmac128(d, S = new Uint8Array(0), k_size = 128) {
return createKeyHash(kmac(d, S, 256, 168, false), {
ALGORITHM: `KMAC128/${d}`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
KEY_SIZE: k_size >> 3,
});
}
/**
* Keccak 消息认证码 (KMAC) 算法
* `KMAC256` 是 `KMAC` 的变体, 由 `cSHAKE256` 构建
*
* The Keccak Message Authentication Code (KMAC) algorithm
* `KMAC256` is a variant of `KMAC`, build from `cSHAKE256`
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} k_size - 推荐密钥大小 / Recommended key size (bit)
*/
export function kmac256(d, S = new Uint8Array(0), k_size = 256) {
return createKeyHash(kmac(d, S, 512, 136, false), {
ALGORITHM: `KMAC256/${d}`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
KEY_SIZE: k_size >> 3,
});
}
/**
* 可变长度输出的 `KMAC`
* `KMAC128XOF` 是 `KMAC128` 的 XOF 模式, 由 `cSHAKE128` 构建
*
* `KMAC` with Arbitrary-Length Output
* `KMAC128XOF` is a XOF mode of `KMAC128`, build from `cSHAKE128`
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} k_size - 推荐密钥大小 / Recommended key size (bit)
*/
export function kmac128XOF(d, S = new Uint8Array(0), k_size = 128) {
return createKeyHash(kmac(d, S, 256, 168, true), {
ALGORITHM: `KMAC128XOF/${d}`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
KEY_SIZE: k_size >> 3,
});
}
/**
* 可变长度输出的 `KMAC`
* `KMAC256XOF` 是 `KMAC256` 的 XOF 模式, 由 `cSHAKE256` 构建
*
* `KMAC` with Arbitrary-Length Output
* `KMAC256XOF` is a XOF mode of `KMAC256`, build from `cSHAKE256`
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} k_size - 推荐密钥大小 / recommended key size (bit)
*/
export function kmac256XOF(d, S = new Uint8Array(0), k_size = 256) {
return createKeyHash(kmac(d, S, 512, 136, true), {
ALGORITHM: `KMAC256XOF/${d}`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
KEY_SIZE: k_size >> 3,
});
}
// * TupleHash
/**
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} c - 安全容量 / capacity (bit)
* @param {number} r_byte - 处理速率 / Rate (byte)
* @param {boolean} XOF - 是否为 XOF 模式 / XOF mode
*/
function tuplehash(d, S, c, r_byte, XOF) {
return (M) => {
const X = bytepad([...encodeString('TupleHash'), ...encodeString(S)], r_byte);
M.forEach(m => X.push(...encodeString(m)));
X.push(rightEncode(XOF ? 0 : d));
return Keccak_c(c, d, cshakePadding)(joinBuffer(...X));
};
}
/**
* `TupleHash` 是一个具有可变长度输出的 `SHA3` 派生散列函数, 旨在以一种明确的方式简单地散列输入字符串的元组, 这些字符串中的任何一个或全部都可以是空字符串.
*
* `TupleHash` is a `SHA3` derived hash function with variable-length output that is designed to simply hash a tuple of input strings, any or all of which may be empty strings, in an unambiguous way.
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function tuplehash128(d, S = new Uint8Array()) {
return createTupleHash(tuplehash(d, S, 256, 168, false), {
ALGORITHM: `TupleHash128/${d}`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
});
}
/**
* `TupleHash` 是一个具有可变长度输出的 `SHA3` 派生散列函数, 旨在以一种明确的方式简单地散列输入字符串的元组, 这些字符串中的任何一个或全部都可以是空字符串.
*
* `TupleHash` is a `SHA3` derived hash function with variable-length output that is designed to simply hash a tuple of input strings, any or all of which may be empty strings, in an unambiguous way.
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function tuplehash256(d, S = new Uint8Array()) {
return createTupleHash(tuplehash(d, S, 512, 136, false), {
ALGORITHM: `TupleHash256/${d}`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
});
}
/**
* 可变长度输出的 `TupleHash`
*
* `TupleHash` with Arbitrary-Length Output
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function tuplehash128XOF(d, S = new Uint8Array()) {
return createTupleHash(tuplehash(d, S, 256, 168, true), {
ALGORITHM: `TupleHash128XOF/${d}`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
});
}
/**
* 可变长度输出的 `TupleHash`
*
* `TupleHash` with Arbitrary-Length Output
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function tuplehash256XOF(d, S = new Uint8Array()) {
return createTupleHash(tuplehash(d, S, 512, 136, true), {
ALGORITHM: `TupleHash256XOF/${d}`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
});
}
// * ParallelHash
// ! Note: This ParallelHash does not actually perform parallel computation, because writing multi-threaded in JavaScript is not easy.
// ! 注意: 此 ParallelHash 实际上并不执行并行计算, 因为在 JavaScript 写多线程并不轻松.
// TODO 计划引入 `multithreading` 依赖, 实现真正的并行计算
/**
* @param {number} b - 状态大小 / State size (bit)
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} c - 安全容量 / capacity (bit)
* @param {number} r_byte - 处理速率 / Rate (byte)
* @param {boolean} XOF - 是否为 XOF 模式 / XOF mode
*/
function parallelhash(b, d, S, c, r_byte, XOF, SHAKE) {
const bByte = b >> 3;
return (M) => {
const n = Math.ceil(M.byteLength / bByte);
const X = bytepad([...encodeString('ParallelHash'), ...encodeString(S)], r_byte);
X.push(leftEncode(b));
for (let i = 0; i < n; i++) {
const B = M.slice(i * (b << 3), (i + 1) * (b << 3));
X.push(SHAKE(B));
}
X.push(rightEncode(n));
X.push(rightEncode(XOF ? 0 : d));
return Keccak_c(c, d, cshakePadding)(joinBuffer(...X));
};
}
/**
* `ParallelHash` 的目的是利用现代处理器中可用的并行性, 支持对非常长的字符串进行高效散列.
*
* The purpose of `ParallelHash` is to support the efficient hashing of very long strings, by taking advantage of the parallelism available in modern processors.
*
* @param {number} b - 状态大小 / State size (bit)
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function parallelhash128(b, d, S = new Uint8Array()) {
return createHash(parallelhash(b, d, S, 256, 168, false, shake128(256)), {
ALGORITHM: `ParallelHash128/${d}`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
});
}
/**
* `ParallelHash` 的目的是利用现代处理器中可用的并行性, 支持对非常长的字符串进行高效散列.
*
* The purpose of `ParallelHash` is to support the efficient hashing of very long strings, by taking advantage of the parallelism available in modern processors.
*
* @param {number} b - 状态大小 / State size (bit)
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function parallelhash256(b, d, S = new Uint8Array()) {
return createHash(parallelhash(b, d, S, 512, 136, false, shake256(512)), {
ALGORITHM: `ParallelHash256/${d}`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
});
}
/**
* 可变长度输出的 `ParallelHash`
*
* `ParallelHash` with Arbitrary-Length Output
*
* @param {number} b - 状态大小 / State size (bit)
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function parallelhash128XOF(b, d, S = new Uint8Array()) {
return createHash(parallelhash(b, d, S, 256, 168, true, shake128(256)), {
ALGORITHM: `ParallelHash128XOF`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
});
}
/**
* 可变长度输出的 `ParallelHash`
*
* `ParallelHash` with Arbitrary-Length Output
*
* @param {number} b - 状态大小 / State size (bit)
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function parallelhash256XOF(b, d, S = new Uint8Array()) {
return createHash(parallelhash(b, d, S, 512, 136, true, shake256(512)), {
ALGORITHM: `ParallelHash256XOF`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
});
}
import { UTF8 } from '../core/codec';
import { createHash } from '../core/hash';
import { KitError, U8, genBitMask, rotateR } from '../core/utils';
// * Constants
const K = new BigUint64Array([0x428a2f98d728ae22n, 0x7137449123ef65cdn, 0xb5c0fbcfec4d3b2fn, 0xe9b5dba58189dbbcn, 0x3956c25bf348b538n, 0x59f111f1b605d019n, 0x923f82a4af194f9bn, 0xab1c5ed5da6d8118n, 0xd807aa98a3030242n, 0x12835b0145706fben, 0x243185be4ee4b28cn, 0x550c7dc3d5ffb4e2n, 0x72be5d74f27b896fn, 0x80deb1fe3b1696b1n, 0x9bdc06a725c71235n, 0xc19bf174cf692694n, 0xe49b69c19ef14ad2n, 0xefbe4786384f25e3n, 0x0fc19dc68b8cd5b5n, 0x240ca1cc77ac9c65n, 0x2de92c6f592b0275n, 0x4a7484aa6ea6e483n, 0x5cb0a9dcbd41fbd4n, 0x76f988da831153b5n, 0x983e5152ee66dfabn, 0xa831c66d2db43210n, 0xb00327c898fb213fn, 0xbf597fc7beef0ee4n, 0xc6e00bf33da88fc2n, 0xd5a79147930aa725n, 0x06ca6351e003826fn, 0x142929670a0e6e70n, 0x27b70a8546d22ffcn, 0x2e1b21385c26c926n, 0x4d2c6dfc5ac42aedn, 0x53380d139d95b3dfn, 0x650a73548baf63den, 0x766a0abb3c77b2a8n, 0x81c2c92e47edaee6n, 0x92722c851482353bn, 0xa2bfe8a14cf10364n, 0xa81a664bbc423001n, 0xc24b8b70d0f89791n, 0xc76c51a30654be30n, 0xd192e819d6ef5218n, 0xd69906245565a910n, 0xf40e35855771202an, 0x106aa07032bbd1b8n, 0x19a4c116b8d2d0c8n, 0x1e376c085141ab53n, 0x2748774cdf8eeb99n, 0x34b0bcb5e19b48a8n, 0x391c0cb3c5c95a63n, 0x4ed8aa4ae3418acbn, 0x5b9cca4f7763e373n, 0x682e6ff3d6b2b8a3n, 0x748f82ee5defb2fcn, 0x78a5636f43172f60n, 0x84c87814a1f0ab72n, 0x8cc702081a6439ecn, 0x90befffa23631e28n, 0xa4506cebde82bde9n, 0xbef9a3f7b2c67915n, 0xc67178f2e372532bn, 0xca273eceea26619cn, 0xd186b8c721c0c207n, 0xeada7dd6cde0eb1en, 0xf57d4f7fee6ed178n, 0x06f067aa72176fban, 0x0a637dc5a2c898a6n, 0x113f9804bef90daen, 0x1b710b35131c471bn, 0x28db77f523047d84n, 0x32caab7b40c72493n, 0x3c9ebe0a15c9bebcn, 0x431d67c49c100d4cn, 0x4cc5d4becb3e42b6n, 0x597f299cfc657e2an, 0x5fcb6fab3ad6faecn, 0x6c44198c4a475817n]);
// * Function
const mask64 = genBitMask(64);
const rotateR64 = (x, n) => rotateR(64, x, n, mask64);
const Ch = (x, y, z) => (x & y) ^ ((~x) & z);
const Maj = (x, y, z) => (x & y) ^ (x & z) ^ (y & z);
const Sigma0 = (x) => rotateR64(x, 28n) ^ rotateR64(x, 34n) ^ rotateR64(x, 39n);
const Sigma1 = (x) => rotateR64(x, 14n) ^ rotateR64(x, 18n) ^ rotateR64(x, 41n);
const sigma0 = (x) => rotateR64(x, 1n) ^ rotateR64(x, 8n) ^ (x >> 7n);
const sigma1 = (x) => rotateR64(x, 19n) ^ rotateR64(x, 61n) ^ (x >> 6n);
/**
* SHA-512/t IV 生成函数 / generator
*
* ```ts
* (0 < t < 512) && (t !== 384)
* ```
*
* @param {number} t - 截断长度 / truncation length (bit)
*/
function IVGen(t) {
if (t <= 0) {
throw new KitError('SHA-512 truncation must be greater than 0');
}
if (t >= 512) {
throw new KitError('SHA-512 truncation must be less than 512');
}
if (t === 384) {
throw new KitError('SHA-512 truncation must not be 384');
}
const state = new U8(64);
const state_view = state.view(8);
state_view.set(0, 0x6a09e667f3bcc908n ^ 0xa5a5a5a5a5a5a5a5n);
state_view.set(1, 0xbb67ae8584caa73bn ^ 0xa5a5a5a5a5a5a5a5n);
state_view.set(2, 0x3c6ef372fe94f82bn ^ 0xa5a5a5a5a5a5a5a5n);
state_view.set(3, 0xa54ff53a5f1d36f1n ^ 0xa5a5a5a5a5a5a5a5n);
state_view.set(4, 0x510e527fade682d1n ^ 0xa5a5a5a5a5a5a5a5n);
state_view.set(5, 0x9b05688c2b3e6c1fn ^ 0xa5a5a5a5a5a5a5a5n);
state_view.set(6, 0x1f83d9abfb41bd6bn ^ 0xa5a5a5a5a5a5a5a5n);
state_view.set(7, 0x5be0cd19137e2179n ^ 0xa5a5a5a5a5a5a5a5n);
return digest(state, UTF8(`SHA-512/${t}`));
}
// * Algorithm
function digest(state, message) {
// * 初始化
state = state.slice(0);
const state_view = state.view(8);
const m_byte = message.byteLength;
const m_bit = BigInt(m_byte) << 3n;
const block_size = 128;
// ceil((m_byte + 17) / 128)
const block_total = (m_byte + 17 + 127) >> 7;
// * 填充
const p = new U8(block_total * block_size);
p.set(message);
// appending the bit '1' to the message
p[m_byte] = 0x80;
// appending length
const p_view = new DataView(p.buffer);
p_view.setBigUint64(p.byteLength - 16, m_bit >> 32n);
p_view.setBigUint64(p.byteLength - 8, m_bit & 0xffffffffffffffffn);
// * 分块处理
for (let offset = 0; offset < p.length; offset += block_size) {
/** B(n) = p[offset:offset + block_size] */
// 准备状态字
const H0 = state_view.get(0);
const H1 = state_view.get(1);
const H2 = state_view.get(2);
const H3 = state_view.get(3);
const H4 = state_view.get(4);
const H5 = state_view.get(5);
const H6 = state_view.get(6);
const H7 = state_view.get(7);
let a = H0;
let b = H1;
let c = H2;
let d = H3;
let e = H4;
let f = H5;
let g = H6;
let h = H7;
// 合并执行 扩展 & 压缩
const W = new BigUint64Array(80);
for (let i = 0; i < W.length; i++) {
// 扩展
if (i < 16)
// W[i] = B(n)[i]
W[i] = p_view.getBigUint64(offset + (i << 3));
else
W[i] = sigma1(W[i - 2]) + W[i - 7] + sigma0(W[i - 15]) + W[i - 16];
// 压缩
const T1 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];
const T2 = Sigma0(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = (d + T1) & 0xffffffffffffffffn;
d = c;
c = b;
b = a;
a = (T1 + T2) & 0xffffffffffffffffn;
}
// 更新状态字
state_view.set(0, H0 + a);
state_view.set(1, H1 + b);
state_view.set(2, H2 + c);
state_view.set(3, H3 + d);
state_view.set(4, H4 + e);
state_view.set(5, H5 + f);
state_view.set(6, H6 + g);
state_view.set(7, H7 + h);
}
// * 返回状态
return state;
}
function sha384Digest(M) {
// * 初始化 SHA-384 状态
const state = new U8(64);
const state_view = state.view(8);
state_view.set(0, 0xcbbb9d5dc1059ed8n);
state_view.set(1, 0x629a292a367cd507n);
state_view.set(2, 0x9159015a3070dd17n);
state_view.set(3, 0x152fecd8f70e5939n);
state_view.set(4, 0x67332667ffc00b31n);
state_view.set(5, 0x8eb44a8768581511n);
state_view.set(6, 0xdb0c2e0d64f98fa7n);
state_view.set(7, 0x47b5481dbefa4fa4n);
return digest(state, M).slice(0, 48);
}
function sha512Digest(M) {
// * 初始化 SHA-512 状态
const state = new U8(64);
const state_view = state.view(8);
state_view.set(0, 0x6a09e667f3bcc908n);
state_view.set(1, 0xbb67ae8584caa73bn);
state_view.set(2, 0x3c6ef372fe94f82bn);
state_view.set(3, 0xa54ff53a5f1d36f1n);
state_view.set(4, 0x510e527fade682d1n);
state_view.set(5, 0x9b05688c2b3e6c1fn);
state_view.set(6, 0x1f83d9abfb41bd6bn);
state_view.set(7, 0x5be0cd19137e2179n);
return digest(state, M);
}
export const sha384 = createHash(sha384Digest, {
ALGORITHM: 'SHA-384',
BLOCK_SIZE: 128,
DIGEST_SIZE: 48,
OID: '2.16.840.1.101.3.4.2.2',
});
export const sha512 = createHash(sha512Digest, {
ALGORITHM: 'SHA-512',
BLOCK_SIZE: 128,
DIGEST_SIZE: 64,
OID: '2.16.840.1.101.3.4.2.3',
});
/**
* @param {number} t - 截断长度 / truncation length (bit)
*/
export function sha512t(t) {
// * 初始化 SHA-512/t 状态
const status = IVGen(t);
let OID;
if (t === 224)
OID = '2.16.840.1.101.3.4.2.5';
if (t === 256)
OID = '2.16.840.1.101.3.4.2.6';
return createHash((M) => digest(status, M).slice(0, t >> 3), {
ALGORITHM: `SHA-512/${t}`,
BLOCK_SIZE: 128,
DIGEST_SIZE: t >> 3,
OID,
});
}
import { createHash } from '../core/hash';
import { U8, rotateL32 } from '../core/utils';
// * Function
const FF = (X, Y, Z, j) => j < 16 ? X ^ Y ^ Z : (X & Y) | (X & Z) | (Y & Z);
const GG = (X, Y, Z, j) => j < 16 ? X ^ Y ^ Z : (X & Y) | (~X & Z);
const P0 = (X) => X ^ rotateL32(X, 9) ^ rotateL32(X, 17);
const P1 = (X) => X ^ rotateL32(X, 15) ^ rotateL32(X, 23);
// * Algorithm
function digest(message) {
// * 初始化
const state = new U8(32);
const state_view = state.view(4);
state_view.set(0, 0x7380166fn);
state_view.set(1, 0x4914b2b9n);
state_view.set(2, 0x172442d7n);
state_view.set(3, 0xda8a0600n);
state_view.set(4, 0xa96f30bcn);
state_view.set(5, 0x163138aan);
state_view.set(6, 0xe38dee4dn);
state_view.set(7, 0xb0fb0e4en);
const m_byte = message.length;
const m_bit = BigInt(m_byte) << 3n;
const block_size = 64;
// ceil((M_BYTE + 9) / 64)
const block_total = (m_byte + 9 + 63) >> 6;
// * 填充
const p = new U8(block_total * block_size);
p.set(message);
// appending the bit '1' to the message
p[m_byte] = 0x80;
// appending length
const p_view = new DataView(p.buffer);
p_view.setBigUint64(p.length - 8, m_bit, false);
// * 迭代压缩
for (let offset = 0; offset < p.length; offset += block_size) {
/** B(n) = p[offset:offset + block_size] */
// 准备状态字
const H0 = Number(state_view.get(0));
const H1 = Number(state_view.get(1));
const H2 = Number(state_view.get(2));
const H3 = Number(state_view.get(3));
const H4 = Number(state_view.get(4));
const H5 = Number(state_view.get(5));
const H6 = Number(state_view.get(6));
const H7 = Number(state_view.get(7));
let A = H0;
let B = H1;
let C = H2;
let D = H3;
let E = H4;
let F = H5;
let G = H6;
let H = H7;
// 合并执行 扩展 & 压缩
const W = new Uint32Array(68);
const W1 = new Uint32Array(64);
for (let i = 0; i < 68; i++) {
// 拓展 W
if (i < 16) {
// W[i] = B(n)[i]
W[i] = p_view.getUint32(offset + (i << 2), false);
}
else {
W[i] = P1(W[i - 16] ^ W[i - 9] ^ rotateL32(W[i - 3], 15)) ^ rotateL32(W[i - 13], 7) ^ W[i - 6];
}
// W1 拓展 & 压缩
if (i > 3) {
// W1 拓展
const j = i - 4;
// W1[j] = W[j] ^ W[j + 4]
W1[j] = W[j] ^ W[i];
// 压缩
const T = j < 16 ? 0x79CC4519 : 0x7A879D8A;
const SS1 = rotateL32(rotateL32(A, 12) + E + rotateL32(T, j), 7);
const SS2 = SS1 ^ rotateL32(A, 12);
const TT1 = FF(A, B, C, j) + D + SS2 + W1[j];
const TT2 = GG(E, F, G, j) + H + SS1 + W[j];
D = C;
C = rotateL32(B, 9);
B = A;
A = TT1;
H = G;
G = rotateL32(F, 19);
F = E;
E = P0(TT2);
}
}
// 更新状态字
state_view.set(0, BigInt(H0 ^ A));
state_view.set(1, BigInt(H1 ^ B));
state_view.set(2, BigInt(H2 ^ C));
state_view.set(3, BigInt(H3 ^ D));
state_view.set(4, BigInt(H4 ^ E));
state_view.set(5, BigInt(H5 ^ F));
state_view.set(6, BigInt(H6 ^ G));
state_view.set(7, BigInt(H7 ^ H));
}
// * 截断输出
return state;
}
export const sm3 = createHash(digest, {
ALGORITHM: 'SM3',
BLOCK_SIZE: 64,
DIGEST_SIZE: 32,
OID: '1.2.156.10197.1.401',
});
import { U8 } from '../core/utils';
import { hmac } from './hmac';
import { sha1 } from './sha1';
/**
* 生成 HOTP (基于计数的一次性密码)
*
* Generate HOTP (HMAC-based One-Time Password)
*
* @param {Uint8Array} secret - 密钥
* @param {Uint8Array} counter - 计数器
* @param {KeyHash} mac - 带密钥的加密散列算法
* @returns {U8} - 返回的 HOTP 字节数组
*/
function hotp(secret, counter, mac = hmac(sha1)) {
const HS = mac(secret, counter);
const offset = HS[HS.length - 1] & 0x0F;
return HS.slice(offset, offset + 4);
}
export function totp(args) {
if (args instanceof Uint8Array) {
const K = args;
const C = U8.fromBI(BigInt(Math.floor(Date.now() / 30000)), 8, false);
const HS = hotp(K, C, hmac(sha1));
const OTP = 0
| (HS[0] & 0x7F) << 24
| (HS[1] & 0xFF) << 16
| (HS[2] & 0xFF) << 8
| (HS[3] & 0xFF);
return (OTP % 1_000_000)
.toString()
.padStart(6, '0');
}
return (secret) => {
let { mac = hmac(sha1), current = Date.now(), epoch = 0, step = 30000, counter = 0, digits = 6, } = args || {};
if (!counter) {
const T = BigInt(Math.floor((current - epoch) / step));
counter = U8.fromBI(T, 8, false);
}
if (!(counter instanceof Uint8Array)) {
counter = U8.fromBI(BigInt(counter), 8, false);
}
const BIN = hotp(secret, counter, mac);
const OTP = 0
| (BIN[0] & 0x7F) << 24
| (BIN[1] & 0xFF) << 16
| (BIN[2] & 0xFF) << 8
| (BIN[3] & 0xFF);
return (OTP % (10 ** digits))
.toString()
.padStart(digits, '0');
};
}
import { createHash } from '../core/hash';
import { KitError } from '../core/utils';
import { keccak_p_1600, sponge_1600 } from './keccak1600';
/**
* turboSHAKE 填充函数 / Padding Function
*
* ```ts
* M || D || 0x00*
* ```
*
* @param {number} rByte - 处理速率 / Rate
* @param {number} D - 域分隔符 / Domain Separator
*/
function turboShakePadding(rByte, D) {
return (M) => {
const sig_byte = M.length + 1;
const block = Math.ceil(sig_byte / rByte);
const P = new Uint8Array(block * rByte);
P.set(M);
P[M.length] = D;
P[P.length - 1] ^= 0x80;
return P;
};
}
/**
* TurboSHAKE128
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {number} [D] - 域分隔符 / Domain Separator (range: 0x01 ~ 0x7F, default: 0x1F)
*/
export function turboshake128(d, D = 0x1F) {
if (D < 0x01 || D > 0x7F) {
throw new KitError('Invalid Domain Separator');
}
const d_byte = d >> 3;
const r_byte = 168;
const f = keccak_p_1600(12);
const pad = turboShakePadding(r_byte, D);
return createHash((M) => sponge_1600(r_byte, d_byte, pad, f)(M), {
ALGORITHM: `TurboSHAKE128/${d}`,
BLOCK_SIZE: r_byte,
DIGEST_SIZE: d_byte,
});
}
/**
* TurboSHAKE256
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {number} [D] - 域分隔符 / Domain Separator (range: 0x01 ~ 0x7F, default: 0x1F)
*/
export function turboshake256(d, D = 0x1F) {
if (D < 0x01 || D > 0x7F) {
throw new KitError('Invalid Domain Separator');
}
const d_byte = d >> 3;
const r_byte = 136;
const f = keccak_p_1600(12);
const pad = turboShakePadding(r_byte, D);
return createHash((M) => sponge_1600(r_byte, d_byte, pad, f)(M), {
ALGORITHM: `TurboSHAKE256/${d}`,
BLOCK_SIZE: r_byte,
DIGEST_SIZE: d_byte,
});
}
// * Utils
export { U8, joinBuffer } from './core/utils';
export { genPrime, isProbablePrime } from './core/prime';
export { UTF8, HEX, B32, B64, B64URL, CSV } from './core/codec';
export { createHash, createTupleHash } from './core/hash';
// * MD5
export { md5 } from './hash/md5';
// * SHA-1
export { sha1 } from './hash/sha1';
// * SHA-2
export { sha224, sha256 } from './hash/sha256';
export { sha384, sha512, sha512t } from './hash/sha512';
// * SHA-3
export { keccak_p_1600, sponge_1600 } from './hash/keccak1600';
export { sha3_224, sha3_256 } from './hash/sha3';
export { sha3_384, sha3_512 } from './hash/sha3';
// * SHAKE
export { shake128, shake256 } from './hash/sha3';
// * cSHAKE
export { cshake128, cshake256 } from './hash/sha3Derived';
// * KMAC
export { kmac128, kmac128XOF } from './hash/sha3Derived';
export { kmac256, kmac256XOF } from './hash/sha3Derived';
// * TupleHash
export { tuplehash128, tuplehash128XOF } from './hash/sha3Derived';
export { tuplehash256, tuplehash256XOF } from './hash/sha3Derived';
// * ParallelHash
export { parallelhash128, parallelhash128XOF } from './hash/sha3Derived';
export { parallelhash256, parallelhash256XOF } from './hash/sha3Derived';
// * TurboSHAKE
export { turboshake128, turboshake256 } from './hash/turboSHAKE';
// * KangarooTwelve
export { kt128, kt256 } from './hash/kangaroo12';
// * SM3
export { sm3 } from './hash/sm3';
// * HMAC
export { hmac } from './hash/hmac';
// * TOTP
export { totp } from './hash/totp';
export { createCipher } from './core/cipher';
// * Block Cipher
export { sm4 } from './cipher/blockCipher/sm4';
export { aes } from './cipher/blockCipher/aes';
export { aria } from './cipher/blockCipher/aria';
export { camellia } from './cipher/blockCipher/camellia';
export { des, t_des } from './cipher/blockCipher/des';
export { arc5 } from './cipher/blockCipher/arc5';
export { blowfish } from './cipher/blockCipher/blowfish';
export { twofish } from './cipher/blockCipher/twofish';
export { tea, xtea, xxtea } from './cipher/blockCipher/tea';
// * Block Cipher Modes
export { ecb, cbc, pcbc, cfb, ofb, ctr, gcm } from './core/cipher';
// * Block Cipher Padding
export { PKCS7_PAD, ZERO_PAD, X923_PAD, ISO7816_PAD, NO_PAD } from './core/cipher';
export { eea3, eia3, zuc } from './cipher/streamCipher/zuc';
export { arc4 } from './cipher/streamCipher/arc4';
export { salsa20 } from './cipher/streamCipher/salsa20';
export { rabbit } from './cipher/streamCipher/rabbit';
export { rsa } from './cipher/pkcs/rsa';
export { pkcs1_es_1_5, pkcs1_es_oaep } from './cipher/pkcs/pkcs1';
export { pkcs1_ssa_1_5, pkcs1_ssa_pss } from './cipher/pkcs/pkcs1';
export { mgf1 } from './cipher/pkcs/pkcs1';
export { x963kdf, hkdf, pbkdf2 } from './core/kdf';
export { FpECC } from './cipher/pkcs/ecc';
export { sm2p256v1 } from './core/ecParams';
// export { secp112r1, secp112r2 } from './core/ecParams'
// export { secp128r1, secp128r2 } from './core/ecParams'
// export { secp160k1, secp160r1, secp160r2 } from './core/ecParams'
export { secp192k1, secp192r1 } from './core/ecParams';
export { secp224k1, secp224r1 } from './core/ecParams';
export { secp256k1, secp256r1 } from './core/ecParams';
export { secp384r1, secp521r1 } from './core/ecParams';
export { prime192v1, prime256v1 } from './core/ecParams';
export { p192, p224, p256, p384, p521 } from './core/ecParams';
export { w25519, w448 } from './core/ecParams';
// TODO 实现 爱德华曲线 后再开放
// export { ed25519, ed448 } from './core/ecParams'
export { curve25519, curve448 } from './core/ecParams';
export { bp192r1, bp224r1, bp256r1, bp320r1, bp384r1, bp512r1 } from './core/ecParams';
export { sm2 } from './cipher/pkcs/sm2';
export { x25519, x448 } from './cipher/pkcs/x25519_448';

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

+82
-5

@@ -25,2 +25,16 @@ /** 字符编解码器 / String Codec */

declare const B64URL: Codec;
interface B32Params {
variant?: 'rfc4648' | 'rfc4648-hex' | 'crockford';
padding?: boolean;
}
interface B32Codec extends Codec {
/**
* 创建一个 base32 编解码器
*
* Create a base32 codec
*/
(params: B32Params): Codec;
}
/** base32 编解码器 / Codec */
declare const B32: B32Codec;
/** 社会主义核心价值观编解码器 / Core Socialist Values Codec */

@@ -77,8 +91,7 @@ declare const CSV: Codec;

/**
* Convert string to U8 (default encoding: UTF-8)
* Convert string to U8
*
* 将 字符串 转换为 U8 (默认编码: UTF-8)
*
* 将 字符串 转换为 U8
*/
static fromString(input: string, codec?: Codec): U8;
static fromString(input: string, codec: Codec): U8;
/**

@@ -455,2 +468,66 @@ * Convert BigInt to U8

interface TOTP {
/**
* 生成 TOTP (时间同步的一次性密码)
*
* Generate TOTP (Time-based One-Time Password)
*
* @param {Uint8Array} secret - 密钥
* @returns {string} - 返回的 TOTP 字符串
*/
(secret: Uint8Array): string;
}
interface TOTPParams {
/**
* 带密钥的加密散列算法 / Keyed Hashing Algorithm (default: HMAC-SHA1)
*/
mac?: KeyHash;
/**
* 当前时间戳 / Current timestamp (default: Date.now() milliseconds)
*
* 指定此参数时,将不再从 `Date.now()` 获取当前时间戳.
*
* When this parameter is specified, the current timestamp will not be obtained from `Date.now()`.
*/
current?: number;
/**
* 纪元时间戳 / Epoch timestamp (default: 0 milliseconds)
*/
epoch?: number;
/**
* 时间步长 / Time step (default: 30000 milliseconds)
*/
step?: number;
/**
* 计数器 / Counter
*
* `counter = (cuttent_time - epoch_time) / step`
*
* 指定此参数时,将不再从当前时间戳计算计数器.
*
* When this parameter is specified, the counter will not be calculated from the current timestamp.
*/
counter?: number | bigint | Uint8Array;
/**
* 返回的数字位数 / Number of digits in the returned OTP (default: 6)
*/
digits?: number;
}
/**
* 生成 TOTP (时间同步的一次性密码)
*
* Generate TOTP (Time-based One-Time Password)
*
* @param {Uint8Array} secret - 密钥
* @returns {string} - 返回的 TOTP 字符串
*/
declare function totp(secret: Uint8Array): string;
/**
* 创建 TOTP 函数 / Create a TOTP function
*
* @param {TOTPParams} params - TOTP 参数
* @returns {TOTP} - 返回的 TOTP 函数
*/
declare function totp(params: TOTPParams): TOTP;
interface Cipherable {

@@ -1680,2 +1757,2 @@ /**

export { B64, B64URL, type BlockCipher, type BlockCipherInfo, CSV, type Cipher, type Codec, type Digest, type ECDSASignature, type ECIESCiphertext, type ECKeyPair, type ECPrivateKey, type ECPublicKey, FpECC, type FpECCrypto, type FpECPoint, type FpMECParams, type FpSM2Crypto, type FpWECParams, HEX, type Hash, type HashDescription, ISO7816_PAD, type IVBlockCipher, type IVCipher, type IVCipherInfo, type IVStreamCipher, type KDF, type KeyDigest, type KeyHash, type KeyHashDescription, type MGF, NO_PAD, PKCS7_PAD, type RSAPrivateKey, type RSAPublicKey, type RandomPrimeGenerator, type SM2DSASignature, type StreamCipher, type StreamCipherInfo, type TupleDigest, type TupleHash, type TupleHashDescription, U8, UTF8, type X25519, type X25519KeyPair, type X25519PrivateKey, type X25519PublicKey, type X448, type X448KeyPair, type X448PrivateKey, type X448PublicKey, X923_PAD, type XXTEAConfig, ZERO_PAD, type ZUCParams, aes, arc4, arc5, aria, blowfish, bp192r1, bp224r1, bp256r1, bp320r1, bp384r1, bp512r1, camellia, cbc, cfb, createCipher, createHash, createTupleHash, cshake128, cshake256, ctr, curve25519, curve448, des, ecb, eea3, eia3, gcm, genPrime, hkdf, hmac, isProbablePrime, joinBuffer, keccak_p_1600, kmac128, kmac128XOF, kmac256, kmac256XOF, kt128, kt256, md5, mgf1, ofb, p192, p224, p256, p384, p521, parallelhash128, parallelhash128XOF, parallelhash256, parallelhash256XOF, pbkdf2, pcbc, pkcs1_es_1_5, pkcs1_es_oaep, pkcs1_ssa_1_5, pkcs1_ssa_pss, prime192v1, prime256v1, rabbit, rsa, salsa20, secp192k1, secp192r1, secp224k1, secp224r1, secp256k1, secp256r1, secp384r1, secp521r1, sha1, sha224, sha256, sha384, sha3_224, sha3_256, sha3_384, sha3_512, sha512, sha512t, shake128, shake256, sm2, sm2p256v1, sm3, sm4, sponge_1600, t_des, tea, tuplehash128, tuplehash128XOF, tuplehash256, tuplehash256XOF, turboshake128, turboshake256, twofish, w25519, w448, x25519, x448, x963kdf, xtea, xxtea, zuc };
export { B32, B64, B64URL, type BlockCipher, type BlockCipherInfo, CSV, type Cipher, type Codec, type Digest, type ECDSASignature, type ECIESCiphertext, type ECKeyPair, type ECPrivateKey, type ECPublicKey, FpECC, type FpECCrypto, type FpECPoint, type FpMECParams, type FpSM2Crypto, type FpWECParams, HEX, type Hash, type HashDescription, ISO7816_PAD, type IVBlockCipher, type IVCipher, type IVCipherInfo, type IVStreamCipher, type KDF, type KeyDigest, type KeyHash, type KeyHashDescription, type MGF, NO_PAD, PKCS7_PAD, type RSAPrivateKey, type RSAPublicKey, type RandomPrimeGenerator, type SM2DSASignature, type StreamCipher, type StreamCipherInfo, type TupleDigest, type TupleHash, type TupleHashDescription, U8, UTF8, type X25519, type X25519KeyPair, type X25519PrivateKey, type X25519PublicKey, type X448, type X448KeyPair, type X448PrivateKey, type X448PublicKey, X923_PAD, type XXTEAConfig, ZERO_PAD, type ZUCParams, aes, arc4, arc5, aria, blowfish, bp192r1, bp224r1, bp256r1, bp320r1, bp384r1, bp512r1, camellia, cbc, cfb, createCipher, createHash, createTupleHash, cshake128, cshake256, ctr, curve25519, curve448, des, ecb, eea3, eia3, gcm, genPrime, hkdf, hmac, isProbablePrime, joinBuffer, keccak_p_1600, kmac128, kmac128XOF, kmac256, kmac256XOF, kt128, kt256, md5, mgf1, ofb, p192, p224, p256, p384, p521, parallelhash128, parallelhash128XOF, parallelhash256, parallelhash256XOF, pbkdf2, pcbc, pkcs1_es_1_5, pkcs1_es_oaep, pkcs1_ssa_1_5, pkcs1_ssa_pss, prime192v1, prime256v1, rabbit, rsa, salsa20, secp192k1, secp192r1, secp224k1, secp224r1, secp256k1, secp256r1, secp384r1, secp521r1, sha1, sha224, sha256, sha384, sha3_224, sha3_256, sha3_384, sha3_512, sha512, sha512t, shake128, shake256, sm2, sm2p256v1, sm3, sm4, sponge_1600, t_des, tea, totp, tuplehash128, tuplehash128XOF, tuplehash256, tuplehash256XOF, turboshake128, turboshake256, twofish, w25519, w448, x25519, x448, x963kdf, xtea, xxtea, zuc };

@@ -25,2 +25,16 @@ /** 字符编解码器 / String Codec */

declare const B64URL: Codec;
interface B32Params {
variant?: 'rfc4648' | 'rfc4648-hex' | 'crockford';
padding?: boolean;
}
interface B32Codec extends Codec {
/**
* 创建一个 base32 编解码器
*
* Create a base32 codec
*/
(params: B32Params): Codec;
}
/** base32 编解码器 / Codec */
declare const B32: B32Codec;
/** 社会主义核心价值观编解码器 / Core Socialist Values Codec */

@@ -77,8 +91,7 @@ declare const CSV: Codec;

/**
* Convert string to U8 (default encoding: UTF-8)
* Convert string to U8
*
* 将 字符串 转换为 U8 (默认编码: UTF-8)
*
* 将 字符串 转换为 U8
*/
static fromString(input: string, codec?: Codec): U8;
static fromString(input: string, codec: Codec): U8;
/**

@@ -455,2 +468,66 @@ * Convert BigInt to U8

interface TOTP {
/**
* 生成 TOTP (时间同步的一次性密码)
*
* Generate TOTP (Time-based One-Time Password)
*
* @param {Uint8Array} secret - 密钥
* @returns {string} - 返回的 TOTP 字符串
*/
(secret: Uint8Array): string;
}
interface TOTPParams {
/**
* 带密钥的加密散列算法 / Keyed Hashing Algorithm (default: HMAC-SHA1)
*/
mac?: KeyHash;
/**
* 当前时间戳 / Current timestamp (default: Date.now() milliseconds)
*
* 指定此参数时,将不再从 `Date.now()` 获取当前时间戳.
*
* When this parameter is specified, the current timestamp will not be obtained from `Date.now()`.
*/
current?: number;
/**
* 纪元时间戳 / Epoch timestamp (default: 0 milliseconds)
*/
epoch?: number;
/**
* 时间步长 / Time step (default: 30000 milliseconds)
*/
step?: number;
/**
* 计数器 / Counter
*
* `counter = (cuttent_time - epoch_time) / step`
*
* 指定此参数时,将不再从当前时间戳计算计数器.
*
* When this parameter is specified, the counter will not be calculated from the current timestamp.
*/
counter?: number | bigint | Uint8Array;
/**
* 返回的数字位数 / Number of digits in the returned OTP (default: 6)
*/
digits?: number;
}
/**
* 生成 TOTP (时间同步的一次性密码)
*
* Generate TOTP (Time-based One-Time Password)
*
* @param {Uint8Array} secret - 密钥
* @returns {string} - 返回的 TOTP 字符串
*/
declare function totp(secret: Uint8Array): string;
/**
* 创建 TOTP 函数 / Create a TOTP function
*
* @param {TOTPParams} params - TOTP 参数
* @returns {TOTP} - 返回的 TOTP 函数
*/
declare function totp(params: TOTPParams): TOTP;
interface Cipherable {

@@ -1680,2 +1757,2 @@ /**

export { B64, B64URL, type BlockCipher, type BlockCipherInfo, CSV, type Cipher, type Codec, type Digest, type ECDSASignature, type ECIESCiphertext, type ECKeyPair, type ECPrivateKey, type ECPublicKey, FpECC, type FpECCrypto, type FpECPoint, type FpMECParams, type FpSM2Crypto, type FpWECParams, HEX, type Hash, type HashDescription, ISO7816_PAD, type IVBlockCipher, type IVCipher, type IVCipherInfo, type IVStreamCipher, type KDF, type KeyDigest, type KeyHash, type KeyHashDescription, type MGF, NO_PAD, PKCS7_PAD, type RSAPrivateKey, type RSAPublicKey, type RandomPrimeGenerator, type SM2DSASignature, type StreamCipher, type StreamCipherInfo, type TupleDigest, type TupleHash, type TupleHashDescription, U8, UTF8, type X25519, type X25519KeyPair, type X25519PrivateKey, type X25519PublicKey, type X448, type X448KeyPair, type X448PrivateKey, type X448PublicKey, X923_PAD, type XXTEAConfig, ZERO_PAD, type ZUCParams, aes, arc4, arc5, aria, blowfish, bp192r1, bp224r1, bp256r1, bp320r1, bp384r1, bp512r1, camellia, cbc, cfb, createCipher, createHash, createTupleHash, cshake128, cshake256, ctr, curve25519, curve448, des, ecb, eea3, eia3, gcm, genPrime, hkdf, hmac, isProbablePrime, joinBuffer, keccak_p_1600, kmac128, kmac128XOF, kmac256, kmac256XOF, kt128, kt256, md5, mgf1, ofb, p192, p224, p256, p384, p521, parallelhash128, parallelhash128XOF, parallelhash256, parallelhash256XOF, pbkdf2, pcbc, pkcs1_es_1_5, pkcs1_es_oaep, pkcs1_ssa_1_5, pkcs1_ssa_pss, prime192v1, prime256v1, rabbit, rsa, salsa20, secp192k1, secp192r1, secp224k1, secp224r1, secp256k1, secp256r1, secp384r1, secp521r1, sha1, sha224, sha256, sha384, sha3_224, sha3_256, sha3_384, sha3_512, sha512, sha512t, shake128, shake256, sm2, sm2p256v1, sm3, sm4, sponge_1600, t_des, tea, tuplehash128, tuplehash128XOF, tuplehash256, tuplehash256XOF, turboshake128, turboshake256, twofish, w25519, w448, x25519, x448, x963kdf, xtea, xxtea, zuc };
export { B32, B64, B64URL, type BlockCipher, type BlockCipherInfo, CSV, type Cipher, type Codec, type Digest, type ECDSASignature, type ECIESCiphertext, type ECKeyPair, type ECPrivateKey, type ECPublicKey, FpECC, type FpECCrypto, type FpECPoint, type FpMECParams, type FpSM2Crypto, type FpWECParams, HEX, type Hash, type HashDescription, ISO7816_PAD, type IVBlockCipher, type IVCipher, type IVCipherInfo, type IVStreamCipher, type KDF, type KeyDigest, type KeyHash, type KeyHashDescription, type MGF, NO_PAD, PKCS7_PAD, type RSAPrivateKey, type RSAPublicKey, type RandomPrimeGenerator, type SM2DSASignature, type StreamCipher, type StreamCipherInfo, type TupleDigest, type TupleHash, type TupleHashDescription, U8, UTF8, type X25519, type X25519KeyPair, type X25519PrivateKey, type X25519PublicKey, type X448, type X448KeyPair, type X448PrivateKey, type X448PublicKey, X923_PAD, type XXTEAConfig, ZERO_PAD, type ZUCParams, aes, arc4, arc5, aria, blowfish, bp192r1, bp224r1, bp256r1, bp320r1, bp384r1, bp512r1, camellia, cbc, cfb, createCipher, createHash, createTupleHash, cshake128, cshake256, ctr, curve25519, curve448, des, ecb, eea3, eia3, gcm, genPrime, hkdf, hmac, isProbablePrime, joinBuffer, keccak_p_1600, kmac128, kmac128XOF, kmac256, kmac256XOF, kt128, kt256, md5, mgf1, ofb, p192, p224, p256, p384, p521, parallelhash128, parallelhash128XOF, parallelhash256, parallelhash256XOF, pbkdf2, pcbc, pkcs1_es_1_5, pkcs1_es_oaep, pkcs1_ssa_1_5, pkcs1_ssa_pss, prime192v1, prime256v1, rabbit, rsa, salsa20, secp192k1, secp192r1, secp224k1, secp224r1, secp256k1, secp256r1, secp384r1, secp521r1, sha1, sha224, sha256, sha384, sha3_224, sha3_256, sha3_384, sha3_512, sha512, sha512t, shake128, shake256, sm2, sm2p256v1, sm3, sm4, sponge_1600, t_des, tea, totp, tuplehash128, tuplehash128XOF, tuplehash256, tuplehash256XOF, turboshake128, turboshake256, twofish, w25519, w448, x25519, x448, x963kdf, xtea, xxtea, zuc };

@@ -25,2 +25,16 @@ /** 字符编解码器 / String Codec */

declare const B64URL: Codec;
interface B32Params {
variant?: 'rfc4648' | 'rfc4648-hex' | 'crockford';
padding?: boolean;
}
interface B32Codec extends Codec {
/**
* 创建一个 base32 编解码器
*
* Create a base32 codec
*/
(params: B32Params): Codec;
}
/** base32 编解码器 / Codec */
declare const B32: B32Codec;
/** 社会主义核心价值观编解码器 / Core Socialist Values Codec */

@@ -77,8 +91,7 @@ declare const CSV: Codec;

/**
* Convert string to U8 (default encoding: UTF-8)
* Convert string to U8
*
* 将 字符串 转换为 U8 (默认编码: UTF-8)
*
* 将 字符串 转换为 U8
*/
static fromString(input: string, codec?: Codec): U8;
static fromString(input: string, codec: Codec): U8;
/**

@@ -455,2 +468,66 @@ * Convert BigInt to U8

interface TOTP {
/**
* 生成 TOTP (时间同步的一次性密码)
*
* Generate TOTP (Time-based One-Time Password)
*
* @param {Uint8Array} secret - 密钥
* @returns {string} - 返回的 TOTP 字符串
*/
(secret: Uint8Array): string;
}
interface TOTPParams {
/**
* 带密钥的加密散列算法 / Keyed Hashing Algorithm (default: HMAC-SHA1)
*/
mac?: KeyHash;
/**
* 当前时间戳 / Current timestamp (default: Date.now() milliseconds)
*
* 指定此参数时,将不再从 `Date.now()` 获取当前时间戳.
*
* When this parameter is specified, the current timestamp will not be obtained from `Date.now()`.
*/
current?: number;
/**
* 纪元时间戳 / Epoch timestamp (default: 0 milliseconds)
*/
epoch?: number;
/**
* 时间步长 / Time step (default: 30000 milliseconds)
*/
step?: number;
/**
* 计数器 / Counter
*
* `counter = (cuttent_time - epoch_time) / step`
*
* 指定此参数时,将不再从当前时间戳计算计数器.
*
* When this parameter is specified, the counter will not be calculated from the current timestamp.
*/
counter?: number | bigint | Uint8Array;
/**
* 返回的数字位数 / Number of digits in the returned OTP (default: 6)
*/
digits?: number;
}
/**
* 生成 TOTP (时间同步的一次性密码)
*
* Generate TOTP (Time-based One-Time Password)
*
* @param {Uint8Array} secret - 密钥
* @returns {string} - 返回的 TOTP 字符串
*/
declare function totp(secret: Uint8Array): string;
/**
* 创建 TOTP 函数 / Create a TOTP function
*
* @param {TOTPParams} params - TOTP 参数
* @returns {TOTP} - 返回的 TOTP 函数
*/
declare function totp(params: TOTPParams): TOTP;
interface Cipherable {

@@ -1680,2 +1757,2 @@ /**

export { B64, B64URL, type BlockCipher, type BlockCipherInfo, CSV, type Cipher, type Codec, type Digest, type ECDSASignature, type ECIESCiphertext, type ECKeyPair, type ECPrivateKey, type ECPublicKey, FpECC, type FpECCrypto, type FpECPoint, type FpMECParams, type FpSM2Crypto, type FpWECParams, HEX, type Hash, type HashDescription, ISO7816_PAD, type IVBlockCipher, type IVCipher, type IVCipherInfo, type IVStreamCipher, type KDF, type KeyDigest, type KeyHash, type KeyHashDescription, type MGF, NO_PAD, PKCS7_PAD, type RSAPrivateKey, type RSAPublicKey, type RandomPrimeGenerator, type SM2DSASignature, type StreamCipher, type StreamCipherInfo, type TupleDigest, type TupleHash, type TupleHashDescription, U8, UTF8, type X25519, type X25519KeyPair, type X25519PrivateKey, type X25519PublicKey, type X448, type X448KeyPair, type X448PrivateKey, type X448PublicKey, X923_PAD, type XXTEAConfig, ZERO_PAD, type ZUCParams, aes, arc4, arc5, aria, blowfish, bp192r1, bp224r1, bp256r1, bp320r1, bp384r1, bp512r1, camellia, cbc, cfb, createCipher, createHash, createTupleHash, cshake128, cshake256, ctr, curve25519, curve448, des, ecb, eea3, eia3, gcm, genPrime, hkdf, hmac, isProbablePrime, joinBuffer, keccak_p_1600, kmac128, kmac128XOF, kmac256, kmac256XOF, kt128, kt256, md5, mgf1, ofb, p192, p224, p256, p384, p521, parallelhash128, parallelhash128XOF, parallelhash256, parallelhash256XOF, pbkdf2, pcbc, pkcs1_es_1_5, pkcs1_es_oaep, pkcs1_ssa_1_5, pkcs1_ssa_pss, prime192v1, prime256v1, rabbit, rsa, salsa20, secp192k1, secp192r1, secp224k1, secp224r1, secp256k1, secp256r1, secp384r1, secp521r1, sha1, sha224, sha256, sha384, sha3_224, sha3_256, sha3_384, sha3_512, sha512, sha512t, shake128, shake256, sm2, sm2p256v1, sm3, sm4, sponge_1600, t_des, tea, tuplehash128, tuplehash128XOF, tuplehash256, tuplehash256XOF, turboshake128, turboshake256, twofish, w25519, w448, x25519, x448, x963kdf, xtea, xxtea, zuc };
export { B32, B64, B64URL, type BlockCipher, type BlockCipherInfo, CSV, type Cipher, type Codec, type Digest, type ECDSASignature, type ECIESCiphertext, type ECKeyPair, type ECPrivateKey, type ECPublicKey, FpECC, type FpECCrypto, type FpECPoint, type FpMECParams, type FpSM2Crypto, type FpWECParams, HEX, type Hash, type HashDescription, ISO7816_PAD, type IVBlockCipher, type IVCipher, type IVCipherInfo, type IVStreamCipher, type KDF, type KeyDigest, type KeyHash, type KeyHashDescription, type MGF, NO_PAD, PKCS7_PAD, type RSAPrivateKey, type RSAPublicKey, type RandomPrimeGenerator, type SM2DSASignature, type StreamCipher, type StreamCipherInfo, type TupleDigest, type TupleHash, type TupleHashDescription, U8, UTF8, type X25519, type X25519KeyPair, type X25519PrivateKey, type X25519PublicKey, type X448, type X448KeyPair, type X448PrivateKey, type X448PublicKey, X923_PAD, type XXTEAConfig, ZERO_PAD, type ZUCParams, aes, arc4, arc5, aria, blowfish, bp192r1, bp224r1, bp256r1, bp320r1, bp384r1, bp512r1, camellia, cbc, cfb, createCipher, createHash, createTupleHash, cshake128, cshake256, ctr, curve25519, curve448, des, ecb, eea3, eia3, gcm, genPrime, hkdf, hmac, isProbablePrime, joinBuffer, keccak_p_1600, kmac128, kmac128XOF, kmac256, kmac256XOF, kt128, kt256, md5, mgf1, ofb, p192, p224, p256, p384, p521, parallelhash128, parallelhash128XOF, parallelhash256, parallelhash256XOF, pbkdf2, pcbc, pkcs1_es_1_5, pkcs1_es_oaep, pkcs1_ssa_1_5, pkcs1_ssa_pss, prime192v1, prime256v1, rabbit, rsa, salsa20, secp192k1, secp192r1, secp224k1, secp224r1, secp256k1, secp256r1, secp384r1, secp521r1, sha1, sha224, sha256, sha384, sha3_224, sha3_256, sha3_384, sha3_512, sha512, sha512t, shake128, shake256, sm2, sm2p256v1, sm3, sm4, sponge_1600, t_des, tea, totp, tuplehash128, tuplehash128XOF, tuplehash256, tuplehash256XOF, turboshake128, turboshake256, twofish, w25519, w448, x25519, x448, x963kdf, xtea, xxtea, zuc };
+18
-13
{
"name": "mima-kit",
"type": "module",
"version": "0.0.16",
"version": "0.0.17",
"packageManager": "pnpm@9.9.0",

@@ -64,5 +64,10 @@ "description": "mima-kit is a cryptographic suite implemented in TypeScript. The goal is to provide an easy-to-use cryptographic library. mima-kit 是一个使用 TypeScript 实现的密码学套件。目标是提供一个简单易用的密码学库。",

"require": "./dist/index.cjs"
},
"./min": {
"types": "./dist/index.d.ts",
"import": "./dist/min/index.mjs",
"require": "./dist/min/index.cjs"
}
},
"main": "./dist/index.js",
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",

@@ -99,18 +104,18 @@ "types": "./dist/index.d.ts",

"@testing-library/vue": "^8.1.0",
"@types/node": "^20.17.10",
"@types/node": "^22.13.1",
"@vitejs/plugin-vue": "^5.2.1",
"@vitest/browser": "^2.1.8",
"bumpp": "^9.9.1",
"eslint": "^8.57.1",
"@vitest/browser": "^3.0.5",
"bumpp": "^10.0.2",
"eslint": "^9.20.0",
"esno": "^4.8.0",
"lint-staged": "^15.2.11",
"playwright": "^1.49.1",
"pnpm": "^9.15.0",
"lint-staged": "^15.4.3",
"playwright": "^1.50.1",
"pnpm": "^10.2.1",
"rimraf": "^5.0.10",
"simple-git-hooks": "^2.11.1",
"typescript": "^5.7.2",
"typescript": "^5.7.3",
"unbuild": "^2.0.0",
"vite": "^5.4.11",
"vitest": "^2.1.8",
"webdriverio": "^9.4.2"
"vite": "^6.1.0",
"vitest": "^3.0.5",
"webdriverio": "^9.8.0"
},

@@ -117,0 +122,0 @@ "simple-git-hooks": {

@@ -60,2 +60,3 @@ <div align="center">

<li><a href="#hmac">HMAC</a></li>
<li><a href="#totp">TOTP</a></li>
<li><a href="#kmac">KMAC</a></li>

@@ -162,2 +163,3 @@ </ul>

- `HEX` 十六进制编码
- `B32` Base32 编码 `RFC 4648` `RFC 4648-HEX` `Crockford`
- `B64` Base64 编码

@@ -219,2 +221,26 @@ - `B64URL` Base64URL 编码

`B32` 编码存在多种事实标准与变体,`mima-kit` 提供了三种变体的编解码器,`B32` 默认不进行填充。
```typescript
interface B32Params {
variant?: 'rfc4648' | 'rfc4648-hex' | 'crockford'
padding?: boolean
}
interface B32Codec extends Codec {
/**
* 创建一个 base32 编解码器
*
* Create a base32 codec
*/
(params: B32Params): Codec
}
// RFC 4648 Base32 with no padding by default
B32(UTF8('cat, 猫, 🐱')) // MNQXILBA46GKWLBA6CPZBMI
// using RFC 4648 Base32-hex with padding
const B32HP = B32({ variant: 'rfc4648-hex', padding: true })
B32HP(UTF8('cat, 猫, 🐱')) // CDGN8B10SU6AMB10U2FP1C8=
```
# 散列算法

@@ -373,2 +399,58 @@

### TOTP
Specification: [RFC 6238](https://www.rfc-editor.org/rfc/rfc6238.txt)
> `TOTP` 是 `HMAC` 的拓展应用,它使用当前时间戳作为计数器,通过协商密钥输出一次性密码
```typescript
const otp = totp(B32('4B7X5MEKEFIJMWWVBQMMCLY6JI3YOC7Y')) // '000000'
const totp_256 = totp({
mac: hmac(sha256),
step: 60_000, // 1 minute
digits: 8, // 8 digits
})
const otp = totp_256(B32('4B7X5MEKEFIJMWWVBQMMCLY6JI3YOC7Y')) // '00000000'
```
```typescript
interface TOTPParams {
/**
* 带密钥的加密散列算法 / Keyed Hashing Algorithm (default: HMAC-SHA1)
*/
mac?: KeyHash
/**
* 当前时间戳 / Current timestamp (default: Date.now() milliseconds)
*
* 指定此参数时,将不再从 `Date.now()` 获取当前时间戳.
*
* When this parameter is specified, the current timestamp will not be obtained from `Date.now()`.
*/
current?: number
/**
* 纪元时间戳 / Epoch timestamp (default: 0 milliseconds)
*/
epoch?: number
/**
* 时间步长 / Time step (default: 30000 milliseconds)
*/
step?: number
/**
* 计数器 / Counter
*
* `counter = (cuttent_time - epoch_time) / step`
*
* 指定此参数时,将不再从当前时间戳计算计数器.
*
* When this parameter is specified, the counter will not be calculated from the current timestamp.
*/
counter?: number | bigint | Uint8Array
/**
* 返回的数字位数 / Number of digits in the returned OTP (default: 6)
*/
digits?: number
}
```
### KMAC

@@ -375,0 +457,0 @@

import { KitError, U8 } from '../../core/utils';
import { createCipher } from '../../core/cipher';
// * Constants
const SBox = new Uint8Array([0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]);
const InvSBox = new Uint8Array([0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D]);
const ROUND = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36];
// * Functions
function GFMultiply(a, b) {
let p = 0;
if (b === 1) {
return a;
}
for (let i = 0; i < 8; i++) {
if (b & 1) {
p ^= a;
}
const carry = a & 0x80;
a <<= 1;
if (carry) {
a ^= 0x1B; // 0x1B 是不可约多项式 x^8 + x^4 + x^3 + x + 1 的低 8 位
}
b >>= 1;
}
return p & 0xFF;
}
function KeyExpansion(K, Nr) {
const Nk = K.byteLength >> 2;
const W = new Uint8Array((Nr + 1) << 4);
W.set(K);
let current = 0;
for (let i = Nk; i < (Nr + 1) << 2; i++) {
const i_1 = (i - 1) << 2;
const temp = W.slice(i_1, i_1 + 4);
if (i % Nk === 0) {
const t0 = temp[0];
temp[0] = SBox[temp[1]] ^ ROUND[current];
temp[1] = SBox[temp[2]];
temp[2] = SBox[temp[3]];
temp[3] = SBox[t0];
current++;
}
else if (Nk > 6 && i % Nk === 4) {
temp[0] = SBox[temp[0]];
temp[1] = SBox[temp[1]];
temp[2] = SBox[temp[2]];
temp[3] = SBox[temp[3]];
}
const i_Nk = (i - Nk) << 2;
const Wi_NK = W.subarray(i_Nk, i_Nk + 4);
for (let j = 0; j < 4; j++) {
temp[j] ^= Wi_NK[j];
}
W.set(temp, i << 2);
}
return W;
}
// * AES Algorithm
function Cipher(M, W, Nr) {
if (M.byteLength !== 16) {
throw new KitError(`AES block must be 16 byte`);
}
const S = new U8(M.slice(0));
const AddRoundKey = (W) => {
for (let i = 0; i < S.byteLength; i++) {
S[i] ^= W[i];
}
};
const SubBytes = () => {
for (let i = 0; i < S.byteLength; i++) {
S[i] = SBox[S[i]];
}
};
const ShiftRows = () => {
const S1 = S[1];
S[1] = S[5];
S[5] = S[9];
S[9] = S[13];
S[13] = S1;
const S2 = S[2];
const S6 = S[6];
S[2] = S[10];
S[6] = S[14];
S[10] = S2;
S[14] = S6;
const S15 = S[15];
S[15] = S[11];
S[11] = S[7];
S[7] = S[3];
S[3] = S15;
};
const MixColumn = () => {
for (let i = 0; i < 4; i++) {
const s0 = S[(i << 2)];
const s1 = S[(i << 2) + 1];
const s2 = S[(i << 2) + 2];
const s3 = S[(i << 2) + 3];
const t0 = GFMultiply(s0, 0x02) ^ GFMultiply(s1, 0x03) ^ GFMultiply(s2, 0x01) ^ GFMultiply(s3, 0x01);
const t1 = GFMultiply(s0, 0x01) ^ GFMultiply(s1, 0x02) ^ GFMultiply(s2, 0x03) ^ GFMultiply(s3, 0x01);
const t2 = GFMultiply(s0, 0x01) ^ GFMultiply(s1, 0x01) ^ GFMultiply(s2, 0x02) ^ GFMultiply(s3, 0x03);
const t3 = GFMultiply(s0, 0x03) ^ GFMultiply(s1, 0x01) ^ GFMultiply(s2, 0x01) ^ GFMultiply(s3, 0x02);
S[(i << 2)] = t0;
S[(i << 2) + 1] = t1;
S[(i << 2) + 2] = t2;
S[(i << 2) + 3] = t3;
}
};
AddRoundKey(W.subarray(0, 16));
for (let i = 1; i < Nr; i++) {
SubBytes();
ShiftRows();
MixColumn();
AddRoundKey(W.subarray(i << 4, (i + 1) << 4));
}
SubBytes();
ShiftRows();
AddRoundKey(W.subarray(W.length - 16, W.length));
return S;
}
function InvCipher(M, W, Nr) {
if (M.byteLength !== 16) {
throw new KitError(`AES block must be 16 byte`);
}
const S = new U8(M.slice(0));
const AddRoundKey = (W) => {
for (let i = 0; i < S.byteLength; i++) {
S[i] ^= W[i];
}
};
const InvSubBytes = () => {
for (let i = 0; i < S.byteLength; i++) {
S[i] = InvSBox[S[i]];
}
};
const InvShiftRows = () => {
const S13 = S[13];
S[13] = S[9];
S[9] = S[5];
S[5] = S[1];
S[1] = S13;
const S2 = S[2];
const S6 = S[6];
S[2] = S[10];
S[6] = S[14];
S[10] = S2;
S[14] = S6;
const S3 = S[3];
S[3] = S[7];
S[7] = S[11];
S[11] = S[15];
S[15] = S3;
};
const InvMixColumn = () => {
for (let i = 0; i < 4; i++) {
const s0 = S[(i << 2)];
const s1 = S[(i << 2) + 1];
const s2 = S[(i << 2) + 2];
const s3 = S[(i << 2) + 3];
const t0 = GFMultiply(s0, 0x0E) ^ GFMultiply(s1, 0x0B) ^ GFMultiply(s2, 0x0D) ^ GFMultiply(s3, 0x09);
const t1 = GFMultiply(s0, 0x09) ^ GFMultiply(s1, 0x0E) ^ GFMultiply(s2, 0x0B) ^ GFMultiply(s3, 0x0D);
const t2 = GFMultiply(s0, 0x0D) ^ GFMultiply(s1, 0x09) ^ GFMultiply(s2, 0x0E) ^ GFMultiply(s3, 0x0B);
const t3 = GFMultiply(s0, 0x0B) ^ GFMultiply(s1, 0x0D) ^ GFMultiply(s2, 0x09) ^ GFMultiply(s3, 0x0E);
S[(i << 2)] = t0;
S[(i << 2) + 1] = t1;
S[(i << 2) + 2] = t2;
S[(i << 2) + 3] = t3;
}
};
AddRoundKey(W.subarray(W.length - 16, W.length));
for (let i = Nr - 1; i > 0; i--) {
InvShiftRows();
InvSubBytes();
AddRoundKey(W.subarray(i << 4, (i + 1) << 4));
InvMixColumn();
}
InvShiftRows();
InvSubBytes();
AddRoundKey(W.subarray(0, 16));
return S;
}
function _aes(K, b) {
if (K.byteLength !== b >> 3) {
throw new KitError(`AES key must be ${b >> 3} byte`);
}
const Nr = b === 128 ? 10 : (b === 192 ? 12 : 14);
const W = KeyExpansion(K, Nr);
return {
encrypt: (M) => Cipher(M, W, Nr),
decrypt: (C) => InvCipher(C, W, Nr),
};
}
/**
* 高级加密标准 (AES) 分组密码算法
*
* Advanced Encryption Standard (AES) block cipher algorithm
*
* @param {128 | 192 | 256} b - 密钥长度 / Key size (bit)
*/
export function aes(b) {
return createCipher((K) => _aes(K, b), {
ALGORITHM: `AES-${b}`,
BLOCK_SIZE: 16,
KEY_SIZE: b >> 3,
MIN_KEY_SIZE: b >> 3,
MAX_KEY_SIZE: b >> 3,
});
}
import { createCipher } from '../../core/cipher';
import { KitError, U8, genBitMask, resizeBuffer, rotateL, rotateR } from '../../core/utils';
// const Eul = [0xB7, 0xE1, 0x51, 0x62, 0x8A, 0xED, 0x2A, 0x6A, 0xBF, 0x71, 0x58, 0x80, 0x9C, 0xF4, 0xF3, 0xC7, 0x62, 0xE7, 0x16, 0x0F, 0x38, 0xB4, 0xDA, 0x56, 0xA7, 0x84, 0xD9, 0x04, 0x51, 0x90, 0xCF, 0xEF]
// const Phi = [0x9E, 0x37, 0x79, 0xB9, 0x7F, 0x4A, 0x7C, 0x15, 0xF3, 0x9C, 0xC0, 0x60, 0x5C, 0xED, 0xC8, 0x34, 0x10, 0x82, 0x27, 0x6B, 0xF3, 0xA2, 0x72, 0x51, 0xF8, 0x6C, 0x6A, 0x11, 0xD0, 0xC1, 0x8E, 0x95]
// const P = Eul{0,...,w-1} - 2) | 1
// const Q = Phi{0,...,w-1} - 2) | 1
// * Functions
function _setup(key, word_size, round, mask) {
const word_bit = BigInt(word_size);
const word_byte = word_size >> 3;
const P = (0xb7e151628aed2a6abf7158809cf4f3c7n >> (128n - word_bit)) | 1n;
const Q = (0x9e3779b97f4a7c15f39cc0605cedc835n >> (128n - word_bit)) | 1n;
// Break the key into w-bit words
const c = Math.ceil((key.length || 1) / word_byte);
const L = resizeBuffer(key, c * word_byte);
const LV = L.view(word_byte);
// Initialize key-independent pseudorandom S array
const t = (round + 1) << 1;
const S = new U8(t * word_byte);
const SV = S.view(word_byte);
// S[0] = P
let prv = P;
SV.set(0, prv, true);
for (let i = 1; i < t; i++) {
// S[i] = S[i-1] + Q
prv = (prv + Q) & mask;
SV.set(i, prv, true);
}
// The main key scheduling loop
let i = 0;
let j = 0;
let A = 0n;
let B = 0n;
const v = 3 * Math.max(c, t);
for (let k = 0; k < v; k++) {
// A = S[i] = (S[i] + A + B) <<< 3
const S = SV.get(i, true);
A = rotateL(word_bit, S + A + B, 3n, mask);
SV.set(i, A, true);
// B = L[j] = (L[j] + A + B) <<< (A + B)
const L = LV.get(j, true);
B = rotateL(word_bit, L + A + B, A + B, mask);
LV.set(j, B, true);
// i = (i + 1) mod t
i = (i + 1) % t;
// j = (j + 1) mod c
j = (j + 1) % c;
}
return S;
}
function _encrypt(M, S, word_size, round, mask) {
if (M.byteLength !== word_size >> 2) {
throw new KitError(`ARC5-${word_size}/${round} block must be ${word_size >> 3} byte`);
}
const word_bit = BigInt(word_size);
const word_byte = word_size >> 3;
const MV = U8.from(M).view(word_byte);
const SV = U8.from(S).view(word_byte);
// A = M[0] + S[0], B = M[1] + S[1]
let A = MV.get(0, true) + SV.get(0, true);
let B = MV.get(1, true) + SV.get(1, true);
A &= mask;
B &= mask;
for (let i = 1; i <= round; i++) {
// A = ((A ^ B) <<< B) + S[2 * i]
A = rotateL(word_bit, A ^ B, B, mask);
A += SV.get(i << 1, true);
A &= mask;
// B = ((B ^ A) <<< A) + S[2 * i + 1]
B = rotateL(word_bit, B ^ A, A, mask);
B += SV.get((i << 1) + 1, true);
B &= mask;
}
return U8.fromBI(B << word_bit | A, word_byte << 1, true);
}
function _decrypt(C, S, word_size, round, mask) {
if (C.byteLength !== word_size >> 2) {
throw new KitError(`ARC5-${word_size}/${round} block must be ${word_size >> 3} byte`);
}
const word_bit = BigInt(word_size);
const word_byte = word_size >> 3;
const CV = U8.from(C).view(word_byte);
const SV = U8.from(S).view(word_byte);
// A = C[0], B = C[1]
let A = CV.get(0, true);
let B = CV.get(1, true);
for (let i = round; i > 0; i--) {
// B = ((B - S[2 * i + 1]) >>> A) ^ A
const S1 = SV.get((i << 1) + 1, true);
B = rotateR(word_bit, B - S1, A, mask);
B = B ^ A;
B &= mask;
// A = ((A - S[2 * i]) >>> B) ^ B
const S0 = SV.get(i << 1, true);
A = rotateR(word_bit, A - S0, B, mask);
A = A ^ B;
A &= mask;
}
// A = A - S[0], B = B - S[1]
A = A - SV.get(0, true);
A &= mask;
B = B - SV.get(1, true);
B &= mask;
return U8.fromBI(B << word_bit | A, word_byte << 1, true);
}
// * ARC5 Algorithm
function _arc5(K, WORD_SIZE, round) {
const mask = genBitMask(WORD_SIZE);
const S = _setup(K, WORD_SIZE, round, mask);
const encrypt = (M) => _encrypt(M, S, WORD_SIZE, round, mask);
const decrypt = (C) => _decrypt(C, S, WORD_SIZE, round, mask);
return { encrypt, decrypt };
}
/**
* ARC5 分组加密算法 / block cipher algorithm
*
* ```ts
* const spec8 = arc5(8, 8) // ARC5-8/8
* const spec16 = arc5(16, 12) // ARC5-16/12
* const spec32 = arc5(32, 16) // ARC5-32/16 (default)
* const spec64 = arc5(64, 20) // ARC5-64/20
* const spec128 = arc5(128, 24) // ARC5-128/24
* ```
*
* @param {16 | 32 | 64} WORD_SIZE - 工作字长 / Word size (default: 32 bit)
* @param {number} round - 轮数 / Rounds (default: 16)
*/
export function arc5(WORD_SIZE = 32, round = 16) {
if (round <= 0 || round > 255) {
throw new KitError('ARC5 round must be between 1 and 255');
}
return createCipher((K) => _arc5(K, WORD_SIZE, round), {
ALGORITHM: `ARC5-${WORD_SIZE}/${round}`,
BLOCK_SIZE: WORD_SIZE >> 2,
KEY_SIZE: 16,
MIN_KEY_SIZE: 1,
MAX_KEY_SIZE: 255,
});
}
import { createCipher } from '../../core/cipher';
import { KitError, U8 } from '../../core/utils';
// * Constants
const SBox1 = new Uint8Array([0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]);
const SBox2 = new Uint8Array([0xE2, 0x4E, 0x54, 0xFC, 0x94, 0xC2, 0x4A, 0xCC, 0x62, 0x0D, 0x6A, 0x46, 0x3C, 0x4D, 0x8B, 0xD1, 0x5E, 0xFA, 0x64, 0xCB, 0xB4, 0x97, 0xBE, 0x2B, 0xBC, 0x77, 0x2E, 0x03, 0xD3, 0x19, 0x59, 0xC1, 0x1D, 0x06, 0x41, 0x6B, 0x55, 0xF0, 0x99, 0x69, 0xEA, 0x9C, 0x18, 0xAE, 0x63, 0xDF, 0xE7, 0xBB, 0x00, 0x73, 0x66, 0xFB, 0x96, 0x4C, 0x85, 0xE4, 0x3A, 0x09, 0x45, 0xAA, 0x0F, 0xEE, 0x10, 0xEB, 0x2D, 0x7F, 0xF4, 0x29, 0xAC, 0xCF, 0xAD, 0x91, 0x8D, 0x78, 0xC8, 0x95, 0xF9, 0x2F, 0xCE, 0xCD, 0x08, 0x7A, 0x88, 0x38, 0x5C, 0x83, 0x2A, 0x28, 0x47, 0xDB, 0xB8, 0xC7, 0x93, 0xA4, 0x12, 0x53, 0xFF, 0x87, 0x0E, 0x31, 0x36, 0x21, 0x58, 0x48, 0x01, 0x8E, 0x37, 0x74, 0x32, 0xCA, 0xE9, 0xB1, 0xB7, 0xAB, 0x0C, 0xD7, 0xC4, 0x56, 0x42, 0x26, 0x07, 0x98, 0x60, 0xD9, 0xB6, 0xB9, 0x11, 0x40, 0xEC, 0x20, 0x8C, 0xBD, 0xA0, 0xC9, 0x84, 0x04, 0x49, 0x23, 0xF1, 0x4F, 0x50, 0x1F, 0x13, 0xDC, 0xD8, 0xC0, 0x9E, 0x57, 0xE3, 0xC3, 0x7B, 0x65, 0x3B, 0x02, 0x8F, 0x3E, 0xE8, 0x25, 0x92, 0xE5, 0x15, 0xDD, 0xFD, 0x17, 0xA9, 0xBF, 0xD4, 0x9A, 0x7E, 0xC5, 0x39, 0x67, 0xFE, 0x76, 0x9D, 0x43, 0xA7, 0xE1, 0xD0, 0xF5, 0x68, 0xF2, 0x1B, 0x34, 0x70, 0x05, 0xA3, 0x8A, 0xD5, 0x79, 0x86, 0xA8, 0x30, 0xC6, 0x51, 0x4B, 0x1E, 0xA6, 0x27, 0xF6, 0x35, 0xD2, 0x6E, 0x24, 0x16, 0x82, 0x5F, 0xDA, 0xE6, 0x75, 0xA2, 0xEF, 0x2C, 0xB2, 0x1C, 0x9F, 0x5D, 0x6F, 0x80, 0x0A, 0x72, 0x44, 0x9B, 0x6C, 0x90, 0x0B, 0x5B, 0x33, 0x7D, 0x5A, 0x52, 0xF3, 0x61, 0xA1, 0xF7, 0xB0, 0xD6, 0x3F, 0x7C, 0x6D, 0xED, 0x14, 0xE0, 0xA5, 0x3D, 0x22, 0xB3, 0xF8, 0x89, 0xDE, 0x71, 0x1A, 0xAF, 0xBA, 0xB5, 0x81]);
const SBox3 = new Uint8Array([0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D]);
const SBox4 = new Uint8Array([0x30, 0x68, 0x99, 0x1B, 0x87, 0xB9, 0x21, 0x78, 0x50, 0x39, 0xDB, 0xE1, 0x72, 0x09, 0x62, 0x3C, 0x3E, 0x7E, 0x5E, 0x8E, 0xF1, 0xA0, 0xCC, 0xA3, 0x2A, 0x1D, 0xFB, 0xB6, 0xD6, 0x20, 0xC4, 0x8D, 0x81, 0x65, 0xF5, 0x89, 0xCB, 0x9D, 0x77, 0xC6, 0x57, 0x43, 0x56, 0x17, 0xD4, 0x40, 0x1A, 0x4D, 0xC0, 0x63, 0x6C, 0xE3, 0xB7, 0xC8, 0x64, 0x6A, 0x53, 0xAA, 0x38, 0x98, 0x0C, 0xF4, 0x9B, 0xED, 0x7F, 0x22, 0x76, 0xAF, 0xDD, 0x3A, 0x0B, 0x58, 0x67, 0x88, 0x06, 0xC3, 0x35, 0x0D, 0x01, 0x8B, 0x8C, 0xC2, 0xE6, 0x5F, 0x02, 0x24, 0x75, 0x93, 0x66, 0x1E, 0xE5, 0xE2, 0x54, 0xD8, 0x10, 0xCE, 0x7A, 0xE8, 0x08, 0x2C, 0x12, 0x97, 0x32, 0xAB, 0xB4, 0x27, 0x0A, 0x23, 0xDF, 0xEF, 0xCA, 0xD9, 0xB8, 0xFA, 0xDC, 0x31, 0x6B, 0xD1, 0xAD, 0x19, 0x49, 0xBD, 0x51, 0x96, 0xEE, 0xE4, 0xA8, 0x41, 0xDA, 0xFF, 0xCD, 0x55, 0x86, 0x36, 0xBE, 0x61, 0x52, 0xF8, 0xBB, 0x0E, 0x82, 0x48, 0x69, 0x9A, 0xE0, 0x47, 0x9E, 0x5C, 0x04, 0x4B, 0x34, 0x15, 0x79, 0x26, 0xA7, 0xDE, 0x29, 0xAE, 0x92, 0xD7, 0x84, 0xE9, 0xD2, 0xBA, 0x5D, 0xF3, 0xC5, 0xB0, 0xBF, 0xA4, 0x3B, 0x71, 0x44, 0x46, 0x2B, 0xFC, 0xEB, 0x6F, 0xD5, 0xF6, 0x14, 0xFE, 0x7C, 0x70, 0x5A, 0x7D, 0xFD, 0x2F, 0x18, 0x83, 0x16, 0xA5, 0x91, 0x1F, 0x05, 0x95, 0x74, 0xA9, 0xC1, 0x5B, 0x4A, 0x85, 0x6D, 0x13, 0x07, 0x4F, 0x4E, 0x45, 0xB2, 0x0F, 0xC9, 0x1C, 0xA6, 0xBC, 0xEC, 0x73, 0x90, 0x7B, 0xCF, 0x59, 0x8F, 0xA1, 0xF9, 0x2D, 0xF2, 0xB1, 0x00, 0x94, 0x37, 0x9F, 0xD0, 0x2E, 0x9C, 0x6E, 0x28, 0x3F, 0x80, 0xF0, 0x3D, 0xD3, 0x25, 0x8A, 0xB5, 0xE7, 0x42, 0xB3, 0xC7, 0xEA, 0xF7, 0x4C, 0x11, 0x33, 0x03, 0xA2, 0xAC, 0x60]);
const C1 = new Uint8Array([0x51, 0x7C, 0xC1, 0xB7, 0x27, 0x22, 0x0A, 0x94, 0xFE, 0x13, 0xAB, 0xE8, 0xFA, 0x9A, 0x6E, 0xE0]);
const C2 = new Uint8Array([0x6D, 0xB1, 0x4A, 0xCC, 0x9E, 0x21, 0xC8, 0x20, 0xFF, 0x28, 0xB1, 0xD5, 0xEF, 0x5D, 0xE2, 0xB0]);
const C3 = new Uint8Array([0xDB, 0x92, 0x37, 0x1D, 0x21, 0x26, 0xE9, 0x70, 0x03, 0x24, 0x97, 0x75, 0x04, 0xE8, 0xC9, 0x0E]);
// * Functions
function RL128(x, n) {
const x_byte = x.length;
const x_bit = x_byte << 3;
// 规范化移位数
const shift = n % x_bit;
if (shift === 0) {
return x.slice(0);
}
// 计算字节和位移
const byte_shift = shift >> 3;
const bit_shift = shift % 8;
const result = new U8(x.length);
for (let i = 0; i < x_byte; i++) {
const current = x[i];
const next = x[(i + 1) % x_byte];
result[i] = (current << bit_shift) | (next >> (8 - bit_shift));
}
// 处理字节移位
if (byte_shift > 0) {
const temp = new Uint8Array(result);
for (let i = 0; i < x_byte; i++) {
result[i] = temp[(i + byte_shift) % x_byte];
}
}
return result;
}
function RR128(x, n) {
const x_byte = x.length;
const x_bit = x_byte << 3;
// 规范化移位数
const shift = n % x_bit;
if (shift === 0) {
return x.slice(0);
}
// 计算字节和位移
const byte_shift = shift >> 3;
const bit_shift = shift % 8;
const result = new U8(x.length);
for (let i = 0; i < x_byte; i++) {
const current = x[i];
const next = x[(i - 1 + x_byte) % x_byte];
result[i] = (current >> bit_shift) | (next << (8 - bit_shift));
}
// 处理字节移位
if (byte_shift > 0) {
const temp = new Uint8Array(result);
for (let i = 0; i < x_byte; i++) {
result[i] = temp[(i - byte_shift + x_byte) % x_byte];
}
}
return result;
}
function XOR(x, y) {
return x.map((_, i) => x[i] ^ y[i]);
}
function FO(D, RK) {
return A(SL1(XOR(D, RK)));
}
function FE(D, RK) {
return A(SL2(XOR(D, RK)));
}
function SL1(x) {
const y = new Uint8Array(16);
// y0 = SB1(x0), y1 = SB2(x1), y2 = SB3(x2), y3 = SB4(x3),
// y4 = SB1(x4), y5 = SB2(x5), y6 = SB3(x6), y7 = SB4(x7),
// y8 = SB1(x8), y9 = SB2(x9), y10 = SB3(x10), y11 = SB4(x11),
// y12 = SB1(x12), y13 = SB2(x13), y14 = SB3(x14), y15 = SB4(x15).
y[0] = SBox1[x[0]];
y[1] = SBox2[x[1]];
y[2] = SBox3[x[2]];
y[3] = SBox4[x[3]];
y[4] = SBox1[x[4]];
y[5] = SBox2[x[5]];
y[6] = SBox3[x[6]];
y[7] = SBox4[x[7]];
y[8] = SBox1[x[8]];
y[9] = SBox2[x[9]];
y[10] = SBox3[x[10]];
y[11] = SBox4[x[11]];
y[12] = SBox1[x[12]];
y[13] = SBox2[x[13]];
y[14] = SBox3[x[14]];
y[15] = SBox4[x[15]];
return y;
}
function SL2(x) {
const y = new Uint8Array(16);
// y0 = SB3(x0), y1 = SB4(x1), y2 = SB1(x2), y3 = SB2(x3),
// y4 = SB3(x4), y5 = SB4(x5), y6 = SB1(x6), y7 = SB2(x7),
// y8 = SB3(x8), y9 = SB4(x9), y10 = SB1(x10), y11 = SB2(x11),
// y12 = SB3(x12), y13 = SB4(x13), y14 = SB1(x14), y15 = SB2(x15).
y[0] = SBox3[x[0]];
y[1] = SBox4[x[1]];
y[2] = SBox1[x[2]];
y[3] = SBox2[x[3]];
y[4] = SBox3[x[4]];
y[5] = SBox4[x[5]];
y[6] = SBox1[x[6]];
y[7] = SBox2[x[7]];
y[8] = SBox3[x[8]];
y[9] = SBox4[x[9]];
y[10] = SBox1[x[10]];
y[11] = SBox2[x[11]];
y[12] = SBox3[x[12]];
y[13] = SBox4[x[13]];
y[14] = SBox1[x[14]];
y[15] = SBox2[x[15]];
return y;
}
function A(x) {
const y = new Uint8Array(16);
// y0 = x3 ^ x4 ^ x6 ^ x8 ^ x9 ^ x13 ^ x14
// y1 = x2 ^ x5 ^ x7 ^ x8 ^ x9 ^ x12 ^ x15
// y2 = x1 ^ x4 ^ x6 ^ x10 ^ x11 ^ x12 ^ x15
// y3 = x0 ^ x5 ^ x7 ^ x10 ^ x11 ^ x13 ^ x14
// y4 = x0 ^ x2 ^ x5 ^ x8 ^ x11 ^ x14 ^ x15
// y5 = x1 ^ x3 ^ x4 ^ x9 ^ x10 ^ x14 ^ x15
// y6 = x0 ^ x2 ^ x7 ^ x9 ^ x10 ^ x12 ^ x13
// y7 = x1 ^ x3 ^ x6 ^ x8 ^ x11 ^ x12 ^ x13
// y8 = x0 ^ x1 ^ x4 ^ x7 ^ x10 ^ x13 ^ x15
// y9 = x0 ^ x1 ^ x5 ^ x6 ^ x11 ^ x12 ^ x14
// y10 = x2 ^ x3 ^ x5 ^ x6 ^ x8 ^ x13 ^ x15
// y11 = x2 ^ x3 ^ x4 ^ x7 ^ x9 ^ x12 ^ x14
// y12 = x1 ^ x2 ^ x6 ^ x7 ^ x9 ^ x11 ^ x12
// y13 = x0 ^ x3 ^ x6 ^ x7 ^ x8 ^ x10 ^ x13
// y14 = x0 ^ x3 ^ x4 ^ x5 ^ x9 ^ x11 ^ x14
// y15 = x1 ^ x2 ^ x4 ^ x5 ^ x8 ^ x10 ^ x15
y[0] = x[3] ^ x[4] ^ x[6] ^ x[8] ^ x[9] ^ x[13] ^ x[14];
y[1] = x[2] ^ x[5] ^ x[7] ^ x[8] ^ x[9] ^ x[12] ^ x[15];
y[2] = x[1] ^ x[4] ^ x[6] ^ x[10] ^ x[11] ^ x[12] ^ x[15];
y[3] = x[0] ^ x[5] ^ x[7] ^ x[10] ^ x[11] ^ x[13] ^ x[14];
y[4] = x[0] ^ x[2] ^ x[5] ^ x[8] ^ x[11] ^ x[14] ^ x[15];
y[5] = x[1] ^ x[3] ^ x[4] ^ x[9] ^ x[10] ^ x[14] ^ x[15];
y[6] = x[0] ^ x[2] ^ x[7] ^ x[9] ^ x[10] ^ x[12] ^ x[13];
y[7] = x[1] ^ x[3] ^ x[6] ^ x[8] ^ x[11] ^ x[12] ^ x[13];
y[8] = x[0] ^ x[1] ^ x[4] ^ x[7] ^ x[10] ^ x[13] ^ x[15];
y[9] = x[0] ^ x[1] ^ x[5] ^ x[6] ^ x[11] ^ x[12] ^ x[14];
y[10] = x[2] ^ x[3] ^ x[5] ^ x[6] ^ x[8] ^ x[13] ^ x[15];
y[11] = x[2] ^ x[3] ^ x[4] ^ x[7] ^ x[9] ^ x[12] ^ x[14];
y[12] = x[1] ^ x[2] ^ x[6] ^ x[7] ^ x[9] ^ x[11] ^ x[12];
y[13] = x[0] ^ x[3] ^ x[6] ^ x[7] ^ x[8] ^ x[10] ^ x[13];
y[14] = x[0] ^ x[3] ^ x[4] ^ x[5] ^ x[9] ^ x[11] ^ x[14];
y[15] = x[1] ^ x[2] ^ x[4] ^ x[5] ^ x[8] ^ x[10] ^ x[15];
return y;
}
function KeyScheduling(K, round) {
const _K = new Uint8Array(32);
_K.set(K);
K = _K;
const KL = new Uint8Array(16);
const KR = new Uint8Array(16);
KL.set(K.subarray(0, 16));
KR.set(K.subarray(16, 32));
let CK1, CK2, CK3;
switch (round) {
case 12:
CK1 = C1;
CK2 = C2;
CK3 = C3;
break;
case 14:
CK1 = C2;
CK2 = C3;
CK3 = C1;
break;
case 16:
CK1 = C3;
CK2 = C1;
CK3 = C2;
break;
}
const W0 = new Uint8Array(16);
const W1 = new Uint8Array(16);
const W2 = new Uint8Array(16);
const W3 = new Uint8Array(16);
W0.set(KL);
W1.set(FO(W0, CK1));
W1.forEach((_, i) => W1[i] ^= KR[i]);
W2.set(FE(W1, CK2));
W2.forEach((_, i) => W2[i] ^= W0[i]);
W3.set(FO(W2, CK3));
W3.forEach((_, i) => W3[i] ^= W1[i]);
const EK = computeEK([W0, W1, W2, W3], round);
const DK = computeDK(EK, round);
return { EK, DK };
}
function computeEK(W, round) {
const [W0, W1, W2, W3] = W;
// ek1 = W0 ^ (W1 >>> 19)
// ek2 = W1 ^ (W2 >>> 19)
// ek3 = W2 ^ (W3 >>> 19)
// ek4 = W3 ^ (W0 >>> 19)
// ek5 = W0 ^ (W1 >>> 31)
// ek6 = W1 ^ (W2 >>> 31)
// ek7 = W2 ^ (W3 >>> 31)
// ek8 = W3 ^ (W0 >>> 31)
// ek9 = W0 ^ (W1 <<< 61)
// ek10 = W1 ^ (W2 <<< 61)
// ek11 = W2 ^ (W3 <<< 61)
// ek12 = W3 ^ (W0 <<< 61)
// ek13 = W0 ^ (W1 <<< 31)
// ek14 = W1 ^ (W2 <<< 31)
// ek15 = W2 ^ (W3 <<< 31)
// ek16 = W3 ^ (W0 <<< 31)
// ek17 = W0 ^ (W1 <<< 19)
const ek01 = XOR(RR128(W1, 19), W0);
const ek02 = XOR(RR128(W2, 19), W1);
const ek03 = XOR(RR128(W3, 19), W2);
const ek04 = XOR(RR128(W0, 19), W3);
const ek05 = XOR(RR128(W1, 31), W0);
const ek06 = XOR(RR128(W2, 31), W1);
const ek07 = XOR(RR128(W3, 31), W2);
const ek08 = XOR(RR128(W0, 31), W3);
const ek09 = XOR(RL128(W1, 61), W0);
const ek10 = XOR(RL128(W2, 61), W1);
const ek11 = XOR(RL128(W3, 61), W2);
const ek12 = XOR(RL128(W0, 61), W3);
const ek13 = XOR(RL128(W1, 31), W0);
if (round === 12) {
return [ek01, ek02, ek03, ek04, ek05, ek06, ek07, ek08, ek09, ek10, ek11, ek12, ek13];
}
const ek14 = XOR(RL128(W2, 31), W1);
const ek15 = XOR(RL128(W3, 31), W2);
if (round === 14) {
return [ek01, ek02, ek03, ek04, ek05, ek06, ek07, ek08, ek09, ek10, ek11, ek12, ek13, ek14, ek15];
}
const ek16 = XOR(RL128(W0, 31), W3);
const ek17 = XOR(RL128(W1, 19), W0);
return [ek01, ek02, ek03, ek04, ek05, ek06, ek07, ek08, ek09, ek10, ek11, ek12, ek13, ek14, ek15, ek16, ek17];
}
function computeDK(EK, round) {
const DK = Array.from({ length: EK.length });
// dk1 = ek{ n + 1 },
// dk2 = A(ek{ n }),
// dk3 = A(ek{ n- 1}),
// ...,
// dk{ n }= A(ek2),
// dk{ n + 1 }= ek1.
DK[0] = EK[round];
let j = round - 1;
for (let i = 1; i < round; i++) {
DK[i] = A(EK[j--]);
}
DK[round] = EK[0];
return DK;
}
// * ARIA Algorithm
function _aria(K, b) {
if (K.byteLength !== b >> 3) {
throw new KitError(`Aria-${b} key must be ${b >> 3} byte`);
}
/**
* - 128-bit key: 12 rounds
* - 192-bit key: 14 rounds
* - 256-bit key: 16 rounds
*/
const round = b === 128 ? 12 : (b === 192 ? 14 : 16);
const { EK, DK } = KeyScheduling(K, round);
const cipher = (M, RK) => {
if (M.byteLength !== 16) {
throw new KitError('ARIA block must be 16 byte');
}
let P = M;
let i = 0;
while (i < round - 2) {
P = FO(P, RK[i++]);
P = FE(P, RK[i++]);
}
P = FO(P, RK[i++]);
P = SL2(XOR(P, RK[i++]));
P = XOR(P, RK[i++]);
return new U8(P);
};
return {
encrypt: (M) => cipher(M, EK),
decrypt: (C) => cipher(C, DK),
};
}
/**
* ARIA 分组密码算法 / block cipher algorithm
*
* @param {128 | 192 | 256} b - 密钥长度 / Key size (bit)
*/
export function aria(b) {
return createCipher((K) => _aria(K, b), {
ALGORITHM: `ARIA-${b}`,
BLOCK_SIZE: 16,
KEY_SIZE: b >> 3,
MIN_KEY_SIZE: 16,
MAX_KEY_SIZE: 32,
});
}
import { createCipher } from '../../core/cipher';
import { KitError, U8 } from '../../core/utils';
// * Blowfish Algorithm
function _blowfish(key) {
if (key.length < 4 || key.length > 56) {
throw new KitError(`Blowfish key must be between 4 and 56 byte`);
}
const P = new Uint32Array([0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, 0x9216D5D9, 0x8979FB1B]);
const S = [
new Uint32Array([0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A]),
new Uint32Array([0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7]),
new Uint32Array([0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0]),
new Uint32Array([0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6]),
];
function F(x) {
let r = 0;
r += S[0][(x >>> 24) & 0xFF];
r += S[1][(x >>> 16) & 0xFF];
r ^= S[2][(x >>> 8) & 0xFF];
r += S[3][(x >>> 0) & 0xFF];
return r;
}
const _encrypt = (l, r) => {
for (let i = 0; i < 16; i++) {
l ^= P[i];
r ^= F(l);
[l, r] = [r, l];
}
l ^= P[16];
r ^= P[17];
return [r, l];
};
const _decrypt = (l, r) => {
for (let i = 17; i > 1; i--) {
l ^= P[i];
r ^= F(l);
[l, r] = [r, l];
}
l ^= P[1];
r ^= P[0];
return [r, l];
};
// init
(() => {
let p = 0;
for (let i = 0; i < 18; i++) {
let k = 0;
for (let j = 0; j < 4; j++) {
k = (k << 8) | key[p];
p = (p + 1) % key.length;
}
P[i] ^= k;
}
let l = 0;
let r = 0;
for (let i = 0; i < 18; i += 2) {
[l, r] = _encrypt(l, r);
P[i] = l;
P[i + 1] = r;
}
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 256; j += 2) {
[l, r] = _encrypt(l, r);
S[i][j] = l;
S[i][j + 1] = r;
}
}
})();
return {
encrypt: (plaintext) => {
if (plaintext.length !== 8) {
throw new KitError(`Blowfish block must be 8 byte`);
}
const c = U8.from(plaintext.slice(0));
const c_view = new DataView(c.buffer);
let c0 = c_view.getUint32(0, false);
let c1 = c_view.getUint32(4, false);
[c0, c1] = _encrypt(c0, c1);
c_view.setUint32(0, c0, false);
c_view.setUint32(4, c1, false);
return c;
},
decrypt: (ciphertext) => {
if (ciphertext.length !== 8) {
throw new KitError(`Blowfish block must be 8 byte`);
}
const p = U8.from(ciphertext.slice(0));
const p_view = new DataView(p.buffer);
let p0 = p_view.getUint32(0, false);
let p1 = p_view.getUint32(4, false);
[p0, p1] = _decrypt(p0, p1);
p_view.setUint32(0, p0, false);
p_view.setUint32(4, p1, false);
return p;
},
};
}
/**
* Blowfish 分组密码算法 / block cipher algorithm
*/
export const blowfish = createCipher(_blowfish, {
ALGORITHM: 'Blowfish',
BLOCK_SIZE: 8,
KEY_SIZE: 16,
MIN_KEY_SIZE: 4,
MAX_KEY_SIZE: 56,
});
import { createCipher } from '../../core/cipher';
import { KitError, U8, rotateL32, rotateR32 } from '../../core/utils';
// * Constants
const SBox1_1110 = new Uint32Array([0x70707000, 0x82828200, 0x2C2C2C00, 0xECECEC00, 0xB3B3B300, 0x27272700, 0xC0C0C000, 0xE5E5E500, 0xE4E4E400, 0x85858500, 0x57575700, 0x35353500, 0xEAEAEA00, 0x0C0C0C00, 0xAEAEAE00, 0x41414100, 0x23232300, 0xEFEFEF00, 0x6B6B6B00, 0x93939300, 0x45454500, 0x19191900, 0xA5A5A500, 0x21212100, 0xEDEDED00, 0x0E0E0E00, 0x4F4F4F00, 0x4E4E4E00, 0x1D1D1D00, 0x65656500, 0x92929200, 0xBDBDBD00, 0x86868600, 0xB8B8B800, 0xAFAFAF00, 0x8F8F8F00, 0x7C7C7C00, 0xEBEBEB00, 0x1F1F1F00, 0xCECECE00, 0x3E3E3E00, 0x30303000, 0xDCDCDC00, 0x5F5F5F00, 0x5E5E5E00, 0xC5C5C500, 0x0B0B0B00, 0x1A1A1A00, 0xA6A6A600, 0xE1E1E100, 0x39393900, 0xCACACA00, 0xD5D5D500, 0x47474700, 0x5D5D5D00, 0x3D3D3D00, 0xD9D9D900, 0x01010100, 0x5A5A5A00, 0xD6D6D600, 0x51515100, 0x56565600, 0x6C6C6C00, 0x4D4D4D00, 0x8B8B8B00, 0x0D0D0D00, 0x9A9A9A00, 0x66666600, 0xFBFBFB00, 0xCCCCCC00, 0xB0B0B000, 0x2D2D2D00, 0x74747400, 0x12121200, 0x2B2B2B00, 0x20202000, 0xF0F0F000, 0xB1B1B100, 0x84848400, 0x99999900, 0xDFDFDF00, 0x4C4C4C00, 0xCBCBCB00, 0xC2C2C200, 0x34343400, 0x7E7E7E00, 0x76767600, 0x05050500, 0x6D6D6D00, 0xB7B7B700, 0xA9A9A900, 0x31313100, 0xD1D1D100, 0x17171700, 0x04040400, 0xD7D7D700, 0x14141400, 0x58585800, 0x3A3A3A00, 0x61616100, 0xDEDEDE00, 0x1B1B1B00, 0x11111100, 0x1C1C1C00, 0x32323200, 0x0F0F0F00, 0x9C9C9C00, 0x16161600, 0x53535300, 0x18181800, 0xF2F2F200, 0x22222200, 0xFEFEFE00, 0x44444400, 0xCFCFCF00, 0xB2B2B200, 0xC3C3C300, 0xB5B5B500, 0x7A7A7A00, 0x91919100, 0x24242400, 0x08080800, 0xE8E8E800, 0xA8A8A800, 0x60606000, 0xFCFCFC00, 0x69696900, 0x50505000, 0xAAAAAA00, 0xD0D0D000, 0xA0A0A000, 0x7D7D7D00, 0xA1A1A100, 0x89898900, 0x62626200, 0x97979700, 0x54545400, 0x5B5B5B00, 0x1E1E1E00, 0x95959500, 0xE0E0E000, 0xFFFFFF00, 0x64646400, 0xD2D2D200, 0x10101000, 0xC4C4C400, 0x00000000, 0x48484800, 0xA3A3A300, 0xF7F7F700, 0x75757500, 0xDBDBDB00, 0x8A8A8A00, 0x03030300, 0xE6E6E600, 0xDADADA00, 0x09090900, 0x3F3F3F00, 0xDDDDDD00, 0x94949400, 0x87878700, 0x5C5C5C00, 0x83838300, 0x02020200, 0xCDCDCD00, 0x4A4A4A00, 0x90909000, 0x33333300, 0x73737300, 0x67676700, 0xF6F6F600, 0xF3F3F300, 0x9D9D9D00, 0x7F7F7F00, 0xBFBFBF00, 0xE2E2E200, 0x52525200, 0x9B9B9B00, 0xD8D8D800, 0x26262600, 0xC8C8C800, 0x37373700, 0xC6C6C600, 0x3B3B3B00, 0x81818100, 0x96969600, 0x6F6F6F00, 0x4B4B4B00, 0x13131300, 0xBEBEBE00, 0x63636300, 0x2E2E2E00, 0xE9E9E900, 0x79797900, 0xA7A7A700, 0x8C8C8C00, 0x9F9F9F00, 0x6E6E6E00, 0xBCBCBC00, 0x8E8E8E00, 0x29292900, 0xF5F5F500, 0xF9F9F900, 0xB6B6B600, 0x2F2F2F00, 0xFDFDFD00, 0xB4B4B400, 0x59595900, 0x78787800, 0x98989800, 0x06060600, 0x6A6A6A00, 0xE7E7E700, 0x46464600, 0x71717100, 0xBABABA00, 0xD4D4D400, 0x25252500, 0xABABAB00, 0x42424200, 0x88888800, 0xA2A2A200, 0x8D8D8D00, 0xFAFAFA00, 0x72727200, 0x07070700, 0xB9B9B900, 0x55555500, 0xF8F8F800, 0xEEEEEE00, 0xACACAC00, 0x0A0A0A00, 0x36363600, 0x49494900, 0x2A2A2A00, 0x68686800, 0x3C3C3C00, 0x38383800, 0xF1F1F100, 0xA4A4A400, 0x40404000, 0x28282800, 0xD3D3D300, 0x7B7B7B00, 0xBBBBBB00, 0xC9C9C900, 0x43434300, 0xC1C1C100, 0x15151500, 0xE3E3E300, 0xADADAD00, 0xF4F4F400, 0x77777700, 0xC7C7C700, 0x80808000, 0x9E9E9E00]);
const SBox4_4404 = new Uint32Array([0x70700070, 0x2C2C002C, 0xB3B300B3, 0xC0C000C0, 0xE4E400E4, 0x57570057, 0xEAEA00EA, 0xAEAE00AE, 0x23230023, 0x6B6B006B, 0x45450045, 0xA5A500A5, 0xEDED00ED, 0x4F4F004F, 0x1D1D001D, 0x92920092, 0x86860086, 0xAFAF00AF, 0x7C7C007C, 0x1F1F001F, 0x3E3E003E, 0xDCDC00DC, 0x5E5E005E, 0x0B0B000B, 0xA6A600A6, 0x39390039, 0xD5D500D5, 0x5D5D005D, 0xD9D900D9, 0x5A5A005A, 0x51510051, 0x6C6C006C, 0x8B8B008B, 0x9A9A009A, 0xFBFB00FB, 0xB0B000B0, 0x74740074, 0x2B2B002B, 0xF0F000F0, 0x84840084, 0xDFDF00DF, 0xCBCB00CB, 0x34340034, 0x76760076, 0x6D6D006D, 0xA9A900A9, 0xD1D100D1, 0x04040004, 0x14140014, 0x3A3A003A, 0xDEDE00DE, 0x11110011, 0x32320032, 0x9C9C009C, 0x53530053, 0xF2F200F2, 0xFEFE00FE, 0xCFCF00CF, 0xC3C300C3, 0x7A7A007A, 0x24240024, 0xE8E800E8, 0x60600060, 0x69690069, 0xAAAA00AA, 0xA0A000A0, 0xA1A100A1, 0x62620062, 0x54540054, 0x1E1E001E, 0xE0E000E0, 0x64640064, 0x10100010, 0x00000000, 0xA3A300A3, 0x75750075, 0x8A8A008A, 0xE6E600E6, 0x09090009, 0xDDDD00DD, 0x87870087, 0x83830083, 0xCDCD00CD, 0x90900090, 0x73730073, 0xF6F600F6, 0x9D9D009D, 0xBFBF00BF, 0x52520052, 0xD8D800D8, 0xC8C800C8, 0xC6C600C6, 0x81810081, 0x6F6F006F, 0x13130013, 0x63630063, 0xE9E900E9, 0xA7A700A7, 0x9F9F009F, 0xBCBC00BC, 0x29290029, 0xF9F900F9, 0x2F2F002F, 0xB4B400B4, 0x78780078, 0x06060006, 0xE7E700E7, 0x71710071, 0xD4D400D4, 0xABAB00AB, 0x88880088, 0x8D8D008D, 0x72720072, 0xB9B900B9, 0xF8F800F8, 0xACAC00AC, 0x36360036, 0x2A2A002A, 0x3C3C003C, 0xF1F100F1, 0x40400040, 0xD3D300D3, 0xBBBB00BB, 0x43430043, 0x15150015, 0xADAD00AD, 0x77770077, 0x80800080, 0x82820082, 0xECEC00EC, 0x27270027, 0xE5E500E5, 0x85850085, 0x35350035, 0x0C0C000C, 0x41410041, 0xEFEF00EF, 0x93930093, 0x19190019, 0x21210021, 0x0E0E000E, 0x4E4E004E, 0x65650065, 0xBDBD00BD, 0xB8B800B8, 0x8F8F008F, 0xEBEB00EB, 0xCECE00CE, 0x30300030, 0x5F5F005F, 0xC5C500C5, 0x1A1A001A, 0xE1E100E1, 0xCACA00CA, 0x47470047, 0x3D3D003D, 0x01010001, 0xD6D600D6, 0x56560056, 0x4D4D004D, 0x0D0D000D, 0x66660066, 0xCCCC00CC, 0x2D2D002D, 0x12120012, 0x20200020, 0xB1B100B1, 0x99990099, 0x4C4C004C, 0xC2C200C2, 0x7E7E007E, 0x05050005, 0xB7B700B7, 0x31310031, 0x17170017, 0xD7D700D7, 0x58580058, 0x61610061, 0x1B1B001B, 0x1C1C001C, 0x0F0F000F, 0x16160016, 0x18180018, 0x22220022, 0x44440044, 0xB2B200B2, 0xB5B500B5, 0x91910091, 0x08080008, 0xA8A800A8, 0xFCFC00FC, 0x50500050, 0xD0D000D0, 0x7D7D007D, 0x89890089, 0x97970097, 0x5B5B005B, 0x95950095, 0xFFFF00FF, 0xD2D200D2, 0xC4C400C4, 0x48480048, 0xF7F700F7, 0xDBDB00DB, 0x03030003, 0xDADA00DA, 0x3F3F003F, 0x94940094, 0x5C5C005C, 0x02020002, 0x4A4A004A, 0x33330033, 0x67670067, 0xF3F300F3, 0x7F7F007F, 0xE2E200E2, 0x9B9B009B, 0x26260026, 0x37370037, 0x3B3B003B, 0x96960096, 0x4B4B004B, 0xBEBE00BE, 0x2E2E002E, 0x79790079, 0x8C8C008C, 0x6E6E006E, 0x8E8E008E, 0xF5F500F5, 0xB6B600B6, 0xFDFD00FD, 0x59590059, 0x98980098, 0x6A6A006A, 0x46460046, 0xBABA00BA, 0x25250025, 0x42420042, 0xA2A200A2, 0xFAFA00FA, 0x07070007, 0x55550055, 0xEEEE00EE, 0x0A0A000A, 0x49490049, 0x68680068, 0x38380038, 0xA4A400A4, 0x28280028, 0x7B7B007B, 0xC9C900C9, 0xC1C100C1, 0xE3E300E3, 0xF4F400F4, 0xC7C700C7, 0x9E9E009E]);
const SBox2_0222 = new Uint32Array([0x00E0E0E0, 0x00050505, 0x00585858, 0x00D9D9D9, 0x00676767, 0x004E4E4E, 0x00818181, 0x00CBCBCB, 0x00C9C9C9, 0x000B0B0B, 0x00AEAEAE, 0x006A6A6A, 0x00D5D5D5, 0x00181818, 0x005D5D5D, 0x00828282, 0x00464646, 0x00DFDFDF, 0x00D6D6D6, 0x00272727, 0x008A8A8A, 0x00323232, 0x004B4B4B, 0x00424242, 0x00DBDBDB, 0x001C1C1C, 0x009E9E9E, 0x009C9C9C, 0x003A3A3A, 0x00CACACA, 0x00252525, 0x007B7B7B, 0x000D0D0D, 0x00717171, 0x005F5F5F, 0x001F1F1F, 0x00F8F8F8, 0x00D7D7D7, 0x003E3E3E, 0x009D9D9D, 0x007C7C7C, 0x00606060, 0x00B9B9B9, 0x00BEBEBE, 0x00BCBCBC, 0x008B8B8B, 0x00161616, 0x00343434, 0x004D4D4D, 0x00C3C3C3, 0x00727272, 0x00959595, 0x00ABABAB, 0x008E8E8E, 0x00BABABA, 0x007A7A7A, 0x00B3B3B3, 0x00020202, 0x00B4B4B4, 0x00ADADAD, 0x00A2A2A2, 0x00ACACAC, 0x00D8D8D8, 0x009A9A9A, 0x00171717, 0x001A1A1A, 0x00353535, 0x00CCCCCC, 0x00F7F7F7, 0x00999999, 0x00616161, 0x005A5A5A, 0x00E8E8E8, 0x00242424, 0x00565656, 0x00404040, 0x00E1E1E1, 0x00636363, 0x00090909, 0x00333333, 0x00BFBFBF, 0x00989898, 0x00979797, 0x00858585, 0x00686868, 0x00FCFCFC, 0x00ECECEC, 0x000A0A0A, 0x00DADADA, 0x006F6F6F, 0x00535353, 0x00626262, 0x00A3A3A3, 0x002E2E2E, 0x00080808, 0x00AFAFAF, 0x00282828, 0x00B0B0B0, 0x00747474, 0x00C2C2C2, 0x00BDBDBD, 0x00363636, 0x00222222, 0x00383838, 0x00646464, 0x001E1E1E, 0x00393939, 0x002C2C2C, 0x00A6A6A6, 0x00303030, 0x00E5E5E5, 0x00444444, 0x00FDFDFD, 0x00888888, 0x009F9F9F, 0x00656565, 0x00878787, 0x006B6B6B, 0x00F4F4F4, 0x00232323, 0x00484848, 0x00101010, 0x00D1D1D1, 0x00515151, 0x00C0C0C0, 0x00F9F9F9, 0x00D2D2D2, 0x00A0A0A0, 0x00555555, 0x00A1A1A1, 0x00414141, 0x00FAFAFA, 0x00434343, 0x00131313, 0x00C4C4C4, 0x002F2F2F, 0x00A8A8A8, 0x00B6B6B6, 0x003C3C3C, 0x002B2B2B, 0x00C1C1C1, 0x00FFFFFF, 0x00C8C8C8, 0x00A5A5A5, 0x00202020, 0x00898989, 0x00000000, 0x00909090, 0x00474747, 0x00EFEFEF, 0x00EAEAEA, 0x00B7B7B7, 0x00151515, 0x00060606, 0x00CDCDCD, 0x00B5B5B5, 0x00121212, 0x007E7E7E, 0x00BBBBBB, 0x00292929, 0x000F0F0F, 0x00B8B8B8, 0x00070707, 0x00040404, 0x009B9B9B, 0x00949494, 0x00212121, 0x00666666, 0x00E6E6E6, 0x00CECECE, 0x00EDEDED, 0x00E7E7E7, 0x003B3B3B, 0x00FEFEFE, 0x007F7F7F, 0x00C5C5C5, 0x00A4A4A4, 0x00373737, 0x00B1B1B1, 0x004C4C4C, 0x00919191, 0x006E6E6E, 0x008D8D8D, 0x00767676, 0x00030303, 0x002D2D2D, 0x00DEDEDE, 0x00969696, 0x00262626, 0x007D7D7D, 0x00C6C6C6, 0x005C5C5C, 0x00D3D3D3, 0x00F2F2F2, 0x004F4F4F, 0x00191919, 0x003F3F3F, 0x00DCDCDC, 0x00797979, 0x001D1D1D, 0x00525252, 0x00EBEBEB, 0x00F3F3F3, 0x006D6D6D, 0x005E5E5E, 0x00FBFBFB, 0x00696969, 0x00B2B2B2, 0x00F0F0F0, 0x00313131, 0x000C0C0C, 0x00D4D4D4, 0x00CFCFCF, 0x008C8C8C, 0x00E2E2E2, 0x00757575, 0x00A9A9A9, 0x004A4A4A, 0x00575757, 0x00848484, 0x00111111, 0x00454545, 0x001B1B1B, 0x00F5F5F5, 0x00E4E4E4, 0x000E0E0E, 0x00737373, 0x00AAAAAA, 0x00F1F1F1, 0x00DDDDDD, 0x00595959, 0x00141414, 0x006C6C6C, 0x00929292, 0x00545454, 0x00D0D0D0, 0x00787878, 0x00707070, 0x00E3E3E3, 0x00494949, 0x00808080, 0x00505050, 0x00A7A7A7, 0x00F6F6F6, 0x00777777, 0x00939393, 0x00868686, 0x00838383, 0x002A2A2A, 0x00C7C7C7, 0x005B5B5B, 0x00E9E9E9, 0x00EEEEEE, 0x008F8F8F, 0x00010101, 0x003D3D3D]);
const SBox3_3033 = new Uint32Array([0x38003838, 0x41004141, 0x16001616, 0x76007676, 0xD900D9D9, 0x93009393, 0x60006060, 0xF200F2F2, 0x72007272, 0xC200C2C2, 0xAB00ABAB, 0x9A009A9A, 0x75007575, 0x06000606, 0x57005757, 0xA000A0A0, 0x91009191, 0xF700F7F7, 0xB500B5B5, 0xC900C9C9, 0xA200A2A2, 0x8C008C8C, 0xD200D2D2, 0x90009090, 0xF600F6F6, 0x07000707, 0xA700A7A7, 0x27002727, 0x8E008E8E, 0xB200B2B2, 0x49004949, 0xDE00DEDE, 0x43004343, 0x5C005C5C, 0xD700D7D7, 0xC700C7C7, 0x3E003E3E, 0xF500F5F5, 0x8F008F8F, 0x67006767, 0x1F001F1F, 0x18001818, 0x6E006E6E, 0xAF00AFAF, 0x2F002F2F, 0xE200E2E2, 0x85008585, 0x0D000D0D, 0x53005353, 0xF000F0F0, 0x9C009C9C, 0x65006565, 0xEA00EAEA, 0xA300A3A3, 0xAE00AEAE, 0x9E009E9E, 0xEC00ECEC, 0x80008080, 0x2D002D2D, 0x6B006B6B, 0xA800A8A8, 0x2B002B2B, 0x36003636, 0xA600A6A6, 0xC500C5C5, 0x86008686, 0x4D004D4D, 0x33003333, 0xFD00FDFD, 0x66006666, 0x58005858, 0x96009696, 0x3A003A3A, 0x09000909, 0x95009595, 0x10001010, 0x78007878, 0xD800D8D8, 0x42004242, 0xCC00CCCC, 0xEF00EFEF, 0x26002626, 0xE500E5E5, 0x61006161, 0x1A001A1A, 0x3F003F3F, 0x3B003B3B, 0x82008282, 0xB600B6B6, 0xDB00DBDB, 0xD400D4D4, 0x98009898, 0xE800E8E8, 0x8B008B8B, 0x02000202, 0xEB00EBEB, 0x0A000A0A, 0x2C002C2C, 0x1D001D1D, 0xB000B0B0, 0x6F006F6F, 0x8D008D8D, 0x88008888, 0x0E000E0E, 0x19001919, 0x87008787, 0x4E004E4E, 0x0B000B0B, 0xA900A9A9, 0x0C000C0C, 0x79007979, 0x11001111, 0x7F007F7F, 0x22002222, 0xE700E7E7, 0x59005959, 0xE100E1E1, 0xDA00DADA, 0x3D003D3D, 0xC800C8C8, 0x12001212, 0x04000404, 0x74007474, 0x54005454, 0x30003030, 0x7E007E7E, 0xB400B4B4, 0x28002828, 0x55005555, 0x68006868, 0x50005050, 0xBE00BEBE, 0xD000D0D0, 0xC400C4C4, 0x31003131, 0xCB00CBCB, 0x2A002A2A, 0xAD00ADAD, 0x0F000F0F, 0xCA00CACA, 0x70007070, 0xFF00FFFF, 0x32003232, 0x69006969, 0x08000808, 0x62006262, 0x00000000, 0x24002424, 0xD100D1D1, 0xFB00FBFB, 0xBA00BABA, 0xED00EDED, 0x45004545, 0x81008181, 0x73007373, 0x6D006D6D, 0x84008484, 0x9F009F9F, 0xEE00EEEE, 0x4A004A4A, 0xC300C3C3, 0x2E002E2E, 0xC100C1C1, 0x01000101, 0xE600E6E6, 0x25002525, 0x48004848, 0x99009999, 0xB900B9B9, 0xB300B3B3, 0x7B007B7B, 0xF900F9F9, 0xCE00CECE, 0xBF00BFBF, 0xDF00DFDF, 0x71007171, 0x29002929, 0xCD00CDCD, 0x6C006C6C, 0x13001313, 0x64006464, 0x9B009B9B, 0x63006363, 0x9D009D9D, 0xC000C0C0, 0x4B004B4B, 0xB700B7B7, 0xA500A5A5, 0x89008989, 0x5F005F5F, 0xB100B1B1, 0x17001717, 0xF400F4F4, 0xBC00BCBC, 0xD300D3D3, 0x46004646, 0xCF00CFCF, 0x37003737, 0x5E005E5E, 0x47004747, 0x94009494, 0xFA00FAFA, 0xFC00FCFC, 0x5B005B5B, 0x97009797, 0xFE00FEFE, 0x5A005A5A, 0xAC00ACAC, 0x3C003C3C, 0x4C004C4C, 0x03000303, 0x35003535, 0xF300F3F3, 0x23002323, 0xB800B8B8, 0x5D005D5D, 0x6A006A6A, 0x92009292, 0xD500D5D5, 0x21002121, 0x44004444, 0x51005151, 0xC600C6C6, 0x7D007D7D, 0x39003939, 0x83008383, 0xDC00DCDC, 0xAA00AAAA, 0x7C007C7C, 0x77007777, 0x56005656, 0x05000505, 0x1B001B1B, 0xA400A4A4, 0x15001515, 0x34003434, 0x1E001E1E, 0x1C001C1C, 0xF800F8F8, 0x52005252, 0x20002020, 0x14001414, 0xE900E9E9, 0xBD00BDBD, 0xDD00DDDD, 0xE400E4E4, 0xA100A1A1, 0xE000E0E0, 0x8A008A8A, 0xF100F1F1, 0xD600D6D6, 0x7A007A7A, 0xBB00BBBB, 0xE300E3E3, 0x40004040, 0x4F004F4F]);
const SIGMA = new Uint32Array([0xA09E667F, 0x3BCC908B, 0xB67AE858, 0x4CAA73B2, 0xC6EF372F, 0xE94F82BE, 0x54FF53A5, 0xF1D36F1C, 0x10E527FA, 0xDE682D1D, 0xB05688C2, 0xB3E6C1FD]);
// * Functions
function ROTL128(s, bit) {
const n = 32 - bit;
const t = s[3] << bit | s[0] >>> n;
s[0] = s[0] << bit | s[1] >>> n;
s[1] = s[1] << bit | s[2] >>> n;
s[2] = s[2] << bit | s[3] >>> n;
s[3] = t;
}
function Camellia_Feistel(sh, sl, kh, kl) {
const t0 = sh[0] ^ kh;
const t1 = sh[1] ^ kl;
const t3 = SBox1_1110[0xFF & (t0 >> 24)]
^ SBox2_0222[0xFF & (t0 >> 16)]
^ SBox3_3033[0xFF & (t0 >> 8)]
^ SBox4_4404[0xFF & (t0)];
const t2 = t3
^ SBox1_1110[0xFF & (t1)]
^ SBox4_4404[0xFF & (t1 >> 8)]
^ SBox3_3033[0xFF & (t1 >> 16)]
^ SBox2_0222[0xFF & (t1 >> 24)];
sl[0] ^= t2;
sl[1] ^= t2 ^ rotateR32(t3, 8);
}
// * Camellia Algorithm
function KeySchedule(K) {
const KView = new DataView(K.buffer);
const k = K.length === 16 ? new Uint32Array(52) : new Uint32Array(68);
const s = new Uint32Array(4);
const sh = s.subarray(0, 2);
const sl = s.subarray(2, 4);
/* Map the key to the keyTable */
switch (K.length) {
case 16:
mapKey128(KView, s, k);
break;
case 24:
mapKey192(KView, s, k);
break;
case 32:
mapKey256(KView, s, k);
break;
}
/* Use the Feistel routine to scramble the key material */
Camellia_Feistel(sh, sl, SIGMA[0], SIGMA[1]);
Camellia_Feistel(sl, sh, SIGMA[2], SIGMA[3]);
s[0] ^= k[0];
s[1] ^= k[1];
s[2] ^= k[2];
s[3] ^= k[3];
Camellia_Feistel(sh, sl, SIGMA[4], SIGMA[5]);
Camellia_Feistel(sl, sh, SIGMA[6], SIGMA[7]);
/* Fill the keyTable. Requires many block rotations. */
switch (K.length) {
case 16:
setup128(s, k);
break;
case 24:
case 32:
setup256(s, k);
break;
}
return k;
}
function mapKey128(KView, s, k) {
s[0] = k[0] = KView.getUint32(0, false);
s[1] = k[1] = KView.getUint32(4, false);
s[2] = k[2] = KView.getUint32(8, false);
s[3] = k[3] = KView.getUint32(12, false);
}
function mapKey192(KView, s, k) {
mapKey128(KView, s, k);
s[0] = k[8] = KView.getUint32(16, false);
s[1] = k[9] = KView.getUint32(20, false);
s[2] = k[10] = ~s[0];
s[3] = k[11] = ~s[1];
s[0] ^= k[0];
s[1] ^= k[1];
s[2] ^= k[2];
s[3] ^= k[3];
}
function mapKey256(KView, s, k) {
mapKey192(KView, s, k);
s[0] = k[8] = KView.getUint32(16, false);
s[1] = k[9] = KView.getUint32(20, false);
s[2] = k[10] = KView.getUint32(24, false);
s[3] = k[11] = KView.getUint32(28, false);
s[0] ^= k[0];
s[1] ^= k[1];
s[2] ^= k[2];
s[3] ^= k[3];
}
function setup128(s, k) {
k[4] = s[0];
k[5] = s[1];
k[6] = s[2];
k[7] = s[3];
ROTL128(s, 15); /* KA <<< 15 */
k[12] = s[0];
k[13] = s[1];
k[14] = s[2];
k[15] = s[3];
ROTL128(s, 15); /* KA <<< 30 */
k[16] = s[0];
k[17] = s[1];
k[18] = s[2];
k[19] = s[3];
ROTL128(s, 15); /* KA <<< 45 */
k[24] = s[0];
k[25] = s[1];
ROTL128(s, 15); /* KA <<< 60 */
k[28] = s[0];
k[29] = s[1];
k[30] = s[2];
k[31] = s[3];
[s[0], s[1], s[2], s[3]] = [s[1], s[2], s[3], s[0]];
ROTL128(s, 2); /* KA <<< 94 */
k[40] = s[0];
k[41] = s[1];
k[42] = s[2];
k[43] = s[3];
ROTL128(s, 17); /* KA <<<111 */
k[48] = s[0];
k[49] = s[1];
k[50] = s[2];
k[51] = s[3];
s[0] = k[0];
s[1] = k[1];
s[2] = k[2];
s[3] = k[3];
ROTL128(s, 15); /* KL <<< 15 */
k[8] = s[0];
k[9] = s[1];
k[10] = s[2];
k[11] = s[3];
ROTL128(s, 30); /* KL <<< 45 */
k[20] = s[0];
k[21] = s[1];
k[22] = s[2];
k[23] = s[3];
ROTL128(s, 15); /* KL <<< 60 */
k[26] = s[2];
k[27] = s[3];
ROTL128(s, 17); /* KL <<< 77 */
k[32] = s[0];
k[33] = s[1];
k[34] = s[2];
k[35] = s[3];
ROTL128(s, 17); /* KL <<< 94 */
k[36] = s[0];
k[37] = s[1];
k[38] = s[2];
k[39] = s[3];
ROTL128(s, 17); /* KL <<<111 */
k[44] = s[0];
k[45] = s[1];
k[46] = s[2];
k[47] = s[3];
}
function setup256(s, k) {
const sh = s.subarray(0, 2);
const sl = s.subarray(2, 4);
k[12] = s[0];
k[13] = s[1];
k[14] = s[2];
k[15] = s[3];
s[0] ^= k[8];
s[1] ^= k[9];
s[2] ^= k[10];
s[3] ^= k[11];
Camellia_Feistel(sh, sl, SIGMA[8], SIGMA[9]);
Camellia_Feistel(sl, sh, SIGMA[10], SIGMA[11]);
k[4] = s[0];
k[5] = s[1];
k[6] = s[2];
k[7] = s[3];
ROTL128(s, 30); /* KB <<< 30 */
k[20] = s[0];
k[21] = s[1];
k[22] = s[2];
k[23] = s[3];
ROTL128(s, 30); /* KB <<< 60 */
k[40] = s[0];
k[41] = s[1];
k[42] = s[2];
k[43] = s[3];
[s[0], s[1], s[2], s[3]] = [s[1], s[2], s[3], s[0]];
ROTL128(s, 19); /* KB <<<111 */
k[64] = s[0];
k[65] = s[1];
k[66] = s[2];
k[67] = s[3];
s[0] = k[8];
s[1] = k[9];
s[2] = k[10];
s[3] = k[11];
ROTL128(s, 15); /* KR <<< 15 */
k[8] = s[0];
k[9] = s[1];
k[10] = s[2];
k[11] = s[3];
ROTL128(s, 15); /* KR <<< 30 */
k[16] = s[0];
k[17] = s[1];
k[18] = s[2];
k[19] = s[3];
ROTL128(s, 30); /* KR <<< 60 */
k[36] = s[0];
k[37] = s[1];
k[38] = s[2];
k[39] = s[3];
[s[0], s[1], s[2], s[3]] = [s[1], s[2], s[3], s[0]];
ROTL128(s, 2); /* KR <<< 94 */
k[52] = s[0];
k[53] = s[1];
k[54] = s[2];
k[55] = s[3];
s[0] = k[12];
s[1] = k[13];
s[2] = k[14];
s[3] = k[15];
ROTL128(s, 15); /* KA <<< 15 */
k[12] = s[0];
k[13] = s[1];
k[14] = s[2];
k[15] = s[3];
ROTL128(s, 30); /* KA <<< 45 */
k[28] = s[0];
k[29] = s[1];
k[30] = s[2];
k[31] = s[3];
/* KA <<< 77 */
k[48] = s[1];
k[49] = s[2];
k[50] = s[3];
k[51] = s[0];
[s[0], s[1], s[2], s[3]] = [s[1], s[2], s[3], s[0]];
ROTL128(s, 17); /* KA <<< 94 */
k[56] = s[0];
k[57] = s[1];
k[58] = s[2];
k[59] = s[3];
s[0] = k[0];
s[1] = k[1];
s[2] = k[2];
s[3] = k[3];
[s[0], s[1], s[2], s[3]] = [s[1], s[2], s[3], s[0]];
ROTL128(s, 13); /* KL <<< 45 */
k[24] = s[0];
k[25] = s[1];
k[26] = s[2];
k[27] = s[3];
ROTL128(s, 15); /* KL <<< 60 */
k[32] = s[0];
k[33] = s[1];
k[34] = s[2];
k[35] = s[3];
ROTL128(s, 17); /* KL <<< 77 */
k[44] = s[0];
k[45] = s[1];
k[46] = s[2];
k[47] = s[3];
[s[0], s[1], s[2], s[3]] = [s[1], s[2], s[3], s[0]];
ROTL128(s, 2); /* KL <<<111 */
k[60] = s[0];
k[61] = s[1];
k[62] = s[2];
k[63] = s[3];
}
function _encrypt128(M, k) {
const C = M.slice(0);
const CView = new DataView(C.buffer);
const s = new Uint32Array(4);
const sh = s.subarray(0, 2);
const sl = s.subarray(2, 4);
s[0] = k[0] ^ CView.getUint32(0, false);
s[1] = k[1] ^ CView.getUint32(4, false);
s[2] = k[2] ^ CView.getUint32(8, false);
s[3] = k[3] ^ CView.getUint32(12, false);
// GR 1
Camellia_Feistel(sh, sl, k[4], k[5]);
Camellia_Feistel(sl, sh, k[6], k[7]);
Camellia_Feistel(sh, sl, k[8], k[9]);
Camellia_Feistel(sl, sh, k[10], k[11]);
Camellia_Feistel(sh, sl, k[12], k[13]);
Camellia_Feistel(sl, sh, k[14], k[15]);
s[1] ^= rotateL32(s[0] & k[16], 1);
s[2] ^= s[3] | k[19];
s[0] ^= s[1] | k[17];
s[3] ^= rotateL32(s[2] & k[18], 1);
// GR 2
Camellia_Feistel(sh, sl, k[20], k[21]);
Camellia_Feistel(sl, sh, k[22], k[23]);
Camellia_Feistel(sh, sl, k[24], k[25]);
Camellia_Feistel(sl, sh, k[26], k[27]);
Camellia_Feistel(sh, sl, k[28], k[29]);
Camellia_Feistel(sl, sh, k[30], k[31]);
s[1] ^= rotateL32(s[0] & k[32], 1);
s[2] ^= s[3] | k[35];
s[0] ^= s[1] | k[33];
s[3] ^= rotateL32(s[2] & k[34], 1);
// GR 3
Camellia_Feistel(sh, sl, k[36], k[37]);
Camellia_Feistel(sl, sh, k[38], k[39]);
Camellia_Feistel(sh, sl, k[40], k[41]);
Camellia_Feistel(sl, sh, k[42], k[43]);
Camellia_Feistel(sh, sl, k[44], k[45]);
Camellia_Feistel(sl, sh, k[46], k[47]);
s[2] ^= k[48];
s[3] ^= k[49];
s[0] ^= k[50];
s[1] ^= k[51];
CView.setUint32(0, s[2], false);
CView.setUint32(4, s[3], false);
CView.setUint32(8, s[0], false);
CView.setUint32(12, s[1], false);
return C;
}
function _encrypt256(M, k) {
const C = M.slice(0);
const CView = new DataView(C.buffer);
const s = new Uint32Array(4);
const sh = s.subarray(0, 2);
const sl = s.subarray(2, 4);
s[0] = k[0] ^ CView.getUint32(0, false);
s[1] = k[1] ^ CView.getUint32(4, false);
s[2] = k[2] ^ CView.getUint32(8, false);
s[3] = k[3] ^ CView.getUint32(12, false);
// GR 1
Camellia_Feistel(sh, sl, k[4], k[5]);
Camellia_Feistel(sl, sh, k[6], k[7]);
Camellia_Feistel(sh, sl, k[8], k[9]);
Camellia_Feistel(sl, sh, k[10], k[11]);
Camellia_Feistel(sh, sl, k[12], k[13]);
Camellia_Feistel(sl, sh, k[14], k[15]);
s[1] ^= rotateL32(s[0] & k[16], 1);
s[2] ^= s[3] | k[19];
s[0] ^= s[1] | k[17];
s[3] ^= rotateL32(s[2] & k[18], 1);
// GR 2
Camellia_Feistel(sh, sl, k[20], k[21]);
Camellia_Feistel(sl, sh, k[22], k[23]);
Camellia_Feistel(sh, sl, k[24], k[25]);
Camellia_Feistel(sl, sh, k[26], k[27]);
Camellia_Feistel(sh, sl, k[28], k[29]);
Camellia_Feistel(sl, sh, k[30], k[31]);
s[1] ^= rotateL32(s[0] & k[32], 1);
s[2] ^= s[3] | k[35];
s[0] ^= s[1] | k[33];
s[3] ^= rotateL32(s[2] & k[34], 1);
// GR 3
Camellia_Feistel(sh, sl, k[36], k[37]);
Camellia_Feistel(sl, sh, k[38], k[39]);
Camellia_Feistel(sh, sl, k[40], k[41]);
Camellia_Feistel(sl, sh, k[42], k[43]);
Camellia_Feistel(sh, sl, k[44], k[45]);
Camellia_Feistel(sl, sh, k[46], k[47]);
s[1] ^= rotateL32(s[0] & k[48], 1);
s[2] ^= s[3] | k[51];
s[0] ^= s[1] | k[49];
s[3] ^= rotateL32(s[2] & k[50], 1);
// GR 4
Camellia_Feistel(sh, sl, k[52], k[53]);
Camellia_Feistel(sl, sh, k[54], k[55]);
Camellia_Feistel(sh, sl, k[56], k[57]);
Camellia_Feistel(sl, sh, k[58], k[59]);
Camellia_Feistel(sh, sl, k[60], k[61]);
Camellia_Feistel(sl, sh, k[62], k[63]);
s[2] ^= k[64];
s[3] ^= k[65];
s[0] ^= k[66];
s[1] ^= k[67];
CView.setUint32(0, s[2], false);
CView.setUint32(4, s[3], false);
CView.setUint32(8, s[0], false);
CView.setUint32(12, s[1], false);
return C;
}
function _decrypt128(C, k) {
const M = C.slice(0);
const MView = new DataView(M.buffer);
const s = new Uint32Array(4);
const sh = s.subarray(0, 2);
const sl = s.subarray(2, 4);
s[0] = k[48] ^ MView.getUint32(0, false);
s[1] = k[49] ^ MView.getUint32(4, false);
s[2] = k[50] ^ MView.getUint32(8, false);
s[3] = k[51] ^ MView.getUint32(12, false);
// GR1
Camellia_Feistel(sh, sl, k[46], k[47]);
Camellia_Feistel(sl, sh, k[44], k[45]);
Camellia_Feistel(sh, sl, k[42], k[43]);
Camellia_Feistel(sl, sh, k[40], k[41]);
Camellia_Feistel(sh, sl, k[38], k[39]);
Camellia_Feistel(sl, sh, k[36], k[37]);
s[1] ^= rotateL32(s[0] & k[34], 1);
s[2] ^= s[3] | k[33];
s[0] ^= s[1] | k[35];
s[3] ^= rotateL32(s[2] & k[32], 1);
// GR2
Camellia_Feistel(sh, sl, k[30], k[31]);
Camellia_Feistel(sl, sh, k[28], k[29]);
Camellia_Feistel(sh, sl, k[26], k[27]);
Camellia_Feistel(sl, sh, k[24], k[25]);
Camellia_Feistel(sh, sl, k[22], k[23]);
Camellia_Feistel(sl, sh, k[20], k[21]);
s[1] ^= rotateL32(s[0] & k[18], 1);
s[2] ^= s[3] | k[17];
s[0] ^= s[1] | k[19];
s[3] ^= rotateL32(s[2] & k[16], 1);
// GR3
Camellia_Feistel(sh, sl, k[14], k[15]);
Camellia_Feistel(sl, sh, k[12], k[13]);
Camellia_Feistel(sh, sl, k[10], k[11]);
Camellia_Feistel(sl, sh, k[8], k[9]);
Camellia_Feistel(sh, sl, k[6], k[7]);
Camellia_Feistel(sl, sh, k[4], k[5]);
s[2] ^= k[0];
s[3] ^= k[1];
s[0] ^= k[2];
s[1] ^= k[3];
MView.setUint32(0, s[2], false);
MView.setUint32(4, s[3], false);
MView.setUint32(8, s[0], false);
MView.setUint32(12, s[1], false);
return M;
}
function _decrypt256(C, k) {
const M = C.slice(0);
const MView = new DataView(M.buffer);
const s = new Uint32Array(4);
const sh = s.subarray(0, 2);
const sl = s.subarray(2, 4);
s[0] = k[64] ^ MView.getUint32(0, false);
s[1] = k[65] ^ MView.getUint32(4, false);
s[2] = k[66] ^ MView.getUint32(8, false);
s[3] = k[67] ^ MView.getUint32(12, false);
// GR1
Camellia_Feistel(sh, sl, k[62], k[63]);
Camellia_Feistel(sl, sh, k[60], k[61]);
Camellia_Feistel(sh, sl, k[58], k[59]);
Camellia_Feistel(sl, sh, k[56], k[57]);
Camellia_Feistel(sh, sl, k[54], k[55]);
Camellia_Feistel(sl, sh, k[52], k[53]);
s[1] ^= rotateL32(s[0] & k[50], 1);
s[2] ^= s[3] | k[49];
s[0] ^= s[1] | k[51];
s[3] ^= rotateL32(s[2] & k[48], 1);
// GR2
Camellia_Feistel(sh, sl, k[46], k[47]);
Camellia_Feistel(sl, sh, k[44], k[45]);
Camellia_Feistel(sh, sl, k[42], k[43]);
Camellia_Feistel(sl, sh, k[40], k[41]);
Camellia_Feistel(sh, sl, k[38], k[39]);
Camellia_Feistel(sl, sh, k[36], k[37]);
s[1] ^= rotateL32(s[0] & k[34], 1);
s[2] ^= s[3] | k[33];
s[0] ^= s[1] | k[35];
s[3] ^= rotateL32(s[2] & k[32], 1);
// GR3
Camellia_Feistel(sh, sl, k[30], k[31]);
Camellia_Feistel(sl, sh, k[28], k[29]);
Camellia_Feistel(sh, sl, k[26], k[27]);
Camellia_Feistel(sl, sh, k[24], k[25]);
Camellia_Feistel(sh, sl, k[22], k[23]);
Camellia_Feistel(sl, sh, k[20], k[21]);
s[1] ^= rotateL32(s[0] & k[18], 1);
s[2] ^= s[3] | k[17];
s[0] ^= s[1] | k[19];
s[3] ^= rotateL32(s[2] & k[16], 1);
// GR4
Camellia_Feistel(sh, sl, k[14], k[15]);
Camellia_Feistel(sl, sh, k[12], k[13]);
Camellia_Feistel(sh, sl, k[10], k[11]);
Camellia_Feistel(sl, sh, k[8], k[9]);
Camellia_Feistel(sh, sl, k[6], k[7]);
Camellia_Feistel(sl, sh, k[4], k[5]);
s[2] ^= k[0];
s[3] ^= k[1];
s[0] ^= k[2];
s[1] ^= k[3];
MView.setUint32(0, s[2], false);
MView.setUint32(4, s[3], false);
MView.setUint32(8, s[0], false);
MView.setUint32(12, s[1], false);
return M;
}
function cipher(M, k, _cipher) {
if (M.length !== 16) {
throw new KitError('Camellia block must be 16 byte');
}
return new U8(_cipher(M, k));
}
function _camellia(key, b) {
if (key.length !== b >>> 3) {
throw new KitError(`Camellia-${b} key must be ${b >>> 3} byte`);
}
const K = KeySchedule(key);
const encrypt = b === 128
? (M) => cipher(M, K, _encrypt128)
: (M) => cipher(M, K, _encrypt256);
const decrypt = b === 128
? (C) => cipher(C, K, _decrypt128)
: (C) => cipher(C, K, _decrypt256);
return { encrypt, decrypt };
}
/**
* Camellia 分组密码算法 / block cipher algorithm
*
* @param {128 | 192 | 256} b - 密钥长度 / Key size (bit)
*/
export function camellia(b) {
return createCipher((K) => _camellia(K, b), {
ALGORITHM: `Camellia-${b}`,
BLOCK_SIZE: 16,
KEY_SIZE: b >>> 3,
MIN_KEY_SIZE: b >>> 3,
MAX_KEY_SIZE: b >>> 3,
});
}
import { KitError, U8 } from '../../core/utils';
import { createCipher } from '../../core/cipher';
// * Constants
const IP = [58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7].map(value => 64 - value);
const FP = [40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25].map(value => 64 - value);
const E = [32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1].map(value => 32 - value);
const PC1 = [57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4].map(value => 64 - value);
const PC2 = [14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32].map(value => 56 - value);
const P = [16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25].map(value => 32 - value);
const KEY_SHIFT = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1];
const S1 = [14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13];
const S2 = [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9];
const S3 = [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12];
const S4 = [7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14];
const S5 = [2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3];
const S6 = [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13];
const S7 = [4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12];
const S8 = [13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11];
// * Functions
function permute(input, table) {
let output = 0n;
for (let i = 0; i < table.length; i++) {
output = output << 1n;
output |= ((input >> BigInt(table[i])) & 0x1n);
}
return output;
}
function substitute(input) {
const s = [S1, S2, S3, S4, S5, S6, S7, S8];
let output = 0n;
for (let i = 0; i < 8; i++) {
const word = Number((input >> BigInt(6 * (7 - i))) & 0x3fn);
const x = (word >> 1) & 0xF;
const y = (word >> 4) & 0b10 | (word & 0b1);
const offset = x + (y << 4);
output = (output << 4n) | BigInt(s[i][offset]);
}
return output;
}
function generateKeys(key) {
const k = permute(key.reduce((acc, cur) => (acc << 8n) | BigInt(cur), 0n), PC1);
const key_set = new Uint8Array(16 * 6);
let l = 0xfffffffn & (k >> 28n);
let r = 0xfffffffn & (k);
for (let i = 0; i < 16; i++) {
l = ((l << BigInt(KEY_SHIFT[i])) | (l >> 28n - BigInt(KEY_SHIFT[i]))) & 0xfffffffn;
r = ((r << BigInt(KEY_SHIFT[i])) | (r >> 28n - BigInt(KEY_SHIFT[i]))) & 0xfffffffn;
const kr = permute((l << 28n) | r, PC2);
const offset = i * 6;
key_set[offset + 0] = Number(0xffn & (kr >> 40n));
key_set[offset + 1] = Number(0xffn & (kr >> 32n));
key_set[offset + 2] = Number(0xffn & (kr >> 24n));
key_set[offset + 3] = Number(0xffn & (kr >> 16n));
key_set[offset + 4] = Number(0xffn & (kr >> 8n));
key_set[offset + 5] = Number(0xffn & (kr));
}
return key_set;
}
function reverseKeys(keys) {
const key_set = new Uint8Array(keys.byteLength);
for (let i = 0; i < 16; i++) {
const offset = keys.byteLength - i * 6;
key_set.set(keys.subarray(offset - 6, offset), i * 6);
}
return key_set;
}
function isEqual(a, b) {
if (a.byteLength !== b.byteLength) {
return false;
}
for (let i = 0; i < a.byteLength; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
// * DES
function Cipher(M, K) {
const m = permute(M.reduce((acc, cur) => acc << 8n | BigInt(cur), 0n), IP);
let l = 0xffffffffn & (m >> 32n);
let r = 0xffffffffn & (m);
for (let i = 0; i < 16; i++) {
const offset = i * 6;
const k = K.subarray(offset, offset + 6).reduce((acc, cur) => (acc << 8n) | BigInt(cur), 0n);
const l_next = r;
r = permute(r, E) ^ k;
r = substitute(r);
r = permute(r, P) ^ l;
l = l_next;
}
return permute((r << 32n) | l, FP);
}
function _des(K) {
const key_set = generateKeys(K);
const inv_key_set = reverseKeys(key_set);
return {
encrypt: (M) => {
const C = new U8(8);
const view = new DataView(C.buffer);
view.setBigUint64(0, Cipher(M, key_set), false);
return C;
},
decrypt: (C) => {
const M = new U8(8);
const view = new DataView(M.buffer);
view.setBigUint64(0, Cipher(C, inv_key_set), false);
return M;
},
};
}
function _t_des(K, l) {
if (K.byteLength !== l >> 3) {
throw new KitError(`3DES key must be ${l >> 3} byte`);
}
const K1 = K.subarray(0, 8);
const K2 = K.subarray(8, 16);
const K3 = l === 128 ? K1 : K.subarray(16, 24);
if (isEqual(K1, K2) || (l === 192 && (isEqual(K1, K3) || isEqual(K2, K3)))) {
console.warn('mima-kit: Weak key detected in 3DES');
}
const d1 = _des(K1);
const d2 = _des(K2);
const d3 = _des(K3);
return {
encrypt: (M) => d3.encrypt(d2.decrypt(d1.encrypt(M))),
decrypt: (C) => d1.decrypt(d2.encrypt(d3.decrypt(C))),
};
}
/**
* Data Encryption Standard (DES) block cipher algorithm
*
* 数据加密标准(DES)分组密码算法
*/
export const des = createCipher(_des, {
ALGORITHM: 'DES',
BLOCK_SIZE: 8,
KEY_SIZE: 8,
MIN_KEY_SIZE: 8,
MAX_KEY_SIZE: 8,
});
/**
* Triple Data Encryption Standard (3DES) block cipher algorithm
*
* 三重数据加密标准(3DES)分组密码算法
*
* @param {128 | 192} l - 密钥长度 / Key Size (bit)
*/
export function t_des(l) {
return createCipher((K) => _t_des(K, l), {
ALGORITHM: '3DES',
BLOCK_SIZE: 8,
KEY_SIZE: l >> 3,
MIN_KEY_SIZE: l >> 3,
MAX_KEY_SIZE: l >> 3,
});
}
import { KitError, U8, rotateL32 } from '../../core/utils';
import { createCipher } from '../../core/cipher';
// * Constants
const SBox = new Uint8Array([0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05, 0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, 0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62, 0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6, 0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8, 0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35, 0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0x78, 0x87, 0xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52, 0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E, 0xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5, 0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1, 0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55, 0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3, 0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60, 0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F, 0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F, 0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 0x51, 0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F, 0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8, 0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD, 0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0, 0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96, 0x77, 0x7E, 0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84, 0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20, 0x79, 0xEE, 0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48]);
const CK = new Uint32Array([0x00070E15, 0x1C232A31, 0x383F464D, 0x545B6269, 0x70777E85, 0x8C939AA1, 0xA8AFB6BD, 0xC4CBD2D9, 0xE0E7EEF5, 0xFC030A11, 0x181F262D, 0x343B4249, 0x50575E65, 0x6C737A81, 0x888F969D, 0xA4ABB2B9, 0xC0C7CED5, 0xDCE3EAF1, 0xF8FF060D, 0x141B2229, 0x30373E45, 0x4C535A61, 0x686F767D, 0x848B9299, 0xA0A7AEB5, 0xBCC3CAD1, 0xD8DFE6ED, 0xF4FB0209, 0x10171E25, 0x2C333A41, 0x484F565D, 0x646B7279]);
// * Functions
/**
* 非线性变换函数 `τ`.
*
* Nonlinear transformation function `τ`.
*
* @param {number} A - 工作字 / word
*/
function tau(A) {
return SBox[A >> 24 & 0xFF] << 24 | SBox[A >> 16 & 0xFF] << 16 | SBox[A >> 8 & 0xFF] << 8 | SBox[A & 0xFF];
}
/**
* 合成置换函数 `T`, 由非线性变换函数 `τ` 和线性变换函数 `L` 组成.
*
* Synthetic permutation function `T`, composed of function `τ` and function `L`.
*
* @param {number} A - 工作字 / word
*/
function T(A) {
const B = tau(A);
return B ^ rotateL32(B, 2) ^ rotateL32(B, 10) ^ rotateL32(B, 18) ^ rotateL32(B, 24);
}
/**
* 合成置换函数 `T1`, 由非线性变换函数 `τ` 和线性变换函数 `L1` 组成.
*
* Synthetic permutation function `T1`, composed of function `τ` and function `L1`.
*
* @param {number} A - 工作字 / word
*/
function T1(A) {
const B = tau(A);
return B ^ rotateL32(B, 13) ^ rotateL32(B, 23);
}
/**
* 密钥扩展函数 / Key expansion function
*/
function expandKey(key) {
if (key.length !== 16) {
throw new KitError('SM4 key must be 16 byte');
}
const KView = new DataView(key.buffer);
let K0 = 0xA3B1BAC6 ^ KView.getUint32(0, false);
let K1 = 0x56AA3350 ^ KView.getUint32(4, false);
let K2 = 0x677D9197 ^ KView.getUint32(8, false);
let K3 = 0xB27022DC ^ KView.getUint32(12, false);
const rk = new Uint32Array(32);
for (let i = 0; i < 32; i++) {
rk[i] = K0 ^ T1(K1 ^ K2 ^ K3 ^ CK[i]);
K0 = K1;
K1 = K2;
K2 = K3;
K3 = rk[i];
}
return rk;
}
/**
* 轮函数 `F` / Round function `F`
*
* @param {number} X0 - 工作字 / word
* @param {number} X1 - 工作字 / word
* @param {number} X2 - 工作字 / word
* @param {number} X3 - 工作字 / word
* @param {number} rk - 轮密钥 / round key
*/
function F(X0, X1, X2, X3, rk) {
return X0 ^ T(X1 ^ X2 ^ X3 ^ rk);
}
// * SM4 Algorithm
/**
* @param {Uint8Array} M - 输入块 / input block
* @param {Uint32Array} rk - 轮密钥 / round keys
*/
function cipher(M, rk) {
if (M.length !== 16) {
throw new KitError('SM4 block must be 16 byte');
}
const MView = new DataView(M.buffer, M.byteOffset);
let X0 = MView.getUint32(0, false);
let X1 = MView.getUint32(4, false);
let X2 = MView.getUint32(8, false);
let X3 = MView.getUint32(12, false);
let X_;
for (let i = 0; i < 32; i++) {
X_ = F(X0, X1, X2, X3, rk[i]);
X0 = X1;
X1 = X2;
X2 = X3;
X3 = X_;
}
const R = new U8(16);
const RView = new DataView(R.buffer);
RView.setUint32(0, X3, false);
RView.setUint32(4, X2, false);
RView.setUint32(8, X1, false);
RView.setUint32(12, X0, false);
return R;
}
function _sm4(K) {
const rk = expandKey(K);
const rkReversed = rk.toReversed();
return {
encrypt: (M) => cipher(M, rk),
decrypt: (M) => cipher(M, rkReversed),
};
}
/**
* SM4 分组密码算法 / block cipher algorithm
*/
export const sm4 = createCipher(_sm4, {
ALGORITHM: 'SM4',
BLOCK_SIZE: 16,
KEY_SIZE: 16,
MIN_KEY_SIZE: 16,
MAX_KEY_SIZE: 16,
});
import { PKCS7_PAD, createCipher } from '../../core/cipher';
import { KitError, U8 } from '../../core/utils';
// * Constants
const DELTA = 0x9E3779B9;
// * Tiny Encryption Algorithm (TEA)
function _tea(K, round) {
if (K.length !== 16) {
throw new KitError('TEA key must be 16 byte');
}
const K32 = new Uint32Array(K.buffer);
const sum_delta = (DELTA * round) & 0xFFFFFFFF;
const encrypt = (M) => {
if (M.length !== 8) {
throw new KitError('TEA block must be 8 byte');
}
const C = U8.from(M.slice(0));
const C32 = new Uint32Array(C.buffer);
let sum = 0;
for (let i = 0; i < round; i++) {
sum += DELTA;
C32[0] += ((C32[1] << 4) + K32[0]) ^ (C32[1] + sum) ^ ((C32[1] >>> 5) + K32[1]);
C32[1] += ((C32[0] << 4) + K32[2]) ^ (C32[0] + sum) ^ ((C32[0] >>> 5) + K32[3]);
}
return C;
};
const decrypt = (C) => {
if (C.length !== 8) {
throw new KitError('TEA block must be 8 byte');
}
const M = U8.from(C.slice(0));
const M32 = new Uint32Array(M.buffer);
let sum = sum_delta;
for (let i = 0; i < round; i++) {
M32[1] -= ((M32[0] << 4) + K32[2]) ^ (M32[0] + sum) ^ ((M32[0] >>> 5) + K32[3]);
M32[0] -= ((M32[1] << 4) + K32[0]) ^ (M32[1] + sum) ^ ((M32[1] >>> 5) + K32[1]);
sum -= DELTA;
}
return M;
};
return { encrypt, decrypt };
}
function _xtea(K, round) {
if (K.length !== 16) {
throw new KitError('XTEA key must be 16 byte');
}
const K32 = new Uint32Array(K.buffer);
const sum_delta = (DELTA * round) & 0xFFFFFFFF;
const encrypt = (M) => {
if (M.length !== 8) {
throw new KitError('XTEA block must be 8 byte');
}
const C = U8.from(M.slice(0));
const C32 = new Uint32Array(C.buffer);
let sum = 0;
for (let i = 0; i < round; i++) {
C32[0] += (C32[1] << 4 ^ C32[1] >>> 5) + C32[1] ^ sum + K32[sum & 3];
sum += DELTA;
C32[1] += (C32[0] << 4 ^ C32[0] >>> 5) + C32[0] ^ sum + K32[(sum >>> 11) & 3];
}
return C;
};
const decrypt = (C) => {
if (C.length !== 8) {
throw new KitError('XTEA block must be 8 byte');
}
const M = U8.from(C.slice(0));
const M32 = new Uint32Array(M.buffer);
let sum = sum_delta;
for (let i = 0; i < round; i++) {
M32[1] -= ((M32[0] << 4 ^ M32[0] >>> 5) + M32[0]) ^ (sum + K32[(sum >>> 11) & 3]);
sum -= DELTA;
M32[0] -= ((M32[1] << 4 ^ M32[1] >>> 5) + M32[1]) ^ (sum + K32[sum & 3]);
}
return M;
};
return { encrypt, decrypt };
}
function _xxtea(K, padding, round) {
if (K.length !== 16) {
throw new KitError('XTEA key must be 16 byte');
}
const K32 = new Uint32Array(K.buffer);
const encrypt = (M) => {
const C = U8.from(padding(M, 4));
if (C.length < 8 || C.length % 4 !== 0) {
throw new KitError('XXTEA block must be a multiple of 4 byte (at least 8 byte)');
}
const C32 = new Uint32Array(C.buffer);
const n = C32.length;
let _round = round || (6 + 52 / n) >>> 0;
let sum = 0;
let y;
let z = C32[n - 1];
let p;
while (_round-- > 0) {
sum += DELTA;
const e = (sum >>> 2) & 3;
for (p = 0; p < n - 1; p++) {
y = C32[p + 1];
z = C32[p] += (((z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4)) ^ ((sum ^ y) + (K32[(p & 3) ^ e] ^ z)));
}
y = C32[0];
z = C32[n - 1] += (((z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4)) ^ ((sum ^ y) + (K32[(p & 3) ^ e] ^ z)));
}
return C;
};
const decrypt = (C) => {
if (C.length % 4 !== 0) {
throw new KitError('Decryption error');
}
const M = U8.from(C.slice(0));
const M32 = new Uint32Array(M.buffer);
const n = M32.length;
let _round = round || (6 + 52 / n) >>> 0;
let sum = (DELTA * _round) & 0xFFFFFFFF;
let y = M32[0];
let z;
let p;
while (_round-- > 0) {
const e = (sum >>> 2) & 3;
for (p = n - 1; p > 0; p--) {
z = M32[p - 1];
y = M32[p] -= (((z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4)) ^ ((sum ^ y) + (K32[(p & 3) ^ e] ^ z)));
}
z = M32[n - 1];
y = M32[0] -= (((z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4)) ^ ((sum ^ y) + (K32[(p & 3) ^ e] ^ z)));
sum -= DELTA;
}
return padding(M);
};
return { encrypt, decrypt };
}
/**
* 微型加密算法 (TEA) 分组密码算法
*
* Tiny Encryption Algorithm (TEA) block cipher algorithm
*
* @param {number} round - 轮数 / Rounds (default: 32)
*/
export function tea(round = 32) {
if (round <= 0) {
throw new KitError('TEA round must be a positive number');
}
return createCipher((K) => _tea(K, round), {
ALGORITHM: 'TEA',
BLOCK_SIZE: 8,
KEY_SIZE: 16,
MIN_KEY_SIZE: 16,
MAX_KEY_SIZE: 16,
});
}
/**
* 扩展微型加密算法 (XTEA) 分组密码算法
*
* eXtended Tiny Encryption Algorithm (XTEA) block cipher algorithm
*
* @param {number} round - 轮数 / Rounds (default: 32)
*/
export function xtea(round = 32) {
if (round <= 0) {
throw new KitError('XTEA round must be a positive number');
}
return createCipher((K) => _xtea(K, round), {
ALGORITHM: 'XTEA',
BLOCK_SIZE: 8,
KEY_SIZE: 16,
MIN_KEY_SIZE: 16,
MAX_KEY_SIZE: 16,
});
}
/**
* 纠正块 TEA (XXTEA) 分组密码算法
*
* Corrected Block TEA (XXTEA) block cipher algorithm
*
* @param {Padding} [config.padding] - 填充方式 / Padding method (default: PKCS7)
* @param {number} [config.round] - 轮数 / Rounds (default: undefined)
* @param {number} [config.BLOCK_SIZE] - 分组大小 / Block size (default: 16)
*/
export function xxtea(config) {
const { BLOCK_SIZE = 16, padding = PKCS7_PAD, round, } = config ?? {};
if (BLOCK_SIZE < 8 || BLOCK_SIZE % 4 !== 0) {
throw new KitError('XXTEA block size must be a multiple of 4 byte (at least 8 byte)');
}
return createCipher((K) => _xxtea(K, padding, round), {
ALGORITHM: 'XXTEA',
BLOCK_SIZE,
KEY_SIZE: 16,
MIN_KEY_SIZE: 16,
MAX_KEY_SIZE: 16,
});
}
import { createCipher } from '../../core/cipher';
import { KitError, U8, rotateL32, rotateR32 } from '../../core/utils';
// * Constants
const P0 = new Uint8Array([0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0]);
const P1 = new Uint8Array([0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91]);
const P = [P0, P1];
const P_00 = 1;
const P_01 = 0;
const P_02 = 0;
const P_03 = P_01 ^ 1;
const P_04 = 1;
const P_10 = 0;
const P_11 = 0;
const P_12 = 1;
const P_13 = P_11 ^ 1;
const P_14 = 0;
const P_20 = 1;
const P_21 = 1;
const P_22 = 0;
const P_23 = P_21 ^ 1;
const P_24 = 0;
const P_30 = 0;
const P_31 = 1;
const P_32 = 1;
const P_33 = P_31 ^ 1;
const P_34 = 1;
const GF256_FDBK_2 = 0x169 >> 1;
const GF256_FDBK_4 = 0x169 >> 2;
const RS_GF_FDBK = 0x14D;
const MDS = [
new Uint32Array(256),
new Uint32Array(256),
new Uint32Array(256),
new Uint32Array(256),
];
// * Functions
const LFSR1 = (x) => (x >> 1) ^ ((x & 0x01) !== 0 ? GF256_FDBK_2 : 0);
const LFSR2 = (x) => (x >> 2) ^ ((x & 0x02) !== 0 ? GF256_FDBK_2 : 0) ^ ((x & 0x01) !== 0 ? GF256_FDBK_4 : 0);
const Mx_X = (x) => x ^ LFSR2(x);
const Mx_Y = (x) => x ^ LFSR1(x) ^ LFSR2(x);
(function initMDS() {
// precompute the MDS matrix
const m1 = new Uint32Array(2);
const mX = new Uint32Array(2);
const mY = new Uint32Array(2);
for (let i = 0; i < 256; i++) {
const j0 = P[0][i] & 0xFF;
m1[0] = j0;
mX[0] = Mx_X(j0) & 0xFF;
mY[0] = Mx_Y(j0) & 0xFF;
const j1 = P[1][i] & 0xFF;
m1[1] = j1;
mX[1] = Mx_X(j1) & 0xFF;
mY[1] = Mx_Y(j1) & 0xFF;
MDS[0][i]
= (m1[P_00] << 0)
| (mX[P_00] << 8)
| (mY[P_00] << 16)
| (mY[P_00] << 24);
MDS[1][i]
= (mY[P_10] << 0)
| (mY[P_10] << 8)
| (mX[P_10] << 16)
| (m1[P_10] << 24);
MDS[2][i]
= (mX[P_20] << 0)
| (mY[P_20] << 8)
| (m1[P_20] << 16)
| (mY[P_20] << 24);
MDS[3][i]
= (mX[P_30] << 0)
| (m1[P_30] << 8)
| (mY[P_30] << 16)
| (mX[P_30] << 24);
}
})();
const b0 = (x) => x & 0xFF;
const b1 = (x) => (x >>> 8) & 0xFF;
const b2 = (x) => (x >>> 16) & 0xFF;
const b3 = (x) => (x >>> 24) & 0xFF;
function chooseB(x, N) {
switch (N & 3) {
case 0: return b0(x);
case 1: return b1(x);
case 2: return b2(x);
case 3: return b3(x);
default: return 0;
}
}
function RS_REM(x) {
const b = (x >>> 24) & 0xFF;
const g2 = ((b << 1) ^ ((b & 0x80) !== 0 ? RS_GF_FDBK : 0)) & 0xFF;
const g3 = (b >>> 1) ^ ((b & 0x01) !== 0 ? (RS_GF_FDBK >>> 1) : 0) ^ g2;
return (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b;
}
function RS_MDS_Encode(k0, k1) {
for (let i = 0; i < 4; i++) {
k1 = RS_REM(k1);
}
k1 ^= k0;
for (let i = 0; i < 4; i++) {
k1 = RS_REM(k1);
}
return k1;
}
function F32(K64SigByte, x, k32) {
let lB0 = b0(x);
let lB1 = b1(x);
let lB2 = b2(x);
let lB3 = b3(x);
const k0 = k32[0] || 0;
const k1 = k32[1] || 0;
const k2 = k32[2] || 0;
const k3 = k32[3] || 0;
let result = 0;
let K64LSB = K64SigByte & 0x3;
if (K64LSB === 1) {
result
= MDS[0][P[P_01][lB0] & 0xFF ^ b0(k0)]
^ MDS[1][P[P_11][lB1] & 0xFF ^ b1(k0)]
^ MDS[2][P[P_21][lB2] & 0xFF ^ b2(k0)]
^ MDS[3][P[P_31][lB3] & 0xFF ^ b3(k0)];
return result;
}
if (K64LSB === 0) {
lB0 = P[P_04][lB0] & 0xFF ^ b0(k3);
lB1 = P[P_14][lB1] & 0xFF ^ b1(k3);
lB2 = P[P_24][lB2] & 0xFF ^ b2(k3);
lB3 = P[P_34][lB3] & 0xFF ^ b3(k3);
K64LSB = 3;
}
if (K64LSB === 3) {
lB0 = P[P_03][lB0] & 0xFF ^ b0(k2);
lB1 = P[P_13][lB1] & 0xFF ^ b1(k2);
lB2 = P[P_23][lB2] & 0xFF ^ b2(k2);
lB3 = P[P_33][lB3] & 0xFF ^ b3(k2);
K64LSB = 2;
}
if (K64LSB === 2) {
result
= MDS[0][P[P_01][P[P_02][lB0] & 0xFF ^ b0(k1)] & 0xFF ^ b0(k0)]
^ MDS[1][P[P_11][P[P_12][lB1] & 0xFF ^ b1(k1)] & 0xFF ^ b1(k0)]
^ MDS[2][P[P_21][P[P_22][lB2] & 0xFF ^ b2(k1)] & 0xFF ^ b2(k0)]
^ MDS[3][P[P_31][P[P_32][lB3] & 0xFF ^ b3(k1)] & 0xFF ^ b3(k0)];
return result;
}
return 0;
}
function Fe32(SBox, x, R) {
const result = SBox[0x000 + 2 * chooseB(x, R + 0) + 0]
^ SBox[0x000 + 2 * chooseB(x, R + 1) + 1]
^ SBox[0x200 + 2 * chooseB(x, R + 2) + 0]
^ SBox[0x200 + 2 * chooseB(x, R + 3) + 1];
return result;
}
// * Blowfish Algorithm
function initKeySchedule(K) {
const K32 = new Uint32Array(K.buffer, K.byteOffset);
const K32e = new Uint32Array([K32[0], K32[2], K32[4], K32[6]]);
const K32o = new Uint32Array([K32[1], K32[3], K32[5], K32[7]]);
const K64Count = K32.length >> 1;
// compute S-box keys using (12, 8) Reed-Solomon code over GF(256)
const SBoxKeys = new Uint32Array(4);
for (let i = 0; i < 4; i++) {
const j = K64Count - 1 - i;
SBoxKeys[j] = RS_MDS_Encode(K32e[i], K32o[i]);
}
// compute the round decryption subkeys for PHT. these same subkeys
// will be used in encryption but will be applied in reverse order.
let q = 0;
const Subkeys = new Uint32Array(40);
for (let i = 0; i < 20; i++) {
let A = F32(K64Count, q, K32e);
let B = F32(K64Count, q + 0x01010101, K32o);
B = rotateL32(B, 8);
A += B;
Subkeys[2 * i] = A;
A += B;
Subkeys[2 * i + 1] = rotateL32(A, 9);
q += 0x02020202;
}
// fully expand the table for speed
const k0 = SBoxKeys[0];
const k1 = SBoxKeys[1];
const k2 = SBoxKeys[2];
const k3 = SBoxKeys[3];
const SBox = new Uint32Array(4 * 256);
for (let i = 0; i < 256; i++) {
let lb0 = i;
let lb1 = i;
let lb2 = i;
let lb3 = i;
let K64CountLSB = K64Count & 3;
if (K64CountLSB === 1) {
SBox[0x000 + 2 * i + 0] = MDS[0][P[P_01][lb0] & 0xFF ^ b0(k0)];
SBox[0x000 + 2 * i + 1] = MDS[1][P[P_11][lb1] & 0xFF ^ b1(k0)];
SBox[0x200 + 2 * i + 0] = MDS[2][P[P_21][lb2] & 0xFF ^ b2(k0)];
SBox[0x200 + 2 * i + 1] = MDS[3][P[P_31][lb3] & 0xFF ^ b3(k0)];
continue;
}
if (K64CountLSB === 0) {
lb0 = P[P_04][lb0] & 0xFF ^ b0(k3);
lb1 = P[P_14][lb1] & 0xFF ^ b1(k3);
lb2 = P[P_24][lb2] & 0xFF ^ b2(k3);
lb3 = P[P_34][lb3] & 0xFF ^ b3(k3);
K64CountLSB = 3;
}
if (K64CountLSB === 3) {
lb0 = P[P_03][lb0] & 0xFF ^ b0(k2);
lb1 = P[P_13][lb1] & 0xFF ^ b1(k2);
lb2 = P[P_23][lb2] & 0xFF ^ b2(k2);
lb3 = P[P_33][lb3] & 0xFF ^ b3(k2);
K64CountLSB = 2;
}
if (K64CountLSB === 2) {
SBox[0x000 + 2 * i + 0]
= MDS[0][P[P_01][P[P_02][lb0] & 0xFF ^ b0(k1)] & 0xFF ^ b0(k0)];
SBox[0x000 + 2 * i + 1]
= MDS[1][P[P_11][P[P_12][lb1] & 0xFF ^ b1(k1)] & 0xFF ^ b1(k0)];
SBox[0x200 + 2 * i + 0]
= MDS[2][P[P_21][P[P_22][lb2] & 0xFF ^ b2(k1)] & 0xFF ^ b2(k0)];
SBox[0x200 + 2 * i + 1]
= MDS[3][P[P_31][P[P_32][lb3] & 0xFF ^ b3(k1)] & 0xFF ^ b3(k0)];
}
}
return { Subkeys, SBox };
}
function _twofish(K, b) {
if (K.byteLength !== b >> 3) {
throw new KitError(`Twofish key must be ${b >> 3} byte`);
}
const { Subkeys, SBox } = initKeySchedule(K);
const encrypt = (M) => {
if (M.byteLength !== 16) {
throw new KitError('Twofish block must be 16 byte');
}
const M32 = new Uint32Array(M.buffer, M.byteOffset);
// input whitening
let x0 = M32[0] ^ Subkeys[0];
let x1 = M32[1] ^ Subkeys[1];
let x2 = M32[2] ^ Subkeys[2];
let x3 = M32[3] ^ Subkeys[3];
let k = 8;
// 16 rounds of encryption
for (let i = 0; i < 16; i += 2) {
let t0 = Fe32(SBox, x0, 0);
let t1 = Fe32(SBox, x1, 3);
x2 ^= t0 + t1 + Subkeys[k++];
x2 = rotateR32(x2, 1);
x3 = rotateL32(x3, 1);
x3 ^= t0 + 2 * t1 + Subkeys[k++];
t0 = Fe32(SBox, x2, 0);
t1 = Fe32(SBox, x3, 3);
x0 ^= t0 + t1 + Subkeys[k++];
x0 = rotateR32(x0, 1);
x1 = rotateL32(x1, 1);
x1 ^= t0 + 2 * t1 + Subkeys[k++];
}
// output whitening
x2 ^= Subkeys[4];
x3 ^= Subkeys[5];
x0 ^= Subkeys[6];
x1 ^= Subkeys[7];
return new U8(new Uint32Array([x2, x3, x0, x1]).buffer);
};
const decrypt = (C) => {
if (C.byteLength !== 16) {
throw new KitError('Twofish block must be 16 byte');
}
const M32 = new Uint32Array(C.buffer, C.byteOffset);
// input whitening
let x2 = M32[0] ^ Subkeys[4];
let x3 = M32[1] ^ Subkeys[5];
let x0 = M32[2] ^ Subkeys[6];
let x1 = M32[3] ^ Subkeys[7];
let k = 39;
// 16 rounds of decryption
for (let i = 0; i < 16; i += 2) {
let t0 = Fe32(SBox, x2, 0);
let t1 = Fe32(SBox, x3, 3);
x1 ^= t0 + 2 * t1 + Subkeys[k--];
x1 = rotateR32(x1, 1);
x0 = rotateL32(x0, 1);
x0 ^= t0 + t1 + Subkeys[k--];
t0 = Fe32(SBox, x0, 0);
t1 = Fe32(SBox, x1, 3);
x3 ^= t0 + 2 * t1 + Subkeys[k--];
x3 = rotateR32(x3, 1);
x2 = rotateL32(x2, 1);
x2 ^= t0 + t1 + Subkeys[k--];
}
// output whitening
x0 ^= Subkeys[0];
x1 ^= Subkeys[1];
x2 ^= Subkeys[2];
x3 ^= Subkeys[3];
return new U8(new Uint32Array([x0, x1, x2, x3]).buffer);
};
return { encrypt, decrypt };
}
/**
* Twofish 分组密码算法 / block cipher algorithm
*
* @param {128 | 192 | 256} b - 密钥长度 / Key size (bit)
*/
export function twofish(b) {
return createCipher((K) => _twofish(K, b), {
ALGORITHM: 'Twofish',
BLOCK_SIZE: 16,
KEY_SIZE: b >> 3,
MIN_KEY_SIZE: b >> 3,
MAX_KEY_SIZE: b >> 3,
});
}
import { cbc, createCipher } from '../../core/cipher';
import { BIPoint, Fp, FpEC, U8Point } from '../../core/ec';
import { KitError, U8, genBitMask, genRandomBI, getBIBits, joinBuffer, mod, modInverse } from '../../core/utils';
import { x963kdf } from '../../core/kdf';
import { aes } from '../blockCipher/aes';
import { sha256 } from '../../hash/sha256';
import { hmac } from '../../hash/hmac';
// * Functions
/**
* 定义 ECIES 配置
*
* Define ECIES Configuration
*
* @param {IVBlockCipher} [config.cipher] - 分组密码算法 / Block Cipher Algorithm (default: AES-256-GCM)
* @param {KeyHash} [config.mac] - 密钥哈希函数 / Key Hash Function (default: HMAC-SHA-256)
* @param {KDF} [config.kdf] - 密钥派生函数 / Key Derivation Function (default: ANSI-X9.63-KDF with SHA-256)
* @param {Uint8Array} [config.S1] - 附加数据1 / Additional Data 1 (default: empty)
* @param {Uint8Array} [config.S2] - 附加数据2 / Additional Data 2 (default: empty)
* @param {Uint8Array} [config.iv] - 初始化向量 / Initialization Vector (default: Uint8Array(cipher.BLOCK_SIZE))
*/
export function defineECIES(config) {
config = config ?? {};
const { cipher = cbc(aes(256)), mac = hmac(sha256), kdf = x963kdf(sha256), S1 = new Uint8Array(0), S2 = new Uint8Array(0), iv = new Uint8Array(cipher.BLOCK_SIZE), } = config;
return { cipher, mac, kdf, S1, S2, iv };
}
// * EC Algorithms
/**
* 素域椭圆曲线密码学组件
*
* Prime Field Elliptic Curve Cryptography Components
*/
export function FpECC(curve) {
const { p, a, b, G, n, h } = curve;
const p_bit = getBIBits(p);
const p_byte = (p_bit + 7) >> 3;
const n_bit = getBIBits(n);
const n_mask = genBitMask(n_bit);
const { addPoint, mulPoint } = FpEC(curve);
const { plus, multiply, root } = Fp(p);
const isLegalPK = (p_key) => {
const { Q } = p_key;
// P != O
if (Q.isInfinity) {
return false;
}
// P(x, y) ∈ E
const P = BIPoint(Q);
const { x, y } = P;
if (x < 0n || x >= p || y < 0n || y >= p) {
return false;
}
if (curve.type === 'Weierstrass') {
// y^2 = x^3 + ax + b
const l = multiply(y, y);
const r = plus(multiply(x, x, x), multiply(a, x), b);
if (l !== r) {
return false;
}
// nP = O
const nP = mulPoint(P, n);
return nP.isInfinity;
}
if (curve.type === 'Montgomery') {
// By^2 = x^3 + Ax^2 + x
const l = multiply(b, y, y);
const r = plus(multiply(x, x, x), multiply(a, x, x), x);
if (l !== r) {
return false;
}
// nP = O
const nP = mulPoint(P, n);
return nP.isInfinity;
}
// unknown curve type
else {
return false;
}
};
const isLegalSK = (s_key) => {
const d = typeof s_key.d === 'bigint' ? s_key.d : U8.from(s_key.d).toBI();
if (d < 0n || d >= p) {
return false;
}
return !mulPoint(G, d).isInfinity;
};
const PointToU8 = (point, compress = false) => {
if (point.isInfinity) {
return new U8([0x00]);
}
const { x, y } = U8Point(point, p_byte);
const sign_y = y[y.length - 1] & 1;
const PC = new U8([compress ? 0x02 | sign_y : 0x04]);
const X1 = x;
const Y1 = compress ? new U8() : y;
return joinBuffer(PC, X1, Y1);
};
const U8ToPoint = (buffer) => {
const point_buffer = U8.from(buffer);
const PC = point_buffer[0];
if (PC === 0x00) {
if (point_buffer.length !== 1) {
throw new KitError('Invalid Point');
}
return U8Point();
}
if (PC !== 0x02 && PC !== 0x03 && PC !== 0x04) {
throw new KitError('Invalid Point');
}
// 无压缩
if (PC === 0x04) {
if (point_buffer.length !== (p_byte << 1) + 1) {
throw new KitError('Invalid Point');
}
const x = point_buffer.slice(1, p_byte + 1);
const y = point_buffer.slice(p_byte + 1);
return { isInfinity: false, x, y };
}
// 解压缩
else {
if (point_buffer.length !== p_byte + 1) {
throw new KitError('Invalid Point');
}
const x_buffer = point_buffer.slice(1);
const x = x_buffer.toBI();
const sign_y = BigInt(PC & 1);
if (curve.type === 'Weierstrass') {
let y = 0n;
y = plus(multiply(x, x, x), multiply(a, x), b);
y = root(y);
y = (y & 1n) === sign_y ? y : p - y;
return U8Point({ isInfinity: false, x: x_buffer, y }, p_byte);
}
else if (curve.type === 'Montgomery') {
let y = 0n;
y = plus(multiply(x, x, x), multiply(a, x, x), x);
y = root(y / b);
y = (y & 1n) === sign_y ? y : p - y;
return U8Point({ isInfinity: false, x: x_buffer, y }, p_byte);
}
else {
throw new KitError('Unknown curve type');
}
}
};
function gen(type = 'key_pair', s_key) {
if (type === 'key_pair') {
// private key
const { buffer, result: d } = genRandomBI(n, p_byte);
// public key
const _ = mulPoint(G, d);
const Q = U8Point(_, p_byte);
return { Q, d: buffer };
}
else if (type === 'private_key') {
return { d: genRandomBI(n, p_byte).buffer };
}
else if (type === 'public_key') {
const d_buffer = typeof s_key.d === 'bigint' ? U8.fromBI(s_key.d) : U8.from(s_key.d);
const d = typeof s_key.d === 'bigint' ? s_key.d : d_buffer.toBI();
if (d === 0n) {
throw new KitError('Invalid private key');
}
const _ = mulPoint(G, d);
const Q = U8Point(_, p_byte);
return { Q, d: d_buffer };
}
}
// Key agreement
const ecdh = (s_key, p_key) => {
if (!isLegalPK(p_key)) {
throw new KitError('Invalid public key');
}
if (!isLegalSK(s_key)) {
throw new KitError('Invalid private key');
}
const Q = p_key.Q;
const d = s_key.d;
const S = mulPoint(Q, d);
if (S.isInfinity) {
throw new KitError('the result of ECDH is the point at infinity');
}
return U8Point(S, p_byte);
};
const eccdh = (s_key, p_key) => {
if (!isLegalPK(p_key)) {
throw new KitError('Invalid public key');
}
if (!isLegalSK(s_key)) {
throw new KitError('Invalid private key');
}
const Q = p_key.Q;
const d = typeof s_key.d === 'bigint' ? s_key.d : U8.from(s_key.d).toBI();
const S = mulPoint(Q, d * h);
if (S.isInfinity) {
throw new KitError('the result of ECCDH is the point at infinity');
}
return U8Point(S, p_byte);
};
const ecmqv = (u1, u2, v1, v2) => {
if (!isLegalPK(v1) || !isLegalPK(v2)) {
throw new KitError('Invalid public key');
}
const ceilLog2n = n_bit;
const L = 1n << BigInt(Math.ceil(ceilLog2n / 2));
const u1d = typeof u1.d === 'bigint' ? u1.d : U8.from(u1.d).toBI();
const u2d = typeof u2.d === 'bigint' ? u2.d : U8.from(u2.d).toBI();
const u2Qx = typeof u2.Q.x === 'bigint' ? u2.Q.x : U8.from(u2.Q.x).toBI();
const v2Qx = typeof v2.Q.x === 'bigint' ? v2.Q.x : U8.from(v2.Q.x).toBI();
const Q2u = mod(u2Qx, L) + L;
const Q2v = mod(v2Qx, L) + L;
const s = mod(u2d + Q2u * u1d, n);
const P = mulPoint(addPoint(v2.Q, mulPoint(v1.Q, Q2v)), s * h);
if (P.isInfinity) {
throw new KitError('Public key not available');
}
return U8Point(P, p_byte);
};
// Digital signature
const ecdsa = (hash = sha256) => {
const sign = (s_key, M) => {
const d = typeof s_key.d === 'bigint' ? s_key.d : U8.from(s_key.d).toBI();
let r = 0n;
let s = 0n;
let z = hash(M).toBI();
while (z > n_mask) {
z = z >> 1n;
}
do {
const K = gen();
const k = K.d.toBI();
const x1 = K.Q.x.toBI();
r = mod(x1, n);
if (r === 0n)
continue;
s = modInverse(k, n) * mod(z + r * d, n);
s = mod(s, n);
} while (s === 0n);
const r_buffer = U8.fromBI(r);
const s_buffer = U8.fromBI(s);
return { r: r_buffer, s: s_buffer };
};
const verify = (p_key, M, signature) => {
const { Q } = p_key;
const r = typeof signature.r === 'bigint' ? signature.r : U8.from(signature.r).toBI();
const s = typeof signature.s === 'bigint' ? signature.s : U8.from(signature.s).toBI();
if (r <= 0n || r >= n || s <= 0n || s >= n) {
return false;
}
let z = hash(M).toBI();
while (z > n_mask) {
z = z >> 1n;
}
const w = modInverse(s, n);
const u1 = mod(z * w, n);
const u2 = mod(r * w, n);
const P = addPoint(mulPoint(G, u1), mulPoint(Q, u2));
const v = mod(P.x, n);
return v === r;
};
return { sign, verify };
};
// Integrated encryption scheme
const ecies = (config) => {
const { cipher, mac, kdf, S1, S2, iv } = defineECIES(config);
const encrypt = (p_key, M) => {
if (!isLegalPK(p_key)) {
throw new KitError('Invalid public key');
}
let s_key;
let deriveShare;
do {
s_key = gen();
deriveShare = ecdh(s_key, p_key);
} while (deriveShare.isInfinity);
const Z = deriveShare.x;
const K = kdf((cipher.KEY_SIZE + mac.KEY_SIZE) << 3, joinBuffer(Z, S1));
const KE = K.slice(0, cipher.KEY_SIZE);
const KM = K.slice(cipher.KEY_SIZE, cipher.KEY_SIZE + mac.KEY_SIZE);
const _cipher = cipher(KE, iv);
const R = { Q: s_key.Q };
const C = _cipher.encrypt(M);
const D = mac(KM, joinBuffer(C, S2));
return { R, C, D };
};
const decrypt = (s_key, CT) => {
const { R, C, D } = CT;
// 密钥派生
const deriveShare = ecdh(s_key, R);
if (deriveShare.isInfinity) {
throw new KitError('ECIES Decryption failed');
}
const Z = deriveShare.x;
const K = kdf((cipher.KEY_SIZE + mac.KEY_SIZE) << 3, joinBuffer(Z, S1));
const KE = K.slice(0, cipher.KEY_SIZE);
const KM = K.slice(cipher.KEY_SIZE, cipher.KEY_SIZE + mac.KEY_SIZE);
const _cipher = cipher(KE, iv);
// 校验
if (mac(KM, joinBuffer(C, S2)).some((v, i) => v !== D[i])) {
throw new KitError('ECIES Decryption failed');
}
const M = _cipher.decrypt(C);
// 解密
return new U8(M);
};
return { encrypt, decrypt };
};
return {
utils: {
addPoint,
mulPoint,
isLegalPK,
isLegalSK,
PointToU8,
U8ToPoint,
},
gen,
dh: ecdh,
cdh: eccdh,
mqv: ecmqv,
dsa: ecdsa,
ies: ecies,
};
}
// * Algorithms for Test
/**
* ! 此加密算法仅用于测试 ECIES
* ! This encryption algorithm is only used for testing ECIES
*/
export const es_xor = createCipher((K) => {
const encrypt = (M) => new U8(M.map((v, i) => v ^ K[i]));
const decrypt = (C) => new U8(C.map((v, i) => v ^ K[i]));
return { encrypt, decrypt };
}, {
ALGORITHM: 'ES-XOR',
BLOCK_SIZE: 20,
KEY_SIZE: 20,
MIN_KEY_SIZE: 20,
MAX_KEY_SIZE: 20,
});
import { ASN1 } from '../../core/asn1';
import { Counter, KitError, U8, getBIBits, joinBuffer } from '../../core/utils';
import { sha256 } from '../../hash/sha256';
import { rsa } from './rsa';
/**
* PKCS#1 v2.2 的 掩码生成函数 MGF1
*
* Mask Generation Function MGF1 of PKCS#1 v2.2
*/
export function mgf1(hash) {
return (mdfSeed, maskLen) => {
const T = [];
const C = new Counter(joinBuffer(mdfSeed, new Uint8Array(4)));
for (let i = 0; i < maskLen; i += hash.DIGEST_SIZE) {
T.push(hash(C));
C.inc(mdfSeed.length);
}
return joinBuffer(...T).slice(0, maskLen);
};
}
// * Encryption Scheme
/**
* 最优非对称加密填充的 RSA 加密方案 (OAEP)
*
* RSA Encryption Scheme with Optimal Asymmetric Encryption Padding (OAEP)
*
* @param {RSAPublicKey | RSAPrivateKey} key - RSA 公钥或私钥 / RSA public or private key
* @param {Hash} [hash] - 散列函数 / Hash function (default: SHA-256)
* @param {MGF} [mgf] - 掩码生成函数 / Mask generation function (default: MGF1)
* @param {Uint8Array} [label] - 标签 / Label (default: empty)
*/
export function pkcs1_es_oaep(key, hash = sha256, mgf = mgf1(hash), label = new Uint8Array()) {
const k = (getBIBits(key.n) + 7) >> 3;
const hLen = hash.DIGEST_SIZE;
const MAX_MESSAGE_LENGTH = k - 2 * hLen - 2;
if (MAX_MESSAGE_LENGTH <= 0) {
throw new KitError('Invalid key or hash function');
}
const _rsa = rsa(key);
const lHash = hash(label);
const encrypt = (M) => {
const mLen = M.length;
if (mLen > MAX_MESSAGE_LENGTH) {
throw new KitError('Message too long');
}
// DB = lHash || PS || 0x01 || M
const PS = new U8(MAX_MESSAGE_LENGTH - mLen);
const DB = joinBuffer(lHash, PS, new U8([0x01]), M);
// EM = 0x00 || maskedSeed || maskedDB
const seed = new U8(hLen);
crypto.getRandomValues(seed);
const dbMask = mgf(seed, DB.length);
const maskedDB = DB.map((v, i) => v ^ dbMask[i]);
const seedMask = mgf(maskedDB, hLen);
const maskedSeed = seed.map((v, i) => v ^ seedMask[i]);
const EM = joinBuffer(new U8([0x00]), maskedSeed, maskedDB);
return U8.fromBI(_rsa.encrypt(EM), k);
};
const decrypt = (C) => {
if (k !== C.length) {
throw new KitError('Decryption error');
}
const EM = U8.fromBI(_rsa.decrypt(C), k);
if (EM[0] !== 0x00) {
throw new KitError('Decryption error');
}
const maskedSeed = EM.subarray(1, hLen + 1);
const maskedDB = EM.subarray(hLen + 1);
const seedMask = mgf(maskedDB, hLen);
const seed = maskedSeed.map((v, i) => v ^ seedMask[i]);
const dbMask = mgf(seed, maskedDB.length);
const DB = maskedDB.map((v, i) => v ^ dbMask[i]);
const lHash_ = DB.subarray(0, hLen);
if (lHash.some((v, i) => v !== lHash_[i])) {
throw new KitError('Decryption error');
}
const PS = DB.subarray(hLen);
const mOffset = PS.findIndex(v => v === 0x01);
if (mOffset === -1) {
throw new KitError('Decryption error');
}
if (PS.subarray(0, mOffset).some(v => v !== 0x00)) {
throw new KitError('Decryption error');
}
const M = PS.slice(mOffset + 1);
return M;
};
return { encrypt, decrypt };
}
/**
* RSA 加密方案 (PKCS#1 v1.5)
*
* RSA Encryption Scheme (PKCS#1 v1.5)
*
* @param {RSAPublicKey | RSAPrivateKey} key - RSA 公钥或私钥 / RSA public or private key
*/
export function pkcs1_es_1_5(key) {
const k = (getBIBits(key.n) + 7) >> 3;
const MAX_MESSAGE_LENGTH = k - 11;
if (MAX_MESSAGE_LENGTH <= 0) {
throw new KitError('Invalid key');
}
const _rsa = rsa(key);
const encrypt = (M) => {
if (M.length > MAX_MESSAGE_LENGTH) {
throw new KitError('Message is too long');
}
const PS = new Uint8Array(k - M.length - 3);
do {
crypto.getRandomValues(PS);
} while (PS.includes(0x00));
const EM = joinBuffer(new U8([0x00, 0x02]), PS, new U8([0x00]), M);
return U8.fromBI(_rsa.encrypt(EM), k);
};
const decrypt = (C) => {
if (C.length !== k) {
throw new KitError('Decryption error');
}
const EM = U8.fromBI(_rsa.decrypt(C), k);
if (EM[0] !== 0x00 || EM[1] !== 0x02) {
throw new KitError('Decryption error');
}
const SeparatorIndex = EM.subarray(2).findIndex(v => v === 0x00);
if (SeparatorIndex === -1) {
throw new KitError('Decryption error');
}
const M = EM.slice(SeparatorIndex + 3);
return M;
};
return { encrypt, decrypt };
}
// * Signature Scheme with Appendix
/**
* 基于 概率签名方案 的 RSA 附录签名方案 (PSS)
*
* RSA Signature Scheme with Appendix - Probabilistic Signature Scheme (PSS)
*
* @param {RSAPublicKey | RSAPrivateKey} key - RSA 公钥或私钥 / RSA public or private key
* @param {Hash} [hash] - 散列函数 / Hash function (default: SHA-256)
* @param {MGF} [mgf] - 掩码生成函数 / Mask generation function (default: MGF1)
* @param {number} [sLen] - 盐长度 / Salt length (default: hash.DIGEST_SIZE)
*/
export function pkcs1_ssa_pss(key, hash = sha256, mgf = mgf1(hash), sLen = hash.DIGEST_SIZE) {
const modBits = getBIBits(key.n);
const k = (modBits + 7) >> 3;
const emLen = (modBits + 6) >> 3;
const emsa = emsa_pss(hash, mgf, sLen);
const _rsa = rsa(key);
const sign = (M) => {
const EM = emsa.encode(M, modBits - 1);
const S = _rsa.sign(EM);
return U8.fromBI(S, k);
};
const verify = (M, S) => {
if (S.length !== k) {
return false;
}
const EM = U8.fromBI(_rsa.verify(S), emLen);
return emsa.verify(M, EM, modBits - 1);
};
return { sign, verify };
}
/**
* RSA 附录签名方案 (PKCS#1 v1.5)
*
* RSA Signature Scheme with Appendix (PKCS#1 v1.5)
*
* @param {RSAPublicKey | RSAPrivateKey} key - RSA 公钥或私钥 / RSA public or private key
* @param {Hash} [hash] - 散列函数 / Hash function (default: SHA-256)
*/
export function pkcs1_ssa_1_5(key, hash = sha256) {
const modBits = getBIBits(key.n);
const k = (modBits + 7) >> 3;
const _rsa = rsa(key);
const sign = (M) => {
const EM = emsa_1_5(M, k, hash);
const S = _rsa.sign(EM);
return U8.fromBI(S, k);
};
const verify = (M, S) => {
if (S.length !== k) {
return false;
}
const EM = U8.fromBI(_rsa.verify(S), k);
const EM2 = emsa_1_5(M, k, hash);
return EM.every((v, i) => v === EM2[i]);
};
return { sign, verify };
}
// * Encoding Method for Signatures with Appendix
function emsa_pss(hash = sha256, mgf = mgf1(hash), sLen = hash.DIGEST_SIZE) {
const hLen = hash.DIGEST_SIZE;
const encode = (M, emBits) => {
const mHash = hash(M);
const emLen = (emBits + 7) >> 3;
if (emLen < hLen + sLen + 2) {
throw new KitError('Encoding error');
}
const salt = new U8(sLen);
crypto.getRandomValues(salt);
const M2 = joinBuffer(new U8(8), mHash, salt);
const H = hash(M2);
const PS = new U8(emLen - sLen - hLen - 2);
const DB = joinBuffer(PS, new U8([0x01]), salt);
const dbMask = mgf(H, DB.length);
const maskedDB = DB.map((v, i) => v ^ dbMask[i]);
const bitMask = 0xFF >> (emLen << 3) - emBits;
maskedDB[0] &= bitMask;
const EM = joinBuffer(maskedDB, H, new U8([0xBC]));
return EM;
};
const verify = (M, EM, emBits) => {
const mHash = hash(M);
const emLen = (emBits + 7) >> 3;
if (emLen !== EM.length || emLen < hLen + sLen + 2) {
return false;
}
if (EM[emLen - 1] !== 0xBC) {
return false;
}
const maskedDB = EM.subarray(0, emLen - hLen - 1);
const H = EM.subarray(maskedDB.length, emLen - 1);
const bitMask = 0xFF >> (emLen << 3) - emBits;
if (maskedDB[0] > bitMask) {
return false;
}
const dbMask = mgf(H, maskedDB.length);
const DB = maskedDB.map((v, i) => v ^ dbMask[i]);
DB[0] &= bitMask;
const PS = DB.subarray(0, DB.length - sLen - 1);
if (PS.some(v => v !== 0x00)) {
return false;
}
if (DB[PS.length] !== 0x01) {
return false;
}
const salt = DB.subarray(PS.length + 1);
const M2 = joinBuffer(new U8(8), mHash, salt);
const H2 = hash(M2);
return H2.every((v, i) => v === H[i]);
};
return { encode, verify };
}
function emsa_1_5(M, emLen, hash = sha256) {
const H = hash(M);
const digestAlgorithm = ASN1.SEQUENCE([
ASN1.OBJECT_IDENTIFIER(hash.OID),
ASN1.NULL(),
]);
const digest = ASN1.OCTET_STRING(H);
const DigestInfo = ASN1.SEQUENCE([
digestAlgorithm,
digest,
]);
const T = DigestInfo;
const psLen = emLen - T.length - 3;
if (psLen < 8) {
throw new KitError('intended encoded message length too short');
}
const PS = new U8(psLen).fill(0xFF);
const EM = joinBuffer(new U8([0x00, 0x01]), PS, new U8([0x00]), T);
return EM;
}
import { genPrime } from '../../core/prime';
import { KitError, U8, gcd, lcm, mod, modInverse, modPow } from '../../core/utils';
// * RSA Algorithm
/**
* RSA 加密原语
*
* RSA encryption primitive
*/
function encryptionPrimitive(key, M) {
const { n, e } = key;
if (e === undefined || n === undefined) {
throw new KitError('Invalid public key');
}
M = typeof M === 'bigint' ? M : U8.from(M).toBI();
if (M >= n) {
throw new KitError('Message representative out of range');
}
return modPow(M, e, n);
}
/**
* RSA 解密原语
*
* RSA decryption primitive
*/
function decryptionPrimitive(key, C) {
const { n, d } = key;
if (d === undefined || n === undefined) {
throw new KitError('Invalid private key');
}
C = typeof C === 'bigint' ? C : U8.from(C).toBI();
if (C >= n) {
throw new KitError('Ciphertext representative out of range');
}
return modPow(C, d, n);
}
/**
* RSA 签名原语
*
* RSA signature primitive
*/
function signaturePrimitive(key, M) {
const { n, d } = key;
if (d === undefined || n === undefined) {
throw new KitError('Invalid private key');
}
M = typeof M === 'bigint' ? M : U8.from(M).toBI();
if (M >= n) {
throw new KitError('Message representative out of range');
}
return modPow(M, d, n);
}
/**
* RSA 验证原语
*
* RSA verification primitive
*/
function verificationPrimitive(key, S) {
const { n, e } = key;
if (e === undefined || n === undefined) {
throw new KitError('Invalid public key');
}
S = typeof S === 'bigint' ? S : U8.from(S).toBI();
if (S >= n) {
throw new KitError('Signature is too long');
}
return modPow(S, e, n);
}
/**
* RSA 密钥生成
*
* RSA key generation
*
* @param {number} b - RSA 私钥长度 / RSA private key length (bit)
* @param {RandomPrimeGenerator} rpg - 随机素数生成器 / Random prime generator
*/
function genKey(b, rpg = genPrime) {
const p = rpg(b >> 1);
const q = rpg(b >> 1);
const n = p * q;
const λ = lcm(p - 1n, q - 1n);
// public key
const e = 65537n;
if (gcd(e, λ) !== 1n) {
throw new KitError('Invalid public exponent');
}
// private key
const d = modInverse(e, λ);
const dP = mod(d, p - 1n);
const dQ = mod(d, q - 1n);
const qInv = modInverse(q, p);
const privateKey = { n, e, d, p, q, dP, dQ, qInv };
return privateKey;
}
function fromKey(key) {
const encrypt = (M) => encryptionPrimitive(key, M);
const decrypt = (C) => decryptionPrimitive(key, C);
const sign = (M) => signaturePrimitive(key, M);
const verify = (S) => verificationPrimitive(key, S);
return {
...key,
encrypt,
decrypt,
sign,
verify,
};
}
export function rsa(b, rpg = genPrime) {
if (typeof b === 'number') {
return fromKey(genKey(b, rpg));
}
return fromKey(b);
}
import { sm2p256v1 } from '../../core/ecParams';
import { x963kdf } from '../../core/kdf';
import { sm3 } from '../../hash/sm3';
import { KitError, U8, genBitMask, getBIBits, joinBuffer, mod, modInverse } from '../../core/utils';
import { FpECC } from './ecc';
/**
* SM2 椭圆曲线公钥密码算法
*
* Public Key Cryptography Algorithm SM2 Based on Elliptic Curves
*
* @param {FpECParams} curve - 椭圆曲线参数 / Elliptic Curve Parameters (default: sm2p256v1)
*/
export function sm2(curve = sm2p256v1) {
const { p, a, b, G, n, h } = curve;
const p_bit = getBIBits(p);
const p_byte = (p_bit + 7) >> 3;
const ecc = FpECC(curve);
const { addPoint, mulPoint } = ecc.utils;
const a_buffer = U8.fromBI(a);
const b_buffer = U8.fromBI(b);
const Gx_buffer = U8.fromBI(G.x);
const Gy_buffer = U8.fromBI(G.y);
const gen = ecc.gen;
const isLegalPK = ecc.utils.isLegalPK;
const PointToU8 = ecc.utils.PointToU8;
const U8ToPoint = ecc.utils.U8ToPoint;
const di = (id, key, hash = sm3) => {
const ent = id.length << 3;
if (ent > 0xFFFF) {
throw new KitError('ID长度超过了最大限制');
}
const ENT = new Uint8Array([ent >> 8, ent & 0xFF]);
const a = a_buffer;
const b = b_buffer;
const Gx = Gx_buffer;
const Gy = Gy_buffer;
const Ax = typeof key.Q.x === 'bigint' ? U8.fromBI(key.Q.x) : U8.from(key.Q.x);
const Ay = typeof key.Q.y === 'bigint' ? U8.fromBI(key.Q.y) : U8.from(key.Q.y);
const ZA = hash(joinBuffer(ENT, id, a, b, Gx, Gy, Ax, Ay));
return ZA;
};
const w = Math.ceil(getBIBits(n) / 2) - 1;
const w_mask = genBitMask(w);
const dh = (KA, KX, KB, KY, ZA = new Uint8Array(), ZB = new Uint8Array()) => {
if (isLegalPK(KB) === false || isLegalPK(KY) === false) {
throw new KitError('非法的公钥');
}
const KA_d = typeof KA.d === 'bigint' ? KA.d : U8.from(KA.d).toBI();
const KX_d = typeof KX.d === 'bigint' ? KX.d : U8.from(KX.d).toBI();
const KX_Q_x = typeof KX.Q.x === 'bigint' ? KX.Q.x : U8.from(KX.Q.x).toBI();
const KY_Q_x = typeof KY.Q.x === 'bigint' ? KY.Q.x : U8.from(KY.Q.x).toBI();
const x1 = (1n << BigInt(w)) + (KX_Q_x & w_mask);
const x2 = (1n << BigInt(w)) + (KY_Q_x & w_mask);
const t = mod(KA_d + KX_d * x1, n);
const V = mulPoint(addPoint(KB.Q, mulPoint(KY.Q, x2)), h * t);
if (V.isInfinity) {
throw new KitError('协商失败');
}
const xu = U8.fromBI(V.x);
const yu = U8.fromBI(V.y);
return joinBuffer(xu, yu, ZA, ZB);
};
const dsa = (hash = sm3) => {
if (hash.DIGEST_SIZE !== 32) {
throw new KitError('不支持的哈希算法');
}
const sign = (Z, key, M) => {
const dA = typeof key.d === 'bigint' ? key.d : U8.from(key.d).toBI();
let r = 0n;
let s = 0n;
const e = hash(joinBuffer(Z, M)).toBI();
do {
const k = gen('private_key').d.toBI();
const p = mulPoint(G, k);
r = mod(e + p.x, n);
if (r === 0n || r + k === n) {
continue;
}
const numerator = mod(k - r * dA, n);
const denominator = modInverse(1n + dA, n);
s = mod(numerator * denominator, n);
if (s === 0n) {
continue;
}
break;
} while (1);
const r_buffer = new U8(p_byte);
const s_buffer = new U8(p_byte);
r_buffer.set(U8.fromBI(r));
s_buffer.set(U8.fromBI(s));
return { r: r_buffer, s: s_buffer };
};
const verify = (Z, key, M, S) => {
const PA = key.Q;
const r = typeof S.r === 'bigint' ? S.r : U8.from(S.r).toBI();
const s = typeof S.s === 'bigint' ? S.s : U8.from(S.s).toBI();
if (r <= 0n || r >= n || s <= 0n || s >= n) {
return false;
}
const e = hash(joinBuffer(Z, M)).toBI();
const t = mod(r + s, n);
if (t === 0n) {
return false;
}
const p = addPoint(mulPoint(G, s), mulPoint(PA, t));
const R = mod(e + p.x, n);
return R === r;
};
return { sign, verify };
};
const es = (hash = sm3, kdf = x963kdf(sm3), order = 'c1c3c2') => {
const encrypt = (p_key, M) => {
const C1 = gen();
const S = mulPoint(p_key.Q, h);
if (S.isInfinity) {
throw new KitError('加密失败');
}
const { x, y } = mulPoint(p_key.Q, C1.d);
const x2 = U8.fromBI(x);
const y2 = U8.fromBI(y);
const ikm = joinBuffer(x2, y2);
const C2 = kdf(M.length << 3, ikm);
C2.forEach((_, i) => C2[i] ^= M[i]);
const C3 = hash(joinBuffer(x2, M, y2));
if (order === 'c1c2c3') {
return joinBuffer(PointToU8(C1.Q), C2, C3);
}
else {
return joinBuffer(PointToU8(C1.Q), C3, C2);
}
};
const decrypt = (s_key, C) => {
const C1_Length = (p_byte << 1) + 1;
const C3_Length = hash.DIGEST_SIZE;
const C2_Length = C.length - C1_Length - C3_Length;
const C1 = U8ToPoint(C.subarray(0, C1_Length));
const S = mulPoint(C1, h);
if (S.isInfinity) {
throw new KitError('解密失败');
}
const { x, y } = mulPoint(C1, s_key.d);
const x2 = U8.fromBI(x);
const y2 = U8.fromBI(y);
const ikm = joinBuffer(x2, y2);
const t = kdf(C2_Length << 3, ikm);
let C2;
let C3;
if (order === 'c1c2c3') {
C2 = C.subarray(C1_Length, C1_Length + C2_Length);
C3 = C.subarray(C1_Length + C2_Length);
}
else {
C3 = C.subarray(C1_Length, C1_Length + C3_Length);
C2 = C.subarray(C1_Length + C3_Length);
}
const M = t.map((_, i) => t[i] ^ C2[i]);
const u = hash(joinBuffer(x2, M, y2));
u.forEach((_, i) => {
if (u[i] !== C3[i]) {
throw new KitError('解密失败');
}
});
return M;
};
return { encrypt, decrypt };
};
return {
utils: ecc.utils,
gen,
di,
es,
dh,
dsa,
};
}
import { Fp } from '../../core/ec';
import { curve25519, curve448 } from '../../core/ecParams';
import { KitError, U8, genRandomBI, getBIBits } from '../../core/utils';
// * X25519 & X448 Algorithms
function cSwap(swap, x_2, x_3) {
const mask = -swap;
const dummy = mask & (x_2 ^ x_3);
x_2 ^= dummy;
x_3 ^= dummy;
return [x_2, x_3];
}
/** 蒙哥马利梯子算法 / Montgomery Ladder Algorithm */
function ladder(k, u, p, a24, bit) {
const { plus, subtract, pow, multiply } = Fp(p);
let x_2 = 1n;
let z_2 = 0n;
let x_3 = u;
let z_3 = 1n;
let swap = 0n;
const bit_array = k.toString(2).padStart(bit, '0').split('').map(BigInt);
for (const bit of bit_array) {
swap ^= bit;
[x_2, x_3] = cSwap(swap, x_2, x_3);
[z_2, z_3] = cSwap(swap, z_2, z_3);
swap = bit;
const A = plus(x_2, z_2);
const AA = pow(A, 2n);
const B = subtract(x_2, z_2);
const BB = pow(B, 2n);
const E = subtract(AA, BB);
const C = plus(x_3, z_3);
const D = subtract(x_3, z_3);
const DA = multiply(D, A);
const CB = multiply(C, B);
x_3 = pow(plus(DA, CB), 2n);
z_3 = multiply(u, pow(subtract(DA, CB), 2n));
x_2 = multiply(AA, BB);
z_2 = multiply(E, plus(AA, multiply(E, a24)));
}
[x_2, x_3] = cSwap(swap, x_2, x_3);
[z_2, z_3] = cSwap(swap, z_2, z_3);
return multiply(x_2, pow(z_2, p - 2n));
}
/** x25519 椭圆曲线算法 / Elliptic Curve Algorithm */
export const x25519 = (() => {
const { p, G, n } = curve25519;
const p_bit = getBIBits(p);
const p_byte = (p_bit + 7) >> 3;
const a24 = 121665n;
const Gx = typeof G.x === 'bigint' ? G.x : U8.from(G.x).toBI();
function clamp(d) {
d = d & 0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8n;
d = d | 0x4000000000000000000000000000000000000000000000000000000000000000n;
return d;
}
function gen(type = 'key_pair', s_key) {
if (type === 'key_pair') {
// private key
const t = genRandomBI(n, p_byte);
const d_buffer = t.buffer;
const d = t.result;
// public key
const x = ladder(clamp(d), Gx, p, a24, 255);
const Q = U8.fromBI(x, p_byte);
return { Q, d: d_buffer };
}
else if (type === 'private_key') {
return { d: genRandomBI(n, p_byte).buffer };
}
else if (type === 'public_key') {
const d_buffer = typeof s_key.d === 'bigint' ? U8.fromBI(s_key.d) : U8.from(s_key.d);
const d = typeof s_key.d === 'bigint' ? s_key.d : d_buffer.toBI();
if (d === 0n) {
throw new KitError('Invalid private key');
}
const x = ladder(clamp(d), Gx, p, a24, 255);
const Q = U8.fromBI(x, p_byte);
return { Q, d: d_buffer };
}
}
const ecdh = (s_key, p_key) => {
const u = typeof p_key.Q === 'bigint' ? p_key.Q : U8.from(p_key.Q).toBI();
const k = typeof s_key.d === 'bigint' ? s_key.d : U8.from(s_key.d).toBI();
const x = ladder(clamp(k), u, p, a24, 255);
return U8.fromBI(x, p_byte);
};
return { gen, dh: ecdh };
})();
/** x448 椭圆曲线算法 / Elliptic Curve Algorithm */
export const x448 = (() => {
const { p, G, n } = curve448;
const p_bit = getBIBits(p);
const p_byte = (p_bit + 7) >> 3;
const a24 = 39081n;
const Gx = typeof G.x === 'bigint' ? G.x : U8.from(G.x).toBI();
function clamp(d) {
d = d & 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcn;
d = d | 0x8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n;
return d;
}
function gen(type = 'key_pair', s_key) {
if (type === 'key_pair') {
// private key
const t = genRandomBI(n, p_byte);
const d_buffer = t.buffer;
const d = t.result;
// public key
const x = ladder(clamp(d), Gx, p, a24, 448);
const Q = U8.fromBI(x, p_byte);
return { Q, d: d_buffer };
}
else if (type === 'private_key') {
return { d: genRandomBI(n, p_byte).buffer };
}
else if (type === 'public_key') {
const d_buffer = typeof s_key.d === 'bigint' ? U8.fromBI(s_key.d) : U8.from(s_key.d);
const d = typeof s_key.d === 'bigint' ? s_key.d : d_buffer.toBI();
if (d === 0n) {
throw new KitError('Invalid private key');
}
const x = ladder(clamp(d), Gx, p, a24, 448);
const Q = U8.fromBI(x, p_byte);
return { Q, d: d_buffer };
}
}
const ecdh = (s_key, p_key) => {
const u = typeof p_key.Q === 'bigint' ? p_key.Q : U8.from(p_key.Q).toBI();
const k = typeof s_key.d === 'bigint' ? s_key.d : U8.from(s_key.d).toBI();
const x = ladder(clamp(k), u, p, a24, 448);
return U8.fromBI(x, p_byte);
};
return { gen, dh: ecdh };
})();
import { createCipher } from '../../core/cipher';
import { KitError, U8 } from '../../core/utils';
// * Functions
function KSA(K) {
const SBox = new Uint8Array(256);
SBox.forEach((_, i) => SBox[i] = i);
let j = 0;
for (let i = 0; i < 256; i++) {
j = (j + SBox[i] + K[i % K.byteLength]) % 256;
[SBox[i], SBox[j]] = [SBox[j], SBox[i]];
}
return SBox;
}
// * RC4 Algorithm
function cipher(M, SBox) {
SBox = SBox.slice(0);
const result = new U8(M.byteLength);
let i = 0;
let j = 0;
M.forEach((_, k) => {
i = (i + 1) % 256;
j = (j + SBox[i]) % 256;
[SBox[i], SBox[j]] = [SBox[j], SBox[i]];
result[k] = M[k] ^ SBox[(SBox[i] + SBox[j]) % 256];
});
return result;
}
function _arc4(K) {
if (K.byteLength < 5 || K.byteLength > 256) {
throw new KitError(`RC4 key must be between 5 and 256 byte`);
}
const SBox = KSA(K);
return {
encrypt: (M) => cipher(M, SBox),
decrypt: (M) => cipher(M, SBox),
};
}
/**
* ARC4 流密码 / stream cipher
*/
export const arc4 = createCipher(_arc4, {
ALGORITHM: `ARC4`,
KEY_SIZE: 16,
MIN_KEY_SIZE: 5,
MAX_KEY_SIZE: 256,
});
import { createCipher } from '../../core/cipher';
import { KitError, U8, resizeBuffer, rotateL32 } from '../../core/utils';
// * Constants
const A = new Uint32Array([0x4D34D34D, 0xD34D34D3, 0x34D34D34, 0x4D34D34D, 0xD34D34D3, 0x34D34D34, 0x4D34D34D, 0xD34D34D3]);
// * Rabbit Algorithm
function _rabbit(key, iv) {
if (key.length !== 16) {
throw new KitError('Rabbit key must be 16 byte');
}
// 内部状态
let carray = 0;
const X = new Uint8Array(32);
const C = new Uint8Array(32);
const X32 = new Uint32Array(X.buffer);
const C32 = new Uint32Array(C.buffer);
const nextState = (skipExtract = false) => {
// Counter System
for (let i = 0; i < 8; i++) {
const T = C32[i] + A[i] + carray;
C32[i] = T | 0;
carray = T > 0xFFFFFFFF ? 1 : 0;
}
// G
const G = new Uint32Array(8);
for (let i = 0; i < 8; i++) {
const T = (BigInt(X32[i]) + BigInt(C32[i])) & 0xffffffffn;
const S = T * T;
G[i] = Number((S ^ (S >> 32n)) & 0xffffffffn);
}
// Next State
X32[0] = 0xFFFFFFFF & (G[0] + rotateL32(G[7], 16) + rotateL32(G[6], 16));
X32[1] = 0xFFFFFFFF & (G[1] + rotateL32(G[0], 8) + G[7]);
X32[2] = 0xFFFFFFFF & (G[2] + rotateL32(G[1], 16) + rotateL32(G[0], 16));
X32[3] = 0xFFFFFFFF & (G[3] + rotateL32(G[2], 8) + G[1]);
X32[4] = 0xFFFFFFFF & (G[4] + rotateL32(G[3], 16) + rotateL32(G[2], 16));
X32[5] = 0xFFFFFFFF & (G[5] + rotateL32(G[4], 8) + G[3]);
X32[6] = 0xFFFFFFFF & (G[6] + rotateL32(G[5], 16) + rotateL32(G[4], 16));
X32[7] = 0xFFFFFFFF & (G[7] + rotateL32(G[6], 8) + G[5]);
if (skipExtract) {
return new Uint8Array();
}
// Extract Output
const S = new Uint32Array(4);
S[0] = X32[0] ^ (X32[5] >>> 16) ^ (X32[3] << 16);
S[1] = X32[2] ^ (X32[7] >>> 16) ^ (X32[5] << 16);
S[2] = X32[4] ^ (X32[1] >>> 16) ^ (X32[7] << 16);
S[3] = X32[6] ^ (X32[3] >>> 16) ^ (X32[1] << 16);
return new Uint8Array(S.buffer);
};
// 初始化
(() => {
// 配置密钥
const K16 = new Uint16Array(key.buffer);
for (let i = 0; i < 8; i++) {
if ((i & 1) === 0) {
const KH = K16[(i + 1) % 8];
const KL = K16[i];
X32[i] = (KH << 16) | KL;
const CH = K16[(i + 4) % 8];
const CL = K16[(i + 5) % 8];
C32[i] = (CH << 16) | CL;
}
else {
const KH = K16[(i + 5) % 8];
const KL = K16[(i + 4) % 8];
X32[i] = (KH << 16) | KL;
const CH = K16[i];
const CL = K16[(i + 1) % 8];
C32[i] = (CH << 16) | CL;
}
}
for (let i = 0; i < 4; i++) {
nextState(true);
}
for (let i = 0; i < 8; i++) {
C32[i] ^= X32[(i + 4) % 8];
}
// 配置 IV
if (iv.length === 8) {
const iv32 = new Uint32Array(iv.buffer);
const iv16 = new Uint16Array(iv.buffer);
C32[0] ^= iv32[0];
C32[1] ^= (iv16[3] << 16) | iv16[1];
C32[2] ^= iv32[1];
C32[3] ^= (iv16[2] << 16) | iv16[0];
C32[4] ^= iv32[0];
C32[5] ^= (iv16[3] << 16) | iv16[1];
C32[6] ^= iv32[1];
C32[7] ^= (iv16[2] << 16) | iv16[0];
for (let i = 0; i < 4; i++) {
nextState(true);
}
}
else if (iv.length !== 0 && iv.length !== 8) {
throw new KitError('Rabbit iv must be 8 byte');
}
})();
// 密钥流
let S = nextState();
let current = 1;
const squeeze = (count) => {
if (current >= count) {
return S;
}
S = resizeBuffer(S, count << 4);
while (current < count) {
S.set(nextState(), current << 4);
current++;
}
return S;
};
const cipher = (M) => {
const BLOCK_TOTAL = Math.ceil(M.length >> 4) || 1;
S = squeeze(BLOCK_TOTAL);
return new U8(M.map((_, i) => _ ^ S[i]));
};
return {
encrypt: (M) => cipher(M),
decrypt: (C) => cipher(C),
};
}
/**
* Rabbit 流密码 / stream cipher
*/
export const rabbit = createCipher(_rabbit, {
ALGORITHM: 'rabbit',
KEY_SIZE: 16,
MIN_KEY_SIZE: 16,
MAX_KEY_SIZE: 16,
IV_SIZE: 8,
MIN_IV_SIZE: 0,
MAX_IV_SIZE: 8,
});
import { createCipher } from '../../core/cipher';
import { Counter, KitError, U8, resizeBuffer, rotateL32 } from '../../core/utils';
// * Functions
function QR(a, b, c, d) {
b ^= rotateL32(a + d, 7);
c ^= rotateL32(b + a, 9);
d ^= rotateL32(c + b, 13);
a ^= rotateL32(d + c, 18);
return [a, b, c, d];
}
function hash(x, rounds = 20) {
// to word
const X = new Uint32Array(x.buffer);
const W = X.slice(0);
// main loop
for (let i = 0; i < rounds; i += 2) {
// ODD Rounds
[W[0], W[4], W[8], W[12]] = QR(W[0], W[4], W[8], W[12]);
[W[5], W[9], W[13], W[1]] = QR(W[5], W[9], W[13], W[1]);
[W[10], W[14], W[2], W[6]] = QR(W[10], W[14], W[2], W[6]);
[W[15], W[3], W[7], W[11]] = QR(W[15], W[3], W[7], W[11]);
// EVEN Rounds
[W[0], W[1], W[2], W[3]] = QR(W[0], W[1], W[2], W[3]);
[W[5], W[6], W[7], W[4]] = QR(W[5], W[6], W[7], W[4]);
[W[10], W[11], W[8], W[9]] = QR(W[10], W[11], W[8], W[9]);
[W[15], W[12], W[13], W[14]] = QR(W[15], W[12], W[13], W[14]);
}
// mix
const Z = new U8(64);
const Z32 = new Uint32Array(Z.buffer);
for (let i = 0; i < 16; i++) {
Z32[i] = X[i] + W[i];
}
return Z;
}
function expand(K, iv) {
if (iv.byteLength !== 8) {
throw new KitError(`Salsa20 iv must be 8 byte`);
}
const S = new Counter(64);
const S32 = new Uint32Array(S.buffer);
const K32 = new Uint32Array(K.buffer);
const N32 = new Uint32Array(iv.buffer);
switch (K.byteLength) {
case 16: // use tau
S32[0] = 0x61707865;
S32[1] = K32[0];
S32[2] = K32[1];
S32[3] = K32[2];
S32[4] = K32[3];
S32[5] = 0x3120646E;
S32[6] = N32[0];
S32[7] = N32[1];
S32[10] = 0x79622D36;
S32[11] = K32[0];
S32[12] = K32[1];
S32[13] = K32[2];
S32[14] = K32[3];
S32[15] = 0x6B206574;
break;
case 32: // use sigma
S32[0] = 0x61707865;
S32[1] = K32[0];
S32[2] = K32[1];
S32[3] = K32[2];
S32[4] = K32[3];
S32[5] = 0x3320646E;
S32[6] = N32[0];
S32[7] = N32[1];
S32[10] = 0x79622D32;
S32[11] = K32[4];
S32[12] = K32[5];
S32[13] = K32[6];
S32[14] = K32[7];
S32[15] = 0x6B206574;
break;
default:
throw new KitError(`Salsa20 key must be 16 or 32 byte`);
}
return S;
}
// * Salsa20 Algorithm
function _salsa20(key, iv) {
/** Counter Block */
const E = expand(key, iv);
/** Presudo Random Byte Stream */
let S = hash(E);
let current = 1;
const cipher = (M) => {
const R = U8.from(M);
const BLOCK_TOTAL = (R.length >> 6) + 1;
if (current > BLOCK_TOTAL) {
return R.map((byte, i) => byte ^ S[i]);
}
// Squeeze
S = resizeBuffer(S, BLOCK_TOTAL << 6);
while (BLOCK_TOTAL > current) {
E.inc(32, 8, true);
S.set(hash(E), current << 6);
current++;
}
return R.map((byte, i) => byte ^ S[i]);
};
return {
encrypt: (M) => cipher(M),
decrypt: (C) => cipher(C),
};
}
/**
* Salsa20 流密码 / Stream Cipher
*/
export const salsa20 = createCipher(_salsa20, {
ALGORITHM: 'Salsa20',
KEY_SIZE: 32,
MIN_KEY_SIZE: 16,
MAX_KEY_SIZE: 32,
IV_SIZE: 8,
MIN_IV_SIZE: 8,
MAX_IV_SIZE: 8,
});
import { KitError, U8, rotateL32, wrap } from '../../core/utils';
// * Constants
const S0 = new Uint8Array([0x3E, 0x72, 0x5B, 0x47, 0xCA, 0xE0, 0x00, 0x33, 0x04, 0xD1, 0x54, 0x98, 0x09, 0xB9, 0x6D, 0xCB, 0x7B, 0x1B, 0xF9, 0x32, 0xAF, 0x9D, 0x6A, 0xA5, 0xB8, 0x2D, 0xFC, 0x1D, 0x08, 0x53, 0x03, 0x90, 0x4D, 0x4E, 0x84, 0x99, 0xE4, 0xCE, 0xD9, 0x91, 0xDD, 0xB6, 0x85, 0x48, 0x8B, 0x29, 0x6E, 0xAC, 0xCD, 0xC1, 0xF8, 0x1E, 0x73, 0x43, 0x69, 0xC6, 0xB5, 0xBD, 0xFD, 0x39, 0x63, 0x20, 0xD4, 0x38, 0x76, 0x7D, 0xB2, 0xA7, 0xCF, 0xED, 0x57, 0xC5, 0xF3, 0x2C, 0xBB, 0x14, 0x21, 0x06, 0x55, 0x9B, 0xE3, 0xEF, 0x5E, 0x31, 0x4F, 0x7F, 0x5A, 0xA4, 0x0D, 0x82, 0x51, 0x49, 0x5F, 0xBA, 0x58, 0x1C, 0x4A, 0x16, 0xD5, 0x17, 0xA8, 0x92, 0x24, 0x1F, 0x8C, 0xFF, 0xD8, 0xAE, 0x2E, 0x01, 0xD3, 0xAD, 0x3B, 0x4B, 0xDA, 0x46, 0xEB, 0xC9, 0xDE, 0x9A, 0x8F, 0x87, 0xD7, 0x3A, 0x80, 0x6F, 0x2F, 0xC8, 0xB1, 0xB4, 0x37, 0xF7, 0x0A, 0x22, 0x13, 0x28, 0x7C, 0xCC, 0x3C, 0x89, 0xC7, 0xC3, 0x96, 0x56, 0x07, 0xBF, 0x7E, 0xF0, 0x0B, 0x2B, 0x97, 0x52, 0x35, 0x41, 0x79, 0x61, 0xA6, 0x4C, 0x10, 0xFE, 0xBC, 0x26, 0x95, 0x88, 0x8A, 0xB0, 0xA3, 0xFB, 0xC0, 0x18, 0x94, 0xF2, 0xE1, 0xE5, 0xE9, 0x5D, 0xD0, 0xDC, 0x11, 0x66, 0x64, 0x5C, 0xEC, 0x59, 0x42, 0x75, 0x12, 0xF5, 0x74, 0x9C, 0xAA, 0x23, 0x0E, 0x86, 0xAB, 0xBE, 0x2A, 0x02, 0xE7, 0x67, 0xE6, 0x44, 0xA2, 0x6C, 0xC2, 0x93, 0x9F, 0xF1, 0xF6, 0xFA, 0x36, 0xD2, 0x50, 0x68, 0x9E, 0x62, 0x71, 0x15, 0x3D, 0xD6, 0x40, 0xC4, 0xE2, 0x0F, 0x8E, 0x83, 0x77, 0x6B, 0x25, 0x05, 0x3F, 0x0C, 0x30, 0xEA, 0x70, 0xB7, 0xA1, 0xE8, 0xA9, 0x65, 0x8D, 0x27, 0x1A, 0xDB, 0x81, 0xB3, 0xA0, 0xF4, 0x45, 0x7A, 0x19, 0xDF, 0xEE, 0x78, 0x34, 0x60]);
const S1 = new Uint8Array([0x55, 0xC2, 0x63, 0x71, 0x3B, 0xC8, 0x47, 0x86, 0x9F, 0x3C, 0xDA, 0x5B, 0x29, 0xAA, 0xFD, 0x77, 0x8C, 0xC5, 0x94, 0x0C, 0xA6, 0x1A, 0x13, 0x00, 0xE3, 0xA8, 0x16, 0x72, 0x40, 0xF9, 0xF8, 0x42, 0x44, 0x26, 0x68, 0x96, 0x81, 0xD9, 0x45, 0x3E, 0x10, 0x76, 0xC6, 0xA7, 0x8B, 0x39, 0x43, 0xE1, 0x3A, 0xB5, 0x56, 0x2A, 0xC0, 0x6D, 0xB3, 0x05, 0x22, 0x66, 0xBF, 0xDC, 0x0B, 0xFA, 0x62, 0x48, 0xDD, 0x20, 0x11, 0x06, 0x36, 0xC9, 0xC1, 0xCF, 0xF6, 0x27, 0x52, 0xBB, 0x69, 0xF5, 0xD4, 0x87, 0x7F, 0x84, 0x4C, 0xD2, 0x9C, 0x57, 0xA4, 0xBC, 0x4F, 0x9A, 0xDF, 0xFE, 0xD6, 0x8D, 0x7A, 0xEB, 0x2B, 0x53, 0xD8, 0x5C, 0xA1, 0x14, 0x17, 0xFB, 0x23, 0xD5, 0x7D, 0x30, 0x67, 0x73, 0x08, 0x09, 0xEE, 0xB7, 0x70, 0x3F, 0x61, 0xB2, 0x19, 0x8E, 0x4E, 0xE5, 0x4B, 0x93, 0x8F, 0x5D, 0xDB, 0xA9, 0xAD, 0xF1, 0xAE, 0x2E, 0xCB, 0x0D, 0xFC, 0xF4, 0x2D, 0x46, 0x6E, 0x1D, 0x97, 0xE8, 0xD1, 0xE9, 0x4D, 0x37, 0xA5, 0x75, 0x5E, 0x83, 0x9E, 0xAB, 0x82, 0x9D, 0xB9, 0x1C, 0xE0, 0xCD, 0x49, 0x89, 0x01, 0xB6, 0xBD, 0x58, 0x24, 0xA2, 0x5F, 0x38, 0x78, 0x99, 0x15, 0x90, 0x50, 0xB8, 0x95, 0xE4, 0xD0, 0x91, 0xC7, 0xCE, 0xED, 0x0F, 0xB4, 0x6F, 0xA0, 0xCC, 0xF0, 0x02, 0x4A, 0x79, 0xC3, 0xDE, 0xA3, 0xEF, 0xEA, 0x51, 0xE6, 0x6B, 0x18, 0xEC, 0x1B, 0x2C, 0x80, 0xF7, 0x74, 0xE7, 0xFF, 0x21, 0x5A, 0x6A, 0x54, 0x1E, 0x41, 0x31, 0x92, 0x35, 0xC4, 0x33, 0x07, 0x0A, 0xBA, 0x7E, 0x0E, 0x34, 0x88, 0xB1, 0x98, 0x7C, 0xF3, 0x3D, 0x60, 0x6C, 0x7B, 0xCA, 0xD3, 0x1F, 0x32, 0x65, 0x04, 0x28, 0x64, 0xBE, 0x85, 0x9B, 0x2F, 0x59, 0x8A, 0xD7, 0xB0, 0x25, 0xAC, 0xAF, 0x12, 0x03, 0xE2, 0xF2]);
const D = new Uint16Array([0x44D7, 0x26BC, 0x626B, 0x135E, 0x5789, 0x35E2, 0x7135, 0x09AF, 0x4D78, 0x2F13, 0x6BC4, 0x1AF1, 0x5E26, 0x3C4D, 0x789A, 0x47AC]);
// * Functions
function mulPow2n(v, n) {
return ((v << n | v >>> (31 - n)) & 0x7FFFFFFF);
}
function addMod31(a, b) {
const c = a + b;
return (c & 0x7FFFFFFF) + (c >>> 31);
}
const L1 = (X) => X ^ rotateL32(X, 2) ^ rotateL32(X, 10) ^ rotateL32(X, 18) ^ rotateL32(X, 24);
const L2 = (X) => X ^ rotateL32(X, 8) ^ rotateL32(X, 14) ^ rotateL32(X, 22) ^ rotateL32(X, 30);
function BR(S, X) {
X[0] = (S[15] & 0x7FFF8000) << 1 | S[14] & 0xFFFF;
X[1] = (S[11] & 0x0000FFFF) << 16 | S[9] >>> 15;
X[2] = (S[7] & 0x0000FFFF) << 16 | S[5] >>> 15;
X[3] = (S[2] & 0x0000FFFF) << 16 | S[0] >>> 15;
}
function F(X0, X1, X2, R) {
const W = (X0 ^ R[0]) + R[1];
const W1 = (R[0] + X1) & 0xFFFFFFFF;
const W2 = R[1] ^ X2;
const r0 = L1((W1 << 16) | (W2 >>> 16));
R[0] = S0[r0 >>> 24] << 24 | S1[(r0 >>> 16) & 0xFF] << 16 | S0[(r0 >>> 8) & 0xFF] << 8 | S1[r0 & 0xFF];
const r1 = L2((W2 << 16) | (W1 >>> 16));
R[1] = S0[r1 >>> 24] << 24 | S1[(r1 >>> 16) & 0xFF] << 16 | S0[(r1 >>> 8) & 0xFF] << 8 | S1[r1 & 0xFF];
return W;
}
/**
* 线性反馈移位寄存器有两种运行模式:初始化模式和工作模式,当输入 `u` 时为初始化模式,否则为工作模式
*
* @param {Uint32Array} S - 线性反馈移位寄存器(LFSR)
* @param {number} u - 初始化模式下的输入
*/
function next(S, u) {
let s16, v;
s16 = S[0];
v = mulPow2n(S[0], 8);
s16 = addMod31(s16, v);
v = mulPow2n(S[4], 20);
s16 = addMod31(s16, v);
v = mulPow2n(S[10], 21);
s16 = addMod31(s16, v);
v = mulPow2n(S[13], 17);
s16 = addMod31(s16, v);
v = mulPow2n(S[15], 15);
s16 = addMod31(s16, v);
s16 = u ? addMod31(s16, u) : s16;
s16 = s16 || 0x7FFFFFFF;
for (let i = 0; i < 15; i++) {
S[i] = S[i + 1];
}
S[15] = s16;
}
// * ZUC Algorithm (presudo-random generator)
/**
* 3GPP ZUC 算法用于生成密钥流,每次调用返回一个 32 位的密钥流.
*
* 3GPP ZUC algorithm is used to generate a key stream, each call returns a 32-bit key stream.
*
* ```ts
* const K = new Uint8Array(16)
* const iv = new Uint8Array(16)
* const prg = zuc(K, iv)
* prg() // 32-bit number
* ```
*/
export function zuc(K, iv) {
if (K.byteLength !== 16) {
throw new KitError('ZUC requires a key of 16 bytes');
}
if (iv.byteLength !== 16) {
throw new KitError('ZUC requires an IV of 16 bytes');
}
const LFSR = new Uint32Array(16);
const X = new Uint32Array(4);
const R = new Uint32Array(2);
(function init() {
for (let i = 0; i < 16; i++) {
LFSR[i] = K[i] << 23 | D[i] << 8 | iv[i];
}
for (let i = 0; i < 32; i++) {
BR(LFSR, X);
const W = F(X[0], X[1], X[2], R);
next(LFSR, W >>> 1);
}
BR(LFSR, X);
F(X[0], X[1], X[2], R);
next(LFSR);
})();
return () => {
BR(LFSR, X);
const W = F(X[0], X[1], X[2], R) ^ X[3];
next(LFSR);
return W;
};
}
// * EEA3 & EIA3
function createEEA_IV(count, bearer, direction) {
const iv = new Uint8Array(16);
iv.set(count, 0);
iv[4] = bearer << 3 | direction << 2;
iv.set(iv.subarray(0, 5), 8);
return iv;
}
function createEIA_IV(count, bearer, direction) {
const iv = new Uint8Array(16);
iv.set(count, 0);
iv[4] = bearer << 3;
iv.set(iv.subarray(0, 5), 8);
iv[8] ^= direction << 7;
iv[14] ^= direction << 7;
return iv;
}
function getWord(Z, bit_offset) {
const ti = bit_offset % 8;
const byte_offset = bit_offset >>> 3;
const W = ti === 0
? Z.getUint32(byte_offset, false)
: Z.getUint32(byte_offset, false) << ti | Z.getUint32(byte_offset + 4, false) >>> (32 - ti);
return W & 0xFFFFFFFF;
}
/**
* 3GPP ZUC 加密算法 / Encryption algorithm
*/
export const eea3 = wrap((param) => {
const { BEARER, DIRECTION, KEY, M } = param;
let { COUNTER, LENGTH } = param;
// 转换参数
COUNTER = typeof COUNTER === 'number' ? new Uint8Array([COUNTER >> 24, COUNTER >> 16, COUNTER >> 8, COUNTER]) : COUNTER;
// 生成密钥流
LENGTH = M.byteLength << 3;
const WORD_COUNT = (LENGTH + 31) >> 5;
const EEA_KeyStream = new Uint8Array(WORD_COUNT << 2);
const KSView = new DataView(EEA_KeyStream.buffer);
const EEA_IV = createEEA_IV(COUNTER, BEARER, DIRECTION);
const prg = zuc(KEY, EEA_IV);
for (let i = 0; i < WORD_COUNT; i++) {
KSView.setUint32(i << 2, prg(), false);
}
// 加密
return new U8(M.map((_, i) => _ ^ EEA_KeyStream[i]));
}, {
ALGORITHM: 'ZUC-EEA3',
KEY_SIZE: 16,
});
/**
* 3GPP ZUC 完整性算法 / Integrity algorithm
*/
export const eia3 = wrap((param) => {
const { BEARER, DIRECTION, KEY, M } = param;
let { COUNTER, LENGTH } = param;
// 转换参数
COUNTER = typeof COUNTER === 'number' ? new Uint8Array([COUNTER >> 24, COUNTER >> 16, COUNTER >> 8, COUNTER]) : COUNTER;
// 生成密钥流
const N = LENGTH + 64;
const WORD_COUNT = N + 31 >> 5;
const EIA_KeyStream = new Uint8Array(WORD_COUNT << 2);
const KSView = new DataView(EIA_KeyStream.buffer);
const EIA_IV = createEIA_IV(COUNTER, BEARER, DIRECTION);
const prg = zuc(KEY, EIA_IV);
for (let i = 0; i < WORD_COUNT; i++) {
KSView.setUint32(i << 2, prg(), false);
}
// 计算 MAC
let t = 0;
for (let i = 0; i < LENGTH; i++) {
const bit = M[i >>> 3] & (1 << (7 - (i % 8)));
if (bit) {
t ^= getWord(KSView, i);
}
}
t ^= getWord(KSView, LENGTH);
t ^= KSView.getUint32(EIA_KeyStream.byteLength - 4);
return new U8([t >> 24, t >> 16, t >> 8, t]);
}, {
ALGORITHM: 'ZUC-EIA3',
KEY_SIZE: 16,
});
import { U8 } from './utils';
export const ASN1 = {
// 0x04
OCTET_STRING: (value) => {
const buffer = new U8(value.length + 2);
buffer.set([0x04, value.length], 0);
buffer.set(value, 2);
return buffer;
},
// 0x05
NULL: () => new U8([0x05, 0x00]),
// 0x06
OBJECT_IDENTIFIER: (id = '') => {
const node = id.split('.').map(Number);
const buffer = [];
buffer.push(node[0] * 40 + node[1]);
for (let i = 2; i < node.length; i++) {
let n = node[i];
if (n < 128) {
buffer.push(n);
}
else {
const bytes = [n & 0x7F];
n >>= 7;
while (n > 0) {
bytes.unshift((n & 0x7F) | 0x80);
n >>= 7;
}
buffer.push(...bytes);
}
}
return new U8([0x06, buffer.length, ...buffer]);
},
// 0x30
SEQUENCE: (value) => {
const length = value.reduce((sum, v) => sum + v.length, 0);
const buffer = new U8(length + 2);
buffer.set([0x30, length], 0);
let offset = 2;
for (const v of value) {
buffer.set(v, offset);
offset += v.length;
}
return buffer;
},
};
import { Counter, KitError, U8, joinBuffer, wrap } from './utils';
export function createCipher(algorithm, description) {
return wrap((key, iv) => wrap(algorithm(key, iv), description), description);
}
export function createPadding(doPad, unPad, description) {
return wrap((M, BLOCK_SIZE) => (typeof BLOCK_SIZE === 'number'
? doPad(M, BLOCK_SIZE)
: unPad(M)), description);
}
// * 填充方案
/** PKCS7 填充方案 / Padding Scheme */
export const PKCS7_PAD = createPadding((M, BLOCK_SIZE) => {
const pad = BLOCK_SIZE - M.length % BLOCK_SIZE;
return joinBuffer(M, new Uint8Array(pad).fill(pad));
}, (P) => {
const pad = P[P.length - 1];
return new U8(P.slice(0, P.length - pad));
}, { ALGORITHM: 'PKCS#7' });
/** ISO/IEC 7816 填充方案 / Padding Scheme */
export const ISO7816_PAD = createPadding((M, BLOCK_SIZE) => {
const BLOCK_TOTAL = Math.ceil((M.length + 1) / BLOCK_SIZE);
const P = new U8(BLOCK_TOTAL * BLOCK_SIZE);
P.set(M);
P[M.length] = 0x80;
return P;
}, (P) => {
let i = P.length - 1;
while (P[i] === 0x80) {
i = i - 1;
if (i < 0) {
console.warn('This message may not be ISO/IEC 7816-4 padded');
return new U8();
}
}
return new U8(P.slice(0, i + 1));
}, { ALGORITHM: 'ISO/IEC 7816-4' });
/** ANSI X9.23 填充方案 / Padding Scheme */
export const X923_PAD = createPadding((M, BLOCK_SIZE) => {
const BLOCK_TOTAL = Math.ceil((M.length + 1) / BLOCK_SIZE);
const P = new U8(BLOCK_TOTAL * BLOCK_SIZE);
P.set(M);
P[P.length - 1] = P.length - M.length;
return P;
}, (P) => {
const pad = P[P.length - 1];
return new U8(P.slice(0, P.length - pad));
}, { ALGORITHM: 'ANSI X9.23' });
/** Zero 零填充方案 / Padding Scheme */
export const ZERO_PAD = createPadding((M, BLOCK_SIZE) => {
const pad = BLOCK_SIZE - M.length % BLOCK_SIZE;
return joinBuffer(M, new Uint8Array(pad));
}, (P) => {
let i = P.length - 1;
while (P[i] === 0) {
i = i - 1;
if (i < 0) {
return new U8();
}
}
return new U8(P.slice(0, i + 1));
}, { ALGORITHM: 'Zero Padding' });
/** 无填充 / No Padding */
export const NO_PAD = createPadding((M) => new U8(M.slice(0)), (P) => new U8(P.slice(0)), { ALGORITHM: 'No Padding' });
/** 电子密码本模式 / Electronic Code Book Mode */
export const ecb = wrap((cipher, padding = PKCS7_PAD) => {
const info = {
ALGORITHM: `ECB-${cipher.ALGORITHM}`,
PADDING: padding,
BLOCK_SIZE: cipher.BLOCK_SIZE,
KEY_SIZE: cipher.KEY_SIZE,
MIN_KEY_SIZE: cipher.MIN_KEY_SIZE,
MAX_KEY_SIZE: cipher.MAX_KEY_SIZE,
IV_SIZE: 0,
MIN_IV_SIZE: 0,
MAX_IV_SIZE: 0,
};
const suite = (K) => {
const { BLOCK_SIZE } = cipher;
const c = cipher(K);
const encrypt = (M) => {
const P = padding(M, BLOCK_SIZE);
const C = new U8(P.length);
for (let i = 0; i < P.length;) {
const offset = i;
const B = P.subarray(i, i += BLOCK_SIZE);
C.set(c.encrypt(B), offset);
}
return C;
};
const decrypt = (C) => {
if (C.length % BLOCK_SIZE !== 0) {
throw new KitError('Decryption error');
}
const P = new U8(C.length);
for (let i = 0; i < C.length;) {
const offset = i;
const B = C.subarray(i, i += BLOCK_SIZE);
P.set(c.decrypt(B), offset);
}
return padding(P);
};
return wrap({ encrypt, decrypt }, info);
};
return wrap(suite, info);
}, { ALGORITHM: 'ECB' });
/** 密码块链接模式 / Cipher Block Chaining Mode */
export const cbc = wrap((cipher, padding = PKCS7_PAD) => {
const info = {
ALGORITHM: `CBC-${cipher.ALGORITHM}`,
PADDING: padding,
BLOCK_SIZE: cipher.BLOCK_SIZE,
KEY_SIZE: cipher.KEY_SIZE,
MIN_KEY_SIZE: cipher.MIN_KEY_SIZE,
MAX_KEY_SIZE: cipher.MAX_KEY_SIZE,
IV_SIZE: cipher.BLOCK_SIZE,
MIN_IV_SIZE: cipher.BLOCK_SIZE,
MAX_IV_SIZE: cipher.BLOCK_SIZE,
};
const suite = (K, iv) => {
// iv 检查
const { BLOCK_SIZE } = cipher;
if (iv.length !== BLOCK_SIZE) {
throw new KitError(`${info.ALGORITHM} iv must be ${BLOCK_SIZE} byte`);
}
const c = cipher(K);
const encrypt = (M) => {
const P = padding(M, BLOCK_SIZE);
const C = new U8(P.length);
let prev = iv.slice(0);
for (let i = 0; i < P.length;) {
const offset = i;
const B = P.subarray(i, i += BLOCK_SIZE);
prev.forEach((_, i) => prev[i] ^= B[i]);
prev = c.encrypt(prev);
C.set(prev, offset);
}
return C;
};
const decrypt = (C) => {
if (C.length % BLOCK_SIZE !== 0) {
throw new KitError('Decryption error');
}
const P = new U8(C.length);
let prev = iv;
for (let i = 0; i < C.length;) {
const offset = i;
const B = C.slice(i, i += BLOCK_SIZE);
c.decrypt(B).forEach((_, i) => prev[i] ^= _);
P.set(prev, offset);
prev = B;
}
return padding(P);
};
return wrap({ encrypt, decrypt }, info);
};
return wrap(suite, info);
}, { ALGORITHM: 'CBC' });
/** 传播密码块链接模式 / Propagating Cipher Block Chaining Mode */
export const pcbc = wrap((cipher, padding = PKCS7_PAD) => {
const info = {
ALGORITHM: `PCBC-${cipher.ALGORITHM}`,
PADDING: padding,
BLOCK_SIZE: cipher.BLOCK_SIZE,
KEY_SIZE: cipher.KEY_SIZE,
MIN_KEY_SIZE: cipher.MIN_KEY_SIZE,
MAX_KEY_SIZE: cipher.MAX_KEY_SIZE,
IV_SIZE: cipher.BLOCK_SIZE,
MIN_IV_SIZE: cipher.BLOCK_SIZE,
MAX_IV_SIZE: cipher.BLOCK_SIZE,
};
const suite = (K, IV) => {
// iv 检查
const { BLOCK_SIZE } = cipher;
if (IV.length !== BLOCK_SIZE) {
throw new KitError(`${info.ALGORITHM} iv must be ${BLOCK_SIZE} byte`);
}
const c = cipher(K);
const encrypt = (M) => {
const P = padding(M, BLOCK_SIZE);
const C = new U8(P.length);
const prev = IV.slice(0);
for (let i = 0; i < P.length;) {
const offset = i;
const B = P.subarray(i, i += BLOCK_SIZE);
prev.forEach((_, i) => prev[i] ^= B[i]);
const _C = c.encrypt(prev);
C.set(_C, offset);
prev.forEach((_, i) => prev[i] = _C[i] ^ B[i]);
}
return C;
};
const decrypt = (C) => {
if (C.length % BLOCK_SIZE !== 0) {
throw new KitError('Decryption error');
}
const P = new U8(C.length);
const prev = IV.slice(0);
for (let i = 0; i < C.length;) {
const offset = i;
const B = C.slice(i, i += BLOCK_SIZE);
const _P = c.decrypt(B);
_P.forEach((_, i) => _P[i] ^= prev[i]);
P.set(_P, offset);
B.forEach((_, i) => prev[i] = B[i] ^ _P[i]);
}
return padding(P);
};
return wrap({ encrypt, decrypt }, info);
};
return wrap(suite, info);
}, { ALGORITHM: 'PCBC' });
/** 密码反馈模式 / Cipher Feedback Mode */
export const cfb = wrap((cipher, padding = PKCS7_PAD) => {
const info = {
ALGORITHM: `CFB-${cipher.ALGORITHM}`,
PADDING: padding,
BLOCK_SIZE: cipher.BLOCK_SIZE,
KEY_SIZE: cipher.KEY_SIZE,
MIN_KEY_SIZE: cipher.MIN_KEY_SIZE,
MAX_KEY_SIZE: cipher.MAX_KEY_SIZE,
IV_SIZE: cipher.BLOCK_SIZE,
MIN_IV_SIZE: cipher.BLOCK_SIZE,
MAX_IV_SIZE: cipher.BLOCK_SIZE,
};
const suite = (K, iv) => {
// iv 检查
const { BLOCK_SIZE } = cipher;
if (iv.length !== BLOCK_SIZE) {
throw new KitError(`${info.ALGORITHM} iv must be ${BLOCK_SIZE} byte`);
}
const c = cipher(K);
const encrypt = (M) => {
const P = padding(M, BLOCK_SIZE);
const C = new U8(P.length);
let prev = iv;
for (let i = 0; i < P.length;) {
const offset = i;
const B = P.subarray(i, i += BLOCK_SIZE);
prev = c.encrypt(prev);
prev.forEach((_, i) => prev[i] ^= B[i]);
C.set(prev.subarray(0, B.length), offset);
}
return C;
};
const decrypt = (C) => {
const P = new U8(C.length);
let prev = iv;
for (let i = 0; i < C.length;) {
const offset = i;
const B = C.subarray(i, i += BLOCK_SIZE);
prev = c.encrypt(prev);
B.forEach((_, i) => prev[i] ^= B[i]);
P.set(prev.subarray(0, B.length), offset);
prev = B;
}
return padding(P);
};
return wrap({ encrypt, decrypt }, info);
};
return wrap(suite, info);
}, { ALGORITHM: 'CFB' });
/** 输出反馈模式 / Output Feedback Mode */
export const ofb = wrap((cipher, padding = PKCS7_PAD) => {
const info = {
ALGORITHM: `OFB-${cipher.ALGORITHM}`,
PADDING: padding,
BLOCK_SIZE: cipher.BLOCK_SIZE,
KEY_SIZE: cipher.KEY_SIZE,
MIN_KEY_SIZE: cipher.MIN_KEY_SIZE,
MAX_KEY_SIZE: cipher.MAX_KEY_SIZE,
IV_SIZE: cipher.BLOCK_SIZE,
MIN_IV_SIZE: cipher.BLOCK_SIZE,
MAX_IV_SIZE: cipher.BLOCK_SIZE,
};
const suite = (K, iv) => {
// iv 检查
const { BLOCK_SIZE } = cipher;
if (iv.length !== BLOCK_SIZE) {
throw new KitError(`${info.ALGORITHM} iv must be ${BLOCK_SIZE} byte`);
}
const c = cipher(K);
let prev = c.encrypt(iv);
let S = prev;
let SByte = BLOCK_SIZE;
const squeeze = (TByte) => {
if (SByte > TByte) {
return S;
}
const buffer = [S];
while (SByte < TByte) {
prev = c.encrypt(prev);
buffer.push(prev);
SByte += BLOCK_SIZE;
}
S = joinBuffer(...buffer);
return S;
};
const encrypt = (M) => {
const P = padding(M, BLOCK_SIZE);
S = squeeze(P.length);
return P.map((_, i) => _ ^ S[i]);
};
const decrypt = (C) => {
S = squeeze(C.length);
return padding(C.map((_, i) => _ ^ S[i]));
};
return wrap({ encrypt, decrypt }, info);
};
return wrap(suite, info);
}, { ALGORITHM: 'OFB' });
/** 计数器模式 / Counter Mode */
export const ctr = wrap((cipher, padding = PKCS7_PAD) => {
const info = {
ALGORITHM: `CTR-${cipher.ALGORITHM}`,
PADDING: padding,
BLOCK_SIZE: cipher.BLOCK_SIZE,
KEY_SIZE: cipher.KEY_SIZE,
MIN_KEY_SIZE: cipher.MIN_KEY_SIZE,
MAX_KEY_SIZE: cipher.MAX_KEY_SIZE,
IV_SIZE: cipher.BLOCK_SIZE,
MIN_IV_SIZE: cipher.BLOCK_SIZE,
MAX_IV_SIZE: cipher.BLOCK_SIZE,
};
const suite = (K, iv) => {
// iv 检查
const { BLOCK_SIZE } = cipher;
if (iv.length !== BLOCK_SIZE) {
throw new KitError(`{info.ALGORITHM} iv must be ${BLOCK_SIZE} byte`);
}
const c = cipher(K);
const counter = new Counter(iv.slice());
let S = new U8();
let SByte = 0;
const squeeze = (TByte) => {
if (SByte > TByte) {
return S;
}
const buffer = [S];
while (SByte < TByte) {
buffer.push(c.encrypt(counter));
counter.inc();
SByte += BLOCK_SIZE;
}
S = joinBuffer(...buffer);
return S;
};
const encrypt = (M) => {
const P = padding(M, BLOCK_SIZE);
S = squeeze(P.length);
return P.map((_, i) => _ ^ S[i]);
};
const decrypt = (C) => {
S = squeeze(C.length);
return padding(C.map((_, i) => _ ^ S[i]));
};
return wrap({ encrypt, decrypt }, info);
};
return wrap(suite, info);
}, { ALGORITHM: 'CTR' });
function GF128Mul(X, Y) {
// R: E1000000000000000000000000000000
const RH = 0xe1n << 56n;
const YView = new DataView(Y.buffer);
let VH = YView.getBigUint64(0, false);
let VL = YView.getBigUint64(8, false);
let ZH = 0n;
let ZL = 0n;
for (let i = 0; i < 16; i++) {
const x = X[i];
for (let j = 7; j >= 0; j--) {
if ((x >> j) & 1) {
ZH ^= VH;
ZL ^= VL;
}
const carry = VL & 1n;
VL = (VH << 63n) | (VL >> 1n);
VL = VL & 0xffffffffffffffffn;
VH = (VH >> 1n);
if (carry) {
VH ^= RH;
}
}
}
const Z = new U8(16);
const ZView = new DataView(Z.buffer);
ZView.setBigUint64(0, ZH, false);
ZView.setBigUint64(8, ZL, false);
return Z;
}
function GHASH(H, A, C) {
const A_BLOCK_TOTAL = Math.ceil(A.length / 16);
const C_BLOCK_TOTAL = Math.ceil(C.length / 16);
const D = new Uint8Array((A_BLOCK_TOTAL + C_BLOCK_TOTAL + 1) * 16);
const view = new DataView(D.buffer);
D.set(A);
D.set(C, A_BLOCK_TOTAL * 16);
view.setBigUint64(D.length - 16, BigInt(A.length << 3), false);
view.setBigUint64(D.length - 8, BigInt(C.length << 3), false);
let X = new U8(16);
for (let i = 0; i < D.length; i += 16) {
const B = D.subarray(i, i + 16);
X.forEach((_, i) => X[i] ^= B[i]);
X = GF128Mul(H, X);
}
return X;
}
/** 伽罗瓦计数器模式 / Galois Counter Mode */
export const gcm = wrap((cipher, padding = PKCS7_PAD, tag_size = 16) => {
const { BLOCK_SIZE } = cipher;
if (BLOCK_SIZE !== 16) {
throw new KitError('GCM cipher block must be 128 bit');
}
const info = {
ALGORITHM: `GCM-${cipher.ALGORITHM}`,
PADDING: padding,
BLOCK_SIZE: cipher.BLOCK_SIZE,
KEY_SIZE: cipher.KEY_SIZE,
MIN_KEY_SIZE: cipher.MIN_KEY_SIZE,
MAX_KEY_SIZE: cipher.MAX_KEY_SIZE,
IV_SIZE: 12,
MIN_IV_SIZE: 0,
MAX_IV_SIZE: Infinity,
AUTH_TAG_SIZE: tag_size,
};
const suite = (K, iv) => {
const c = cipher(K);
const H = c.encrypt(new Uint8Array(BLOCK_SIZE));
let IV = new Counter(16);
if (iv.length === 12) {
IV.set(iv);
IV[15] = 1;
}
else {
IV = new Counter(GHASH(H, new Uint8Array(), iv.slice(0)));
}
let S = c.encrypt(IV);
let SByte = 0;
const squeeze = (TByte) => {
if (SByte > TByte) {
return S;
}
const buffer = [S];
while (SByte < TByte) {
IV.inc();
buffer.push(c.encrypt(IV));
SByte += BLOCK_SIZE;
}
S = joinBuffer(...buffer);
return S;
};
const encrypt = (M) => {
const P = padding(M, BLOCK_SIZE);
S = squeeze(P.length);
return P.map((_, i) => _ ^ S[i + BLOCK_SIZE]);
};
const decrypt = (C) => {
S = squeeze(C.length);
return padding(C.map((_, i) => _ ^ S[i + BLOCK_SIZE]));
};
const sign = (C, A = new Uint8Array()) => {
const T = GHASH(H, A, C);
T.forEach((_, i) => T[i] ^= S[i]);
return T.slice(0, tag_size);
};
const verify = (T, C, A) => {
if (T.length !== tag_size) {
return false;
}
const T1 = sign(C, A);
return T.every((_, i) => _ === T1[i]);
};
return wrap({ encrypt, decrypt, sign, verify }, info);
};
return wrap(suite, info);
}, {
ALGORITHM: 'GCM',
IV_SIZE: 12,
});
import { KitError, U8, wrap } from './utils';
function createCodec(parse, stringify, format) {
function codec(input) {
if (typeof input === 'string') {
return parse(input);
}
else {
return stringify(input);
}
}
return wrap(codec, { FORMAT: format });
}
/** provided by xingluo233 */
function UTF8ToU8(input) {
const buffer = [];
for (let i = 0; i < input.length; i++) {
const char_code = input.codePointAt(i);
if (char_code === undefined) {
continue;
}
else if (char_code < 0x80) {
buffer.push(char_code);
}
else if (char_code < 0x800) {
buffer.push(0xC0 | (char_code >> 6));
buffer.push(0x80 | (char_code & 0x3F));
}
else if (char_code < 0x10000) {
buffer.push(0xE0 | (char_code >> 12));
buffer.push(0x80 | ((char_code >> 6) & 0x3F));
buffer.push(0x80 | (char_code & 0x3F));
}
else if (char_code < 0x110000) {
buffer.push(0xF0 | (char_code >> 18));
buffer.push(0x80 | ((char_code >> 12) & 0x3F));
buffer.push(0x80 | ((char_code >> 6) & 0x3F));
buffer.push(0x80 | (char_code & 0x3F));
i++;
}
}
return U8.from(buffer);
}
/** provided by xingluo233 */
function U8ToUTF8(input) {
const str = [];
let i = 0;
while (i < input.length) {
const byte1 = input[i++];
if (byte1 < 0x80) {
str.push(String.fromCharCode(byte1));
}
else if (byte1 >= 0xC0 && byte1 < 0xE0) {
const byte2 = input[i++];
const char_code = ((byte1 & 0x1F) << 6) | (byte2 & 0x3F);
str.push(String.fromCharCode(char_code));
}
else if (byte1 >= 0xE0 && byte1 < 0xF0) {
const byte2 = input[i++];
const byte3 = input[i++];
const char_code = ((byte1 & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | (byte3 & 0x3F);
str.push(String.fromCharCode(char_code));
}
else if (byte1 >= 0xF0 && byte1 < 0xF8) {
const byte2 = input[i++];
const byte3 = input[i++];
const byte4 = input[i++];
const char_code = ((byte1 & 0x07) << 18) | ((byte2 & 0x3F) << 12) | ((byte3 & 0x3F) << 6) | (byte4 & 0x3F);
str.push(String.fromCodePoint(char_code));
}
}
return str.join('');
}
/** UTF-8 编解码器 / Codec */
export const UTF8 = createCodec(UTF8ToU8, U8ToUTF8, 'utf-8');
function HEXToU8(input) {
const arr = input.match(/[\da-f]{2}/gi);
if (arr == null) {
return new U8();
}
return new U8(arr.map(h => Number.parseInt(h, 16)));
}
function U8ToHEX(input) {
let result = '';
for (let i = 0; i < input.length; i++) {
result += input[i].toString(16).padStart(2, '0');
}
return result;
}
/** hex 编解码器 / Codec */
export const HEX = createCodec(HEXToU8, U8ToHEX, 'hex');
function B64ToU8(input) {
return B64CommonParse(input, false);
}
function U8ToB64(input) {
return B64CommonStringify(input, false);
}
/** base64 编解码器 / Codec */
export const B64 = createCodec(B64ToU8, U8ToB64, 'base64');
function B64URLToU8(input) {
return B64CommonParse(input, true);
}
function U8ToB64URL(input) {
return B64(input).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}
/** base64url 编解码器 / Codec */
export const B64URL = createCodec(B64URLToU8, U8ToB64URL, 'base64url');
/**
* provided by xingluo233
*
* B64CommonParse can parse B64 or B64url string to Uint8Array
*
* B64CommonParse 可以将 B64 或者 B64url 字符串解析为 Uint8Array
*
* @param {string} input - B64 或 B64url 字符串
* @param {boolean} url - 是否是 B64url 字符串
*/
function B64CommonParse(input, url) {
const map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
if (url) {
input = input.replace(/-/g, '+').replace(/_/g, '/');
while (input.length % 4) {
input += '=';
}
}
input = input.replace(/[^A-Z0-9+/]/gi, '');
const length = input.length * 0.75;
const result = new U8(length);
let i = 0;
let j = 0;
while (i < input.length) {
const a = map.indexOf(input.charAt(i++));
const b = map.indexOf(input.charAt(i++));
const c = map.indexOf(input.charAt(i++));
const d = map.indexOf(input.charAt(i++));
const combined = (a << 18) | (b << 12) | (c << 6) | d;
result[j++] = (combined >> 16) & 0xFF;
result[j++] = (combined >> 8) & 0xFF;
result[j++] = combined & 0xFF;
}
return result;
}
/**
* B64CommonStringify can stringify Uint8Array to B64 or B64url string
*
* B64CommonStringify 可以将 Uint8Array 编码为 B64 或 B64url 字符串
*
* @param {Uint8Array} input - Uint8Array
* @param {boolean} url - 是否是 B64url 字符串
*/
function B64CommonStringify(input, url) {
let map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
map += url ? '-_' : '+/';
let result = '';
let i;
for (i = 0; i < input.length - 2; i += 3) {
result += map[input[i] >> 2];
result += map[((input[i] & 3) << 4) | (input[i + 1] >> 4)];
result += map[((input[i + 1] & 15) << 2) | (input[i + 2] >> 6)];
result += map[input[i + 2] & 63];
}
if (i === input.length - 2) {
result += map[input[i] >> 2];
result += map[((input[i] & 3) << 4) | (input[i + 1] >> 4)];
result += map[(input[i + 1] & 15) << 2];
result += url ? '' : '=';
}
else if (i === input.length - 1) {
result += map[input[i] >> 2];
result += map[(input[i] & 3) << 4];
result += url ? '' : '==';
}
return result;
}
function CSVToU8(input) {
const coreValueMap = new Map();
coreValueMap.set('富强', 0);
coreValueMap.set('民主', 1);
coreValueMap.set('文明', 2);
coreValueMap.set('和谐', 3);
coreValueMap.set('自由', 4);
coreValueMap.set('平等', 5);
coreValueMap.set('公正', 6);
coreValueMap.set('法治', 7);
coreValueMap.set('爱国', 8);
coreValueMap.set('敬业', 9);
coreValueMap.set('诚信', 10);
coreValueMap.set('友善', 11);
const from = (value) => {
const nibble = coreValueMap.get(value);
if (nibble === undefined) {
throw new KitError('你竟然在社会主义核心价值观里夹带私货!');
}
return nibble;
};
const coreValues = input.match(/(\S){2}/g);
if (coreValues == null) {
return new U8();
}
let h = 0;
let l = 0;
let count = 0;
const result = [];
for (let i = 0; i < coreValues.length; i++) {
const isHigh = count % 2 === 0;
let nibble = from(coreValues[i]);
if (nibble === 10 || nibble === 11) {
i++;
if (i === coreValues.length) {
throw new KitError('你的社会主义核心价值观破碎了!');
}
nibble = nibble === 10
? 10 + from(coreValues[i])
: 6 + from(coreValues[i]);
}
if (isHigh) {
h = nibble;
}
else {
l = nibble;
}
if (!isHigh) {
result.push(((h << 4) | l) & 0xFF);
}
count++;
}
return new U8(result);
}
function U8ToCSV(input) {
const rand = () => Math.random() >= 0.5;
const map = ['富强', '民主', '文明', '和谐', '自由', '平等', '公正', '法治', '爱国', '敬业', '诚信', '友善'];
let result = '';
input.forEach((byte) => {
const h = (byte >> 4) & 0xF;
const l = byte & 0xF;
if (h < 10) {
result += map[h];
}
else if (rand()) {
result += map[11] + map[h - 6];
}
else {
result += map[11] + map[h - 6];
}
if (l < 10) {
result += map[l];
}
else if (rand()) {
result += map[10] + map[l - 10];
}
else {
result += map[11] + map[l - 6];
}
});
return result;
}
/** 社会主义核心价值观编解码器 / Core Socialist Values Codec */
export const CSV = createCodec(CSVToU8, U8ToCSV, 'core-socialist-values');
import { U8, mod, modInverse, modPow, modPrimeSquare } from './utils';
// * FpEC Components
/**
* 将椭圆曲线点转换为 U8 格式
*
* Convert EC Point to U8 Format
*/
export function U8Point(point, byte) {
if (!point) {
return { isInfinity: true, x: new U8(), y: new U8() };
}
const isInfinity = point.isInfinity;
const x = typeof point.x === 'bigint'
? U8.fromBI(point.x, byte)
: U8.from(point.x);
const y = typeof point.y === 'bigint'
? U8.fromBI(point.y, byte)
: U8.from(point.y);
return { isInfinity, x, y };
}
/**
* 将椭圆曲线点转换为 bigint 格式
*
* Convert EC Point to bigint Format
*/
export function BIPoint(point) {
if (!point) {
return { isInfinity: true, x: 0n, y: 0n };
}
const isInfinity = point.isInfinity;
const x = typeof point.x === 'bigint'
? point.x
: U8.from(point.x).toBI();
const y = typeof point.y === 'bigint'
? point.y
: U8.from(point.y).toBI();
return { isInfinity, x, y };
}
/**
* 蒙哥马利梯子点乘法
*
* Montgomery Ladder Point Multiplication
*
* @param addPoint 素域椭圆曲线点加法函数 / Prime Field EC Point Addition Function
* @param {FpECPoint} P 椭圆曲线点 / EC Point
* @param {bigint | Uint8Array} k 标量 / Scalar
*/
function LadderMultiply(addPoint, P, k) {
k = typeof k === 'bigint' ? k : U8.from(k).toBI();
let R0 = BIPoint();
let R1 = BIPoint(P);
// MSb -> LSb
const bit_array = k.toString(2).split('');
for (const bit of bit_array) {
if (bit === '1') {
R0 = addPoint(R0, R1);
R1 = addPoint(R1, R1);
}
else {
R1 = addPoint(R0, R1);
R0 = addPoint(R0, R0);
}
}
return R0;
}
/** 素域运算 / Prime Field Operations */
export function Fp(p) {
const _mod = (a) => mod(a, p);
const inverse = (a) => modInverse(a, p);
const root = (a) => modPrimeSquare(a, p);
const pow = (a, b) => modPow(a, b, p);
const plus = (...args) => args.reduce((acc, cur) => _mod(acc + cur));
const multiply = (...args) => args.reduce((acc, cur) => _mod(acc * cur));
const subtract = (a, ...args) => {
const b = args.map(v => _mod(p - v));
return plus(a, ...b);
};
const divide = (a, b) => multiply(a, inverse(b));
return {
plus,
multiply,
subtract,
divide,
mod: _mod,
pow,
inverse,
root,
};
}
/**
* 素域椭圆曲线运算
*
* Prime Field Elliptic Curve Operations
*/
export function FpEC(curve) {
switch (curve.type) {
case 'Weierstrass':
return FpWEC(curve);
case 'Montgomery':
return FpMEC(curve);
case 'TwistedEdwards':
return FpTEC(curve);
}
}
/**
* 素域 Weierstrass 椭圆曲线运算
*
* Prime Field Weierstrass Elliptic Curve Operations
*/
export function FpWEC(curve) {
const { p, a } = curve;
const { plus, multiply, subtract, divide } = Fp(p);
const addPoint = (A, B) => {
// O + P = P
if (A.isInfinity) {
return BIPoint(B);
}
if (B.isInfinity) {
return BIPoint(A);
}
let [x1, y1] = [A.x, A.y];
let [x2, y2] = [B.x, B.y];
x1 = typeof x1 === 'bigint' ? x1 : U8.from(x1).toBI();
y1 = typeof y1 === 'bigint' ? y1 : U8.from(y1).toBI();
x2 = typeof x2 === 'bigint' ? x2 : U8.from(x2).toBI();
y2 = typeof y2 === 'bigint' ? y2 : U8.from(y2).toBI();
// P + (-P) = O
if (x1 === x2 && y1 !== y2) {
return BIPoint();
}
let λ = 0n;
// P1 + P2
if (x1 !== x2) {
// λ = (y2 - y1) / (x2 - x1)
const numerator = subtract(y2, y1);
const denominator = subtract(x2, x1);
λ = divide(numerator, denominator);
}
// P1 + P1
else {
// λ = (3 * x1 * x1 + a) / 2 * y1
const numerator = plus(multiply(3n, x1, x1), a);
const denominator = multiply(2n, y1);
λ = divide(numerator, denominator);
}
// x3 = λ * λ - x1 - x2
const x3 = subtract(multiply(λ, λ), x1, x2);
// y3 = λ * (x1 - x3) - y1
const y3 = subtract(multiply(λ, subtract(x1, x3)), y1);
return { isInfinity: false, x: x3, y: y3 };
};
const mulPoint = (P, k) => LadderMultiply(addPoint, P, k);
return { addPoint, mulPoint };
}
/**
* 素域 Montgomery 椭圆曲线运算
*
* Prime Field Montgomery Elliptic Curve Operations
*/
export function FpMEC(curve) {
const { p, a, b } = curve;
const { plus, multiply, subtract, divide } = Fp(p);
const addPoint = (A, B) => {
// O + P = P
if (A.isInfinity) {
return BIPoint(B);
}
if (B.isInfinity) {
return BIPoint(A);
}
let [x1, y1] = [A.x, A.y];
let [x2, y2] = [B.x, B.y];
x1 = typeof x1 === 'bigint' ? x1 : U8.from(x1).toBI();
y1 = typeof y1 === 'bigint' ? y1 : U8.from(y1).toBI();
x2 = typeof x2 === 'bigint' ? x2 : U8.from(x2).toBI();
y2 = typeof y2 === 'bigint' ? y2 : U8.from(y2).toBI();
// P + (-P) = O
if (x1 === x2 && y1 !== y2) {
return BIPoint();
}
let λ = 0n;
// P1 + P2
if (x1 !== x2) {
// λ = (y2 - y1) / (x2 - x1)
const numerator = subtract(y2, y1);
const denominator = subtract(x2, x1);
λ = divide(numerator, denominator);
}
// P1 + P1
else {
// λ = (3 * x1 * x1 + 2 * a * x1 + 1) / 2 * b * y1
const numerator = plus(multiply(3n, x1, x1), multiply(2n, a, x1), 1n);
const denominator = multiply(2n, b, y1);
λ = divide(numerator, denominator);
}
// x3 = b * λ * λ - a - x1 - x2
const x3 = subtract(multiply(λ, λ, b), a, x1, x2);
// y3 = (2 x1 + x2 + a) * λ - b * λ * λ * λ - y1
const y3 = subtract(multiply(2n * x1 + x2 + a, λ), multiply(λ, λ, λ, b), y1);
return { isInfinity: false, x: x3, y: y3 };
};
const mulPoint = (P, k) => LadderMultiply(addPoint, P, k);
return { addPoint, mulPoint };
}
/**
* 素域 Twisted Edwards 椭圆曲线运算
*
* Prime Field Twisted Edwards Elliptic Curve Operations
*/
// eslint-disable-next-line unused-imports/no-unused-vars
export function FpTEC(curve) {
// TODO
return {};
}
// * Prime Filed Elliptic Curve Interfaces
// * SM2 Prime Curve
/**
* 256 位素域上的 SM2 曲线
*
* SM2 curve over a 256 bit prime field
*/
export const sm2p256v1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffffn,
a: 0xfffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffcn,
b: 0x28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93n,
G: {
isInfinity: false,
x: 0x32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7n,
y: 0xbc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0n,
},
n: 0xfffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123n,
h: 1n,
});
// * SEC-1 Prime Curves
/**
* 112 位素域上的 SECG/WTLS 曲线
*
* SECG/WTLS curve over a 112 bit prime field
*
* @alias secp112r1
* @alias wtls6
*/
export const secp112r1 = Object.freeze({
type: 'Weierstrass',
p: 0xdb7c2abf62e35e668076bead208bn,
a: 0xdb7c2abf62e35e668076bead2088n,
b: 0x659ef8ba043916eede8911702b22n,
G: {
isInfinity: false,
x: 0x09487239995a5ee76b55f9c2f098n,
y: 0xa89ce5af8724c0a23e0e0ff77500n,
},
n: 0xdb7c2abf62e35e7628dfac6561c5n,
h: 1n,
});
/**
* 112 位素域上的 SECG 曲线
*
* SECG curve over a 112 bit prime field
*/
export const secp112r2 = Object.freeze({
type: 'Weierstrass',
p: 0xdb7c2abf62e35e668076bead208bn,
a: 0x6127c24c05f38a0aaaf65c0ef02cn,
b: 0x51def1815db5ed74fcc34c85d709n,
G: {
isInfinity: false,
x: 0x4ba30ab5e892b4e1649dd0928643n,
y: 0xadcd46f5882e3747def36e956e97n,
},
n: 0x36df0aafd8b8d7597ca10520d04bn,
h: 4n,
});
/**
* 128 位素域上的 SECG 曲线
*
* SECG curve over a 128 bit prime field
*/
export const secp128r1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffdffffffffffffffffffffffffn,
a: 0xfffffffdfffffffffffffffffffffffcn,
b: 0xe87579c11079f43dd824993c2cee5ed3n,
G: {
isInfinity: false,
x: 0x161ff7528b899b2d0c28607ca52c5b86n,
y: 0xcf5ac8395bafeb13c02da292dded7a83n,
},
n: 0xfffffffe0000000075a30d1b9038a115n,
h: 1n,
});
/**
* 128 位素域上的 SECG 曲线
*
* SECG curve over a 128 bit prime field
*/
export const secp128r2 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffdffffffffffffffffffffffffn,
a: 0xd6031998d1b3bbfebf59cc9bbff9aee1n,
b: 0x5eeefca380d02919dc2c6558bb6d8a5dn,
G: {
isInfinity: false,
x: 0x7b6aa5d85e572983e6fb32a7cdebc140n,
y: 0x27b6916a894d3aee7106fe805fc34b44n,
},
n: 0x3fffffff7fffffffbe0024720613b5a3n,
h: 4n,
});
/**
* 160 位素域上的 SECG 曲线
*
* SECG curve over a 160 bit prime field
*/
export const secp160k1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffffffffffffffffffffffffffeffffac73n,
a: 0n,
b: 7n,
G: {
isInfinity: false,
x: 0x3b4c382ce37aa192a4019e763036f4f5dd4d7ebbn,
y: 0x938cf935318fdced6bc28286531733c3f03c4feen,
},
n: 0x0100000000000000000001b8fa16dfab9aca16b6b3n,
h: 1n,
});
/**
* 160 位素域上的 SECG/WTLS 曲线
*
* SECG/WTLS curve over a 160 bit prime field
*
* @alias secp160r1
* @alias wtls7
*/
export const secp160r1 = Object.freeze({
type: 'Weierstrass',
p: 0xffffffffffffffffffffffffffffffff7fffffffn,
a: 0xffffffffffffffffffffffffffffffff7ffffffcn,
b: 0x1c97befc54bd7a8b65acf89f81d4d4adc565fa45n,
G: {
isInfinity: false,
x: 0x4a96b5688ef573284664698968c38bb913cbfc82n,
y: 0x23a628553168947d59dcc912042351377ac5fb32n,
},
n: 0x0100000000000000000001f4c8f927aed3ca752257n,
h: 1n,
});
/**
* 160 位素域上的 SECG 曲线
*
* SECG curve over a 160 bit prime field
*/
export const secp160r2 = Object.freeze({
type: 'Weierstrass',
p: 0xffffffffffffffffffffffffffffffff7fffffffn,
a: 0xffffffffffffffffffffffffffffffff7ffffffcn,
b: 0xb4e134d3fb59eb8bab57274904664d5af50388ban,
G: {
isInfinity: false,
x: 0x52dcb034293a117e1f4ff11b30f7199d3144ce6dn,
y: 0xfeaffef2e331f296e071fa0df9982cfea7d43f2en,
},
n: 0x0100000000000000000000351ee786a818f3a1a16bn,
h: 1n,
});
/**
* 192 位素域上的 SECG 曲线
*
* SECG curve over a 192 bit prime field
*/
export const secp192k1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffffffffffffffffffffffffffffffffffeffffee37n,
a: 0x000000000000000000000000000000000000000000000000n,
b: 0x000000000000000000000000000000000000000000000003n,
G: {
isInfinity: false,
x: 0xdb4ff10ec057e9ae26b07d0280b7f4341da5d1b1eae06c7dn,
y: 0x9b2f2f6d9c5628a7844163d015be86344082aa88d95e2f9dn,
},
n: 0xfffffffffffffffffffffffe26f2fc170f69466a74defd8dn,
h: 1n,
});
/**
* 192 位素域上的 NIST/X9.62/SECG 曲线
*
* NIST/X9.62/SECG curve over a 192 bit prime field
*
* @alias p192
* @alias prime192v1
* @alias secp192r1
*/
export const secp192r1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffffffffffffffffffffffffffeffffffffffffffffn,
a: 0xfffffffffffffffffffffffffffffffefffffffffffffffcn,
b: 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1n,
G: {
isInfinity: false,
x: 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012n,
y: 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811n,
},
n: 0xffffffffffffffffffffffff99def836146bc9b1b4d22831n,
h: 1n,
});
/**
* 224 位素域上的 SECG 曲线
*
* SECG curve over a 224 bit prime field
*/
export const secp224k1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffffffffffffffffffffffffffffffffffffffffffeffffe56dn,
a: 0x00000000000000000000000000000000000000000000000000000000n,
b: 0x00000000000000000000000000000000000000000000000000000005n,
G: {
isInfinity: false,
x: 0xa1455b334df099df30fc28a169a467e9e47075a90f7e650eb6b7a45cn,
y: 0x7e089fed7fba344282cafbd6f7e319f7c0b0bd59e2ca4bdb556d61a5n,
},
n: 0x010000000000000000000000000001dce8d2ec6184caf0a971769fb1f7n,
h: 1n,
});
/**
* 224 位素域上的 NIST/SECG 曲线
*
* NIST/SECG curve over a 224 bit prime field
*
* @alias p224
* @alias secp224r1
*/
export const secp224r1 = Object.freeze({
type: 'Weierstrass',
p: 0xffffffffffffffffffffffffffffffff000000000000000000000001n,
a: 0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffen,
b: 0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4n,
G: {
isInfinity: false,
x: 0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21n,
y: 0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34n,
},
n: 0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3dn,
h: 1n,
});
/**
* 256 位素域上的 SECG 曲线
*
* SECG curve over a 256 bit prime field
*/
export const secp256k1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn,
a: 0x0000000000000000000000000000000000000000000000000000000000000000n,
b: 0x0000000000000000000000000000000000000000000000000000000000000007n,
G: {
isInfinity: false,
x: 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798n,
y: 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8n,
},
n: 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n,
h: 1n,
});
/**
* 256 位素域上的 NIST/X9.62/SECG 曲线
*
* NIST/X9.62/SECG curve over a 256 bit prime field
*
* @alias p256
* @alias prime256v1
* @alias secp256r1
*/
export const secp256r1 = Object.freeze({
type: 'Weierstrass',
p: 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffffn,
a: 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffcn,
b: 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604bn,
G: {
isInfinity: false,
x: 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296n,
y: 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5n,
},
n: 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551n,
h: 1n,
});
/**
* 384 位素域上的 NIST/SECG 曲线
*
* NIST/SECG curve over a 384 bit prime field
*
* @alias p384
* @alias secp384r1
*/
export const secp384r1 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffffn,
a: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffcn,
b: 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aefn,
G: {
isInfinity: false,
x: 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7n,
y: 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5fn,
},
n: 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973n,
h: 1n,
});
/**
* 521 位素域上的 NIST/SECG 曲线
*
* NIST/SECG curve over a 521 bit prime field
*
* @alias p521
* @alias secp521r1
*/
export const secp521r1 = Object.freeze({
type: 'Weierstrass',
p: 0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
a: 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcn,
b: 0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00n,
G: {
isInfinity: false,
x: 0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66n,
y: 0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650n,
},
n: 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409n,
h: 1n,
});
// * SEC-1 Binary Curves
export const sect163k1 = Object.freeze({
m: 163,
f: (x) => x ** 163n + x ** 7n + x ** 6n + x ** 3n + 1n,
a: 0x1n,
b: 0x1n,
G: {
isInfinity: false,
x: 0x02fe13c0537bbc11acaa07d793de4e6d5e5c94eee8n,
y: 0x0289070fb05d38ff58321f2e800536d538ccdaa3d9n,
},
n: 0x04000000000000000000020108a2e0cc0d99f8a5efn,
h: 2n,
});
// * X9.63 Prime Curves
/**
* 192 位素域上的 NIST/X9.62/SECG 曲线
*
* NIST/X9.62/SECG curve over a 192 bit prime field
*
* @alias p192
* @alias prime192v1
* @alias secp192r1
*/
export const prime192v1 = secp192r1;
/**
* 256 位素域上的 NIST/X9.62/SECG 曲线
*
* NIST/X9.62/SECG curve over a 256 bit prime field
*
* @alias p256
* @alias prime256v1
* @alias secp256r1
*/
export const prime256v1 = secp256r1;
// * NIST Prime Curves
/**
* 192 位素域上的 NIST/X9.62/SECG 曲线
*
* NIST/X9.62/SECG curve over a 192 bit prime field
*
* @alias p192
* @alias prime192v1
* @alias secp192r1
*/
export const p192 = secp192r1;
/**
* 224 位素域上的 NIST/SECG 曲线
*
* NIST/SECG curve over a 224 bit prime field
*
* @alias p224
* @alias secp224r1
*/
export const p224 = secp224r1;
/**
* 256 位素域上的 SECG 曲线
*
* SECG curve over a 256 bit prime field
*
* @alias p256
* @alias prime256v1
* @alias secp256r1
*/
export const p256 = secp256r1;
/**
* 384 位素域上的 NIST/SECG 曲线
*
* NIST/SECG curve over a 384 bit prime field
*
* @alias p384
* @alias secp384r1
*/
export const p384 = secp384r1;
/**
* 521 位素域上的 NIST/SECG 曲线
*
* NIST/SECG curve over a 521 bit prime field
*
* @alias p521
* @alias secp521r1
*/
export const p521 = secp521r1;
/**
* NIST W-25519 是与 Curve25519 同构的 Weierstrass 曲线
*
* NIST W-25519 is a Weierstrass curve isomorphic to Curve25519
*/
export const w25519 = Object.freeze({
type: 'Weierstrass',
p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
a: 0x2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa984914a144n,
b: 0x7b425ed097b425ed097b425ed097b425ed097b425ed097b4260b5e9c7710c864n,
G: {
isInfinity: false,
x: 0x2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaad245an,
y: 0x5f51e65e475f794b1fe122d388b72eb36dc2b28192839e4dd6163a5d81312c14n,
},
n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,
h: 8n,
});
/**
* NIST W-448 是与 Curve448 同构的 Weierstrass 曲线
*
* NISt W-448 is a Weierstrass curve isomorphic to Curve448
*/
export const w448 = Object.freeze({
type: 'Weierstrass',
p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
a: 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9fffffffffffffffffffffffffffffffffffffffffffffffe1a76d41fn,
b: 0x5ed097b425ed097b425ed097b425ed097b425ed097b425ed097b425e71c71c71c71c71c71c71c71c71c71c71c71c71c71c72c87b7cc69f70n,
G: {
isInfinity: false,
x: 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000000000000000000000000000000000000000000000000000cb91n,
y: 0x7d235d1295f5b1f66c98ab6e58326fcecbae5d34f55545d060f75dc28df3f6edb8027e2346430d211312c4b150677af76fd7223d457b5b1an,
},
n: 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3n,
h: 4n,
});
/**
* 素域 p^255 - 19 上的 NIST Montgomery 曲线
*
* NIST Montgomery curve over a prime field p^255 - 19
*/
export const curve25519 = Object.freeze({
type: 'Montgomery',
p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
a: 486662n,
b: 1n,
G: {
isInfinity: false,
x: 9n,
y: 0x5f51e65e475f794b1fe122d388b72eb36dc2b28192839e4dd6163a5d81312c14n,
},
n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,
h: 8n,
});
/**
* 素域 p^448 - 2^224 - 1 上的 NIST Montgomery 曲线
*
* NIST Montgomery curve over a prime field p^448 - 2^224 - 1
*/
export const curve448 = Object.freeze({
type: 'Montgomery',
p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
a: 156326n,
b: 1n,
G: {
isInfinity: false,
x: 5n,
y: 0x7d235d1295f5b1f66c98ab6e58326fcecbae5d34f55545d060f75dc28df3f6edb8027e2346430d211312c4b150677af76fd7223d457b5b1an,
},
n: 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3n,
h: 4n,
});
/**
* ed25519 是与 Curve25519 同构的 Twisted Edwards 曲线
*
* ed25519 is a Twisted Edwards curve isomorphic to Curve25519
*/
export const ed25519 = Object.freeze({
type: 'TwistedEdwards',
p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
a: -1n,
d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,
G: {
isInfinity: false,
x: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,
y: 0x6666666666666666666666666666666666666666666666666666666666666658n,
},
n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,
h: 8n,
});
/**
* ed448 是与 Curve448 同构的 Twisted Edwards 曲线
*
* ed448 is a Twisted Edwards curve isomorphic to Curve448
*/
export const ed448 = Object.freeze({
type: 'TwistedEdwards',
p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
a: 1n,
d: -39081n,
G: {
isInfinity: false,
x: 0x4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05en,
y: 0x693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14n,
},
n: 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3n,
h: 4n,
});
// * Brainpool Prime Curves
/**
* 160 位素域上的 RFC 5639 曲线
*
* RFC 5639 curve over a 160 bit prime field
*/
export const bp160r1 = Object.freeze({
type: 'Weierstrass',
p: 0xe95e4a5f737059dc60dfc7ad95b3d8139515620fn,
a: 0x340e7be2a280eb74e2be61bada745d97e8f7c300n,
b: 0x1e589a8595423412134faa2dbdec95c8d8675e58n,
G: {
isInfinity: false,
x: 0xbed5af16ea3f6a4f62938c4631eb5af7bdbcdbc3n,
y: 0x1667cb477a1a8ec338f94741669c976316da6321n,
},
n: 0xe95e4a5f737059dc60df5991d45029409e60fc09n,
h: 1n,
});
/**
* 192 位素域上的 RFC 5639 曲线
*
* RFC 5639 curve over a 192 bit prime field
*/
export const bp192r1 = Object.freeze({
type: 'Weierstrass',
p: 0xc302f41d932a36cda7a3463093d18db78fce476de1a86297n,
a: 0x6a91174076b1e0e19c39c031fe8685c1cae040e5c69a28efn,
b: 0x469a28ef7c28cca3dc721d044f4496bcca7ef4146fbf25c9n,
G: {
isInfinity: false,
x: 0xc0a0647eaab6a48753b033c56cb0f0900a2f5c4853375fd6n,
y: 0x14b690866abd5bb88b5f4828c1490002e6773fa2fa299b8fn,
},
n: 0xc302f41d932a36cda7a3462f9e9e916b5be8f1029ac4acc1n,
h: 1n,
});
/**
* 224 位素域上的 RFC 5639 曲线
*
* RFC 5639 curve over a 224 bit prime field
*/
export const bp224r1 = Object.freeze({
type: 'Weierstrass',
p: 0xd7c134aa264366862a18302575d1d787b09f075797da89f57ec8c0ffn,
a: 0x68a5e62ca9ce6c1c299803a6c1530b514e182ad8b0042a59cad29f43n,
b: 0x2580f63ccfe44138870713b1a92369e33e2135d266dbb372386c400bn,
G: {
isInfinity: false,
x: 0x0d9029ad2c7e5cf4340823b2a87dc68c9e4ce3174c1e6efdee12c07dn,
y: 0x58aa56f772c0726f24c6b89e4ecdac24354b9e99caa3f6d3761402cdn,
},
n: 0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939fn,
h: 1n,
});
/**
* 256 位素域上的 RFC 5639 曲线
*
* RFC 5639 curve over a 256 bit prime field
*/
export const bp256r1 = Object.freeze({
type: 'Weierstrass',
p: 0xa9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5377n,
a: 0x7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9n,
b: 0x26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6n,
G: {
isInfinity: false,
x: 0x8bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262n,
y: 0x547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f046997n,
},
n: 0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7n,
h: 1n,
});
/**
* 320 位素域上的 RFC 5639 曲线
*
* RFC 5639 curve over a 320 bit prime field
*/
export const bp320r1 = Object.freeze({
type: 'Weierstrass',
p: 0xd35e472036bc4fb7e13c785ed201e065f98fcfa6f6f40def4f92b9ec7893ec28fcd412b1f1b32e27n,
a: 0x3ee30b568fbab0f883ccebd46d3f3bb8a2a73513f5eb79da66190eb085ffa9f492f375a97d860eb4n,
b: 0x520883949dfdbc42d3ad198640688a6fe13f41349554b49acc31dccd884539816f5eb4ac8fb1f1a6n,
G: {
isInfinity: false,
x: 0x43bd7e9afb53d8b85289bcc48ee5bfe6f20137d10a087eb6e7871e2a10a599c710af8d0d39e20611n,
y: 0x14fdd05545ec1cc8ab4093247f77275e0743ffed117182eaa9c77877aaac6ac7d35245d1692e8ee1n,
},
n: 0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59311n,
h: 1n,
});
/**
* 384 位素域上的 RFC 5639 曲线
*
* RFC 5639 curve over a 384 bit prime field
*/
export const bp384r1 = Object.freeze({
type: 'Weierstrass',
p: 0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123acd3a729901d1a71874700133107ec53n,
a: 0x7bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f8aa5814a503ad4eb04a8c7dd22ce2826n,
b: 0x04a8c7dd22ce28268b39b55416f0447c2fb77de107dcd2a62e880ea53eeb62d57cb4390295dbc9943ab78696fa504c11n,
G: {
isInfinity: false,
x: 0x1d1c64f068cf45ffa2a63a81b7c13f6b8847a3e77ef14fe3db7fcafe0cbd10e8e826e03436d646aaef87b2e247d4af1en,
y: 0x8abe1d7520f9c2a45cb1eb8e95cfd55262b70b29feec5864e19c054ff99129280e4646217791811142820341263c5315n,
},
n: 0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e9046565n,
h: 1n,
});
/**
* 512 位素域上的 RFC 5639 曲线
*
* RFC 5639 curve over a 512 bit prime field
*/
export const bp512r1 = Object.freeze({
type: 'Weierstrass',
p: 0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca703308717d4d9b009bc66842aecda12ae6a380e62881ff2f2d82c68528aa6056583a48f3n,
a: 0x7830a3318b603b89e2327145ac234cc594cbdd8d3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94can,
b: 0x3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94cadc083e67984050b75ebae5dd2809bd638016f723n,
G: {
isInfinity: false,
x: 0x81aee4bdd82ed9645a21322e9c4c6a9385ed9f70b5d916c1b43b62eef4d0098eff3b1f78e2d0d48d50d1687b93b97d5f7c6d5047406a5e688b352209bcb9f822n,
y: 0x7dde385d566332ecc0eabfa9cf7822fdf209f70024a57b1aa000c55b881f8111b2dcde494a5f485e5bca4bd88a2763aed1ca2b2fa8f0540678cd1e0f3ad80892n,
},
n: 0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90069n,
h: 1n,
});
import { wrap } from './utils';
/**
* 散列算法包装器,
* 提供散列算法描述, 以实现 `HMAC` 等拓展算法.
*
* Hash algorithm wrapper,
* provide hash algorithm description to implement extended algorithms such as `HMAC`.
*
* @param {Digest} digest - 摘要函数 / digest function
* @param {HashDescription} description - 算法描述 / algorithm description
*
* ```ts
* const digest: Digest = (M: Uint8Array): U8 => { ... }
* const description: HashDescription = { ... }
* const hash = createHash(digest, description)
* ```
*/
export const createHash = (digest, description) => wrap(digest, description);
/**
* 元组散列算法包装器
*
* Tuple hash algorithm wrapper
*
* @param {TupleDigest} digest - 元组摘要函数 / tuple digest function
* @param {TupleHashDescription} description - 算法描述 / algorithm description
*
* ```ts
* const digest: TupleDigest = (M: Uint8Array[]): U8 => { ... }
* const description: TupleHashDescription = { ... }
* const hash = createTupleHash(digest, description)
* ```
*/
export const createTupleHash = (digest, description) => wrap(digest, description);
export const createKeyHash = (digest, description) => wrap(digest, description);
import { Counter, joinBuffer } from './utils';
/**
* ANSI-X9.63 Key Derivation Function
*
* ANSI-X9.63 密钥派生函数
*/
export function x963kdf(hash) {
const d_bit = hash.DIGEST_SIZE << 3;
return (k_bit, ikm, info = new Uint8Array(0)) => {
/** Output Keying Material */
const okm = [];
const counter = new Counter([0, 0, 0, 1]);
for (let okm_bit = 0; okm_bit < k_bit; okm_bit += d_bit) {
const data = joinBuffer(ikm, counter, info);
okm.push(hash(data));
counter.inc();
}
return joinBuffer(...okm).slice(0, k_bit >> 3);
};
}
/**
* HMAC-based Key Derivation Function (HKDF), please combine `hmac` and `hash` externally to control the behavior of calling `hmac` inside the function.
*
* 基于 HMAC 的密钥派生函数 (HKDF), 请在外部组合 `hmac` 和 `hash` 函数, 以控制在函数内部调用 `hmac` 时的行为.
*/
export function hkdf(k_hash, salt = new Uint8Array(k_hash.DIGEST_SIZE)) {
const d_bit = k_hash.DIGEST_SIZE << 3;
return (k_bit, ikm, info = new Uint8Array(0)) => {
/** Pseudo-Random Key */
const prk = k_hash(salt, ikm);
/** Output Keying Material */
const okm = [];
const counter = new Uint8Array([1]);
let prv = new Uint8Array(0);
for (let okm_bit = 0; okm_bit < k_bit; okm_bit += d_bit) {
prv = k_hash(prk, joinBuffer(prv, info, counter));
okm.push(prv);
counter[0]++;
}
return joinBuffer(...okm).slice(0, k_bit >> 3);
};
}
/**
* Password-Based Key Derivation Function 2 (PBKDF2), please combine `hmac` and `hash` externally to control the behavior of calling `hmac` inside the function.
* Also, PBKDF2 does not use the `info` parameter, if provided, it will be ignored.
*
* PBKDF2 密码基础密钥派生函数 (PBKDF2), 请在外部组合 `hmac` 和 `hash` 函数, 以控制在函数内部调用 `hmac` 时的行为.
* 同时, PBKDF2 不使用 `info` 参数, 如果提供 `info`, 将被忽略.
*/
export function pbkdf2(k_hash, salt = new Uint8Array(k_hash.DIGEST_SIZE), iterations = 1000) {
const d_bit = k_hash.DIGEST_SIZE << 3;
return (k_bit, ikm) => {
ikm = joinBuffer(ikm);
/** Output Keying Material */
const okm = [];
let T;
let U;
const counter = new Counter([0, 0, 0, 1]);
for (let okm_bit = 0; okm_bit < k_bit; okm_bit += d_bit) {
T = new Uint8Array(k_hash.DIGEST_SIZE);
U = joinBuffer(salt, counter);
for (let i = 0; i < iterations; i++) {
U = k_hash(ikm, U);
T.forEach((_, j) => T[j] ^= U[j]);
}
okm.push(T);
counter.inc();
}
return joinBuffer(...okm).slice(0, k_bit >> 3);
};
}
import { U8, modPow } from './utils';
// * Constants
/** deterministic >= 1 - 0.5^t */
const T = 40;
const LOW_PRIMES = [2n, 3n, 5n, 7n, 11n, 13n, 17n, 19n, 23n, 29n, 31n, 37n, 41n, 43n, 47n, 53n, 59n, 61n, 67n, 71n, 73n, 79n, 83n, 89n, 97n, 101n, 103n, 107n, 109n, 113n, 127n, 131n, 137n, 139n, 149n, 151n, 157n, 163n, 167n, 173n, 179n, 181n, 191n, 193n, 197n, 199n, 211n, 223n, 227n, 229n, 233n, 239n, 241n, 251n, 257n, 263n, 269n, 271n, 277n, 281n, 283n, 293n, 307n, 311n, 313n, 317n, 331n, 337n, 347n, 349n, 353n, 359n, 367n, 373n, 379n, 383n, 389n, 397n, 401n, 409n, 419n, 421n, 431n, 433n, 439n, 443n, 449n, 457n, 461n, 463n, 467n, 479n, 487n, 491n, 499n, 503n, 509n, 521n, 523n, 541n, 547n, 557n, 563n, 569n, 571n, 577n, 587n, 593n, 599n, 601n, 607n, 613n, 617n, 619n, 631n, 641n, 643n, 647n, 653n, 659n, 661n, 673n, 677n, 683n, 691n, 701n, 709n, 719n, 727n, 733n, 739n, 743n, 751n, 757n, 761n, 769n, 773n, 787n, 797n, 809n, 811n, 821n, 823n, 827n, 829n, 839n, 853n, 857n, 859n, 863n, 877n, 881n, 883n, 887n, 907n, 911n, 919n, 929n, 937n, 941n, 947n, 953n, 967n, 971n, 977n, 983n, 991n, 997n];
const LOW_PRIMES_LIMIT = (1n << 26n) / LOW_PRIMES[LOW_PRIMES.length - 1];
// * Functions
/** Miller-Rabin 素性测试 / Primality Test */
function MillerRabin(n, t) {
const n_1 = n - 1n;
let s = 0n;
let d = n_1;
while ((d & 1n) === 0n) {
d >>= 1n;
s++;
}
t = (t + 1) >> 1;
if (t > LOW_PRIMES.length)
t = LOW_PRIMES.length;
const tested = [2n];
for (let i = 0; i < t; ++i) {
// Pick bases at random
let base;
do {
base = LOW_PRIMES[Math.floor(Math.random() * LOW_PRIMES.length)];
} while (tested.includes(base));
tested.push(base);
if (StrongPseudoPrime(n, n_1, s, d, base) === false) {
return false;
}
}
return true;
}
/**
* 根据费马小定理: `base^(n-1) ≡ 1 (mod n)` 时 `n` 可能是素数,
* 通过将 `n-1` 分解为 `2^s * d` 优化计算
*
* According to Fermat's Little Theorem: `base^(n-1) ≡ 1 (mod n)` when `n` may be a prime,
* optimize the calculation by decomposing `n-1` into `2^s * d`
*
* @param {bigint} n - 待测试的数
* @param {bigint} n_1 - n - 1
* @param {bigint} s - n - 1 = 2^s * d
* @param {bigint} d - n - 1 = 2^s * d
* @param {bigint} base - 测试基数
*/
function StrongPseudoPrime(n, n_1, s, d, base) {
let x = modPow(base, d, n);
if (x === 1n || x === n_1)
return true;
let y = 0n;
for (let i = 1; i < s; i++) {
y = modPow(x, 2n, n);
if (y === 1n && x !== 1n && x !== n_1)
return false;
x = y;
}
return y === 1n;
}
/**
* 高级素性测试: 确定性 >= 1-.5^t
*
* Advanced primality test: deterministic >= 1-.5^t
*/
function _isProbablePrime(n, t = T) {
// 低素数倍数
for (let i = 1; i < LOW_PRIMES.length;) {
let m = LOW_PRIMES[i];
let j = i + 1;
while (j < LOW_PRIMES.length && m < LOW_PRIMES_LIMIT) {
m *= LOW_PRIMES[j++];
}
m = n % m;
while (i < j) {
if (m % LOW_PRIMES[i++] === 0n)
return false;
}
}
return MillerRabin(n, t);
}
function genPrimeCandidate(buffer) {
crypto.getRandomValues(buffer);
buffer[0] |= 0x80;
let n = buffer.toBI() | 1n;
const n_mod_6 = n % 6n;
if (n_mod_6 !== 1n && n_mod_6 !== 5n)
n += 4n;
return n;
}
/** 随机素数生成器 / Random Prime Generator */
export const genPrime = (b) => {
const buffer = new U8(b >> 3);
let n;
do {
n = genPrimeCandidate(buffer);
} while (!_isProbablePrime(n));
return n;
};
/**
* 素性测试: 确定性 >= 1-.5^t
*
* Primality test: deterministic >= 1-.5^t
*
* @param {bigint} n - 待测试的数 / Number to be tested
* @param {number} t - 测试轮数 / Number of tests
*/
export function isProbablePrime(n, t = T) {
if (t <= 0)
return false;
// 偶数
if ((n & 1n) === 0n)
return false;
// 六倍原理
const n_mod_6 = n % 6n;
if (n_mod_6 !== 1n && n_mod_6 !== 5n)
return false;
// 小素数
if (n <= LOW_PRIMES[LOW_PRIMES.length - 1])
return LOW_PRIMES.includes(n);
return _isProbablePrime(n, t);
}
import { UTF8 } from './codec';
// * Math utility functions
/** 32-bit 循环左移 */
export function rotateL32(x, n) {
x >>>= 0;
n %= 32;
x = (x << n) | (x >>> (32 - n));
return x >>> 0;
}
/** 32-bit 循环右移 */
export function rotateR32(x, n) {
x >>>= 0;
n %= 32;
x = (x >>> n) | (x << (32 - n));
return x >>> 0;
}
/**
* 位循环左移 / Rotate Left
*
* @param {number} bit - 位数 / bit
* @param {number | bigint} x - 数值 / value
* @param {number | bigint} n - 位移 / shift
* @param {bigint} [mask] - 位掩码 / bit mask
*/
export function rotateL(bit, x, n, mask) {
bit = BigInt(bit);
mask ??= genBitMask(bit);
x = BigInt(x);
n = BigInt(n);
x &= mask;
n %= bit;
x = (x << n) | (x >> (bit - n));
return x & mask;
}
/**
* 位循环右移 / Rotate Right
*
* @param {number} bit - 位数 / bit
* @param {number | bigint} x - 数值 / value
* @param {number | bigint} n - 位移 / shift
* @param {bigint} [mask] - 位掩码 / bit mask
*/
export function rotateR(bit, x, n, mask) {
bit = BigInt(bit);
mask ??= genBitMask(bit);
x = BigInt(x);
n = BigInt(n);
x &= mask;
n %= bit;
x = (x >> n) | (x << (bit - n));
return x & mask;
}
/** 生成随机大整数 / Generate Random BigInt */
export function genRandomBI(max, byte) {
let result = 0n;
// 生成随机数
const buffer = new U8(byte);
do {
crypto.getRandomValues(buffer);
result = buffer.toBI();
} while (result >= max);
return { buffer, result };
}
/**
* 获取大整数的比特长度
*
* Get the bit length of a BigInt
*/
export function getBIBits(n) {
let bit = 0;
while (n > 0) {
bit++;
n >>= 1n;
}
return bit;
}
/**
* 生成位掩码 / Generate Bit Mask
*
* @param {number} w - 位数 / bit
*
* ```ts
* const mask = genBitMask(8) // 0xFFn
* ```
*/
export function genBitMask(w) {
w = BigInt(w);
let mask = 0x0n;
for (let i = 0; i < w; i++) {
mask = (mask << 1n) | 1n;
}
return mask;
}
/**
* 扩展欧几里得算法
*
* Extended Euclidean Algorithm
*
* - gcd: 最大公约数 / greatest common divisor
* - a_inv: a 的模逆 / modular inverse of a
* - b_inv: b 的模逆 / modular inverse of b
*/
function extendedEuclidean(a, b) {
let [s0, s1, t0, t1, r0, r1] = [1n, 0n, 0n, 1n, a, b];
if (b === 0n) {
return {
gcd: a,
a_inv: 1n,
b_inv: 0n,
};
}
while (r1 !== 0n) {
const q = r0 / r1;
[r0, r1] = [r1, r0 - q * r1];
[s0, s1] = [s1, s0 - q * s1];
[t0, t1] = [t1, t0 - q * t1];
}
return {
gcd: r0,
a_inv: s0,
b_inv: t0,
};
}
/**
* 勒让德符号
*
* Legendre Symbol
*/
function legendreSymbol(a, p) {
return modPow(a, (p - 1n) >> 1n, p);
}
/**
* 托内利-香克斯算法
*
* Tonelli-Shanks Algorithm
*/
function tonelliShanks(a, p) {
if (legendreSymbol(a, p) !== 1n) {
throw new KitError('There is no square root');
}
if (a === 0n) {
return 0n;
}
if (p === 2n) {
return a;
}
if (p % 4n === 3n) {
return modPow(a, (p + 1n) >> 2n, p);
}
let q = p - 1n;
let s = 0n;
while (mod(q, 2n) === 0n) {
q >>= 1n;
s++;
}
let z = 2n;
while (legendreSymbol(z, p) !== p - 1n) {
z++;
}
let m = s;
let c = modPow(z, q, p);
let t = modPow(a, q, p);
let r = modPow(a, (q + 1n) >> 1n, p);
while (t !== 0n && t !== 1n) {
let t2i = t;
let i = 1n;
for (; i < m; i++) {
t2i = modPow(t2i, 2n, p);
if (t2i === 1n) {
break;
}
}
const b = modPow(c, 1n << (m - i - 1n), p);
m = i;
c = modPow(b, 2n, p);
t = t * c % p;
r = r * b % p;
}
return r;
}
/**
* 最大公约数
*
* Greatest Common Divisor
*/
export function gcd(a, b) {
return extendedEuclidean(a, b).gcd;
}
/**
* 最小公倍数
*
* Least Common Multiple
*/
export function lcm(a, b) {
return a * b / gcd(a, b);
}
/**
* 求模: a mod b
*
* Modulo operation: a mod b
*
* @param {bigint} a - dividend
* @param {bigint} b - divisor
*/
export function mod(a, b) {
const r = a % b;
return r < 0n ? r + b : r;
}
/**
* 模幂运算: x ^ y mod n
*
* Modular exponentiation: x ^ y mod n
*
* @param {bigint} x - base
* @param {bigint} y - exponent
* @param {bigint} n - modulus
*/
export function modPow(x, y, n) {
x %= n;
let r = 1n;
while (y > 0n) {
if (y & 1n)
r = r * x % n;
x = x * x % n;
y >>= 1n;
}
return r;
}
/**
* 模逆运算: e ≡ x ^ -1 (mod n)
*
* Modular inverse operation: e ≡ x ^ -1 (mod n)
*
* @param {bigint} x - base
* @param {bigint} n - modulus
*/
export function modInverse(x, n) {
const { gcd, a_inv: inv } = extendedEuclidean(x, n);
if (gcd !== 1n) {
throw new KitError('Modular inverse does not exist');
}
return mod(inv, n);
}
/**
* 模素平方根运算: n ^ 0.5 (mod p)
*
* Modular prime square operation: n ^ 0.5 (mod p)
*/
export function modPrimeSquare(n, p) {
n = mod(n, p);
return tonelliShanks(n, p);
}
// * Buffer utility functions
/**
* @extends Uint8Array
*/
export class U8 extends Uint8Array {
/**
* 从 U8 中获取一个字 / Get a word from U8
*
* @param {number} word_byte - 字长 / word size
* @param {number} index - 字索引 / word index
* @param {boolean} [little_endian] - 是否为小端序 / little-endian (default: false)
*/
getWord(word_byte, index, little_endian = false) {
const offset = index * word_byte;
const buffer = this.subarray(offset, offset + word_byte);
return little_endian ? buffer.toBI(true) : buffer.toBI();
}
/**
* 将一个字写入 U8 / Set a word to U8
*
* @param {number} word_byte - 字长 / word size
* @param {number} index - 字索引 / word index
* @param {bigint | Uint8Array} word - 字 / word
* @param {boolean} [little_endian] - 是否为小端序 / little-endian (default: false)
*/
setWord(word_byte, index, word, little_endian = false) {
const offset = index * word_byte;
const buffer = typeof word === 'bigint' ? U8.fromBI(word, word_byte) : word;
this.set(little_endian ? buffer.toReversed() : buffer, offset);
}
/**
* U8 视图 / U8 view
*
* @param {number} word_byte - 字长 / word size
*/
view(word_byte) {
const length = Math.floor(this.length / word_byte);
const get = (index, little_endian = false) => this.getWord(word_byte, index, little_endian);
const set = (index, word, little_endian = false) => this.setWord(word_byte, index, word, little_endian);
return { get, set, length };
}
/**
* 将 U8 编码为字符串 / stringify U8 to encoded string
*/
to(codec) {
return codec(this);
}
/**
* 将 U8 转换为 BigInt / Convert U8 to BigInt
*
* @param {boolean} [little_endian] - 是否为小端序 / little-endian (default: false)
*/
toBI(little_endian = false) {
const buffer = little_endian ? this.toReversed() : this;
let bigint = 0n;
buffer.forEach(byte => bigint = (bigint << 8n) | BigInt(byte));
return bigint;
}
/**
* Convert U8 to Uint8Array
*
* 将 U8 转换为 Uint8Array
*/
toUint8Array() {
return new Uint8Array(this);
}
/**
* Convert string to U8 (default encoding: UTF-8)
*
* 将 字符串 转换为 U8 (默认编码: UTF-8)
*
*/
static fromString(input, codec = UTF8) {
return codec(input);
}
/**
* Convert BigInt to U8
*
* 将 BigInt 转换为 U8
*/
static fromBI(bigint, length, little_endian = false) {
length = length || (getBIBits(bigint) + 7) >> 3;
const buffer = new U8(length);
if (little_endian) {
for (let i = 0; i < buffer.length; i++) {
buffer[i] = Number(bigint & 0xffn);
bigint >>= 8n;
}
}
else {
for (let i = buffer.length - 1; i >= 0; i--) {
buffer[i] = Number(bigint & 0xffn);
bigint >>= 8n;
}
}
return buffer;
}
static from(arrayLike, mapfn, thisArg) {
return new U8(super.from(arrayLike, mapfn, thisArg));
}
filter(predicate, thisArg) {
return new U8(super.filter(predicate, thisArg));
}
map(callbackfn, thisArg) {
return new U8(super.map(callbackfn, thisArg));
}
static of(...items) {
return new U8(super.of(...items));
}
toReversed() {
return super.reverse();
}
toSorted(compareFn) {
return super.sort(compareFn);
}
reverse() {
return super.reverse();
}
slice(start, end) {
return new U8(super.slice(start, end));
}
subarray(begin, end) {
return new U8(super.subarray(begin, end));
}
with(index, value) {
return new U8(super.with(index, value));
}
}
/**
* Merging multiple ArrayBuffers
*
* 合并多个 ArrayBuffer
*/
export function joinBuffer(...buffers) {
const byteTotal = buffers.reduce((acc, cur) => acc + cur.byteLength, 0);
const result = new U8(byteTotal);
let offset = 0;
for (const buffer of buffers) {
result.set(new U8(buffer), offset);
offset += buffer.byteLength;
}
return result;
}
/**
* resize ArrayBuffer
*
* 调整 ArrayBuffer 大小
*
* @param {ArrayBuffer} buffer
* @param {number} size - byte
*/
export function resizeBuffer(buffer, size) {
const B = new U8(size);
B.set(new U8(buffer));
return B;
}
const nibbleReverseMap = [0x0n, 0x8n, 0x4n, 0xcn, 0x2n, 0xan, 0x6n, 0xen, 0x1n, 0x9n, 0x5n, 0xdn, 0x3n, 0xbn, 0x7n, 0xfn];
/**
* 快速翻转字节位序 / Fast Reverse Byte's Bit Order
*
* @param {number} byte - 字节 / byte
*/
export function reverseBit(byte) {
byte &= 0xFF;
const b_h = nibbleReverseMap[byte >> 4];
const b_l = nibbleReverseMap[byte & 0xF];
return (b_l << 4n) | b_h;
}
export class Counter extends U8 {
/**
* @param {number} offset - 计数器偏移 / counter offset
* @param {number} length - 计数器长度 / counter length
*/
inc(offset, length, little_endian = false) {
// 如果不提供偏移,则默认计数器从 0 开始
offset = offset || 0;
if (offset < 0 || offset >= this.length) {
throw new KitError('Invalid counter offset');
}
// 如果不提供长度,则默认计数器长度为剩余长度
length = length || this.length - offset;
if (length < 0 || offset + length > this.length) {
throw new KitError('Invalid counter length');
}
if (little_endian) {
for (let i = offset; i < offset + length; i++) {
if (this[i] < 0xFF) {
this[i] += 1;
break;
}
this[i] = 0;
}
}
else {
for (let i = offset + length - 1; i >= offset; i--) {
if (this[i] < 0xFF) {
this[i] += 1;
break;
}
this[i] = 0;
}
}
}
}
// * Other utility functions
export function wrap(...args) {
if (args.length === 0) {
return {};
}
// @ts-expect-error Object assign
return Object.assign(...args);
}
export class KitError extends Error {
constructor(message) {
super(message);
this.name = 'mima-kit Error';
}
}
import { createKeyHash } from '../core/hash';
import { joinBuffer } from '../core/utils';
function _hmac(hash, K, M) {
const { BLOCK_SIZE } = hash;
const K0 = new Uint8Array(BLOCK_SIZE);
K0.set(K.length > BLOCK_SIZE ? hash(K) : K);
const iPad = K0.map(byte => (byte ^ 0x36));
const oPad = K0.map(byte => (byte ^ 0x5C));
const innerBuffer = hash(joinBuffer(iPad, M));
const outerBuffer = hash(joinBuffer(oPad, innerBuffer));
return outerBuffer;
}
/**
* FIPS.198-1: 散列消息认证码 (HMAC).
* 如果 `d_size` 大于散列算法的摘要大小, 则回退到散列算法的摘要大小.
*
* FIPS.198-1: The Keyed-Hash Message Authentication Code (HMAC).
* If `d_size` is larger than the hash algorithm's digest size, fallback to the hash algorithm's digest size.
*
* @param {Hash} hash - 散列算法 / hash algorithm
* @param {number} [d_size] - 摘要大小 (bit) / digest size (bit)
* @param {number} [k_size] - 推荐密钥大小 (bit) / recommended key size (bit)
*/
export function hmac(hash, d_size, k_size) {
const { ALGORITHM, BLOCK_SIZE, DIGEST_SIZE } = hash;
d_size = d_size ? Math.min(d_size >> 3, DIGEST_SIZE) : DIGEST_SIZE;
k_size = k_size ? k_size >> 3 : DIGEST_SIZE;
const description = {
ALGORITHM: `HMAC-${ALGORITHM}-${d_size << 3}`,
BLOCK_SIZE,
DIGEST_SIZE: d_size,
KEY_SIZE: k_size,
};
return createKeyHash((K, M) => _hmac(hash, K, M).slice(0, d_size), description);
}
import { createHash } from '../core/hash';
import { joinBuffer } from '../core/utils';
import { turboshake128, turboshake256 } from './turboSHAKE';
function lengthEncode(x) {
const S = [];
while (x > 0) {
S.unshift(x & 0xFF);
x >>= 8;
}
S.push(S.length);
return new Uint8Array(S);
}
/**
* KangarooTwelve
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} C - 自定义参数 / Customization
* @param {typeof turboshake128} SHAKE - TurboSHAKE 函数 / Function
* @param {number} cv - 中间压缩值长度 / Compressed Value Size (bit)
*/
function kt(d, C, SHAKE, cv) {
return (M) => {
const length_encode = lengthEncode(C.length);
const S = joinBuffer(M, C, length_encode);
if (S.length <= 8192) {
return SHAKE(d, 0x07)(S);
}
else {
// KangarooTwelve hopping
const FinalNode = [];
FinalNode.push(S.slice(0, 8192));
FinalNode.push(new Uint8Array([0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]));
let offset = 8192;
let num_block = 0;
while (offset < S.length) {
const CV = SHAKE(cv, 0x0B)(S.slice(offset, offset += 8192));
FinalNode.push(CV);
num_block++;
}
FinalNode.push(lengthEncode(num_block));
FinalNode.push(new Uint8Array([0xFF, 0xFF]));
return SHAKE(d, 0x06)(joinBuffer(...FinalNode));
}
};
}
/**
* KangarooTwelve 128
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} [C] - 自定义参数 / Customization
*/
export function kt128(d, C = new Uint8Array()) {
return createHash(kt(d, C, turboshake128, 256), {
ALGORITHM: `KangarooTwelve128/${d}`,
BLOCK_SIZE: 8192,
DIGEST_SIZE: d >> 3,
});
}
/**
* KangarooTwelve 256
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} [C] - 自定义参数 / Customization
*/
export function kt256(d, C = new Uint8Array()) {
return createHash(kt(d, C, turboshake256, 512), {
ALGORITHM: `KangarooTwelve256/${d}`,
BLOCK_SIZE: 8192,
DIGEST_SIZE: d >> 3,
});
}
import { KitError, U8, genBitMask, joinBuffer, rotateL } from '../core/utils';
// * Constants
/**
* ρ(A) 位移表 / Shift Table
*/
const R = [
[0n, 36n, 3n, 41n, 18n],
[1n, 44n, 10n, 45n, 2n],
[62n, 6n, 43n, 15n, 61n],
[28n, 55n, 25n, 21n, 56n],
[27n, 20n, 39n, 8n, 14n],
];
/**
* https://datatracker.ietf.org/doc/draft-irtf-cfrg-kangarootwelve/
*/
const RC12 = [
0x000000008000808bn,
0x800000000000008bn,
0x8000000000008089n,
0x8000000000008003n,
0x8000000000008002n,
0x8000000000000080n,
0x000000000000800an,
0x800000008000000an,
0x8000000080008081n,
0x8000000000008080n,
0x0000000080000001n,
0x8000000080008008n,
];
/**
* `RCGen(6, 24)`
*/
const RC24 = [
0x0000000000000001n,
0x0000000000008082n,
0x800000000000808an,
0x8000000080008000n,
0x000000000000808bn,
0x0000000080000001n,
0x8000000080008081n,
0x8000000000008009n,
0x000000000000008an,
0x0000000000000088n,
0x0000000080008009n,
0x000000008000000an,
0x000000008000808bn,
0x800000000000008bn,
0x8000000000008089n,
0x8000000000008003n,
0x8000000000008002n,
0x8000000000000080n,
0x000000000000800an,
0x800000008000000an,
0x8000000080008081n,
0x8000000000008080n,
0x0000000080000001n,
0x8000000080008008n,
];
const mask64 = genBitMask(64);
const rotateL64 = (x, n) => rotateL(64, x, n, mask64);
// * Keccak Utils
/**
* RC Table Generation Function
*
* @param {number} l - log2(w)
* @param {number} [nr] - 轮数
*/
export function RCGen(l = 6, nr = 24) {
const RCTable = [];
for (let ir = 0; ir < nr; ir++) {
let RC = 0n;
for (let j = 0; j <= l; j++) {
const t = j + 7 * ir;
// rc(t)
let rc;
if (t % 255 === 0) {
rc = 1n;
}
else {
let R = 0x80n;
for (let i = 1; i <= t % 255; i++) {
const b = R & 1n;
R ^= (b << 8n) | (b << 4n) | (b << 3n) | (b << 2n);
R >>= 1n;
}
rc = R >> 7n;
}
// RC[2^j - 1] = rc(j + 7ir)
RC |= (rc << BigInt(2 ** j - 1));
}
RCTable.push(RC);
}
return RCTable;
}
/**
* @param {number} w - 工作字长度 / Word Size
*/
export function RGen(w) {
w = BigInt(w);
const R = [
[0n, 36n, 3n, 105n, 210n],
[1n, 300n, 10n, 45n, 66n],
[190n, 6n, 171n, 15n, 253n],
[28n, 276n, 120n, 136n, 55n],
[91n, 276n, 210n, 66n, 253n],
];
return R.map(x => x.map(y => y % w));
}
/**
* create a 5x5 `State Array`
*
* 创建一个 5x5 `状态矩阵`
*/
function createStateArray() {
return Array.from({ length: 5 }).map(() => new BigUint64Array(5));
}
/**
* Converting `State` to `State Arrays`
*
* 将 `状态` 转换为 `状态矩阵`
*/
function toStateArray(S) {
const A = createStateArray();
const view = new DataView(S.buffer);
for (let x = 0; x < 5; x++) {
for (let y = 0; y < 5; y++) {
A[x][y] = view.getBigUint64((y * 5 + x) << 3, true);
}
}
return A;
}
/**
* Converting `State Arrays` to `State`
*
* 将 `状态矩阵` 转换为 `状态`
*/
function toState(A) {
const S = new Uint8Array(200);
const view = new DataView(S.buffer);
for (let x = 0; x < 5; x++) {
for (let y = 0; y < 5; y++) {
view.setBigUint64((y * 5 + x) << 3, A[x][y], true);
}
}
return S;
}
// * Mapping Function
/** Algorithm 1: θ(A) */
function theta(A) {
const C = new BigUint64Array(5);
const D = new BigUint64Array(5);
for (let x = 0; x < 5; x++) {
C[x] = A[x][0] ^ A[x][1] ^ A[x][2] ^ A[x][3] ^ A[x][4];
}
for (let x = 0; x < 5; x++) {
D[x] = C[(x + 4) % 5] ^ rotateL64(C[(x + 1) % 5], 1n);
for (let y = 0; y < 5; y++) {
A[x][y] = A[x][y] ^ D[x];
}
}
return A;
}
/** Algorithm 2: ρ(A) */
// eslint-disable-next-line unused-imports/no-unused-vars
function rho(A) {
const _A = createStateArray();
for (let x = 0; x < 5; x++) {
for (let y = 0; y < 5; y++) {
_A[x][y] = rotateL64(A[x][y], R[x][y]);
}
}
return _A;
}
/** Algorithm 3: π(A) */
// eslint-disable-next-line unused-imports/no-unused-vars
function pi(A) {
const _A = createStateArray();
for (let x = 0; x < 5; x++) {
for (let y = 0; y < 5; y++) {
_A[x][y] = A[(x + 3 * y) % 5][x];
}
}
return _A;
}
/**
* Combining π(ρ(A))
*
* 合并执行 π(ρ(A))
*/
function rhoPi(A) {
const _A = createStateArray();
for (let x = 0; x < 5; x++) {
for (let y = 0; y < 5; y++) {
_A[y][(2 * x + 3 * y) % 5] = rotateL64(A[x][y], R[x][y]);
}
}
return _A;
}
/** Algorithm 4: χ(A) */
function chi(A) {
const _A = createStateArray();
for (let x = 0; x < 5; x++) {
for (let y = 0; y < 5; y++) {
_A[x][y] = A[x][y] ^ ((~A[(x + 1) % 5][y]) & A[(x + 2) % 5][y]);
}
}
return _A;
}
/** Algorithm 6: ι(A, ir) */
function iota(A, RC) {
A[0][0] = A[0][0] ^ RC;
return A;
}
/**
* `Keccak-p[1600, nr]` 置换函数 / Permutate Function
*
* @param {number} [nr] - 轮数 / Rounds (default: 24)
*/
export function keccak_p_1600(nr = 24) {
// b = 1600
const bByte = 200;
const l = 6;
// 当轮数非默认的情况下,重新生成 RC
let RC;
if (nr === 12) {
RC = RC12;
}
else if (nr === 24) {
RC = RC24;
}
else {
RC = RCGen(l, nr);
}
return (S) => {
if (S.byteLength !== bByte) {
throw new KitError('Invalid state size');
}
let A = toStateArray(S);
for (let i = 0; i < nr; i++) {
A = iota(chi(rhoPi(theta(A))), RC[i]);
}
return new U8(toState(A));
};
}
/**
* `SPONGE` & `Keccak-p[1600]`
*
* @param {number} r_byte - 处理速率 / Rate
* @param {number} d_byte - 输出长度 / Digest Size
* @param {SpongePadding} pad - 填充函数 / Padding Function
* @param {Keccak_p} f - Keccak-p 置换函数 / Permutate Function
*/
export function sponge_1600(r_byte, d_byte, pad, f = keccak_p_1600()) {
return (M) => {
// * 填充
const P = pad(M);
// * 吸收
let S = new Uint8Array(200);
let i = 0;
while (i < P.byteLength) {
const Pi = P.slice(i, i += r_byte);
S.forEach((byte, index) => S[index] = byte ^ Pi[index]);
S = f(S);
}
// * 挤出
const z = [S.slice(0, r_byte)];
let z_byte = r_byte;
while (z_byte < d_byte) {
S = f(S);
z.push(S.slice(0, r_byte));
z_byte += r_byte;
}
// * 截断输出
return joinBuffer(...z).slice(0, d_byte);
};
}
import { createHash } from '../core/hash';
import { U8, rotateL32 } from '../core/utils';
// * Constants
/**
* 轮常量列表 K 由 64 个 32 位无符号整数组成, 使用 1 到 64 的正弦函数生成.
*
* The round constants K is a list of 64 32-bit unsigned integers,
* generated by the sine function from 1 to 64.
*
* ```ts
* const K: number[] = []
* for (let i = 0; i < 64; i++) {
* K[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) >>> 0
* }
* ```
*/
const K = new Uint32Array([0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE, 0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501, 0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE, 0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821, 0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA, 0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8, 0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED, 0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A, 0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C, 0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70, 0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05, 0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665, 0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039, 0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1, 0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1, 0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391]);
// * Function
function FF(a, b, c, d, m, s, k) {
const n = a + ((b & c) | (~b & d)) + m + k;
return rotateL32(n, s) + b;
}
function GG(a, b, c, d, m, s, k) {
const n = a + ((b & d) | (c & ~d)) + m + k;
return rotateL32(n, s) + b;
}
function HH(a, b, c, d, m, s, k) {
const n = a + (b ^ c ^ d) + m + k;
return rotateL32(n, s) + b;
}
function II(a, b, c, d, m, s, k) {
const n = a + (c ^ (b | ~d)) + m + k;
return rotateL32(n, s) + b;
}
// * Algorithm
function digest(message) {
// * 初始化
const state = new Uint32Array([0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476]);
const m_byte = message.length;
const m_bit = BigInt(m_byte) << 3n;
const block_size = 64;
// ceil((M_BYTE + 9) / 64)
const block_total = (m_byte + 9 + 63) >> 6;
// * 填充
const p = new U8(block_total * block_size);
p.set(message);
// appending the bit '1' to the message
p[m_byte] = 0x80;
// appending length
const p_view = new DataView(p.buffer);
p_view.setBigUint64(p.length - 8, m_bit, true);
// * 分块处理
for (let offset = 0; offset < p.length;) {
// 获取分块
const current_buffer = p.subarray(offset, offset += block_size).buffer;
// 准备状态字
const A = state[0];
const B = state[1];
const C = state[2];
const D = state[3];
let a = A;
let b = B;
let c = C;
let d = D;
// 划分词典
const M = new Uint32Array(current_buffer);
/* Round 1 */
a = FF(a, b, c, d, M[0], 7, K[0]);
d = FF(d, a, b, c, M[1], 12, K[1]);
c = FF(c, d, a, b, M[2], 17, K[2]);
b = FF(b, c, d, a, M[3], 22, K[3]);
a = FF(a, b, c, d, M[4], 7, K[4]);
d = FF(d, a, b, c, M[5], 12, K[5]);
c = FF(c, d, a, b, M[6], 17, K[6]);
b = FF(b, c, d, a, M[7], 22, K[7]);
a = FF(a, b, c, d, M[8], 7, K[8]);
d = FF(d, a, b, c, M[9], 12, K[9]);
c = FF(c, d, a, b, M[10], 17, K[10]);
b = FF(b, c, d, a, M[11], 22, K[11]);
a = FF(a, b, c, d, M[12], 7, K[12]);
d = FF(d, a, b, c, M[13], 12, K[13]);
c = FF(c, d, a, b, M[14], 17, K[14]);
b = FF(b, c, d, a, M[15], 22, K[15]);
/* Round 2 */
a = GG(a, b, c, d, M[1], 5, K[16]);
d = GG(d, a, b, c, M[6], 9, K[17]);
c = GG(c, d, a, b, M[11], 14, K[18]);
b = GG(b, c, d, a, M[0], 20, K[19]);
a = GG(a, b, c, d, M[5], 5, K[20]);
d = GG(d, a, b, c, M[10], 9, K[21]);
c = GG(c, d, a, b, M[15], 14, K[22]);
b = GG(b, c, d, a, M[4], 20, K[23]);
a = GG(a, b, c, d, M[9], 5, K[24]);
d = GG(d, a, b, c, M[14], 9, K[25]);
c = GG(c, d, a, b, M[3], 14, K[26]);
b = GG(b, c, d, a, M[8], 20, K[27]);
a = GG(a, b, c, d, M[13], 5, K[28]);
d = GG(d, a, b, c, M[2], 9, K[29]);
c = GG(c, d, a, b, M[7], 14, K[30]);
b = GG(b, c, d, a, M[12], 20, K[31]);
/* Round 3 */
a = HH(a, b, c, d, M[5], 4, K[32]);
d = HH(d, a, b, c, M[8], 11, K[33]);
c = HH(c, d, a, b, M[11], 16, K[34]);
b = HH(b, c, d, a, M[14], 23, K[35]);
a = HH(a, b, c, d, M[1], 4, K[36]);
d = HH(d, a, b, c, M[4], 11, K[37]);
c = HH(c, d, a, b, M[7], 16, K[38]);
b = HH(b, c, d, a, M[10], 23, K[39]);
a = HH(a, b, c, d, M[13], 4, K[40]);
d = HH(d, a, b, c, M[0], 11, K[41]);
c = HH(c, d, a, b, M[3], 16, K[42]);
b = HH(b, c, d, a, M[6], 23, K[43]);
a = HH(a, b, c, d, M[9], 4, K[44]);
d = HH(d, a, b, c, M[12], 11, K[45]);
c = HH(c, d, a, b, M[15], 16, K[46]);
b = HH(b, c, d, a, M[2], 23, K[47]);
/* Round 4 */
a = II(a, b, c, d, M[0], 6, K[48]);
d = II(d, a, b, c, M[7], 10, K[49]);
c = II(c, d, a, b, M[14], 15, K[50]);
b = II(b, c, d, a, M[5], 21, K[51]);
a = II(a, b, c, d, M[12], 6, K[52]);
d = II(d, a, b, c, M[3], 10, K[53]);
c = II(c, d, a, b, M[10], 15, K[54]);
b = II(b, c, d, a, M[1], 21, K[55]);
a = II(a, b, c, d, M[8], 6, K[56]);
d = II(d, a, b, c, M[15], 10, K[57]);
c = II(c, d, a, b, M[6], 15, K[58]);
b = II(b, c, d, a, M[13], 21, K[59]);
a = II(a, b, c, d, M[4], 6, K[60]);
d = II(d, a, b, c, M[11], 10, K[61]);
c = II(c, d, a, b, M[2], 15, K[62]);
b = II(b, c, d, a, M[9], 21, K[63]);
// 更新状态字
state[0] = A + a;
state[1] = B + b;
state[2] = C + c;
state[3] = D + d;
}
// * 返回状态
return new U8(state.buffer);
}
export const md5 = createHash(digest, {
ALGORITHM: 'MD5',
BLOCK_SIZE: 64,
DIGEST_SIZE: 16,
OID: '1.2.840.113549.2.5',
});
import { createHash } from '../core/hash';
import { U8, rotateL32 } from '../core/utils';
// * Constants
function K(t) {
if (t < 20)
return 0x5A827999;
if (t < 40)
return 0x6ED9EBA1;
if (t < 60)
return 0x8F1BBCDC;
return 0xCA62C1D6;
}
// * Function
const Ch = (x, y, z) => (x & y) ^ ((~x) & z);
const Parity = (x, y, z) => x ^ y ^ z;
const Maj = (x, y, z) => (x & y) ^ (x & z) ^ (y & z);
function ft(x, y, z, t) {
if (t < 20)
return Ch(x, y, z);
if (t < 40)
return Parity(x, y, z);
if (t < 60)
return Maj(x, y, z);
return Parity(x, y, z);
}
// * Algorithm
function digest(message) {
// * 初始化
const state = new U8(20);
const state_view = state.view(4);
state_view.set(0, 0x67452301n);
state_view.set(1, 0xefcdab89n);
state_view.set(2, 0x98badcfen);
state_view.set(3, 0x10325476n);
state_view.set(4, 0xc3d2e1f0n);
const m_byte = message.length;
const m_bit = BigInt(m_byte) << 3n;
const block_size = 64;
// ceil((M_BYTE + 9) / 64)
const block_total = (m_byte + 9 + 63) >> 6;
// * 填充
const p = new U8(block_total * block_size);
p.set(message);
// appending the bit '1' to the message
p[m_byte] = 0x80;
// appending length
const p_view = new DataView(p.buffer);
p_view.setBigUint64(p.length - 8, m_bit);
// * 分块处理
for (let offset = 0; offset < p.length; offset += block_size) {
/** B(n) = p[offset:offset + block_size] */
// 准备状态字
const H0 = Number(state_view.get(0));
const H1 = Number(state_view.get(1));
const H2 = Number(state_view.get(2));
const H3 = Number(state_view.get(3));
const H4 = Number(state_view.get(4));
let a = H0;
let b = H1;
let c = H2;
let d = H3;
let e = H4;
// 合并执行 扩展 & 压缩
const W = new Uint32Array(80);
for (let i = 0; i < 80; i++) {
// 扩展
if (i < 16)
// W[i] = B(n)[i]
W[i] = p_view.getUint32(offset + (i << 2));
else
W[i] = rotateL32(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1);
// 压缩
const T = rotateL32(a, 5) + ft(b, c, d, i) + K(i) + e + W[i];
e = d;
d = c;
c = rotateL32(b, 30);
b = a;
a = T;
}
// 更新状态字
state_view.set(0, BigInt(H0 + a));
state_view.set(1, BigInt(H1 + b));
state_view.set(2, BigInt(H2 + c));
state_view.set(3, BigInt(H3 + d));
state_view.set(4, BigInt(H4 + e));
}
// * 返回状态
return state;
}
export const sha1 = createHash(digest, {
ALGORITHM: 'SHA-1',
BLOCK_SIZE: 64,
DIGEST_SIZE: 20,
OID: '1.3.14.3.2.26',
});
import { createHash } from '../core/hash';
import { U8, rotateR32 } from '../core/utils';
// * Constants
const K = new Uint32Array([0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2]);
// * Function
const Ch = (x, y, z) => (x & y) ^ ((~x) & z);
const Maj = (x, y, z) => (x & y) ^ (x & z) ^ (y & z);
const Sigma0 = (x) => rotateR32(x, 2) ^ rotateR32(x, 13) ^ rotateR32(x, 22);
const Sigma1 = (x) => rotateR32(x, 6) ^ rotateR32(x, 11) ^ rotateR32(x, 25);
const sigma0 = (x) => rotateR32(x, 7) ^ rotateR32(x, 18) ^ (x >>> 3);
const sigma1 = (x) => rotateR32(x, 17) ^ rotateR32(x, 19) ^ (x >>> 10);
// * Algorithm
function digest(state, message) {
// * 初始化
state = state.slice(0);
const state_view = state.view(4);
const m_byte = message.length;
const m_bit = BigInt(m_byte) << 3n;
const block_size = 64;
// ceil((m_byte + 9) / 64)
const block_total = (m_byte + 9 + 63) >> 6;
// * 填充
const p = new U8(block_total * block_size);
p.set(message);
// appending the bit '1' to the message
p[m_byte] = 0x80;
// appending length
const p_view = new DataView(p.buffer);
p_view.setBigUint64(p.length - 8, m_bit);
// * 分块处理
for (let offset = 0; offset < p.length; offset += block_size) {
/** B(n) = p[offset:offset + block_size] */
// 准备状态字
const h0 = Number(state_view.get(0));
const h1 = Number(state_view.get(1));
const h2 = Number(state_view.get(2));
const h3 = Number(state_view.get(3));
const h4 = Number(state_view.get(4));
const h5 = Number(state_view.get(5));
const h6 = Number(state_view.get(6));
const h7 = Number(state_view.get(7));
let a = h0;
let b = h1;
let c = h2;
let d = h3;
let e = h4;
let f = h5;
let g = h6;
let h = h7;
// 合并执行 扩展 & 压缩
const W = new Uint32Array(64);
for (let i = 0; i < W.length; i++) {
// 扩展
if (i < 16)
// W[i] = B(n)[i]
W[i] = p_view.getUint32(offset + (i << 2));
else
W[i] = sigma1(W[i - 2]) + W[i - 7] + sigma0(W[i - 15]) + W[i - 16];
// 压缩
const T1 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];
const T2 = Sigma0(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
}
// 更新状态字
state_view.set(0, BigInt(h0 + a));
state_view.set(1, BigInt(h1 + b));
state_view.set(2, BigInt(h2 + c));
state_view.set(3, BigInt(h3 + d));
state_view.set(4, BigInt(h4 + e));
state_view.set(5, BigInt(h5 + f));
state_view.set(6, BigInt(h6 + g));
state_view.set(7, BigInt(h7 + h));
}
// * 返回状态
return state;
}
function sha224Digest(M) {
// * 初始化 SHA-224 状态
const state = new U8(32);
const state_view = state.view(4);
state_view.set(0, 0xc1059ed8n);
state_view.set(1, 0x367cd507n);
state_view.set(2, 0x3070dd17n);
state_view.set(3, 0xf70e5939n);
state_view.set(4, 0xffc00b31n);
state_view.set(5, 0x68581511n);
state_view.set(6, 0x64f98fa7n);
state_view.set(7, 0xbefa4fa4n);
return digest(state, M).slice(0, 28);
}
function sha256Digest(M) {
// * 初始化 SHA-256 状态
const state = new U8(32);
const state_view = state.view(4);
state_view.set(0, 0x6a09e667n);
state_view.set(1, 0xbb67ae85n);
state_view.set(2, 0x3c6ef372n);
state_view.set(3, 0xa54ff53an);
state_view.set(4, 0x510e527fn);
state_view.set(5, 0x9b05688cn);
state_view.set(6, 0x1f83d9abn);
state_view.set(7, 0x5be0cd19n);
return digest(state, M);
}
export const sha224 = createHash(sha224Digest, {
ALGORITHM: 'SHA-224',
BLOCK_SIZE: 64,
DIGEST_SIZE: 28,
OID: '2.16.840.1.101.3.4.2.4',
});
export const sha256 = createHash(sha256Digest, {
ALGORITHM: 'SHA-256',
BLOCK_SIZE: 64,
DIGEST_SIZE: 32,
OID: '2.16.840.1.101.3.4.2.1',
});
import { createHash } from '../core/hash';
import { sponge_1600 } from './keccak1600';
/**
* `SHA3` 填充函数 / Padding Function
*
* ```ts
* M || 01 || 10*1
* ```
*
* @param {number} r_byte - 处理速率 / Rate
*/
const sha3Padding = (r_byte) => {
return (M) => {
const sig_byte = M.length;
const pad_byte = r_byte - (sig_byte % r_byte);
const P = new Uint8Array(sig_byte + pad_byte);
P.set(M);
if (pad_byte === 1) {
P[sig_byte] = 0x86;
}
P[sig_byte] = 0x06;
P[P.length - 1] |= 0x80;
return P;
};
};
/**
* `SHAKE` 填充函数 / Padding Function
*
* ```ts
* M || 1111 || 10*1
* ```
*
* @param {number} r_byte - 处理速率 / Rate
*/
const shakePadding = (r_byte) => {
return (M) => {
const sig_byte = M.length;
const pad_byte = r_byte - (sig_byte % r_byte);
const P = new Uint8Array(sig_byte + pad_byte);
P.set(M);
if (pad_byte === 1) {
P[sig_byte] = 0x9F;
}
P[sig_byte] = 0x1F;
P[P.length - 1] |= 0x80;
return P;
};
};
// * SHA3 Function Specification
/**
* @param {number} c - 安全容量 / Capacity (bit)
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Sha3Padding} padding - 填充函数 / Padding Function
*/
export function Keccak_c(c, d, padding) {
const r = 1600 - c;
const rByte = r >> 3;
const pad = padding(rByte);
return (M) => sponge_1600(rByte, d >> 3, pad)(M);
}
export const sha3_224 = createHash((M) => Keccak_c(448, 224, sha3Padding)(M), {
ALGORITHM: 'SHA3-224',
BLOCK_SIZE: 144,
DIGEST_SIZE: 28,
OID: '2.16.840.1.101.3.4.2.7',
});
export const sha3_256 = createHash((M) => Keccak_c(512, 256, sha3Padding)(M), {
ALGORITHM: 'SHA3-256',
BLOCK_SIZE: 136,
DIGEST_SIZE: 32,
OID: '2.16.840.1.101.3.4.2.8',
});
export const sha3_384 = createHash((M) => Keccak_c(768, 384, sha3Padding)(M), {
ALGORITHM: 'SHA3-384',
BLOCK_SIZE: 104,
DIGEST_SIZE: 48,
OID: '2.16.840.1.101.3.4.2.9',
});
export const sha3_512 = createHash((M) => Keccak_c(1024, 512, sha3Padding)(M), {
ALGORITHM: 'SHA3-512',
BLOCK_SIZE: 72,
DIGEST_SIZE: 64,
OID: '2.16.840.1.101.3.4.2.10',
});
/**
* @param {number} d - 输出长度 / Digest Size (bit)
*/
export function shake128(d) {
return createHash((M) => Keccak_c(256, d, shakePadding)(M), {
ALGORITHM: `SHAKE128/${d}`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
});
}
/**
* @param {number} d - 输出长度 / Digest Size (bit)
*/
export function shake256(d) {
return createHash((M) => Keccak_c(512, d, shakePadding)(M), {
ALGORITHM: `SHAKE256/${d}`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
});
}
import { UTF8 } from '../core/codec';
import { KitError, joinBuffer } from '../core/utils';
import { createHash, createKeyHash, createTupleHash } from '../core/hash';
import { Keccak_c, shake128, shake256 } from './sha3';
// * Encode and Padding Function
/**
* SP.800-185 2.3.1:
*
* 左侧整数编码 / left_encode
*
* Inspired by https://github.com/paulmillr/noble-hashes
*
* ```ts
* leftEncode(0) // Uint8Array(2) [ 1, 0 ]
* leftEncode(18446744073709551615n) // Uint8Array(9) [ 8, 255, 255, 255, 255, 255, 255, 255, 255 ]
* ```
*
* @param {number} x - 输入 / input
*/
function leftEncode(x) {
const result = [];
do {
result.unshift(x & 0xFF);
x = x >> 8;
} while (x > 0);
result.unshift(result.length);
return Uint8Array.from(result);
}
/**
* SP.800-185 2.3.1:
*
* 右侧整数编码 / right_encode
*
* Inspired by https://github.com/paulmillr/noble-hashes
*
* ```ts
* rightEncode(0) // Uint8Array(2) [ 0, 1 ]
* rightEncode(18446744073709551615n) // Uint8Array(9) [ 255, 255, 255, 255, 255, 255, 255, 255, 8 ]
* ```
*
* @param {number | bigint} x - 输入 / input
*/
function rightEncode(x) {
const result = [];
do {
result.unshift(x & 0xFF);
x = x >> 8;
} while (x > 0);
result.push(result.length);
return Uint8Array.from(result);
}
/**
* SP.800-185 2.3.2:
*
* 字符编码 / encode_string
*
* 与规范文档不同, 这个实现不会进行串接操作, 而是返回一个数组, 串接操作在外部进行. 详细见 `bytepad` 函数.
*
* Unlike the specification document, this implementation does not perform concatenation operations, but returns an array, and the concatenation operation is performed externally. See `bytepad` function for details.
*
* ```ts
* encodeString(K) // [left_encode(len(K)), K]
* ```
*
* @param {string | Uint8Array} input - 输入 / input
*/
function encodeString(input) {
input = typeof input === 'string' ? UTF8(input) : input;
return [leftEncode(input.byteLength << 3), input];
}
/**
* SP.800-185 2.3.3:
*
* 在算法中 `bytePad` 涉及很多串接操作, 但对 `Javascript` 实现来说, 每次串接都意味着创建 `Uint8Array` 进行合并. 频繁地创建 `Uint8Array` 有可能导致性能问题.
* 这是一个优化后的实现. 将输入 `X` 改为数组, 最后也返回数组, 将合并操作移动到外部.
*
* The `bytePad` is used by many algorithms which involves many concatenation operations, but for `Javascript` implementation, each concatenation means creating a `Uint8Array` for merging. Frequent creation of `Uint8Array` may cause performance issues.
* This is an optimized implementation. The input `X` is changed to an array, and the final return is also an array. The merge operation is moved to the outside.
*
*
* ```ts
* bytepad(X, w) = left_encode(w) || X0 || ... || Xn || 0^z
* ```
*
* @param {Uint8Array} X - 输入数组 / input array
* @param {number} w - 字节倍数 / byte multiple
*/
function bytepad(X, w) {
if (w <= 0) {
throw new KitError('w must be greater than 0');
}
// 使用 leftEncode 函数编码 w
const left_encoded_w = leftEncode(w);
// z = left_encode(w) || X0 || ... || Xn
// 计算 z 的有效字节长度总和, 用于计算填充零字节的数量
let z_byte = left_encoded_w.length;
X.forEach(x => z_byte += x.length);
// 计算需要填充的零字节的数量
const zero_byte = w - z_byte % w;
X.unshift(left_encoded_w);
X.push(new Uint8Array(zero_byte));
return X;
}
/**
* `cSHAKE` 填充函数 / Padding Function
*
* ```ts
* M || 00 || 10*1
* ```
*
* @param {number} r_byte - 处理速率 / Rate
*/
const cshakePadding = (r_byte) => {
return (M) => {
const sig_byte = M.length;
const pad_byte = r_byte - (sig_byte % r_byte);
const P = new Uint8Array(sig_byte + pad_byte);
P.set(M);
if (pad_byte === 1) {
P[sig_byte] = 0x84;
}
P[sig_byte] = 0x04;
P[P.length - 1] |= 0x80;
return P;
};
};
// * cSHAKE
/**
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} N - 函数名 / Function name
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} c - 安全容量 / capacity (bit)
* @param {number} r_byte - 处理速率 / Rate (byte)
* @param {Hash} SHAKE - SHAKE 函数
*/
function cshake(d, N, S, c, r_byte, SHAKE) {
if (N.byteLength === 0 && S.byteLength === 0) {
return (M) => SHAKE(d)(M);
}
return (M) => {
const P = bytepad([...encodeString(N), ...encodeString(S)], r_byte);
P.push(M);
return Keccak_c(c, d, cshakePadding)(joinBuffer(...P));
};
}
/**
* `cSHAKE128` 是 `SHAKE128` 的可定制变体
*
* `cSHAKE128` is a customizable variant of `SHAKE128`
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} [N] - 函数名 / Function name
* @param {Uint8Array} [S] - 自定义参数 / Customization
*/
export function cshake128(d, N = new Uint8Array(), S = new Uint8Array()) {
return createHash(cshake(d, N, S, 256, 168, shake128), {
ALGORITHM: `cSHAKE128/${d}`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
});
}
/**
* `cSHAKE256` 是 `SHAKE256` 的可定制变体
*
* `cSHAKE256` is a customizable variant of `SHAKE256`
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} [N] - 函数名 / Function name
* @param {Uint8Array} [S] - 自定义参数 / Customization
*/
export function cshake256(d, N = new Uint8Array(), S = new Uint8Array()) {
return createHash(cshake(d, N, S, 512, 136, shake256), {
ALGORITHM: `cSHAKE256/${d}`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
});
}
// * KMAC
/**
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} c - 安全容量 / capacity (bit)
* @param {number} r_byte - 处理速率 / Rate (byte)
* @param {boolean} XOF - 是否为 XOF 模式 / XOF mode
*/
function kmac(d, S, c, r_byte, XOF) {
return (K, M) => {
const X = bytepad([...encodeString('KMAC'), ...encodeString(S)], r_byte);
X.push(...bytepad(encodeString(K), r_byte));
X.push(M);
X.push(rightEncode(XOF ? 0 : d));
return Keccak_c(c, d, cshakePadding)(joinBuffer(...X));
};
}
/**
* Keccak 消息认证码 (KMAC) 算法
* `KMAC128` 是 `KMAC` 的变体, 由 `cSHAKE128` 构建
*
* The Keccak Message Authentication Code (KMAC) algorithm
* `KMAC128` is a variant of `KMAC`, build from `cSHAKE128`
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} k_size - 推荐密钥大小 / Recommended key size (bit)
*/
export function kmac128(d, S = new Uint8Array(0), k_size = 128) {
return createKeyHash(kmac(d, S, 256, 168, false), {
ALGORITHM: `KMAC128/${d}`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
KEY_SIZE: k_size >> 3,
});
}
/**
* Keccak 消息认证码 (KMAC) 算法
* `KMAC256` 是 `KMAC` 的变体, 由 `cSHAKE256` 构建
*
* The Keccak Message Authentication Code (KMAC) algorithm
* `KMAC256` is a variant of `KMAC`, build from `cSHAKE256`
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} k_size - 推荐密钥大小 / Recommended key size (bit)
*/
export function kmac256(d, S = new Uint8Array(0), k_size = 256) {
return createKeyHash(kmac(d, S, 512, 136, false), {
ALGORITHM: `KMAC256/${d}`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
KEY_SIZE: k_size >> 3,
});
}
/**
* 可变长度输出的 `KMAC`
* `KMAC128XOF` 是 `KMAC128` 的 XOF 模式, 由 `cSHAKE128` 构建
*
* `KMAC` with Arbitrary-Length Output
* `KMAC128XOF` is a XOF mode of `KMAC128`, build from `cSHAKE128`
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} k_size - 推荐密钥大小 / Recommended key size (bit)
*/
export function kmac128XOF(d, S = new Uint8Array(0), k_size = 128) {
return createKeyHash(kmac(d, S, 256, 168, true), {
ALGORITHM: `KMAC128XOF/${d}`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
KEY_SIZE: k_size >> 3,
});
}
/**
* 可变长度输出的 `KMAC`
* `KMAC256XOF` 是 `KMAC256` 的 XOF 模式, 由 `cSHAKE256` 构建
*
* `KMAC` with Arbitrary-Length Output
* `KMAC256XOF` is a XOF mode of `KMAC256`, build from `cSHAKE256`
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} k_size - 推荐密钥大小 / recommended key size (bit)
*/
export function kmac256XOF(d, S = new Uint8Array(0), k_size = 256) {
return createKeyHash(kmac(d, S, 512, 136, true), {
ALGORITHM: `KMAC256XOF/${d}`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
KEY_SIZE: k_size >> 3,
});
}
// * TupleHash
/**
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} c - 安全容量 / capacity (bit)
* @param {number} r_byte - 处理速率 / Rate (byte)
* @param {boolean} XOF - 是否为 XOF 模式 / XOF mode
*/
function tuplehash(d, S, c, r_byte, XOF) {
return (M) => {
const X = bytepad([...encodeString('TupleHash'), ...encodeString(S)], r_byte);
M.forEach(m => X.push(...encodeString(m)));
X.push(rightEncode(XOF ? 0 : d));
return Keccak_c(c, d, cshakePadding)(joinBuffer(...X));
};
}
/**
* `TupleHash` 是一个具有可变长度输出的 `SHA3` 派生散列函数, 旨在以一种明确的方式简单地散列输入字符串的元组, 这些字符串中的任何一个或全部都可以是空字符串.
*
* `TupleHash` is a `SHA3` derived hash function with variable-length output that is designed to simply hash a tuple of input strings, any or all of which may be empty strings, in an unambiguous way.
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function tuplehash128(d, S = new Uint8Array()) {
return createTupleHash(tuplehash(d, S, 256, 168, false), {
ALGORITHM: `TupleHash128/${d}`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
});
}
/**
* `TupleHash` 是一个具有可变长度输出的 `SHA3` 派生散列函数, 旨在以一种明确的方式简单地散列输入字符串的元组, 这些字符串中的任何一个或全部都可以是空字符串.
*
* `TupleHash` is a `SHA3` derived hash function with variable-length output that is designed to simply hash a tuple of input strings, any or all of which may be empty strings, in an unambiguous way.
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function tuplehash256(d, S = new Uint8Array()) {
return createTupleHash(tuplehash(d, S, 512, 136, false), {
ALGORITHM: `TupleHash256/${d}`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
});
}
/**
* 可变长度输出的 `TupleHash`
*
* `TupleHash` with Arbitrary-Length Output
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function tuplehash128XOF(d, S = new Uint8Array()) {
return createTupleHash(tuplehash(d, S, 256, 168, true), {
ALGORITHM: `TupleHash128XOF/${d}`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
});
}
/**
* 可变长度输出的 `TupleHash`
*
* `TupleHash` with Arbitrary-Length Output
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function tuplehash256XOF(d, S = new Uint8Array()) {
return createTupleHash(tuplehash(d, S, 512, 136, true), {
ALGORITHM: `TupleHash256XOF/${d}`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
});
}
// * ParallelHash
// ! Note: This ParallelHash does not actually perform parallel computation, because writing multi-threaded in JavaScript is not easy.
// ! 注意: 此 ParallelHash 实际上并不执行并行计算, 因为在 JavaScript 写多线程并不轻松.
// TODO 计划引入 `multithreading` 依赖, 实现真正的并行计算
/**
* @param {number} b - 状态大小 / State size (bit)
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
* @param {number} c - 安全容量 / capacity (bit)
* @param {number} r_byte - 处理速率 / Rate (byte)
* @param {boolean} XOF - 是否为 XOF 模式 / XOF mode
*/
function parallelhash(b, d, S, c, r_byte, XOF, SHAKE) {
const bByte = b >> 3;
return (M) => {
const n = Math.ceil(M.byteLength / bByte);
const X = bytepad([...encodeString('ParallelHash'), ...encodeString(S)], r_byte);
X.push(leftEncode(b));
for (let i = 0; i < n; i++) {
const B = M.slice(i * (b << 3), (i + 1) * (b << 3));
X.push(SHAKE(B));
}
X.push(rightEncode(n));
X.push(rightEncode(XOF ? 0 : d));
return Keccak_c(c, d, cshakePadding)(joinBuffer(...X));
};
}
/**
* `ParallelHash` 的目的是利用现代处理器中可用的并行性, 支持对非常长的字符串进行高效散列.
*
* The purpose of `ParallelHash` is to support the efficient hashing of very long strings, by taking advantage of the parallelism available in modern processors.
*
* @param {number} b - 状态大小 / State size (bit)
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function parallelhash128(b, d, S = new Uint8Array()) {
return createHash(parallelhash(b, d, S, 256, 168, false, shake128(256)), {
ALGORITHM: `ParallelHash128/${d}`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
});
}
/**
* `ParallelHash` 的目的是利用现代处理器中可用的并行性, 支持对非常长的字符串进行高效散列.
*
* The purpose of `ParallelHash` is to support the efficient hashing of very long strings, by taking advantage of the parallelism available in modern processors.
*
* @param {number} b - 状态大小 / State size (bit)
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function parallelhash256(b, d, S = new Uint8Array()) {
return createHash(parallelhash(b, d, S, 512, 136, false, shake256(512)), {
ALGORITHM: `ParallelHash256/${d}`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
});
}
/**
* 可变长度输出的 `ParallelHash`
*
* `ParallelHash` with Arbitrary-Length Output
*
* @param {number} b - 状态大小 / State size (bit)
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function parallelhash128XOF(b, d, S = new Uint8Array()) {
return createHash(parallelhash(b, d, S, 256, 168, true, shake128(256)), {
ALGORITHM: `ParallelHash128XOF`,
BLOCK_SIZE: 168,
DIGEST_SIZE: d >> 3,
});
}
/**
* 可变长度输出的 `ParallelHash`
*
* `ParallelHash` with Arbitrary-Length Output
*
* @param {number} b - 状态大小 / State size (bit)
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {Uint8Array} S - 自定义参数 / Customization
*/
export function parallelhash256XOF(b, d, S = new Uint8Array()) {
return createHash(parallelhash(b, d, S, 512, 136, true, shake256(512)), {
ALGORITHM: `ParallelHash256XOF`,
BLOCK_SIZE: 136,
DIGEST_SIZE: d >> 3,
});
}
import { UTF8 } from '../core/codec';
import { createHash } from '../core/hash';
import { KitError, U8, genBitMask, rotateR } from '../core/utils';
// * Constants
const K = new BigUint64Array([0x428a2f98d728ae22n, 0x7137449123ef65cdn, 0xb5c0fbcfec4d3b2fn, 0xe9b5dba58189dbbcn, 0x3956c25bf348b538n, 0x59f111f1b605d019n, 0x923f82a4af194f9bn, 0xab1c5ed5da6d8118n, 0xd807aa98a3030242n, 0x12835b0145706fben, 0x243185be4ee4b28cn, 0x550c7dc3d5ffb4e2n, 0x72be5d74f27b896fn, 0x80deb1fe3b1696b1n, 0x9bdc06a725c71235n, 0xc19bf174cf692694n, 0xe49b69c19ef14ad2n, 0xefbe4786384f25e3n, 0x0fc19dc68b8cd5b5n, 0x240ca1cc77ac9c65n, 0x2de92c6f592b0275n, 0x4a7484aa6ea6e483n, 0x5cb0a9dcbd41fbd4n, 0x76f988da831153b5n, 0x983e5152ee66dfabn, 0xa831c66d2db43210n, 0xb00327c898fb213fn, 0xbf597fc7beef0ee4n, 0xc6e00bf33da88fc2n, 0xd5a79147930aa725n, 0x06ca6351e003826fn, 0x142929670a0e6e70n, 0x27b70a8546d22ffcn, 0x2e1b21385c26c926n, 0x4d2c6dfc5ac42aedn, 0x53380d139d95b3dfn, 0x650a73548baf63den, 0x766a0abb3c77b2a8n, 0x81c2c92e47edaee6n, 0x92722c851482353bn, 0xa2bfe8a14cf10364n, 0xa81a664bbc423001n, 0xc24b8b70d0f89791n, 0xc76c51a30654be30n, 0xd192e819d6ef5218n, 0xd69906245565a910n, 0xf40e35855771202an, 0x106aa07032bbd1b8n, 0x19a4c116b8d2d0c8n, 0x1e376c085141ab53n, 0x2748774cdf8eeb99n, 0x34b0bcb5e19b48a8n, 0x391c0cb3c5c95a63n, 0x4ed8aa4ae3418acbn, 0x5b9cca4f7763e373n, 0x682e6ff3d6b2b8a3n, 0x748f82ee5defb2fcn, 0x78a5636f43172f60n, 0x84c87814a1f0ab72n, 0x8cc702081a6439ecn, 0x90befffa23631e28n, 0xa4506cebde82bde9n, 0xbef9a3f7b2c67915n, 0xc67178f2e372532bn, 0xca273eceea26619cn, 0xd186b8c721c0c207n, 0xeada7dd6cde0eb1en, 0xf57d4f7fee6ed178n, 0x06f067aa72176fban, 0x0a637dc5a2c898a6n, 0x113f9804bef90daen, 0x1b710b35131c471bn, 0x28db77f523047d84n, 0x32caab7b40c72493n, 0x3c9ebe0a15c9bebcn, 0x431d67c49c100d4cn, 0x4cc5d4becb3e42b6n, 0x597f299cfc657e2an, 0x5fcb6fab3ad6faecn, 0x6c44198c4a475817n]);
// * Function
const mask64 = genBitMask(64);
const rotateR64 = (x, n) => rotateR(64, x, n, mask64);
const Ch = (x, y, z) => (x & y) ^ ((~x) & z);
const Maj = (x, y, z) => (x & y) ^ (x & z) ^ (y & z);
const Sigma0 = (x) => rotateR64(x, 28n) ^ rotateR64(x, 34n) ^ rotateR64(x, 39n);
const Sigma1 = (x) => rotateR64(x, 14n) ^ rotateR64(x, 18n) ^ rotateR64(x, 41n);
const sigma0 = (x) => rotateR64(x, 1n) ^ rotateR64(x, 8n) ^ (x >> 7n);
const sigma1 = (x) => rotateR64(x, 19n) ^ rotateR64(x, 61n) ^ (x >> 6n);
/**
* SHA-512/t IV 生成函数 / generator
*
* ```ts
* (0 < t < 512) && (t !== 384)
* ```
*
* @param {number} t - 截断长度 / truncation length (bit)
*/
function IVGen(t) {
if (t <= 0) {
throw new KitError('SHA-512 truncation must be greater than 0');
}
if (t >= 512) {
throw new KitError('SHA-512 truncation must be less than 512');
}
if (t === 384) {
throw new KitError('SHA-512 truncation must not be 384');
}
const state = new U8(64);
const state_view = state.view(8);
state_view.set(0, 0x6a09e667f3bcc908n ^ 0xa5a5a5a5a5a5a5a5n);
state_view.set(1, 0xbb67ae8584caa73bn ^ 0xa5a5a5a5a5a5a5a5n);
state_view.set(2, 0x3c6ef372fe94f82bn ^ 0xa5a5a5a5a5a5a5a5n);
state_view.set(3, 0xa54ff53a5f1d36f1n ^ 0xa5a5a5a5a5a5a5a5n);
state_view.set(4, 0x510e527fade682d1n ^ 0xa5a5a5a5a5a5a5a5n);
state_view.set(5, 0x9b05688c2b3e6c1fn ^ 0xa5a5a5a5a5a5a5a5n);
state_view.set(6, 0x1f83d9abfb41bd6bn ^ 0xa5a5a5a5a5a5a5a5n);
state_view.set(7, 0x5be0cd19137e2179n ^ 0xa5a5a5a5a5a5a5a5n);
return digest(state, UTF8(`SHA-512/${t}`));
}
// * Algorithm
function digest(state, message) {
// * 初始化
state = state.slice(0);
const state_view = state.view(8);
const m_byte = message.byteLength;
const m_bit = BigInt(m_byte) << 3n;
const block_size = 128;
// ceil((m_byte + 17) / 128)
const block_total = (m_byte + 17 + 127) >> 7;
// * 填充
const p = new U8(block_total * block_size);
p.set(message);
// appending the bit '1' to the message
p[m_byte] = 0x80;
// appending length
const p_view = new DataView(p.buffer);
p_view.setBigUint64(p.byteLength - 16, m_bit >> 32n);
p_view.setBigUint64(p.byteLength - 8, m_bit & 0xffffffffffffffffn);
// * 分块处理
for (let offset = 0; offset < p.length; offset += block_size) {
/** B(n) = p[offset:offset + block_size] */
// 准备状态字
const H0 = state_view.get(0);
const H1 = state_view.get(1);
const H2 = state_view.get(2);
const H3 = state_view.get(3);
const H4 = state_view.get(4);
const H5 = state_view.get(5);
const H6 = state_view.get(6);
const H7 = state_view.get(7);
let a = H0;
let b = H1;
let c = H2;
let d = H3;
let e = H4;
let f = H5;
let g = H6;
let h = H7;
// 合并执行 扩展 & 压缩
const W = new BigUint64Array(80);
for (let i = 0; i < W.length; i++) {
// 扩展
if (i < 16)
// W[i] = B(n)[i]
W[i] = p_view.getBigUint64(offset + (i << 3));
else
W[i] = sigma1(W[i - 2]) + W[i - 7] + sigma0(W[i - 15]) + W[i - 16];
// 压缩
const T1 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];
const T2 = Sigma0(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = (d + T1) & 0xffffffffffffffffn;
d = c;
c = b;
b = a;
a = (T1 + T2) & 0xffffffffffffffffn;
}
// 更新状态字
state_view.set(0, H0 + a);
state_view.set(1, H1 + b);
state_view.set(2, H2 + c);
state_view.set(3, H3 + d);
state_view.set(4, H4 + e);
state_view.set(5, H5 + f);
state_view.set(6, H6 + g);
state_view.set(7, H7 + h);
}
// * 返回状态
return state;
}
function sha384Digest(M) {
// * 初始化 SHA-384 状态
const state = new U8(64);
const state_view = state.view(8);
state_view.set(0, 0xcbbb9d5dc1059ed8n);
state_view.set(1, 0x629a292a367cd507n);
state_view.set(2, 0x9159015a3070dd17n);
state_view.set(3, 0x152fecd8f70e5939n);
state_view.set(4, 0x67332667ffc00b31n);
state_view.set(5, 0x8eb44a8768581511n);
state_view.set(6, 0xdb0c2e0d64f98fa7n);
state_view.set(7, 0x47b5481dbefa4fa4n);
return digest(state, M).slice(0, 48);
}
function sha512Digest(M) {
// * 初始化 SHA-512 状态
const state = new U8(64);
const state_view = state.view(8);
state_view.set(0, 0x6a09e667f3bcc908n);
state_view.set(1, 0xbb67ae8584caa73bn);
state_view.set(2, 0x3c6ef372fe94f82bn);
state_view.set(3, 0xa54ff53a5f1d36f1n);
state_view.set(4, 0x510e527fade682d1n);
state_view.set(5, 0x9b05688c2b3e6c1fn);
state_view.set(6, 0x1f83d9abfb41bd6bn);
state_view.set(7, 0x5be0cd19137e2179n);
return digest(state, M);
}
export const sha384 = createHash(sha384Digest, {
ALGORITHM: 'SHA-384',
BLOCK_SIZE: 128,
DIGEST_SIZE: 48,
OID: '2.16.840.1.101.3.4.2.2',
});
export const sha512 = createHash(sha512Digest, {
ALGORITHM: 'SHA-512',
BLOCK_SIZE: 128,
DIGEST_SIZE: 64,
OID: '2.16.840.1.101.3.4.2.3',
});
/**
* @param {number} t - 截断长度 / truncation length (bit)
*/
export function sha512t(t) {
// * 初始化 SHA-512/t 状态
const status = IVGen(t);
let OID;
if (t === 224)
OID = '2.16.840.1.101.3.4.2.5';
if (t === 256)
OID = '2.16.840.1.101.3.4.2.6';
return createHash((M) => digest(status, M).slice(0, t >> 3), {
ALGORITHM: `SHA-512/${t}`,
BLOCK_SIZE: 128,
DIGEST_SIZE: t >> 3,
OID,
});
}
import { createHash } from '../core/hash';
import { U8, rotateL32 } from '../core/utils';
// * Function
const FF = (X, Y, Z, j) => j < 16 ? X ^ Y ^ Z : (X & Y) | (X & Z) | (Y & Z);
const GG = (X, Y, Z, j) => j < 16 ? X ^ Y ^ Z : (X & Y) | (~X & Z);
const P0 = (X) => X ^ rotateL32(X, 9) ^ rotateL32(X, 17);
const P1 = (X) => X ^ rotateL32(X, 15) ^ rotateL32(X, 23);
// * Algorithm
function digest(message) {
// * 初始化
const state = new U8(32);
const state_view = state.view(4);
state_view.set(0, 0x7380166fn);
state_view.set(1, 0x4914b2b9n);
state_view.set(2, 0x172442d7n);
state_view.set(3, 0xda8a0600n);
state_view.set(4, 0xa96f30bcn);
state_view.set(5, 0x163138aan);
state_view.set(6, 0xe38dee4dn);
state_view.set(7, 0xb0fb0e4en);
const m_byte = message.length;
const m_bit = BigInt(m_byte) << 3n;
const block_size = 64;
// ceil((M_BYTE + 9) / 64)
const block_total = (m_byte + 9 + 63) >> 6;
// * 填充
const p = new U8(block_total * block_size);
p.set(message);
// appending the bit '1' to the message
p[m_byte] = 0x80;
// appending length
const p_view = new DataView(p.buffer);
p_view.setBigUint64(p.length - 8, m_bit, false);
// * 迭代压缩
for (let offset = 0; offset < p.length; offset += block_size) {
/** B(n) = p[offset:offset + block_size] */
// 准备状态字
const H0 = Number(state_view.get(0));
const H1 = Number(state_view.get(1));
const H2 = Number(state_view.get(2));
const H3 = Number(state_view.get(3));
const H4 = Number(state_view.get(4));
const H5 = Number(state_view.get(5));
const H6 = Number(state_view.get(6));
const H7 = Number(state_view.get(7));
let A = H0;
let B = H1;
let C = H2;
let D = H3;
let E = H4;
let F = H5;
let G = H6;
let H = H7;
// 合并执行 扩展 & 压缩
const W = new Uint32Array(68);
const W1 = new Uint32Array(64);
for (let i = 0; i < 68; i++) {
// 拓展 W
if (i < 16) {
// W[i] = B(n)[i]
W[i] = p_view.getUint32(offset + (i << 2), false);
}
else {
W[i] = P1(W[i - 16] ^ W[i - 9] ^ rotateL32(W[i - 3], 15)) ^ rotateL32(W[i - 13], 7) ^ W[i - 6];
}
// W1 拓展 & 压缩
if (i > 3) {
// W1 拓展
const j = i - 4;
// W1[j] = W[j] ^ W[j + 4]
W1[j] = W[j] ^ W[i];
// 压缩
const T = j < 16 ? 0x79CC4519 : 0x7A879D8A;
const SS1 = rotateL32(rotateL32(A, 12) + E + rotateL32(T, j), 7);
const SS2 = SS1 ^ rotateL32(A, 12);
const TT1 = FF(A, B, C, j) + D + SS2 + W1[j];
const TT2 = GG(E, F, G, j) + H + SS1 + W[j];
D = C;
C = rotateL32(B, 9);
B = A;
A = TT1;
H = G;
G = rotateL32(F, 19);
F = E;
E = P0(TT2);
}
}
// 更新状态字
state_view.set(0, BigInt(H0 ^ A));
state_view.set(1, BigInt(H1 ^ B));
state_view.set(2, BigInt(H2 ^ C));
state_view.set(3, BigInt(H3 ^ D));
state_view.set(4, BigInt(H4 ^ E));
state_view.set(5, BigInt(H5 ^ F));
state_view.set(6, BigInt(H6 ^ G));
state_view.set(7, BigInt(H7 ^ H));
}
// * 截断输出
return state;
}
export const sm3 = createHash(digest, {
ALGORITHM: 'SM3',
BLOCK_SIZE: 64,
DIGEST_SIZE: 32,
OID: '1.2.156.10197.1.401',
});
import { createHash } from '../core/hash';
import { KitError } from '../core/utils';
import { keccak_p_1600, sponge_1600 } from './keccak1600';
/**
* turboSHAKE 填充函数 / Padding Function
*
* ```ts
* M || D || 0x00*
* ```
*
* @param {number} rByte - 处理速率 / Rate
* @param {number} D - 域分隔符 / Domain Separator
*/
function turboShakePadding(rByte, D) {
return (M) => {
const sig_byte = M.length + 1;
const block = Math.ceil(sig_byte / rByte);
const P = new Uint8Array(block * rByte);
P.set(M);
P[M.length] = D;
P[P.length - 1] ^= 0x80;
return P;
};
}
/**
* TurboSHAKE128
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {number} [D] - 域分隔符 / Domain Separator (range: 0x01 ~ 0x7F, default: 0x1F)
*/
export function turboshake128(d, D = 0x1F) {
if (D < 0x01 || D > 0x7F) {
throw new KitError('Invalid Domain Separator');
}
const d_byte = d >> 3;
const r_byte = 168;
const f = keccak_p_1600(12);
const pad = turboShakePadding(r_byte, D);
return createHash((M) => sponge_1600(r_byte, d_byte, pad, f)(M), {
ALGORITHM: `TurboSHAKE128/${d}`,
BLOCK_SIZE: r_byte,
DIGEST_SIZE: d_byte,
});
}
/**
* TurboSHAKE256
*
* @param {number} d - 输出长度 / Digest Size (bit)
* @param {number} [D] - 域分隔符 / Domain Separator (range: 0x01 ~ 0x7F, default: 0x1F)
*/
export function turboshake256(d, D = 0x1F) {
if (D < 0x01 || D > 0x7F) {
throw new KitError('Invalid Domain Separator');
}
const d_byte = d >> 3;
const r_byte = 136;
const f = keccak_p_1600(12);
const pad = turboShakePadding(r_byte, D);
return createHash((M) => sponge_1600(r_byte, d_byte, pad, f)(M), {
ALGORITHM: `TurboSHAKE256/${d}`,
BLOCK_SIZE: r_byte,
DIGEST_SIZE: d_byte,
});
}
// * Utils
export { U8, joinBuffer } from './core/utils';
export { genPrime, isProbablePrime } from './core/prime';
export { UTF8, HEX, B64, B64URL, CSV } from './core/codec';
export { createHash, createTupleHash } from './core/hash';
// * MD5
export { md5 } from './hash/md5';
// * SHA-1
export { sha1 } from './hash/sha1';
// * SHA-2
export { sha224, sha256 } from './hash/sha256';
export { sha384, sha512, sha512t } from './hash/sha512';
// * SHA-3
// export { Keccak_p_200, Sponge_200 } from './hash/keccak200'
// export { Keccak_p_400, Sponge_400 } from './hash/keccak400'
// export { Keccak_p_800, Sponge_800 } from './hash/keccak800'
export { keccak_p_1600, sponge_1600 } from './hash/keccak1600';
export { sha3_224, sha3_256 } from './hash/sha3';
export { sha3_384, sha3_512 } from './hash/sha3';
// * SHAKE
export { shake128, shake256 } from './hash/sha3';
// * cSHAKE
export { cshake128, cshake256 } from './hash/sha3Derived';
// * KMAC
export { kmac128, kmac128XOF } from './hash/sha3Derived';
export { kmac256, kmac256XOF } from './hash/sha3Derived';
// * TupleHash
export { tuplehash128, tuplehash128XOF } from './hash/sha3Derived';
export { tuplehash256, tuplehash256XOF } from './hash/sha3Derived';
// * ParallelHash
export { parallelhash128, parallelhash128XOF } from './hash/sha3Derived';
export { parallelhash256, parallelhash256XOF } from './hash/sha3Derived';
// * TurboSHAKE
export { turboshake128, turboshake256 } from './hash/turboSHAKE';
// * KangarooTwelve
export { kt128, kt256 } from './hash/kangaroo12';
// * SM3
export { sm3 } from './hash/sm3';
// * HMAC
export { hmac } from './hash/hmac';
export { createCipher } from './core/cipher';
// * Block Cipher
export { sm4 } from './cipher/blockCipher/sm4';
export { aes } from './cipher/blockCipher/aes';
export { aria } from './cipher/blockCipher/aria';
export { camellia } from './cipher/blockCipher/camellia';
export { des, t_des } from './cipher/blockCipher/des';
export { arc5 } from './cipher/blockCipher/arc5';
export { blowfish } from './cipher/blockCipher/blowfish';
export { twofish } from './cipher/blockCipher/twofish';
export { tea, xtea, xxtea } from './cipher/blockCipher/tea';
// * Block Cipher Modes
export { ecb, cbc, pcbc, cfb, ofb, ctr, gcm } from './core/cipher';
// * Block Cipher Padding
export { PKCS7_PAD, ZERO_PAD, X923_PAD, ISO7816_PAD, NO_PAD } from './core/cipher';
export { eea3, eia3, zuc } from './cipher/streamCipher/zuc';
export { arc4 } from './cipher/streamCipher/arc4';
export { salsa20 } from './cipher/streamCipher/salsa20';
export { rabbit } from './cipher/streamCipher/rabbit';
export { rsa } from './cipher/pkcs/rsa';
export { pkcs1_es_1_5, pkcs1_es_oaep } from './cipher/pkcs/pkcs1';
export { pkcs1_ssa_1_5, pkcs1_ssa_pss } from './cipher/pkcs/pkcs1';
export { mgf1 } from './cipher/pkcs/pkcs1';
export { x963kdf, hkdf, pbkdf2 } from './core/kdf';
export { FpECC } from './cipher/pkcs/ecc';
export { sm2p256v1 } from './core/ecParams';
// export { secp112r1, secp112r2 } from './core/ecParams'
// export { secp128r1, secp128r2 } from './core/ecParams'
// export { secp160k1, secp160r1, secp160r2 } from './core/ecParams'
export { secp192k1, secp192r1 } from './core/ecParams';
export { secp224k1, secp224r1 } from './core/ecParams';
export { secp256k1, secp256r1 } from './core/ecParams';
export { secp384r1, secp521r1 } from './core/ecParams';
export { prime192v1, prime256v1 } from './core/ecParams';
export { p192, p224, p256, p384, p521 } from './core/ecParams';
export { w25519, w448 } from './core/ecParams';
// TODO 实现 爱德华曲线 后再开放
// export { ed25519, ed448 } from './core/ecParams'
export { curve25519, curve448 } from './core/ecParams';
export { bp192r1, bp224r1, bp256r1, bp320r1, bp384r1, bp512r1 } from './core/ecParams';
export { sm2 } from './cipher/pkcs/sm2';
export { x25519, x448 } from './cipher/pkcs/x25519_448';

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display