@li0ard/crapto1_ts
Version:
Crapto1 TypeScript implement
189 lines (188 loc) • 8.96 kB
JavaScript
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";