2019-11-13 14:12:04 +00:00
/*
This file is part of Telegram Desktop ,
the official desktop application for the Telegram messaging service .
For license and copyright information please follow this link :
https : //github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
# include "mtproto/details/mtproto_dc_key_creator.h"
2019-12-02 13:10:19 +00:00
# include "mtproto/details/mtproto_rsa_public_key.h"
2019-11-13 14:12:04 +00:00
# include "mtproto/connection_abstract.h"
# include "mtproto/mtproto_dh_utils.h"
# include "base/openssl_help.h"
# include "base/unixtime.h"
# include "scheme.h"
# include "logs.h"
2019-11-15 14:11:05 +00:00
# include <cmath>
2019-11-13 14:12:04 +00:00
namespace MTP : : details {
namespace {
struct ParsedPQ {
QByteArray p ;
QByteArray q ;
} ;
[[nodiscard]] ParsedPQ ParsePQ ( const QByteArray & pqStr ) {
if ( pqStr . length ( ) > 8 ) {
// More than 64 bit pq.
return ParsedPQ ( ) ;
}
uint64 pq = 0 , p , q ;
const uchar * pqChars = ( const uchar * ) pqStr . constData ( ) ;
for ( uint32 i = 0 , l = pqStr . length ( ) ; i < l ; + + i ) {
pq < < = 8 ;
pq | = ( uint64 ) pqChars [ i ] ;
}
uint64 pqSqrt = ( uint64 ) sqrtl ( ( long double ) pq ) , ySqr , y ;
while ( pqSqrt * pqSqrt > pq ) - - pqSqrt ;
while ( pqSqrt * pqSqrt < pq ) + + pqSqrt ;
for ( ySqr = pqSqrt * pqSqrt - pq ; ; + + pqSqrt , ySqr = pqSqrt * pqSqrt - pq ) {
y = ( uint64 ) sqrtl ( ( long double ) ySqr ) ;
while ( y * y > ySqr ) - - y ;
while ( y * y < ySqr ) + + y ;
if ( ! ySqr | | y + pqSqrt > = pq ) {
return ParsedPQ ( ) ;
}
if ( y * y = = ySqr ) {
p = pqSqrt + y ;
q = ( pqSqrt > y ) ? ( pqSqrt - y ) : ( y - pqSqrt ) ;
break ;
}
}
if ( p > q ) std : : swap ( p , q ) ;
auto pStr = QByteArray ( 4 , Qt : : Uninitialized ) ;
uchar * pChars = ( uchar * ) pStr . data ( ) ;
for ( uint32 i = 0 ; i < 4 ; + + i ) {
* ( pChars + 3 - i ) = ( uchar ) ( p & 0xFF ) ;
p > > = 8 ;
}
auto qStr = QByteArray ( 4 , Qt : : Uninitialized ) ;
uchar * qChars = ( uchar * ) qStr . data ( ) ;
for ( uint32 i = 0 ; i < 4 ; + + i ) {
* ( qChars + 3 - i ) = ( uchar ) ( q & 0xFF ) ;
q > > = 8 ;
}
return { pStr , qStr } ;
}
2019-11-14 07:13:17 +00:00
template < typename PQInnerData >
2019-11-13 14:12:04 +00:00
[[nodiscard]] bytes : : vector EncryptPQInnerRSA (
2019-11-14 07:13:17 +00:00
const PQInnerData & data ,
2019-11-13 14:12:04 +00:00
const RSAPublicKey & key ) {
constexpr auto kSkipPrimes = 6 ;
constexpr auto kMaxPrimes = 65 ; // 260 bytes
2019-11-14 13:34:58 +00:00
using BoxedPQInnerData = std : : conditional_t <
tl : : is_boxed_v < PQInnerData > ,
PQInnerData ,
tl : : boxed < PQInnerData > > ;
const auto boxed = BoxedPQInnerData ( data ) ;
const auto p_q_inner_size = tl : : count_length ( boxed ) ;
2019-11-13 14:12:04 +00:00
const auto sizeInPrimes = ( p_q_inner_size > > 2 ) + kSkipPrimes ;
if ( sizeInPrimes > = kMaxPrimes ) {
auto tmp = mtpBuffer ( ) ;
tmp . reserve ( sizeInPrimes ) ;
2019-11-14 13:34:58 +00:00
boxed . write ( tmp ) ;
2019-11-13 14:12:04 +00:00
LOG ( ( " AuthKey Error: too large data for RSA encrypt, size %1 " ) . arg ( sizeInPrimes * sizeof ( mtpPrime ) ) ) ;
DEBUG_LOG ( ( " AuthKey Error: bad data for RSA encrypt %1 " ) . arg ( Logs : : mb ( & tmp [ 0 ] , tmp . size ( ) * 4 ) . str ( ) ) ) ;
return { } ; // can't be 255-byte string
}
auto encBuffer = mtpBuffer ( ) ;
encBuffer . reserve ( kMaxPrimes ) ;
encBuffer . resize ( kSkipPrimes ) ;
2019-11-14 13:34:58 +00:00
boxed . write ( encBuffer ) ;
2019-11-13 14:12:04 +00:00
encBuffer . resize ( kMaxPrimes ) ;
const auto bytes = bytes : : make_span ( encBuffer ) ;
const auto hashSrc = bytes . subspan (
kSkipPrimes * sizeof ( mtpPrime ) ,
p_q_inner_size ) ;
bytes : : copy ( bytes . subspan ( sizeof ( mtpPrime ) ) , openssl : : Sha1 ( hashSrc ) ) ;
bytes : : set_random ( bytes . subspan ( sizeInPrimes * sizeof ( mtpPrime ) ) ) ;
const auto bytesToEncrypt = bytes . subspan ( 3 , 256 ) ;
return key . encrypt ( bytesToEncrypt ) ;
}
[[nodiscard]] std : : string EncryptClientDHInner (
const MTPClient_DH_Inner_Data & data ,
const void * aesKey ,
const void * aesIV ) {
constexpr auto kSkipPrimes = openssl : : kSha1Size / sizeof ( mtpPrime ) ;
auto client_dh_inner_size = tl : : count_length ( data ) ;
auto encSize = ( client_dh_inner_size > > 2 ) + kSkipPrimes ;
auto encFullSize = encSize ;
if ( encSize & 0x03 ) {
encFullSize + = 4 - ( encSize & 0x03 ) ;
}
auto encBuffer = mtpBuffer ( ) ;
encBuffer . reserve ( encFullSize ) ;
encBuffer . resize ( kSkipPrimes ) ;
data . write ( encBuffer ) ;
encBuffer . resize ( encFullSize ) ;
const auto bytes = bytes : : make_span ( encBuffer ) ;
const auto hash = openssl : : Sha1 ( bytes . subspan (
kSkipPrimes * sizeof ( mtpPrime ) ,
client_dh_inner_size ) ) ;
bytes : : copy ( bytes , hash ) ;
bytes : : set_random ( bytes . subspan ( encSize * sizeof ( mtpPrime ) ) ) ;
auto sdhEncString = std : : string ( encFullSize * 4 , ' ' ) ;
aesIgeEncryptRaw ( & encBuffer [ 0 ] , & sdhEncString [ 0 ] , encFullSize * sizeof ( mtpPrime ) , aesKey , aesIV ) ;
return sdhEncString ;
}
// 128 lower-order bits of SHA1.
MTPint128 NonceDigest ( bytes : : const_span data ) {
const auto hash = openssl : : Sha1 ( data ) ;
return * ( MTPint128 * ) ( hash . data ( ) + 4 ) ;
}
} // namespace
2019-11-19 10:10:51 +00:00
DcKeyCreator : : Attempt : : ~ Attempt ( ) {
const auto clearBytes = [ ] ( bytes : : span bytes ) {
OPENSSL_cleanse ( bytes . data ( ) , bytes . size ( ) ) ;
} ;
OPENSSL_cleanse ( & data , sizeof ( data ) ) ;
clearBytes ( dhPrime ) ;
clearBytes ( g_a ) ;
clearBytes ( authKey ) ;
}
2019-11-13 14:12:04 +00:00
DcKeyCreator : : DcKeyCreator (
DcId dcId ,
int16 protocolDcId ,
not_null < AbstractConnection * > connection ,
not_null < DcOptions * > dcOptions ,
2019-11-14 07:13:17 +00:00
Delegate delegate ,
2019-11-20 09:16:53 +00:00
DcKeyRequest request )
2019-11-13 14:12:04 +00:00
: _connection ( connection )
, _dcOptions ( dcOptions )
, _dcId ( dcId )
, _protocolDcId ( protocolDcId )
2019-11-19 10:10:51 +00:00
, _request ( request )
2019-11-13 14:12:04 +00:00
, _delegate ( std : : move ( delegate ) ) {
2019-11-19 10:10:51 +00:00
Expects ( _request . temporaryExpiresIn > 0 ) ;
2019-11-13 14:12:04 +00:00
Expects ( _delegate . done ! = nullptr ) ;
2019-11-19 10:10:51 +00:00
QObject : : connect ( _connection , & AbstractConnection : : receivedData , [ = ] {
answered ( ) ;
} ) ;
if ( _request . persistentNeeded ) {
pqSend ( & _persistent , 0 ) ;
2019-11-19 16:22:02 +00:00
} else {
pqSend ( & _temporary , _request . temporaryExpiresIn ) ;
2019-11-19 10:10:51 +00:00
}
2019-11-13 14:12:04 +00:00
}
DcKeyCreator : : ~ DcKeyCreator ( ) {
2019-11-15 13:04:32 +00:00
if ( _delegate . done ) {
stopReceiving ( ) ;
}
2019-11-13 14:12:04 +00:00
}
2019-11-19 10:10:51 +00:00
template < typename RequestType >
void DcKeyCreator : : sendNotSecureRequest ( const RequestType & request ) {
auto packet = _connection - > prepareNotSecurePacket (
request ,
base : : unixtime : : mtproto_msg_id ( ) ) ;
2019-11-13 14:12:04 +00:00
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Info: sending request, size: %1, time: %3 "
) . arg ( packet . size ( ) - 8
) . arg ( packet [ 5 ] ) ) ;
2019-11-13 14:12:04 +00:00
2019-11-19 10:10:51 +00:00
const auto bytesSize = packet . size ( ) * sizeof ( mtpPrime ) ;
2019-11-13 14:12:04 +00:00
2019-11-19 10:10:51 +00:00
_connection - > sendData ( std : : move ( packet ) ) ;
2019-11-13 14:12:04 +00:00
2019-11-19 10:10:51 +00:00
if ( _delegate . sentSome ) {
_delegate . sentSome ( bytesSize ) ;
2019-11-13 14:12:04 +00:00
}
2019-11-19 10:10:51 +00:00
}
2019-11-13 14:12:04 +00:00
2019-11-19 10:10:51 +00:00
template < typename RequestType , typename Response >
std : : optional < Response > DcKeyCreator : : readNotSecureResponse (
gsl : : span < const mtpPrime > answer ) {
auto from = answer . data ( ) ;
auto result = Response ( ) ;
if ( result . read ( from , from + answer . size ( ) ) ) {
return result ;
2019-11-13 14:12:04 +00:00
}
2019-11-19 10:10:51 +00:00
return std : : nullopt ;
}
2019-11-13 14:12:04 +00:00
2019-11-19 10:10:51 +00:00
void DcKeyCreator : : answered ( ) {
if ( _delegate . receivedSome ) {
_delegate . receivedSome ( ) ;
}
2019-11-13 14:12:04 +00:00
2019-11-19 10:10:51 +00:00
if ( _connection - > received ( ) . empty ( ) ) {
LOG ( ( " AuthKey Error: "
" trying to read response from empty received list " ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
const auto buffer = std : : move ( _connection - > received ( ) . front ( ) ) ;
_connection - > received ( ) . pop_front ( ) ;
const auto answer = _connection - > parseNotSecureResponse ( buffer ) ;
if ( answer . empty ( ) ) {
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
handleAnswer ( answer ) ;
}
2019-11-13 14:12:04 +00:00
2019-11-19 10:10:51 +00:00
DcKeyCreator : : Attempt * DcKeyCreator : : attemptByNonce ( const MTPint128 & nonce ) {
if ( _temporary . data . nonce = = nonce ) {
DEBUG_LOG ( ( " AuthKey Info: receiving answer for temporary... " ) ) ;
return & _temporary ;
} else if ( _persistent . data . nonce = = nonce ) {
DEBUG_LOG ( ( " AuthKey Info: receiving answer for persistent... " ) ) ;
return & _persistent ;
}
LOG ( ( " AuthKey Error: attempt by nonce not found. " ) ) ;
return nullptr ;
}
2019-11-13 14:12:04 +00:00
2019-11-19 10:10:51 +00:00
void DcKeyCreator : : handleAnswer ( gsl : : span < const mtpPrime > answer ) {
if ( const auto resPQ = readNotSecureResponse < MTPReq_pq > ( answer ) ) {
const auto nonce = resPQ - > match ( [ ] ( const auto & data ) {
return data . vnonce ( ) ;
} ) ;
if ( const auto attempt = attemptByNonce ( nonce ) ) {
DEBUG_LOG ( ( " AuthKey Info: receiving Req_pq answer... " ) ) ;
return pqAnswered ( attempt , * resPQ ) ;
}
} else if ( const auto resDH = readNotSecureResponse < MTPReq_DH_params > ( answer ) ) {
const auto nonce = resDH - > match ( [ ] ( const auto & data ) {
return data . vnonce ( ) ;
} ) ;
if ( const auto attempt = attemptByNonce ( nonce ) ) {
DEBUG_LOG ( ( " AuthKey Info: receiving Req_DH_params answer... " ) ) ;
return dhParamsAnswered ( attempt , * resDH ) ;
}
} else if ( const auto result = readNotSecureResponse < MTPSet_client_DH_params > ( answer ) ) {
const auto nonce = result - > match ( [ ] ( const auto & data ) {
return data . vnonce ( ) ;
} ) ;
if ( const auto attempt = attemptByNonce ( nonce ) ) {
DEBUG_LOG ( ( " AuthKey Info: receiving Req_client_DH_params answer... " ) ) ;
return dhClientParamsAnswered ( attempt , * result ) ;
}
}
LOG ( ( " AuthKey Error: Unknown answer received. " ) ) ;
failed ( ) ;
2019-11-13 14:12:04 +00:00
}
2019-11-19 10:10:51 +00:00
void DcKeyCreator : : pqSend ( not_null < Attempt * > attempt , TimeId expiresIn ) {
DEBUG_LOG ( ( " AuthKey Info: sending Req_pq for %1... "
) . arg ( expiresIn ? " temporary " : " persistent " ) ) ;
attempt - > stage = Stage : : WaitingPQ ;
attempt - > expiresIn = expiresIn ;
attempt - > data . nonce = openssl : : RandomValue < MTPint128 > ( ) ;
sendNotSecureRequest ( MTPReq_pq_multi ( attempt - > data . nonce ) ) ;
}
2019-11-13 14:12:04 +00:00
2019-11-19 10:10:51 +00:00
void DcKeyCreator : : pqAnswered (
not_null < Attempt * > attempt ,
const MTPresPQ & data ) {
data . match ( [ & ] ( const MTPDresPQ & data ) {
Expects ( data . vnonce ( ) = = attempt - > data . nonce ) ;
if ( attempt - > stage ! = Stage : : WaitingPQ ) {
LOG ( ( " AuthKey Error: Unexpected stage %1 " ) . arg ( int ( attempt - > stage ) ) ) ;
return failed ( ) ;
}
const auto rsaKey = _dcOptions - > getDcRSAKey (
_dcId ,
data . vserver_public_key_fingerprints ( ) . v ) ;
if ( ! rsaKey . valid ( ) ) {
2019-11-20 09:16:53 +00:00
return failed ( DcKeyError : : UnknownPublicKey ) ;
2019-11-19 10:10:51 +00:00
}
attempt - > data . server_nonce = data . vserver_nonce ( ) ;
attempt - > data . new_nonce = openssl : : RandomValue < MTPint256 > ( ) ;
const auto & pq = data . vpq ( ) . v ;
const auto parsed = ParsePQ ( data . vpq ( ) . v ) ;
if ( parsed . p . isEmpty ( ) | | parsed . q . isEmpty ( ) ) {
LOG ( ( " AuthKey Error: could not factor pq! " ) ) ;
DEBUG_LOG ( ( " AuthKey Error: problematic pq: %1 " ) . arg ( Logs : : mb ( pq . constData ( ) , pq . length ( ) ) . str ( ) ) ) ;
return failed ( ) ;
}
2019-11-13 14:12:04 +00:00
2019-11-19 10:10:51 +00:00
const auto dhEncString = [ & ] {
return ( attempt - > expiresIn = = 0 )
? EncryptPQInnerRSA (
MTP_p_q_inner_data_dc (
data . vpq ( ) ,
MTP_bytes ( parsed . p ) ,
MTP_bytes ( parsed . q ) ,
attempt - > data . nonce ,
attempt - > data . server_nonce ,
attempt - > data . new_nonce ,
MTP_int ( _protocolDcId ) ) ,
rsaKey )
: EncryptPQInnerRSA (
MTP_p_q_inner_data_temp_dc (
data . vpq ( ) ,
MTP_bytes ( parsed . p ) ,
MTP_bytes ( parsed . q ) ,
attempt - > data . nonce ,
attempt - > data . server_nonce ,
attempt - > data . new_nonce ,
MTP_int ( _protocolDcId ) ,
MTP_int ( attempt - > expiresIn ) ) ,
rsaKey ) ;
} ( ) ;
if ( dhEncString . empty ( ) ) {
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
attempt - > stage = Stage : : WaitingDH ;
DEBUG_LOG ( ( " AuthKey Info: sending Req_DH_params... " ) ) ;
sendNotSecureRequest ( MTPReq_DH_params (
attempt - > data . nonce ,
attempt - > data . server_nonce ,
MTP_bytes ( parsed . p ) ,
MTP_bytes ( parsed . q ) ,
MTP_long ( rsaKey . fingerprint ( ) ) ,
MTP_bytes ( dhEncString ) ) ) ;
} ) ;
}
void DcKeyCreator : : dhParamsAnswered (
not_null < Attempt * > attempt ,
const MTPserver_DH_Params & data ) {
if ( attempt - > stage ! = Stage : : WaitingDH ) {
LOG ( ( " AuthKey Error: Unexpected stage %1 " ) . arg ( int ( attempt - > stage ) ) ) ;
return failed ( ) ;
}
data . match ( [ & ] ( const MTPDserver_DH_params_ok & data ) {
Expects ( data . vnonce ( ) = = attempt - > data . nonce ) ;
if ( data . vserver_nonce ( ) ! = attempt - > data . server_nonce ) {
2019-11-13 14:12:04 +00:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_params_ok)! " ) ) ;
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & data . vserver_nonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & attempt - > data . server_nonce , 16 ) . str ( ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
auto & encDHStr = data . vencrypted_answer ( ) . v ;
2019-11-13 14:12:04 +00:00
uint32 encDHLen = encDHStr . length ( ) , encDHBufLen = encDHLen > > 2 ;
if ( ( encDHLen & 0x03 ) | | encDHBufLen < 6 ) {
LOG ( ( " AuthKey Error: bad encrypted data length %1 (in server_DH_params_ok)! " ) . arg ( encDHLen ) ) ;
DEBUG_LOG ( ( " AuthKey Error: received encrypted data %1 " ) . arg ( Logs : : mb ( encDHStr . constData ( ) , encDHLen ) . str ( ) ) ) ;
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
const auto nlen = sizeof ( attempt - > data . new_nonce ) ;
const auto slen = sizeof ( attempt - > data . server_nonce ) ;
2019-11-13 14:12:04 +00:00
auto tmp_aes_buffer = bytes : : array < 1024 > ( ) ;
const auto tmp_aes = bytes : : make_span ( tmp_aes_buffer ) ;
2019-11-19 10:10:51 +00:00
bytes : : copy ( tmp_aes , bytes : : object_as_span ( & attempt - > data . new_nonce ) ) ;
bytes : : copy ( tmp_aes . subspan ( nlen ) , bytes : : object_as_span ( & attempt - > data . server_nonce ) ) ;
bytes : : copy ( tmp_aes . subspan ( nlen + slen ) , bytes : : object_as_span ( & attempt - > data . new_nonce ) ) ;
bytes : : copy ( tmp_aes . subspan ( nlen + slen + nlen ) , bytes : : object_as_span ( & attempt - > data . new_nonce ) ) ;
2019-11-13 14:12:04 +00:00
const auto sha1ns = openssl : : Sha1 ( tmp_aes . subspan ( 0 , nlen + slen ) ) ;
const auto sha1sn = openssl : : Sha1 ( tmp_aes . subspan ( nlen , nlen + slen ) ) ;
const auto sha1nn = openssl : : Sha1 ( tmp_aes . subspan ( nlen + slen , nlen + nlen ) ) ;
mtpBuffer decBuffer ;
decBuffer . resize ( encDHBufLen ) ;
2019-11-19 10:10:51 +00:00
const auto aesKey = bytes : : make_span ( attempt - > data . aesKey ) ;
const auto aesIV = bytes : : make_span ( attempt - > data . aesIV ) ;
2019-11-13 14:12:04 +00:00
bytes : : copy ( aesKey , bytes : : make_span ( sha1ns ) . subspan ( 0 , 20 ) ) ;
bytes : : copy ( aesKey . subspan ( 20 ) , bytes : : make_span ( sha1sn ) . subspan ( 0 , 12 ) ) ;
bytes : : copy ( aesIV , bytes : : make_span ( sha1sn ) . subspan ( 12 , 8 ) ) ;
bytes : : copy ( aesIV . subspan ( 8 ) , bytes : : make_span ( sha1nn ) . subspan ( 0 , 20 ) ) ;
2019-11-19 10:10:51 +00:00
bytes : : copy ( aesIV . subspan ( 28 ) , bytes : : object_as_span ( & attempt - > data . new_nonce ) . subspan ( 0 , 4 ) ) ;
2019-11-13 14:12:04 +00:00
aesIgeDecryptRaw ( encDHStr . constData ( ) , & decBuffer [ 0 ] , encDHLen , aesKey . data ( ) , aesIV . data ( ) ) ;
const mtpPrime * from ( & decBuffer [ 5 ] ) , * to ( from ) , * end ( from + ( encDHBufLen - 5 ) ) ;
MTPServer_DH_inner_data dh_inner ;
if ( ! dh_inner . read ( to , end ) ) {
LOG ( ( " AuthKey Error: could not decrypt server_DH_inner_data! " ) ) ;
return failed ( ) ;
}
const auto & dh_inner_data ( dh_inner . c_server_DH_inner_data ( ) ) ;
2019-11-19 10:10:51 +00:00
if ( dh_inner_data . vnonce ( ) ! = attempt - > data . nonce ) {
2019-11-13 14:12:04 +00:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in server_DH_inner_data)! " ) ) ;
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Error: received nonce: %1, sent nonce: %2 " ) . arg ( Logs : : mb ( & dh_inner_data . vnonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & attempt - > data . nonce , 16 ) . str ( ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
if ( dh_inner_data . vserver_nonce ( ) ! = attempt - > data . server_nonce ) {
2019-11-13 14:12:04 +00:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_inner_data)! " ) ) ;
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & dh_inner_data . vserver_nonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & attempt - > data . server_nonce , 16 ) . str ( ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
const auto sha1Buffer = openssl : : Sha1 (
bytes : : make_span ( decBuffer ) . subspan (
5 * sizeof ( mtpPrime ) ,
( to - from ) * sizeof ( mtpPrime ) ) ) ;
const auto sha1Dec = bytes : : make_span ( decBuffer ) . subspan (
0 ,
openssl : : kSha1Size ) ;
if ( bytes : : compare ( sha1Dec , sha1Buffer ) ) {
LOG ( ( " AuthKey Error: sha1 hash of encrypted part did not match! " ) ) ;
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Error: sha1 did not match, server_nonce: %1, new_nonce %2, encrypted data %3 " ) . arg ( Logs : : mb ( & attempt - > data . server_nonce , 16 ) . str ( ) ) . arg ( Logs : : mb ( & attempt - > data . new_nonce , 16 ) . str ( ) ) . arg ( Logs : : mb ( encDHStr . constData ( ) , encDHLen ) . str ( ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
base : : unixtime : : update ( dh_inner_data . vserver_time ( ) . v ) ;
// check that dhPrime and (dhPrime - 1) / 2 are really prime
if ( ! IsPrimeAndGood ( bytes : : make_span ( dh_inner_data . vdh_prime ( ) . v ) , dh_inner_data . vg ( ) . v ) ) {
LOG ( ( " AuthKey Error: bad dh_prime primality! " ) ) ;
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
attempt - > dhPrime = bytes : : make_vector (
2019-11-13 14:12:04 +00:00
dh_inner_data . vdh_prime ( ) . v ) ;
2019-11-19 10:10:51 +00:00
attempt - > data . g = dh_inner_data . vg ( ) . v ;
attempt - > g_a = bytes : : make_vector ( dh_inner_data . vg_a ( ) . v ) ;
attempt - > data . retry_id = MTP_long ( 0 ) ;
attempt - > retries = 0 ;
dhClientParamsSend ( attempt ) ;
} , [ & ] ( const MTPDserver_DH_params_fail & data ) {
Expects ( data . vnonce ( ) = = attempt - > data . nonce ) ;
if ( data . vserver_nonce ( ) ! = attempt - > data . server_nonce ) {
2019-11-13 14:12:04 +00:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_params_fail)! " ) ) ;
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & data . vserver_nonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & attempt - > data . server_nonce , 16 ) . str ( ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
if ( data . vnew_nonce_hash ( ) ! = NonceDigest ( bytes : : object_as_span ( & attempt - > data . new_nonce ) ) ) {
2019-11-13 14:12:04 +00:00
LOG ( ( " AuthKey Error: received new_nonce_hash did not match! " ) ) ;
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Error: received new_nonce_hash: %1, new_nonce: %2 " ) . arg ( Logs : : mb ( & data . vnew_nonce_hash ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & attempt - > data . new_nonce , 32 ) . str ( ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
LOG ( ( " AuthKey Error: server_DH_params_fail received! " ) ) ;
2019-11-19 10:10:51 +00:00
failed ( ) ;
} ) ;
2019-11-13 14:12:04 +00:00
}
2019-11-19 10:10:51 +00:00
void DcKeyCreator : : dhClientParamsSend ( not_null < Attempt * > attempt ) {
if ( + + attempt - > retries > 5 ) {
LOG ( ( " AuthKey Error: could not create auth_key for %1 retries " ) . arg ( attempt - > retries - 1 ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
// gen rand 'b'
auto randomSeed = bytes : : vector ( ModExpFirst : : kRandomPowerSize ) ;
bytes : : set_random ( randomSeed ) ;
2019-11-19 10:10:51 +00:00
auto g_b_data = CreateModExp ( attempt - > data . g , attempt - > dhPrime , randomSeed ) ;
2019-11-13 14:12:04 +00:00
if ( g_b_data . modexp . empty ( ) ) {
LOG ( ( " AuthKey Error: could not generate good g_b. " ) ) ;
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
auto computedAuthKey = CreateAuthKey ( attempt - > g_a , g_b_data . randomPower , attempt - > dhPrime ) ;
2019-11-13 14:12:04 +00:00
if ( computedAuthKey . empty ( ) ) {
LOG ( ( " AuthKey Error: could not generate auth_key. " ) ) ;
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
AuthKey : : FillData ( attempt - > authKey , computedAuthKey ) ;
2019-11-13 14:12:04 +00:00
2019-11-19 10:10:51 +00:00
auto auth_key_sha = openssl : : Sha1 ( attempt - > authKey ) ;
memcpy ( & attempt - > data . auth_key_aux_hash , auth_key_sha . data ( ) , 8 ) ;
memcpy ( & attempt - > data . auth_key_hash , auth_key_sha . data ( ) + 12 , 8 ) ;
2019-11-13 14:12:04 +00:00
const auto client_dh_inner = MTP_client_DH_inner_data (
2019-11-19 10:10:51 +00:00
attempt - > data . nonce ,
attempt - > data . server_nonce ,
attempt - > data . retry_id ,
2019-11-13 14:12:04 +00:00
MTP_bytes ( g_b_data . modexp ) ) ;
auto sdhEncString = EncryptClientDHInner (
client_dh_inner ,
2019-11-19 10:10:51 +00:00
attempt - > data . aesKey . data ( ) ,
attempt - > data . aesIV . data ( ) ) ;
2019-11-13 14:12:04 +00:00
2019-11-19 10:10:51 +00:00
attempt - > stage = Stage : : WaitingDone ;
2019-11-13 14:12:04 +00:00
DEBUG_LOG ( ( " AuthKey Info: sending Req_client_DH_params... " ) ) ;
sendNotSecureRequest ( MTPSet_client_DH_params (
2019-11-19 10:10:51 +00:00
attempt - > data . nonce ,
attempt - > data . server_nonce ,
2019-11-13 14:12:04 +00:00
MTP_string ( std : : move ( sdhEncString ) ) ) ) ;
}
2019-11-19 10:10:51 +00:00
void DcKeyCreator : : dhClientParamsAnswered (
not_null < Attempt * > attempt ,
const MTPset_client_DH_params_answer & data ) {
if ( attempt - > stage ! = Stage : : WaitingDone ) {
LOG ( ( " AuthKey Error: Unexpected stage %1 " ) . arg ( int ( attempt - > stage ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
data . match ( [ & ] ( const MTPDdh_gen_ok & data ) {
if ( data . vnonce ( ) ! = attempt - > data . nonce ) {
2019-11-13 14:12:04 +00:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in dh_gen_ok)! " ) ) ;
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Error: received nonce: %1, sent nonce: %2 " ) . arg ( Logs : : mb ( & data . vnonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & attempt - > data . nonce , 16 ) . str ( ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
if ( data . vserver_nonce ( ) ! = attempt - > data . server_nonce ) {
2019-11-13 14:12:04 +00:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_ok)! " ) ) ;
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & data . vserver_nonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & attempt - > data . server_nonce , 16 ) . str ( ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
attempt - > data . new_nonce_buf [ 32 ] = bytes : : type ( 1 ) ;
if ( data . vnew_nonce_hash1 ( ) ! = NonceDigest ( attempt - > data . new_nonce_buf ) ) {
2019-11-13 14:12:04 +00:00
LOG ( ( " AuthKey Error: received new_nonce_hash1 did not match! " ) ) ;
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Error: received new_nonce_hash1: %1, new_nonce_buf: %2 " ) . arg ( Logs : : mb ( & data . vnew_nonce_hash1 ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( attempt - > data . new_nonce_buf . data ( ) , 41 ) . str ( ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
uint64 salt1 = attempt - > data . new_nonce . l . l , salt2 = attempt - > data . server_nonce . l ;
attempt - > data . doneSalt = salt1 ^ salt2 ;
attempt - > stage = Stage : : Ready ;
done ( ) ;
} , [ & ] ( const MTPDdh_gen_retry & data ) {
if ( data . vnonce ( ) ! = attempt - > data . nonce ) {
2019-11-13 14:12:04 +00:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in dh_gen_retry)! " ) ) ;
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Error: received nonce: %1, sent nonce: %2 " ) . arg ( Logs : : mb ( & data . vnonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & attempt - > data . nonce , 16 ) . str ( ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
if ( data . vserver_nonce ( ) ! = attempt - > data . server_nonce ) {
2019-11-13 14:12:04 +00:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_retry)! " ) ) ;
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & data . vserver_nonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & attempt - > data . server_nonce , 16 ) . str ( ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
attempt - > data . new_nonce_buf [ 32 ] = bytes : : type ( 2 ) ;
2019-11-13 14:12:04 +00:00
uchar sha1Buffer [ 20 ] ;
2019-11-19 10:10:51 +00:00
if ( data . vnew_nonce_hash2 ( ) ! = NonceDigest ( attempt - > data . new_nonce_buf ) ) {
2019-11-13 14:12:04 +00:00
LOG ( ( " AuthKey Error: received new_nonce_hash2 did not match! " ) ) ;
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Error: received new_nonce_hash2: %1, new_nonce_buf: %2 " ) . arg ( Logs : : mb ( & data . vnew_nonce_hash2 ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( attempt - > data . new_nonce_buf . data ( ) , 41 ) . str ( ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
attempt - > data . retry_id = attempt - > data . auth_key_aux_hash ;
dhClientParamsSend ( attempt ) ;
} , [ & ] ( const MTPDdh_gen_fail & data ) {
if ( data . vnonce ( ) ! = attempt - > data . nonce ) {
2019-11-13 14:12:04 +00:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in dh_gen_fail)! " ) ) ;
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Error: received nonce: %1, sent nonce: %2 " ) . arg ( Logs : : mb ( & data . vnonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & attempt - > data . nonce , 16 ) . str ( ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
if ( data . vserver_nonce ( ) ! = attempt - > data . server_nonce ) {
2019-11-13 14:12:04 +00:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_fail)! " ) ) ;
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & data . vserver_nonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & attempt - > data . server_nonce , 16 ) . str ( ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
2019-11-19 10:10:51 +00:00
attempt - > data . new_nonce_buf [ 32 ] = bytes : : type ( 3 ) ;
2019-11-13 14:12:04 +00:00
uchar sha1Buffer [ 20 ] ;
2019-11-19 10:10:51 +00:00
if ( data . vnew_nonce_hash3 ( ) ! = NonceDigest ( attempt - > data . new_nonce_buf ) ) {
2019-11-13 14:12:04 +00:00
LOG ( ( " AuthKey Error: received new_nonce_hash3 did not match! " ) ) ;
2019-11-19 10:10:51 +00:00
DEBUG_LOG ( ( " AuthKey Error: received new_nonce_hash3: %1, new_nonce_buf: %2 " ) . arg ( Logs : : mb ( & data . vnew_nonce_hash3 ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( attempt - > data . new_nonce_buf . data ( ) , 41 ) . str ( ) ) ) ;
2019-11-13 14:12:04 +00:00
return failed ( ) ;
}
LOG ( ( " AuthKey Error: dh_gen_fail received! " ) ) ;
2019-11-19 10:10:51 +00:00
failed ( ) ;
} ) ;
2019-11-13 14:12:04 +00:00
}
2019-11-20 09:16:53 +00:00
void DcKeyCreator : : failed ( DcKeyError error ) {
2019-11-15 13:04:32 +00:00
stopReceiving ( ) ;
auto onstack = base : : take ( _delegate . done ) ;
2019-11-13 14:12:04 +00:00
onstack ( tl : : unexpected ( error ) ) ;
}
2019-11-19 10:10:51 +00:00
void DcKeyCreator : : done ( ) {
2019-11-19 16:22:02 +00:00
if ( _temporary . stage = = Stage : : None ) {
pqSend ( & _temporary , _request . temporaryExpiresIn ) ;
2019-11-19 10:10:51 +00:00
return ;
}
2019-11-19 16:22:02 +00:00
Assert ( _temporary . stage = = Stage : : Ready ) ;
Assert ( _persistent . stage = = Stage : : Ready | | _persistent . stage = = Stage : : None ) ;
2019-11-19 10:10:51 +00:00
2019-11-20 09:16:53 +00:00
auto result = DcKeyResult ( ) ;
2019-11-19 10:10:51 +00:00
result . temporaryKey = std : : make_shared < AuthKey > (
AuthKey : : Type : : Temporary ,
2019-11-13 14:12:04 +00:00
_dcId ,
2019-11-19 10:10:51 +00:00
_temporary . authKey ) ;
result . temporaryServerSalt = _temporary . data . doneSalt ;
if ( _persistent . stage = = Stage : : Ready ) {
result . persistentKey = std : : make_shared < AuthKey > (
AuthKey : : Type : : Generated ,
_dcId ,
_persistent . authKey ) ;
result . persistentServerSalt = _persistent . data . doneSalt ;
}
2019-11-15 13:04:32 +00:00
stopReceiving ( ) ;
auto onstack = base : : take ( _delegate . done ) ;
2019-11-13 14:12:04 +00:00
onstack ( std : : move ( result ) ) ;
}
2019-11-15 13:04:32 +00:00
void DcKeyCreator : : stopReceiving ( ) {
QObject : : disconnect (
_connection ,
& AbstractConnection : : receivedData ,
nullptr ,
nullptr ) ;
}
2019-11-13 14:12:04 +00:00
} // namespace MTP::details