tweb/src/lib/mtproto/transports/obfuscation.ts

167 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//import aesjs from 'aes-js';
import AES from "@cryptography/aes";
import { bytesFromWordss } from "../../../helpers/bytes";
import { Codec } from "./codec";
class Counter {
_counter: Uint8Array;
constructor(initialValue: Uint8Array) {
this._counter = initialValue;
}
increment() {
for(let i = 15; i >= 0; i--) {
if(this._counter[i] === 255) {
this._counter[i] = 0;
} else {
this._counter[i]++;
break;
}
}
}
}
class CTR {
_counter: Counter;
_remainingCounter: Uint8Array = null;
_remainingCounterIndex = 16;
_aes: AES;
constructor(key: Uint8Array, counter: Uint8Array) {
this._counter = new Counter(counter);
this._aes = new AES(key);
}
update(payload: Uint8Array) {
const encrypted = payload.slice();
for(let i = 0; i < encrypted.length; i++) {
if(this._remainingCounterIndex === 16) {
this._remainingCounter = new Uint8Array(bytesFromWordss(this._aes.encrypt(this._counter._counter)));
this._remainingCounterIndex = 0;
this._counter.increment();
}
encrypted[i] ^= this._remainingCounter[this._remainingCounterIndex++];
}
return encrypted;
}
}
/*
@cryptography/aes не работает с массивами которые не кратны 4, поэтому использую intermediate а не abridged
*/
export default class Obfuscation {
/* public enc: aesjs.ModeOfOperation.ModeOfOperationCTR;
public dec: aesjs.ModeOfOperation.ModeOfOperationCTR; */
public encNew: CTR;
public decNew: CTR;
public init(codec: Codec) {
const initPayload = new Uint8Array(64);
initPayload.randomize();
while(true) {
let val = (initPayload[3] << 24) | (initPayload[2] << 16) | (initPayload[1] << 8) | (initPayload[0]);
let val2 = (initPayload[7] << 24) | (initPayload[6] << 16) | (initPayload[5] << 8) | (initPayload[4]);
if(initPayload[0] !== 0xef &&
val !== 0x44414548 &&
val !== 0x54534f50 &&
val !== 0x20544547 &&
val !== 0x4954504f &&
val !== 0xeeeeeeee &&
val !== 0xdddddddd &&
val2 !== 0x00000000) {
//initPayload[56] = initPayload[57] = initPayload[58] = initPayload[59] = transport;
break;
}
initPayload.randomize();
}
////////////////////////initPayload.subarray(60, 62).hex = dcId;
/* initPayload.set(new Uint8Array([161, 208, 67, 71, 118, 109, 20, 111, 113, 255, 134, 10, 159, 241, 7, 44, 217, 82, 187, 76, 108, 131, 200, 186, 33, 57, 177, 251, 52, 34, 18, 54, 65, 105, 37, 89, 38, 20, 47, 168, 126, 181, 24, 138, 212, 68, 60, 150, 225, 37, 181, 4, 201, 50, 72, 151, 168, 143, 204, 169, 81, 187, 241, 23]));
console.log('initPayload', initPayload); */
const reversedPayload = initPayload.slice().reverse();
const encKey = initPayload.slice(8, 40);
const encIv = initPayload.slice(40, 56);
const decKey = reversedPayload.slice(8, 40);
const decIv = reversedPayload.slice(40, 56);
/* this.enc = new aesjs.ModeOfOperation.ctr(encKey, new aesjs.Counter(encIv as any));
this.dec = new aesjs.ModeOfOperation.ctr(decKey, new aesjs.Counter(decIv as any)); */
console.log('encKey', encKey.hex, encIv.hex);
console.log('decKey', decKey.hex, decIv.hex);
this.encNew = new CTR(encKey, encIv);
this.decNew = new CTR(decKey, decIv);
initPayload.set(codec.obfuscateTag, 56);
const encrypted = this.encode(initPayload);
//console.log('encrypted', encrypted);
initPayload.set(encrypted.slice(56, 64), 56);
return initPayload;
}
/* public encode(payload: Uint8Array) {
let startTime = performance.now();
let res = this.enc.encrypt(payload);
let time = performance.now() - startTime;
try {
startTime = performance.now();
let arr = this.encNew.encrypt(payload);
//let resNew = bytesFromWords({words: arr, sigBytes: arr.length});
let resNew = new Uint8Array(bytesFromWordss(arr));
let time2 = performance.now() - startTime;
console.log('Obfuscation: encode comparison:', res, arr, resNew, res.hex === resNew.hex, time2 < time);
} catch(err) {
console.error('Obfuscation: error:', err);
}
return res;
}
public decode(payload: Uint8Array) {
let res = this.dec.encrypt(payload);
try {
let arr = this.decNew.decrypt(payload);
//let resNew = bytesFromWords({words: arr, sigBytes: arr.length});
let resNew = new Uint8Array(bytesFromWordss(arr));
console.log('Obfuscation: decode comparison:', res, arr, resNew, res.hex === resNew.hex);
} catch(err) {
console.error('Obfuscation: error:', err);
}
return res;
} */
public encode(payload: Uint8Array) {
return this.encNew.update(payload);
}
public decode(payload: Uint8Array) {
return this.decNew.update(payload);
}
/* public encode(payload: Uint8Array) {
let res = this.encNew.encrypt(payload);
let bytes = new Uint8Array(bytesFromWordss(res));
return bytes;
}
public decode(payload: Uint8Array) {
let res = this.decNew.decrypt(payload);
let bytes = new Uint8Array(bytesFromWordss(res));
return bytes;
} */
}