package ru.denull.mtproto; import static ru.denull.mtproto.CryptoUtils.*; import java.nio.ByteBuffer; import java.nio.ByteOrder; import tl.TL; import tl.TLObject; public class Message { public int error = 0; public long message_id; public TLObject payload; public Message(long message_id, TLObject payload) { this.message_id = message_id; this.payload = payload; } public Message(int error) { this.error = error; } public ByteBuffer encrypt(byte[] auth_key) throws Exception { //System.out.println("sending raw " + payload); if (error != 0) { return ByteBuffer.allocateDirect(4).putInt(-error); } int size = payload.length(true); ByteBuffer buffer = ByteBuffer.allocateDirect(size + 20); buffer.order(ByteOrder.LITTLE_ENDIAN); buffer.putLong(0); buffer.putLong(message_id); buffer.putInt(size); payload.writeTo(buffer); buffer.rewind(); return buffer; } public static Message decrypt(ByteBuffer buffer) throws Exception { return decrypt(buffer, null, 0); } public static Message decrypt(ByteBuffer buffer, byte[] auth_key, long auth_key_id) throws Exception { if (buffer == null) { return null; } if (buffer.capacity() == 4) { return new Message(-buffer.getInt()); } long _auth_key_id = buffer.getLong(); if (_auth_key_id == 0) { long message_id = buffer.getLong(); int size = buffer.getInt(); return new Message(message_id, TL.read(buffer)); } else if (_auth_key_id == auth_key_id) { byte[] msg_key = new byte[16]; buffer.get(msg_key); byte[] encrypted_data = new byte[buffer.capacity() - 24]; buffer.get(encrypted_data); int x = 8; byte[] sha1_a = SHA1(concat(msg_key, substr(auth_key, x, 32))); byte[] sha1_b = SHA1(concat(substr(auth_key, 32 + x, 16), msg_key, substr(auth_key, 48 + x, 16))); byte[] sha1_c = SHA1(concat(substr(auth_key, 64 + x, 32), msg_key)); byte[] sha1_d = SHA1(concat(msg_key, substr(auth_key, 96 + x, 32))); byte[] aes_key = concat(substr(sha1_a, 0, 8), substr(sha1_b, 8, 12), substr(sha1_c, 4, 12)); byte[] aes_iv = concat(substr(sha1_a, 8, 12), substr(sha1_b, 0, 8), substr(sha1_c, 16, 4), substr(sha1_d, 0, 8)); ByteBuffer innerBuffer = ByteBuffer.wrap(AESDecrypt(encrypted_data, 0, encrypted_data.length, aes_key, aes_iv)); innerBuffer.order(ByteOrder.LITTLE_ENDIAN); long server_salt = innerBuffer.getLong(); long session_id = innerBuffer.getLong(); long message_id = innerBuffer.getLong(); int seq_no = innerBuffer.getInt(); int size = innerBuffer.getInt(); return new EncryptedMessage(message_id, TL.read(innerBuffer), session_id, _auth_key_id, server_salt, seq_no); } else { throw new Exception("Unknown auth_key received"); } } }