private ServerDHInnerData DecryptServerDHInnerData(byte[] encryptedAnswer, byte[] tmpAesKey, byte[] tmpAesIV) { /* encrypted_answer := AES256_ige_encrypt (answer_with_hash, tmp_aes_key, tmp_aes_iv); * here, tmp_aes_key is a 256-bit key, and tmp_aes_iv is a 256-bit initialization vector. * The same as in all the other instances that use AES encryption, * the encrypted data is padded with random bytes to a length divisible by 16 immediately prior to encryption. */ // Decrypting. byte[] answerWithHash = _encryptionServices.Aes256IgeDecrypt(encryptedAnswer, tmpAesKey, tmpAesIV); if ((answerWithHash.Length % 16) != 0) { throw new InvalidResponseException("Decrypted ServerDHInnerData with hash has invalid length."); } var answerHash = new byte[HashLength]; ServerDHInnerData serverDHInnerData; using (var streamer = new TLStreamer(answerWithHash)) { streamer.Read(answerHash, 0, answerHash.Length); serverDHInnerData = _tlRig.Deserialize <ServerDHInnerData>(streamer); } // Checking the hash. byte[] serverDHInnerDataBytes = _tlRig.Serialize(serverDHInnerData); byte[] serverDHInnerDataBytesHash = ComputeSHA1(serverDHInnerDataBytes); if (!serverDHInnerDataBytesHash.SequenceEqual(answerHash)) { throw new InvalidResponseException("Decrypted ServerDHInnerData hash is invalid."); } return(serverDHInnerData); }
public IMessage DecodeEncryptedMessage(byte[] messageBytes, byte[] authKey, Sender sender, out UInt64 salt, out UInt64 sessionId) { Argument.IsNotNull(() => authKey); Argument.IsNotNull(() => messageBytes); ulong providedAuthKeyId = ComputeAuthKeyId(authKey); var encryptedData = new byte[messageBytes.Length - EncryptedOuterHeaderLength]; Int128 msgKey; using (var streamer = new TLStreamer(messageBytes)) { // Reading header. ulong authKeyId = streamer.ReadUInt64(); if (authKeyId != providedAuthKeyId) { throw new InvalidAuthKey(string.Format("Message encrypted with auth key with id={0}, but auth key provided for decryption with id={1}.", authKeyId, providedAuthKeyId)); } msgKey = streamer.ReadInt128(); // Reading encrypted data. streamer.Read(encryptedData, 0, encryptedData.Length); } // Decrypting. byte[] aesKey, aesIV; ComputeAesKeyAndIV(authKey, msgKey, out aesKey, out aesIV, sender); byte[] innerDataWithPadding = _encryptionServices.Aes256IgeDecrypt(encryptedData, aesKey, aesIV); Int32 msgDataLength; UInt64 msgId; UInt32 seqno; Object body; using (var streamer = new TLStreamer(innerDataWithPadding)) { salt = streamer.ReadUInt64(); sessionId = streamer.ReadUInt64(); msgId = streamer.ReadUInt64(); seqno = streamer.ReadUInt32(); msgDataLength = streamer.ReadInt32(); body = _tlRig.Deserialize(streamer); } int innerDataLength = EncryptedInnerHeaderLength + msgDataLength; // When an encrypted message is received, it must be checked that // msg_key is in fact equal to the 128 lower-order bits // of the SHA1 hash of the previously encrypted portion. Int128 expectedMsgKey = ComputeMsgKey(new ArraySegment <byte>(innerDataWithPadding, 0, innerDataLength)); if (msgKey != expectedMsgKey) { throw new InvalidMessageException(string.Format("Expected message key to be {0}, but actual is {1}.", expectedMsgKey, msgKey)); } return(new Message(msgId, seqno, body)); }
private static void CheckWriteToStream(Action <TLStreamer> write, byte[] testBytesInBigEndian, bool streamAsLittleEndian) { int bytesCount = testBytesInBigEndian.Length; using (var streamer = new TLStreamer { StreamAsLittleEndian = streamAsLittleEndian }) { write(streamer); streamer.Length.Should().Be(bytesCount); streamer.Position = 0; var bytes = new byte[bytesCount]; streamer.Read(bytes, 0, bytesCount); if (streamAsLittleEndian) { Array.Reverse(bytes); } for (byte i = 0; i < bytesCount; i++) { bytes[i].Should().Be(testBytesInBigEndian[i]); } } }
/// <summary> /// Initializes a new instance of the <see cref="EncryptedMessage" /> class from a whole message bytes, which contain /// encrypted data. /// </summary> /// <param name="authKey"> /// Authorization Key a 2048-bit key shared by the client device and the server, created upon user /// registration directly on the client device be exchanging Diffie-Hellman keys, and never transmitted over a network. /// Each authorization key is user-specific. There is nothing that prevents a user from having several keys (that /// correspond to “permanent sessions” on different devices), and some of these may be locked forever in the event the /// device is lost. /// </param> /// <param name="messageBytes">Whole message bytes, which contain encrypted data.</param> /// <param name="sender">Sender of the message.</param> /// <param name="hashServices">Hash services.</param> /// <param name="encryptionServices">Encryption services.</param> public EncryptedMessage([NotNull] byte[] authKey, [NotNull] byte[] messageBytes, Sender sender, [NotNull] IHashServices hashServices, [NotNull] IEncryptionServices encryptionServices) { Argument.IsNotNull(() => authKey); Argument.IsNotNull(() => messageBytes); Argument.IsNotNull(() => hashServices); Argument.IsNotNull(() => encryptionServices); ulong authKeyId = ComputeAuthKeyId(authKey, hashServices); _messageBytes = messageBytes; _length = _messageBytes.Length; var encryptedData = new byte[_length - OuterHeaderLength]; using (var streamer = new TLStreamer(_messageBytes)) { // Reading header. _authKeyId = streamer.ReadUInt64(); if (_authKeyId != authKeyId) { throw new InvalidAuthKey(string.Format("Message encrypted with auth key with id={0}, but auth key provided for decryption with id={1}.", _authKeyId, authKeyId)); } _msgKey = streamer.ReadInt128(); // Reading encrypted data. streamer.Read(encryptedData, 0, encryptedData.Length); } // Decrypting. byte[] aesKey, aesIV; ComputeAesKeyAndIV(authKey, _msgKey, out aesKey, out aesIV, hashServices, sender); byte[] innerDataWithPadding = encryptionServices.Aes256IgeDecrypt(encryptedData, aesKey, aesIV); using (var streamer = new TLStreamer(innerDataWithPadding)) { _salt = streamer.ReadUInt64(); _sessionId = streamer.ReadUInt64(); _messageId = streamer.ReadUInt64(); _seqNumber = streamer.ReadUInt32(); _messageDataLength = streamer.ReadInt32(); _messageData = streamer.ReadBytes(_messageDataLength); } int innerDataLength = InnerHeaderLength + _messageDataLength; // When an encrypted message is received, it must be checked that // msg_key is in fact equal to the 128 lower-order bits // of the SHA1 hash of the previously encrypted portion. var msgKey = ComputeMsgKey(new ArraySegment <byte>(innerDataWithPadding, 0, innerDataLength), hashServices); if (_msgKey != msgKey) { throw new InvalidMessageException(string.Format("Expected message key to be {0}, but actual is {1}.", _msgKey, msgKey)); } }