@ -20,7 +20,7 @@ import { logger, LogTypes } from "../logger";
import { bytesCmp , bytesToHex , bytesFromHex , bytesXor } from "../../helpers/bytes" ;
import { bytesCmp , bytesToHex , bytesFromHex , bytesXor } from "../../helpers/bytes" ;
import DEBUG from "../../config/debug" ;
import DEBUG from "../../config/debug" ;
import { cmp , int2bigInt , one , pow , str2bigInt , sub } from "../../vendor/leemon" ;
import { cmp , int2bigInt , one , pow , str2bigInt , sub } from "../../vendor/leemon" ;
import { Awaited } from "../../type s";
import { addPadding } from "./bin_util s";
/ * l e t f N e w N o n c e : a n y = b y t e s F r o m H e x ( ' 8 7 6 1 9 7 0 c 2 4 c b 2 3 2 9 b 5 b 2 4 5 9 7 5 2 c 5 0 2 f 3 0 5 7 c b 7 e 8 d b a b 2 0 0 e 5 2 6 e 8 7 6 7 f d c 7 3 b 3 c ' ) . r e v e r s e ( ) ;
/ * l e t f N e w N o n c e : a n y = b y t e s F r o m H e x ( ' 8 7 6 1 9 7 0 c 2 4 c b 2 3 2 9 b 5 b 2 4 5 9 7 5 2 c 5 0 2 f 3 0 5 7 c b 7 e 8 d b a b 2 0 0 e 5 2 6 e 8 7 6 7 f d c 7 3 b 3 c ' ) . r e v e r s e ( ) ;
let fNonce : any = bytesFromHex ( 'b597720d11faa5914ef485c529cde414' ) . reverse ( ) ;
let fNonce : any = bytesFromHex ( 'b597720d11faa5914ef485c529cde414' ) . reverse ( ) ;
@ -44,14 +44,14 @@ type AuthOptions = {
} ,
} ,
// good
// good
p? : number [ ] ,
p? : Uint8Array ,
q? : number [ ] ,
q? : Uint8Array ,
newNonce? : Uint8Array ,
newNonce? : Uint8Array ,
retry? : number ,
retry? : number ,
b? : number [ ] ,
b? : Uint8Array ,
g? : number ,
g? : number ,
gA? : Uint8Array ,
gA? : Uint8Array ,
dhPrime? : Uint8Array ,
dhPrime? : Uint8Array ,
@ -60,13 +60,41 @@ type AuthOptions = {
tmpAesIv? : Uint8Array ,
tmpAesIv? : Uint8Array ,
authKeyId? : Uint8Array ,
authKeyId? : Uint8Array ,
authKey? : number [ ] ,
authKey? : Uint8Array ,
serverSalt? : number [ ] ,
serverSalt? : Uint8Array ,
localTime? : number ,
localTime? : number ,
serverTime? : any
serverTime? : any
} ;
} ;
type ResPQ = {
_ : 'resPQ' ;
nonce : Uint8Array ;
pq : Uint8Array ;
server_nonce : Uint8Array ;
server_public_key_fingerprints : string [ ] ;
} ;
type P_Q_inner_data = {
_ : 'p_q_inner_data_dc' ;
pq : Uint8Array ;
p : Uint8Array ;
q : Uint8Array ;
nonce : Uint8Array ;
server_nonce : Uint8Array ;
new_nonce : Uint8Array ;
dc : number ;
} ;
type req_DH_params = {
nonce : Uint8Array ;
server_nonce : Uint8Array ;
p : Uint8Array ;
q : Uint8Array ;
public_key_fingerprint : string ;
encrypted_data : Uint8Array ;
} ;
export class Authorizer {
export class Authorizer {
private cached : {
private cached : {
[ dcId : number ] : Promise < AuthOptions >
[ dcId : number ] : Promise < AuthOptions >
@ -78,36 +106,24 @@ export class Authorizer {
this . log = logger ( ` AUTHORIZER ` , LogTypes . Error | LogTypes . Log ) ;
this . log = logger ( ` AUTHORIZER ` , LogTypes . Error | LogTypes . Log ) ;
}
}
public mtpS endPlainRequest ( dcId : number , requestArray : Uint8Array ) {
private s endPlainRequest ( dcId : number , requestArray : Uint8Array ) {
const requestLength = requestArray . byteLength ;
const requestLength = requestArray . byteLength ;
//requestArray = new /* Int32Array */Uint8Array(requestBuffer);
const header = new TLSerialization ( ) ;
const header = new TLSerialization ( ) ;
header . storeLongP ( 0 , 0 , 'auth_key_id' ) ; // Auth key
header . storeLongP ( 0 , 0 , 'auth_key_id' ) ;
header . storeLong ( timeManager . generateId ( ) , 'msg_id' ) ; // Msg_id
header . storeLong ( timeManager . generateId ( ) , 'msg_id' ) ;
header . storeInt ( requestLength , 'request_length' ) ;
header . storeInt ( requestLength , 'request_length' ) ;
const headerArray = header . getBytes ( true ) as Uint8Array ;
const headerArray = header . getBytes ( true ) as Uint8Array ;
const resultArray = new Uint8Array ( headerArray . byteLength + requestLength ) ;
const resultArray = new Uint8Array ( headerArray . byteLength + requestLength ) ;
resultArray . set ( headerArray ) ;
resultArray . set ( headerArray ) ;
resultArray . set ( requestArray , headerArray . length ) ;
resultArray . set ( requestArray , headerArray . length ) ;
/ * c o n s t h e a d e r B u f f e r = h e a d e r . g e t B u f f e r ( ) ,
headerArray = new Int32Array ( headerBuffer ) ;
const headerLength = headerBuffer . byteLength ;
const resultBuffer = new ArrayBuffer ( headerLength + requestLength ) ,
resultArray = new Int32Array ( resultBuffer ) ;
resultArray . set ( headerArray ) ;
resultArray . set ( requestArray , headerArray . length ) ;
const requestData = xhrSendBuffer ? resultBuffer : resultArray ; * /
const transport = dcConfigurator . chooseServer ( dcId ) ;
const transport = dcConfigurator . chooseServer ( dcId ) ;
const baseError = {
const baseError = {
code : 406 ,
code : 406 ,
type : 'NETWORK_BAD_RESPONSE' ,
type : 'NETWORK_BAD_RESPONSE' ,
transport : transport
transport
} ;
} ;
if ( DEBUG ) {
if ( DEBUG ) {
@ -121,7 +137,7 @@ export class Authorizer {
}
}
if ( ! result || ! result . byteLength ) {
if ( ! result || ! result . byteLength ) {
return Promise . reject ( baseError ) ;
throw baseError ;
}
}
try {
try {
@ -129,6 +145,13 @@ export class Authorizer {
fResult = new Uint8Array ( 0 ) ; * /
fResult = new Uint8Array ( 0 ) ; * /
const deserializer = new TLDeserialization ( result , { mtproto : true } ) ;
const deserializer = new TLDeserialization ( result , { mtproto : true } ) ;
if ( result . length === 4 ) {
const errorCode = deserializer . fetchInt ( ) ;
this . log . error ( 'mtpSendPlainRequest: wrong response, error code:' , errorCode ) ;
throw errorCode ;
}
const auth_key_id = deserializer . fetchLong ( 'auth_key_id' ) ;
const auth_key_id = deserializer . fetchLong ( 'auth_key_id' ) ;
if ( auth_key_id !== '0' ) this . log . error ( 'auth_key_id !== 0' , auth_key_id ) ;
if ( auth_key_id !== '0' ) this . log . error ( 'auth_key_id !== 0' , auth_key_id ) ;
@ -144,39 +167,38 @@ export class Authorizer {
const error = Object . assign ( baseError , { originalError : e } ) ;
const error = Object . assign ( baseError , { originalError : e } ) ;
throw error ;
throw error ;
}
}
} , error = > {
} , ( error ) = > {
if ( ! error . message && ! error . type ) {
if ( ! error . message && ! error . type ) {
error = Object . assign ( baseError , {
error = Object . assign ( baseError , {
originalError : error
originalError : error
} ) ;
} ) ;
}
}
return Promise . reject ( error ) ;
throw error ;
} ) ;
} ) ;
}
}
public async mtpS endReqPQ ( auth : AuthOptions ) {
private async s endReqPQ ( auth : AuthOptions ) {
const request = new TLSerialization ( { mtproto : true } ) ;
const request = new TLSerialization ( { mtproto : true } ) ;
request . storeMethod ( 'req_pq_multi' , { nonce : auth.nonce } ) ;
request . storeMethod ( 'req_pq_multi' , { nonce : auth.nonce } ) ;
// need
rsaKeysManager . prepare ( ) . then ( ( ) = > { } ) ;
if ( DEBUG ) {
if ( DEBUG ) {
this . log ( 'Send req_pq' , auth . nonce . hex ) ;
this . log ( 'Send req_pq' , auth . nonce . hex ) ;
}
}
let deserializer : TLDeserialization ;
let deserializer : TLDeserialization ;
try {
try {
deserializer = await this . mtpSendPlainRequest ( auth . dcId , request . getBytes ( true ) ) ;
const promise = this . sendPlainRequest ( auth . dcId , request . getBytes ( true ) ) ;
rsaKeysManager . prepare ( ) ;
deserializer = await promise ;
} catch ( error ) {
} catch ( error ) {
this . log . error ( 'req_pq error' , error . message ) ;
this . log . error ( 'req_pq error' , error . message ) ;
throw error ;
throw error ;
}
}
const response = deserializer . fetchObject ( 'ResPQ' ) ;
const response : ResPQ = deserializer . fetchObject ( 'ResPQ' ) ;
if ( response . _ !== 'resPQ' ) {
if ( response . _ !== 'resPQ' ) {
throw new Error ( '[MT] resPQ response invalid: ' + response . _ ) ;
throw new Error ( '[MT] resPQ response invalid: ' + response . _ ) ;
}
}
@ -186,8 +208,7 @@ export class Authorizer {
throw new Error ( '[MT] resPQ nonce mismatch' ) ;
throw new Error ( '[MT] resPQ nonce mismatch' ) ;
}
}
//auth.serverNonce = response.server_nonce;
auth . serverNonce = response . server_nonce ; // need
auth . serverNonce = new Uint8Array ( response . server_nonce ) ; // need
auth . pq = response . pq ;
auth . pq = response . pq ;
auth . fingerprints = response . server_public_key_fingerprints ;
auth . fingerprints = response . server_public_key_fingerprints ;
@ -206,9 +227,9 @@ export class Authorizer {
this . log ( 'PQ factorization start' , auth . pq ) ;
this . log ( 'PQ factorization start' , auth . pq ) ;
}
}
let pAndQ : Awaited < ReturnType < typeof CryptoWorker [ ' factorize ' ] > > ;
// let pAndQ: Awaited<ReturnType<typeof CryptoWorker['factorize']>>;
try {
try {
pAndQ = await CryptoWorker . factorize ( auth . pq ) ;
var pAndQ = await CryptoWorker . invokeCrypto ( 'factorize' , auth . pq ) ;
} catch ( error ) {
} catch ( error ) {
this . log . error ( 'worker error factorize' , error ) ;
this . log . error ( 'worker error factorize' , error ) ;
throw error ;
throw error ;
@ -220,62 +241,66 @@ export class Authorizer {
if ( DEBUG ) {
if ( DEBUG ) {
this . log ( 'PQ factorization done' , pAndQ ) ;
this . log ( 'PQ factorization done' , pAndQ ) ;
}
}
/ * c o n s t p = n e w U i n t 3 2 A r r a y ( n e w U i n t 8 A r r a y ( a u t h . p ) . b u f f e r ) [ 0 ] ;
const q = new Uint32Array ( new Uint8Array ( auth . q ) . buffer ) [ 0 ] ;
console . log ( dT ( ) , 'PQ factorization done' , pAndQ , p . toString ( 16 ) , q . toString ( 16 ) ) ; * /
return this . mtpS endReqDhParams( auth ) ;
return this . sendReqDhParams ( auth ) ;
}
}
public async mtpS endReqDhParams ( auth : AuthOptions ) {
private async s endReqDhParams ( auth : AuthOptions ) {
auth . newNonce = new Uint8Array ( 32 ) . randomize ( ) ;
auth . newNonce = new Uint8Array ( 32 ) . randomize ( ) ;
/* auth.newNonce = new Array(32); / / need array , not uint8array !
MTProto . secureRandom . nextBytes ( auth . newNonce ) ; * /
const p_q_inner_data_dc : P_Q_inner_data = {
_ : 'p_q_inner_data_dc' ,
//console.log("TCL: Authorizer -> mtpSendReqDhParams -> auth.newNonce", auth.newNonce)
// remove
// auth.newNonce = fNewNonce ? fNewNonce : auth.newNonce;
// console.log("TCL: Authorizer -> mtpSendReqDhParams -> auth.newNonce", auth.newNonce);
const p_q_inner_data = {
_ : 'p_q_inner_data' ,
pq : auth.pq ,
pq : auth.pq ,
p : auth.p ,
p : auth.p ,
q : auth.q ,
q : auth.q ,
nonce : auth.nonce ,
nonce : auth.nonce ,
server_nonce : auth.serverNonce ,
server_nonce : auth.serverNonce ,
new_nonce : auth.newNonce
new_nonce : auth.newNonce ,
dc : 0
} ;
} ;
const data = new TLSerialization ( { mtproto : true } ) ;
const pQInnerDataSerialization = new TLSerialization ( { mtproto : true } ) ;
data . storeObject ( p_q_inner_data , 'P_Q_inner_data' , 'DECRYPTED_DATA' ) ;
pQInnerDataSerialization . storeObject ( p_q_inner_data_dc , 'P_Q_inner_data' , 'DECRYPTED_DATA' ) ;
/ * c o n s o l e . l o g ( ' p _ q _ i n n e r _ d a t a ' , p _ q _ i n n e r _ d a t a ,
bytesToHex ( bytesFromArrayBuffer ( data . getBuffer ( ) ) ) ,
const data = pQInnerDataSerialization . getBytes ( true ) ;
sha1BytesSync ( data . getBuffer ( ) ) ,
if ( data . length > 144 ) {
bytesFromArrayBuffer ( await CryptoWorker . sha1Hash ( data . getBuffer ( ) ) ) ) ; * /
throw 'DH_params: data is more than 144 bytes!' ;
}
const uint8Data = data . getBytes ( true ) ;
const sha1Hashed = await CryptoWorker . sha1Hash ( uint8Data ) ;
const dataWithPadding = addPadding ( data , 192 , false , true , false ) ;
const dataPadReversed = dataWithPadding . slice ( ) . reverse ( ) ;
//const dataWithHash = sha1BytesSync(data.getBuffer()).concat(data.getBytes() as number[]);
const dataWithHash = sha1Hashed . concat ( uint8Data ) ;
const getKeyAesEncrypted = async ( ) = > {
for ( ; ; ) {
//dataWithHash = addPadding(dataWithHash, 255);
const tempKey = new Uint8Array ( 32 ) . randomize ( ) ;
//dataWithHash = dataWithHash.concat(bytesFromHex('96228ea7790e71caaabc2ab67f4412e9aa224c664d232cc08617a32ce1796aa052da4a737083211689858f461e4473fd6394afd3aa0c8014840dc13f47beaf4fc3b9229aea9cfa83f9f6e676e50ee7676542fb75606879ee7e65cf3a2295b4ba0934ceec1011560c62395a6e9593bfb117cd0da75ba56723672d100ac17ec4d805aa59f7852e3a25a79ee4'));
const dataWithHash = dataPadReversed . concat ( await CryptoWorker . invokeCrypto ( 'sha256-hash' , tempKey . concat ( dataWithPadding ) ) ) ;
//console.log('sha1Hashed', bytesToHex(sha1Hashed), 'dataWithHash', bytesToHex(dataWithHash), dataWithHash.length);
if ( dataWithHash . length !== 224 ) {
throw 'DH_params: dataWithHash !== 224 bytes!' ;
const rsaEncrypted = await CryptoWorker . rsaEncrypt ( auth . publicKey , dataWithHash ) ;
}
//console.log('rsaEncrypted', rsaEncrypted, new Uint8Array(rsaEncrypted).hex);
const aesEncrypted = await CryptoWorker . invokeCrypto ( 'aes-encrypt' , dataWithHash , tempKey , new Uint8Array ( [ 0 ] ) ) ;
const tempKeyXor = bytesXor ( tempKey , await CryptoWorker . invokeCrypto ( 'sha256-hash' , aesEncrypted ) ) ;
const keyAesEncrypted = tempKeyXor . concat ( aesEncrypted ) ;
const keyAesEncryptedBigInt = str2bigInt ( bytesToHex ( keyAesEncrypted ) , 16 ) ;
const publicKeyModulusBigInt = str2bigInt ( auth . publicKey . modulus , 16 ) ;
if ( cmp ( keyAesEncryptedBigInt , publicKeyModulusBigInt ) === - 1 ) {
return keyAesEncrypted ;
}
}
} ;
const req_DH_params = {
const keyAesEncrypted = await getKeyAesEncrypted ( ) ;
const encryptedData = await CryptoWorker . invokeCrypto ( 'rsa-encrypt' , keyAesEncrypted , auth . publicKey ) ;
const req_DH_params : req_DH_params = {
nonce : auth.nonce ,
nonce : auth.nonce ,
server_nonce : auth.serverNonce ,
server_nonce : auth.serverNonce ,
p : auth.p ,
p : auth.p ,
q : auth.q ,
q : auth.q ,
public_key_fingerprint : auth.publicKey.fingerprint ,
public_key_fingerprint : auth.publicKey.fingerprint ,
encrypted_data : rsaEncrypted
encrypted_data : encryptedData
} ;
} ;
const request = new TLSerialization ( { mtproto : true } ) ;
const request = new TLSerialization ( { mtproto : true } ) ;
@ -289,7 +314,7 @@ export class Authorizer {
let deserializer : TLDeserialization ;
let deserializer : TLDeserialization ;
try {
try {
deserializer = await this . mtpS endPlainRequest( auth . dcId , requestBytes ) ;
deserializer = await this . s endPlainRequest( auth . dcId , requestBytes ) ;
} catch ( error ) {
} catch ( error ) {
this . log . error ( 'Send req_DH_params FAIL!' , error ) ;
this . log . error ( 'Send req_DH_params FAIL!' , error ) ;
throw error ;
throw error ;
@ -314,8 +339,7 @@ export class Authorizer {
}
}
if ( response . _ === 'server_DH_params_fail' ) {
if ( response . _ === 'server_DH_params_fail' ) {
//const newNonceHash = sha1BytesSync(auth.newNonce).slice(-16);
const newNonceHash = ( await CryptoWorker . invokeCrypto ( 'sha1-hash' , auth . newNonce ) ) . slice ( - 16 ) ;
const newNonceHash = ( await CryptoWorker . sha1Hash ( auth . newNonce ) ) . slice ( - 16 ) ;
if ( ! bytesCmp ( newNonceHash , response . new_nonce_hash ) ) {
if ( ! bytesCmp ( newNonceHash , response . new_nonce_hash ) ) {
throw new Error ( '[MT] server_DH_params_fail new_nonce_hash mismatch' ) ;
throw new Error ( '[MT] server_DH_params_fail new_nonce_hash mismatch' ) ;
}
}
@ -325,7 +349,7 @@ export class Authorizer {
// fill auth object
// fill auth object
try {
try {
await this . mtpD ecryptServerDhDataAnswer( auth , response . encrypted_answer ) ;
await this . d ecryptServerDhDataAnswer( auth , response . encrypted_answer ) ;
} catch ( e ) {
} catch ( e ) {
this . log . error ( 'mtpDecryptServerDhDataAnswer FAILED!' , e ) ;
this . log . error ( 'mtpDecryptServerDhDataAnswer FAILED!' , e ) ;
throw e ;
throw e ;
@ -333,35 +357,24 @@ export class Authorizer {
//console.log(dT(), 'mtpSendReqDhParams: executing mtpSendSetClientDhParams...');
//console.log(dT(), 'mtpSendReqDhParams: executing mtpSendSetClientDhParams...');
return this . mtpS endSetClientDhParams( auth as any ) ; // костыль
return this . s endSetClientDhParams( auth ) ;
}
}
public async mtpD ecryptServerDhDataAnswer ( auth : AuthOptions , encryptedAnswer : any ) {
private async d ecryptServerDhDataAnswer ( auth : AuthOptions , encryptedAnswer : any ) {
auth . localTime = Date . now ( ) ;
auth . localTime = Date . now ( ) ;
// can't concat Array with Uint8Array!
// ! can't concat Array with Uint8Array!
//auth.tmpAesKey = sha1BytesSync(auth.newNonce.concat(auth.serverNonce)).concat(sha1BytesSync(auth.serverNonce.concat(auth.newNonce)).slice(0, 12));
auth . tmpAesKey = ( await CryptoWorker . invokeCrypto ( 'sha1-hash' , auth . newNonce . concat ( auth . serverNonce ) ) )
//auth.tmpAesIv = sha1BytesSync(auth.serverNonce.concat(auth.newNonce)).slice(12).concat(sha1BytesSync([].concat(auth.newNonce, auth.newNonce)), auth.newNonce.slice(0, 4));
. concat ( ( await CryptoWorker . invokeCrypto ( 'sha1-hash' , auth . serverNonce . concat ( auth . newNonce ) ) ) . slice ( 0 , 12 ) ) ;
auth . tmpAesKey = ( await CryptoWorker . sha1Hash ( auth . newNonce . concat ( auth . serverNonce ) ) )
. concat ( ( await CryptoWorker . sha1Hash ( auth . serverNonce . concat ( auth . newNonce ) ) ) . slice ( 0 , 12 ) ) ;
auth . tmpAesIv = ( await CryptoWorker . sha1Hash ( auth . serverNonce . concat ( auth . newNonce ) ) ) . slice ( 12 )
. concat ( await CryptoWorker . sha1Hash ( auth . newNonce . concat ( auth . newNonce ) ) , auth . newNonce . slice ( 0 , 4 ) ) ;
/ * c o n s o l e . l o g ( a u t h . s e r v e r N o n c e . c o n c a t ( a u t h . n e w N o n c e ) ) ;
console . log ( auth . newNonce . concat ( auth . serverNonce ) ) ;
console . log ( auth . newNonce . concat ( auth . newNonce ) ) ; * /
auth . tmpAesIv = ( await CryptoWorker . invokeCrypto ( 'sha1-hash' , auth . serverNonce . concat ( auth . newNonce ) ) ) . slice ( 12 )
. concat ( await CryptoWorker . invokeCrypto ( 'sha1-hash' , auth . newNonce . concat ( auth . newNonce ) ) , auth . newNonce . slice ( 0 , 4 ) ) ;
//const answerWithHash = aesDecryptSync(encryptedAnswer, auth.tmpAesKey, auth.tmpAesIv);
const answerWithHash = new Uint8Array ( await CryptoWorker . invokeCrypto ( 'aes-decrypt' , encryptedAnswer , auth . tmpAesKey , auth . tmpAesIv ) ) ;
const answerWithHash = new Uint8Array ( await CryptoWorker . aesDecrypt ( encryptedAnswer , auth . tmpAesKey , auth . tmpAesIv ) ) ;
const hash = answerWithHash . slice ( 0 , 20 ) ;
const hash = answerWithHash . slice ( 0 , 20 ) ;
const answerWithPadding = answerWithHash . slice ( 20 ) ;
const answerWithPadding = answerWithHash . slice ( 20 ) ;
// console.log('hash', hash);
const deserializer = new TLDeserialization ( answerWithPadding , { mtproto : true } ) ;
const deserializer = new TLDeserialization ( answerWithPadding , { mtproto : true } ) ;
const response = deserializer . fetchObject ( 'Server_DH_inner_data' ) ;
const response = deserializer . fetchObject ( 'Server_DH_inner_data' ) ;
@ -386,19 +399,18 @@ export class Authorizer {
auth . serverTime = response . server_time ;
auth . serverTime = response . server_time ;
auth . retry = 0 ;
auth . retry = 0 ;
this . mtpV erifyDhParams( auth . g , auth . dhPrime , auth . gA ) ;
this . v erifyDhParams( auth . g , auth . dhPrime , auth . gA ) ;
const offset = deserializer . getOffset ( ) ;
const offset = deserializer . getOffset ( ) ;
//if(!bytesCmp(hash, sha1BytesSync(answerWithPadding.slice(0, offset)))) {
if ( ! bytesCmp ( hash , await CryptoWorker . invokeCrypto ( 'sha1-hash' , answerWithPadding . slice ( 0 , offset ) ) ) ) {
if ( ! bytesCmp ( hash , await CryptoWorker . sha1Hash ( answerWithPadding . slice ( 0 , offset ) ) ) ) {
throw new Error ( '[MT] server_DH_inner_data SHA1-hash mismatch' ) ;
throw new Error ( '[MT] server_DH_inner_data SHA1-hash mismatch' ) ;
}
}
timeManager . applyServerTime ( auth . serverTime , auth . localTime ) ;
timeManager . applyServerTime ( auth . serverTime , auth . localTime ) ;
}
}
public mtpV erifyDhParams ( g : number , dhPrime : Uint8Array , gA : Uint8Array ) {
private v erifyDhParams ( g : number , dhPrime : Uint8Array , gA : Uint8Array ) {
if ( DEBUG ) {
if ( DEBUG ) {
this . log ( 'Verifying DH params' , g , dhPrime , gA ) ;
this . log ( 'Verifying DH params' , g , dhPrime , gA ) ;
}
}
@ -413,20 +425,13 @@ export class Authorizer {
this . log ( 'dhPrime cmp OK' ) ;
this . log ( 'dhPrime cmp OK' ) ;
}
}
//const gABigInt = new BigInteger(bytesToHex(gA), 16);
const _gABigInt = str2bigInt ( bytesToHex ( gA ) , 16 ) ;
const _gABigInt = str2bigInt ( bytesToHex ( gA ) , 16 ) ;
//const dhPrimeBigInt = new BigInteger(dhPrimeHex, 16);
const _dhPrimeBigInt = str2bigInt ( dhPrimeHex , 16 ) ;
const _dhPrimeBigInt = str2bigInt ( dhPrimeHex , 16 ) ;
//this.log('gABigInt.compareTo(BigInteger.ONE) <= 0', gABigInt.compareTo(BigInteger.ONE), BigInteger.ONE.compareTo(BigInteger.ONE), greater(_gABigInt, one));
//if(gABigInt.compareTo(BigInteger.ONE) <= 0) {
if ( cmp ( _gABigInt , one ) <= 0 ) {
if ( cmp ( _gABigInt , one ) <= 0 ) {
throw new Error ( '[MT] DH params are not verified: gA <= 1' ) ;
throw new Error ( '[MT] DH params are not verified: gA <= 1' ) ;
}
}
/ * t h i s . l o g ( ' g A B i g I n t . c o m p a r e T o ( d h P r i m e B i g I n t . s u b t r a c t ( B i g I n t e g e r . O N E ) ) > = 0 ' , g A B i g I n t . c o m p a r e T o ( d h P r i m e B i g I n t . s u b t r a c t ( B i g I n t e g e r . O N E ) ) ,
greater ( gABigInt , sub ( _dhPrimeBigInt , one ) ) ) ; * /
//if(gABigInt.compareTo(dhPrimeBigInt.subtract(BigInteger.ONE)) >= 0) {
if ( cmp ( _gABigInt , sub ( _dhPrimeBigInt , one ) ) >= 0 ) {
if ( cmp ( _gABigInt , sub ( _dhPrimeBigInt , one ) ) >= 0 ) {
throw new Error ( '[MT] DH params are not verified: gA >= dhPrime - 1' ) ;
throw new Error ( '[MT] DH params are not verified: gA >= dhPrime - 1' ) ;
}
}
@ -435,25 +440,12 @@ export class Authorizer {
this . log ( '1 < gA < dhPrime-1 OK' ) ;
this . log ( '1 < gA < dhPrime-1 OK' ) ;
}
}
//const two = new BigInteger(/* null */'');
//two.fromInt(2);
const _two = int2bigInt ( 2 , 32 , 0 ) ;
const _two = int2bigInt ( 2 , 32 , 0 ) ;
//this.log('_two:', bigInt2str(_two, 16), two.toString(16));
// let perf = performance.now();
//const twoPow = two.pow(2048 - 64);
//console.log('jsbn pow', performance.now() - perf);
// perf = performance.now();
const _twoPow = pow ( _two , 2048 - 64 ) ;
const _twoPow = pow ( _two , 2048 - 64 ) ;
//console.log('leemon pow', performance.now() - perf);
//this.log('twoPow:', twoPow.toString(16), bigInt2str(_twoPow, 16));
// this.log('gABigInt.compareTo(twoPow) < 0');
//if(gABigInt.compareTo(twoPow) < 0) {
if ( cmp ( _gABigInt , _twoPow ) < 0 ) {
if ( cmp ( _gABigInt , _twoPow ) < 0 ) {
throw new Error ( '[MT] DH params are not verified: gA < 2^{2048-64}' ) ;
throw new Error ( '[MT] DH params are not verified: gA < 2^{2048-64}' ) ;
}
}
//if(gABigInt.compareTo(dhPrimeBigInt.subtract(twoPow)) >= 0) {
if ( cmp ( _gABigInt , sub ( _dhPrimeBigInt , _twoPow ) ) >= 0 ) {
if ( cmp ( _gABigInt , sub ( _dhPrimeBigInt , _twoPow ) ) >= 0 ) {
throw new Error ( '[MT] DH params are not verified: gA > dhPrime - 2^{2048-64}' ) ;
throw new Error ( '[MT] DH params are not verified: gA > dhPrime - 2^{2048-64}' ) ;
}
}
@ -465,16 +457,15 @@ export class Authorizer {
return true ;
return true ;
}
}
public async mtpS endSetClientDhParams ( auth : AuthOptions ) : Promise < AuthOptions > {
private async s endSetClientDhParams ( auth : AuthOptions ) : Promise < AuthOptions > {
const gBytes = bytesFromHex ( auth . g . toString ( 16 ) ) ;
const gBytes = bytesFromHex ( auth . g . toString ( 16 ) ) ;
auth . b = new Array ( 256 ) ;
auth . b = new Uint8Array ( 256 ) . randomize ( ) ;
auth . b = [ . . . new Uint8Array ( auth . b . length ) . randomize ( ) ] ;
//MTProto.secureRandom.nextBytes(auth.b);
//MTProto.secureRandom.nextBytes(auth.b);
let gB : number [ ] ;
// let gB: Awaited<ReturnType<typeof CryptoWorker['modPow']>>;
try {
try {
gB = await CryptoWorker . modPow ( gBytes , auth . b , auth . dhPrime ) ;
var gB = await CryptoWorker . invokeCrypto ( 'mod-pow' , gBytes , auth . b , auth . dhPrime ) ;
} catch ( error ) {
} catch ( error ) {
throw error ;
throw error ;
}
}
@ -488,11 +479,8 @@ export class Authorizer {
g_b : gB
g_b : gB
} , 'Client_DH_Inner_Data' ) ;
} , 'Client_DH_Inner_Data' ) ;
//const dataWithHash = sha1BytesSync(data.getBuffer()).concat(data.getBytes());
const dataWithHash = ( await CryptoWorker . invokeCrypto ( 'sha1-hash' , data . getBuffer ( ) ) ) . concat ( data . getBytes ( true ) ) ;
const dataWithHash = ( await CryptoWorker . sha1Hash ( data . getBuffer ( ) ) ) . concat ( data . getBytes ( ) ) ;
const encryptedData = await CryptoWorker . invokeCrypto ( 'aes-encrypt' , dataWithHash , auth . tmpAesKey , auth . tmpAesIv ) ;
//const encryptedData = aesEncryptSync(dataWithHash, auth.tmpAesKey, auth.tmpAesIv);
const encryptedData = await CryptoWorker . aesEncrypt ( dataWithHash , auth . tmpAesKey , auth . tmpAesIv ) ;
const request = new TLSerialization ( { mtproto : true } ) ;
const request = new TLSerialization ( { mtproto : true } ) ;
request . storeMethod ( 'set_client_DH_params' , {
request . storeMethod ( 'set_client_DH_params' , {
@ -507,7 +495,7 @@ export class Authorizer {
let deserializer : TLDeserialization ;
let deserializer : TLDeserialization ;
try {
try {
deserializer = await this . mtpS endPlainRequest( auth . dcId , request . getBytes ( true ) ) ;
deserializer = await this . s endPlainRequest( auth . dcId , request . getBytes ( true ) ) ;
} catch ( err ) {
} catch ( err ) {
throw err ;
throw err ;
}
}
@ -526,15 +514,14 @@ export class Authorizer {
throw new Error ( '[MT] Set_client_DH_params_answer server_nonce mismatch' ) ;
throw new Error ( '[MT] Set_client_DH_params_answer server_nonce mismatch' ) ;
}
}
let authKey : number [ ] ;
// let authKey: Uint8Array;
try {
try {
authKey = await CryptoWorker . modPow ( auth . gA , auth . b , auth . dhPrime ) ;
var authKey = await CryptoWorker . invokeCrypto ( 'mod-pow' , auth . gA , auth . b , auth . dhPrime ) ;
} catch ( err ) {
} catch ( err ) {
throw authKey ;
throw authKey ;
}
}
//const authKeyHash = sha1BytesSync(authKey),
const authKeyHash = await CryptoWorker . invokeCrypto ( 'sha1-hash' , authKey ) ,
const authKeyHash = await CryptoWorker . sha1Hash ( new Uint8Array ( authKey ) ) ,
authKeyAux = authKeyHash . slice ( 0 , 8 ) ,
authKeyAux = authKeyHash . slice ( 0 , 8 ) ,
authKeyId = authKeyHash . slice ( - 8 ) ;
authKeyId = authKeyHash . slice ( - 8 ) ;
@ -542,9 +529,8 @@ export class Authorizer {
this . log ( 'Got Set_client_DH_params_answer' , response . _ , authKey ) ;
this . log ( 'Got Set_client_DH_params_answer' , response . _ , authKey ) ;
}
}
switch ( response . _ ) {
switch ( response . _ ) {
case 'dh_gen_ok' :
case 'dh_gen_ok' : {
const newNonceHash1 = ( await CryptoWorker . sha1Hash ( auth . newNonce . concat ( [ 1 ] , authKeyAux ) ) ) . slice ( - 16 ) ;
const newNonceHash1 = ( await CryptoWorker . invokeCrypto ( 'sha1-hash' , auth . newNonce . concat ( [ 1 ] , authKeyAux ) ) ) . slice ( - 16 ) ;
//const newNonceHash1 = sha1BytesSync(auth.newNonce.concat([1], authKeyAux)).slice(-16);
if ( ! bytesCmp ( newNonceHash1 , response . new_nonce_hash1 ) ) {
if ( ! bytesCmp ( newNonceHash1 , response . new_nonce_hash1 ) ) {
throw new Error ( '[MT] Set_client_DH_params_answer new_nonce_hash1 mismatch' ) ;
throw new Error ( '[MT] Set_client_DH_params_answer new_nonce_hash1 mismatch' ) ;
@ -560,29 +546,28 @@ export class Authorizer {
auth . serverSalt = serverSalt ;
auth . serverSalt = serverSalt ;
return auth ;
return auth ;
break ;
}
case 'dh_gen_retry' :
case 'dh_gen_retry' : {
//const newNonceHash2 = sha1BytesSync(auth.newNonce.concat([2], authKeyAux)).slice(-16);
const newNonceHash2 = ( await CryptoWorker . invokeCrypto ( 'sha1-hash' , auth . newNonce . concat ( [ 2 ] , authKeyAux ) ) ) . slice ( - 16 ) ;
const newNonceHash2 = ( await CryptoWorker . sha1Hash ( auth . newNonce . concat ( [ 2 ] , authKeyAux ) ) ) . slice ( - 16 ) ;
if ( ! bytesCmp ( newNonceHash2 , response . new_nonce_hash2 ) ) {
if ( ! bytesCmp ( newNonceHash2 , response . new_nonce_hash2 ) ) {
throw new Error ( '[MT] Set_client_DH_params_answer new_nonce_hash2 mismatch' ) ;
throw new Error ( '[MT] Set_client_DH_params_answer new_nonce_hash2 mismatch' ) ;
}
}
return this . mtpSendSetClientDhParams ( auth ) ;
return this . sendSetClientDhParams ( auth ) ;
}
case 'dh_gen_fail' :
case 'dh_gen_fail' : {
//const newNonceHash3 = sha1BytesSync(auth.newNonce.concat([3], authKeyAux)).slice(-16);
const newNonceHash3 = ( await CryptoWorker . invokeCrypto ( 'sha1-hash' , auth . newNonce . concat ( [ 3 ] , authKeyAux ) ) ) . slice ( - 16 ) ;
const newNonceHash3 = ( await CryptoWorker . sha1Hash ( auth . newNonce . concat ( [ 3 ] , authKeyAux ) ) ) . slice ( - 16 ) ;
if ( ! bytesCmp ( newNonceHash3 , response . new_nonce_hash3 ) ) {
if ( ! bytesCmp ( newNonceHash3 , response . new_nonce_hash3 ) ) {
throw new Error ( '[MT] Set_client_DH_params_answer new_nonce_hash3 mismatch' ) ;
throw new Error ( '[MT] Set_client_DH_params_answer new_nonce_hash3 mismatch' ) ;
}
}
throw new Error ( '[MT] Set_client_DH_params_answer fail' ) ;
throw new Error ( '[MT] Set_client_DH_params_answer fail' ) ;
}
}
}
}
}
// mtpAuth
public async auth ( dcId : number ) : Promise < AuthOptions > {
public async auth ( dcId : number ) : Promise < AuthOptions > {
if ( dcId in this . cached ) {
if ( dcId in this . cached ) {
return this . cached [ dcId ] ;
return this . cached [ dcId ] ;
@ -596,8 +581,10 @@ export class Authorizer {
return Promise . reject ( new Error ( '[MT] No server found for dc ' + dcId ) ) ;
return Promise . reject ( new Error ( '[MT] No server found for dc ' + dcId ) ) ;
}
}
// await new Promise((resolve) => setTimeout(resolve, 2e3));
try {
try {
const promise = this . mtpSendReqPQ ( { dcId , nonce } ) ;
const promise = this . s endReqPQ( { dcId , nonce } ) ;
this . cached [ dcId ] = promise ;
this . cached [ dcId ] = promise ;
return await promise ;
return await promise ;
} catch ( err ) {
} catch ( err ) {