Telegram Web K with changes to work inside I2P
https://web.telegram.i2p/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
6.9 KiB
225 lines
6.9 KiB
/* |
|
* https://github.com/morethanwords/tweb |
|
* Copyright (C) 2019-2021 Eduard Kuzmenko |
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE |
|
*/ |
|
|
|
//import aesjs from 'aes-js'; |
|
import randomize from "../../../helpers/array/randomize"; |
|
import cryptoMessagePort from "../../crypto/cryptoMessagePort"; |
|
import { Codec } from "./codec"; |
|
|
|
/* |
|
@cryptography/aes не работает с массивами которые не кратны 4, поэтому использую intermediate а не abridged |
|
*/ |
|
export default class Obfuscation { |
|
/* private enc: aesjs.ModeOfOperation.ModeOfOperationCTR; |
|
private dec: aesjs.ModeOfOperation.ModeOfOperationCTR; */ |
|
|
|
private id: number; |
|
private idPromise: Promise<Obfuscation['id']>; |
|
private process: (data: Uint8Array, operation: 'encrypt' | 'decrypt') => ReturnType<Obfuscation['_process']>; |
|
|
|
// private cryptoEncKey: CryptoKey; |
|
// private cryptoDecKey: CryptoKey; |
|
// private cryptoKey: CryptoKey; |
|
|
|
// private encIv: Uint8Array; |
|
// private decIv: Uint8Array; |
|
|
|
// private decIvCounter: Counter; |
|
|
|
public async init(codec: Codec) { |
|
if(this.idPromise !== undefined) { |
|
this.release(); |
|
} |
|
|
|
const initPayload = new Uint8Array(64); |
|
randomize(initPayload); |
|
|
|
while(true) { |
|
const val = (initPayload[3] << 24) | (initPayload[2] << 16) | (initPayload[1] << 8) | initPayload[0]; |
|
const 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; |
|
} |
|
randomize(initPayload); |
|
} |
|
|
|
////////////////////////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 = /* this.encIv = */initPayload.slice(40, 56); |
|
const decKey = reversedPayload.slice(8, 40); |
|
const decIv = /* this.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); |
|
|
|
const idPromise = this.idPromise = cryptoMessagePort.invokeCrypto('aes-ctr-prepare', { |
|
encKey, |
|
encIv, |
|
decKey, |
|
decIv |
|
}); |
|
|
|
this.process = async(data, operation) => { |
|
await idPromise; |
|
return this._process(data, operation); |
|
}; |
|
|
|
this.id = await idPromise; |
|
|
|
this.process = this._process; |
|
|
|
// this.decIvCounter = new Counter(this.decIv); |
|
/* const key = this.cryptoEncKey = await subtle.importKey( |
|
'raw', |
|
encKey, |
|
{name: 'AES-CTR'}, |
|
false, |
|
['encrypt'] |
|
); */ |
|
|
|
// this.cryptoDecKey = await subtle.importKey( |
|
// 'raw', |
|
// decKey, |
|
// {name: 'AES-CTR'}, |
|
// false, |
|
// ['encrypt'] |
|
// ); |
|
|
|
// this.cryptoKey = await subtle.importKey( |
|
// 'raw', |
|
// encKey, |
|
// {name: 'AES-CTR'}, |
|
// false, |
|
// ['encrypt', 'decrypt'] |
|
// ); |
|
|
|
initPayload.set(codec.obfuscateTag, 56); |
|
const encrypted = await this.encode(initPayload.slice()); |
|
|
|
//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; |
|
} */ |
|
|
|
private _process = (data: Uint8Array, operation: 'encrypt' | 'decrypt') => { |
|
return cryptoMessagePort.invoke('invoke', { |
|
method: 'aes-ctr-process', |
|
args: [{id: this.id, data, operation}], |
|
}, undefined, undefined, [data.buffer]) as Promise<Uint8Array>; |
|
}; |
|
|
|
public encode(payload: Uint8Array) { |
|
/* return subtle.encrypt({ |
|
name: 'AES-CTR', |
|
counter: this.encIv, |
|
length: 64 |
|
}, |
|
this.cryptoEncKey, |
|
payload |
|
); */ |
|
return this.process(payload, 'encrypt'); |
|
} |
|
|
|
public decode(payload: Uint8Array) { |
|
return this.process(payload, 'decrypt'); |
|
} |
|
|
|
public async release() { |
|
const idPromise = this.idPromise; |
|
if(idPromise === undefined) { |
|
return; |
|
} |
|
|
|
this.id = undefined; |
|
this.idPromise = undefined; |
|
|
|
const id = await idPromise; |
|
cryptoMessagePort.invokeCrypto('aes-ctr-destroy', id); |
|
} |
|
|
|
public destroy() { |
|
this.release(); |
|
} |
|
|
|
// public encode(payload: Uint8Array) { |
|
// let res = this.encNew.encrypt(payload); |
|
// let bytes = new Uint8Array(bytesFromWordss(res)); |
|
|
|
// return bytes; |
|
// } |
|
|
|
// public async decode(payload: Uint8Array) { |
|
// const counter = this.decIvCounter.counter.slice(); |
|
// this.decIvCounter.increment(); |
|
|
|
// const n: ArrayBuffer = await subtle.encrypt({ |
|
// name: 'AES-CTR', |
|
// counter: counter, |
|
// length: 64 |
|
// }, |
|
// this.cryptoDecKey, |
|
// payload |
|
// ); |
|
|
|
// const decoded = this.decNew.update(payload); |
|
|
|
// console.log('decode', bytesToHex(decoded), 'new', n, bytesToHex(new Uint8Array(n))); |
|
|
|
// return decoded; |
|
// } |
|
} |