UNPKG

@li0ard/crapto1_ts

Version:
189 lines (188 loc) 8.96 kB
import { LF_POLY_EVEN, LF_POLY_ODD, bebit, bit, filter } from "./index.js"; import { bitBigInt, evenParity32 } from "./utils.js"; /** Crypto1 state */ export class Crypto1State { odd; even; constructor(odd = 0, even = 0) { this.odd = odd; this.even = even; } /** Initialize state from key (aka LFSR value) */ static fromKey(key) { let odd = 0n; let even = 0n; for (let i = 47; i > 0; i -= 2) { odd = odd << 1n | bitBigInt(key, (i - 1) ^ 7); even = even << 1n | bitBigInt(key, i ^ 7); } return new Crypto1State(Number(odd), Number(even)); } /** Get LFSR value (aka Key) */ get lfsr() { let lfsr = 0n; for (let i = 23; i >= 0; --i) { lfsr = lfsr << 1n | BigInt(bit(this.odd, i ^ 3)); lfsr = lfsr << 1n | BigInt(bit(this.even, i ^ 3)); } return lfsr; } /** Get filtered state `odd` value */ get peekCrypto1Bit() { return filter(this.odd); } /** * Generate keystream (bit) * @param input Input bit * @param isEncrypted Is input bit encrypted? */ bit(input = 0, isEncrypted = false) { const ret = this.peekCrypto1Bit; const feedin = (ret & (isEncrypted ? 1 : 0)) ^ ((input !== 0) ? 1 : 0) ^ (LF_POLY_ODD & this.odd) ^ (LF_POLY_EVEN & this.even); [this.odd, this.even] = [((this.even << 1) | evenParity32(feedin)) >>> 0, this.odd]; return ret; } /** * Generate keystream (byte) * @param input Input byte * @param isEncrypted Is input byte encrypted? */ byte(input = 0, isEncrypted = false) { let ret = 0; //for (let i = 0; i < 8; ++i) ret |= crypto1_bit(s, bit(input, i), isEncrypted) << i; ret |= this.bit(bit(input, 0), isEncrypted) << 0; ret |= this.bit(bit(input, 1), isEncrypted) << 1; ret |= this.bit(bit(input, 2), isEncrypted) << 2; ret |= this.bit(bit(input, 3), isEncrypted) << 3; ret |= this.bit(bit(input, 4), isEncrypted) << 4; ret |= this.bit(bit(input, 5), isEncrypted) << 5; ret |= this.bit(bit(input, 6), isEncrypted) << 6; ret |= this.bit(bit(input, 7), isEncrypted) << 7; return ret; } /** * Generate keystream (word) * @param input Input word (uint32) * @param isEncrypted Is input word encrypted? */ word(input = 0, isEncrypted = false) { let ret = 0; //for (let i = 0; i < 32; ++i) ret |= crypto1_bit(s, bebit(input, i), isEncrypted) << (i ^ 24); ret |= this.bit(bebit(input, 0), isEncrypted) << 24; ret |= this.bit(bebit(input, 1), isEncrypted) << 25; ret |= this.bit(bebit(input, 2), isEncrypted) << 26; ret |= this.bit(bebit(input, 3), isEncrypted) << 27; ret |= this.bit(bebit(input, 4), isEncrypted) << 28; ret |= this.bit(bebit(input, 5), isEncrypted) << 29; ret |= this.bit(bebit(input, 6), isEncrypted) << 30; ret |= this.bit(bebit(input, 7), isEncrypted) << 31; ret |= this.bit(bebit(input, 8), isEncrypted) << 16; ret |= this.bit(bebit(input, 9), isEncrypted) << 17; ret |= this.bit(bebit(input, 10), isEncrypted) << 18; ret |= this.bit(bebit(input, 11), isEncrypted) << 19; ret |= this.bit(bebit(input, 12), isEncrypted) << 20; ret |= this.bit(bebit(input, 13), isEncrypted) << 21; ret |= this.bit(bebit(input, 14), isEncrypted) << 22; ret |= this.bit(bebit(input, 15), isEncrypted) << 23; ret |= this.bit(bebit(input, 16), isEncrypted) << 8; ret |= this.bit(bebit(input, 17), isEncrypted) << 9; ret |= this.bit(bebit(input, 18), isEncrypted) << 10; ret |= this.bit(bebit(input, 19), isEncrypted) << 11; ret |= this.bit(bebit(input, 20), isEncrypted) << 12; ret |= this.bit(bebit(input, 21), isEncrypted) << 13; ret |= this.bit(bebit(input, 22), isEncrypted) << 14; ret |= this.bit(bebit(input, 23), isEncrypted) << 15; ret |= this.bit(bebit(input, 24), isEncrypted) << 0; ret |= this.bit(bebit(input, 25), isEncrypted) << 1; ret |= this.bit(bebit(input, 26), isEncrypted) << 2; ret |= this.bit(bebit(input, 27), isEncrypted) << 3; ret |= this.bit(bebit(input, 28), isEncrypted) << 4; ret |= this.bit(bebit(input, 29), isEncrypted) << 5; ret |= this.bit(bebit(input, 30), isEncrypted) << 6; ret |= this.bit(bebit(input, 31), isEncrypted) << 7; return ret; } /** * Proceed encryption/decryption process * @param data Input data * @param isIn Use input data as input word for keystream generation? */ crypt(data, isIn = false) { const result = []; for (let i = 0; i < data.length; i++) result[i] = data[i] ^ this.byte(isIn ? data[i] : 0); return result; } /** * Rollback state (bit) * @param input Input bit * @param isEncrypted Is input bit encrypted? */ rollback_bit(input = 0, isEncrypted = false) { [this.even, this.odd] = [(this.odd & 0xffffff), this.even]; const ret = this.peekCrypto1Bit; const out = (this.even & 1) ^ (LF_POLY_EVEN & (this.even >>>= 1)) ^ (LF_POLY_ODD & this.odd) ^ (input !== 0 ? 1 : 0) ^ (ret & (isEncrypted ? 1 : 0)); this.even |= evenParity32(out) << 23; return ret; } /** * Rollback state (byte) * @param input Input byte * @param isEncrypted Is input byte encrypted? */ rollback_byte(input = 0, isEncrypted = false) { let ret = 0; //for (let i = 7; i >= 0; --i) ret |= this.rollback_bit(bit(input, i), isEncrypted) << i; ret |= this.rollback_bit(bit(input, 7), isEncrypted) << 7; ret |= this.rollback_bit(bit(input, 6), isEncrypted) << 6; ret |= this.rollback_bit(bit(input, 5), isEncrypted) << 5; ret |= this.rollback_bit(bit(input, 4), isEncrypted) << 4; ret |= this.rollback_bit(bit(input, 3), isEncrypted) << 3; ret |= this.rollback_bit(bit(input, 2), isEncrypted) << 2; ret |= this.rollback_bit(bit(input, 1), isEncrypted) << 1; ret |= this.rollback_bit(bit(input, 0), isEncrypted) << 0; return ret; } /** * Rollback state (word) * @param input Input word (uint32) * @param isEncrypted Is input word encrypted? */ rollback_word(input = 0, isEncrypted = false) { let ret = 0; //for (let i = 31; i >= 0; --i) ret |= this.rollback_bit(bebit(input, i), isEncrypted) << (i ^ 24); ret |= this.rollback_bit(bebit(input, 31), isEncrypted) << 7; ret |= this.rollback_bit(bebit(input, 30), isEncrypted) << 6; ret |= this.rollback_bit(bebit(input, 29), isEncrypted) << 5; ret |= this.rollback_bit(bebit(input, 28), isEncrypted) << 4; ret |= this.rollback_bit(bebit(input, 27), isEncrypted) << 3; ret |= this.rollback_bit(bebit(input, 26), isEncrypted) << 2; ret |= this.rollback_bit(bebit(input, 25), isEncrypted) << 1; ret |= this.rollback_bit(bebit(input, 24), isEncrypted) << 0; ret |= this.rollback_bit(bebit(input, 23), isEncrypted) << 15; ret |= this.rollback_bit(bebit(input, 22), isEncrypted) << 14; ret |= this.rollback_bit(bebit(input, 21), isEncrypted) << 13; ret |= this.rollback_bit(bebit(input, 20), isEncrypted) << 12; ret |= this.rollback_bit(bebit(input, 19), isEncrypted) << 11; ret |= this.rollback_bit(bebit(input, 18), isEncrypted) << 10; ret |= this.rollback_bit(bebit(input, 17), isEncrypted) << 9; ret |= this.rollback_bit(bebit(input, 16), isEncrypted) << 8; ret |= this.rollback_bit(bebit(input, 15), isEncrypted) << 23; ret |= this.rollback_bit(bebit(input, 14), isEncrypted) << 22; ret |= this.rollback_bit(bebit(input, 13), isEncrypted) << 21; ret |= this.rollback_bit(bebit(input, 12), isEncrypted) << 20; ret |= this.rollback_bit(bebit(input, 11), isEncrypted) << 19; ret |= this.rollback_bit(bebit(input, 10), isEncrypted) << 18; ret |= this.rollback_bit(bebit(input, 9), isEncrypted) << 17; ret |= this.rollback_bit(bebit(input, 8), isEncrypted) << 16; ret |= this.rollback_bit(bebit(input, 7), isEncrypted) << 31; ret |= this.rollback_bit(bebit(input, 6), isEncrypted) << 30; ret |= this.rollback_bit(bebit(input, 5), isEncrypted) << 29; ret |= this.rollback_bit(bebit(input, 4), isEncrypted) << 28; ret |= this.rollback_bit(bebit(input, 3), isEncrypted) << 27; ret |= this.rollback_bit(bebit(input, 2), isEncrypted) << 26; ret |= this.rollback_bit(bebit(input, 1), isEncrypted) << 25; ret |= this.rollback_bit(bebit(input, 0), isEncrypted) << 24; return ret; } } export * from "./crapto1.js"; export * from "./utils.js";