feat: Add fallback transport server and enhance file download handling with blurhash support

This commit is contained in:
k1ngsterr1
2026-01-24 16:04:23 +05:00
parent d5083e60a5
commit 8c87b12c5f
5 changed files with 593 additions and 314 deletions

View File

@@ -513,6 +513,44 @@ object MessageCrypto {
* Расшифровка MESSAGES attachment blob
* Формат: ivBase64:ciphertextBase64
* Использует PBKDF2 + AES-256-CBC + zlib decompression
*
* @param encryptedData зашифрованный контент (ivBase64:ciphertextBase64)
* @param chachaKeyPlain Уже расшифрованный ChaCha ключ (32 bytes)
*/
fun decryptAttachmentBlobWithPlainKey(
encryptedData: String,
chachaKeyPlain: ByteArray
): String? {
return try {
android.util.Log.d("MessageCrypto", "🔐 decryptAttachmentBlobWithPlainKey: data length=${encryptedData.length}, key=${chachaKeyPlain.size} bytes")
// ВАЖНО: Для attachment используем только первые 32 bytes (ChaCha key без nonce)
val keyOnly = chachaKeyPlain.copyOfRange(0, 32)
// 1. Конвертируем key в строку используя bytesToJsUtf8String
// чтобы совпадало с JS Buffer.toString('utf-8') который заменяет
// невалидные UTF-8 последовательности на U+FFFD
val chachaKeyString = bytesToJsUtf8String(keyOnly)
android.util.Log.d("MessageCrypto", "🔑 ChaCha key string length: ${chachaKeyString.length}")
// 2. Генерируем PBKDF2 ключ (salt='rosetta', 1000 iterations, sha1)
val pbkdf2Key = generatePBKDF2Key(chachaKeyString)
android.util.Log.d("MessageCrypto", "🔑 PBKDF2 key: ${pbkdf2Key.size} bytes")
// 3. Расшифровываем AES-256-CBC
val result = decryptWithPBKDF2Key(encryptedData, pbkdf2Key)
android.util.Log.d("MessageCrypto", "✅ Decryption result: ${if (result != null) "success (${result.length} chars)" else "null"}")
result
} catch (e: Exception) {
android.util.Log.e("MessageCrypto", "❌ decryptAttachmentBlobWithPlainKey failed: ${e.message}", e)
null
}
}
/**
* Расшифровка MESSAGES attachment blob (Legacy - с RSA расшифровкой ключа)
* Формат: ivBase64:ciphertextBase64
* Использует PBKDF2 + AES-256-CBC + zlib decompression
*/
fun decryptAttachmentBlob(
encryptedData: String,
@@ -520,20 +558,16 @@ object MessageCrypto {
myPrivateKey: String
): String? {
return try {
android.util.Log.d("MessageCrypto", "🔐 decryptAttachmentBlob: data length=${encryptedData.length}, key length=${encryptedKey.length}")
// 1. Расшифровываем ChaCha ключ (как для сообщений)
val keyAndNonce = decryptKeyFromSender(encryptedKey, myPrivateKey)
android.util.Log.d("MessageCrypto", "🔑 Decrypted keyAndNonce: ${keyAndNonce.size} bytes")
// 2. Конвертируем key+nonce в строку используя bytesToJsUtf8String
// чтобы совпадало с JS Buffer.toString('utf-8') который заменяет
// невалидные UTF-8 последовательности на U+FFFD
val chachaKeyString = bytesToJsUtf8String(keyAndNonce)
// 3. Генерируем PBKDF2 ключ (salt='rosetta', 1000 iterations, sha1)
val pbkdf2Key = generatePBKDF2Key(chachaKeyString)
// 4. Расшифровываем AES-256-CBC
decryptWithPBKDF2Key(encryptedData, pbkdf2Key)
// 2. Используем новую функцию
decryptAttachmentBlobWithPlainKey(encryptedData, keyAndNonce)
} catch (e: Exception) {
android.util.Log.e("MessageCrypto", "❌ decryptAttachmentBlob failed: ${e.message}", e)
null
}
}
@@ -559,13 +593,20 @@ object MessageCrypto {
*/
private fun decryptWithPBKDF2Key(encryptedData: String, pbkdf2Key: ByteArray): String? {
return try {
android.util.Log.d("MessageCrypto", "🔓 decryptWithPBKDF2Key: data length=${encryptedData.length}")
android.util.Log.d("MessageCrypto", "🔓 First 100 chars: ${encryptedData.take(100)}")
android.util.Log.d("MessageCrypto", "🔓 Contains colon: ${encryptedData.contains(":")}")
val parts = encryptedData.split(":")
android.util.Log.d("MessageCrypto", "🔓 Split parts: ${parts.size}")
if (parts.size != 2) {
android.util.Log.e("MessageCrypto", "❌ Invalid format: expected 2 parts, got ${parts.size}")
return null
}
val iv = android.util.Base64.decode(parts[0], android.util.Base64.DEFAULT)
val ciphertext = android.util.Base64.decode(parts[1], android.util.Base64.DEFAULT)
android.util.Log.d("MessageCrypto", "🔓 IV: ${iv.size} bytes, Ciphertext: ${ciphertext.size} bytes")
// AES-256-CBC расшифровка
val cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding")
@@ -573,6 +614,7 @@ object MessageCrypto {
val ivSpec = javax.crypto.spec.IvParameterSpec(iv)
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, secretKey, ivSpec)
val decrypted = cipher.doFinal(ciphertext)
android.util.Log.d("MessageCrypto", "🔓 AES decrypted: ${decrypted.size} bytes")
// Zlib декомпрессия
val inflater = java.util.zip.Inflater()
@@ -585,8 +627,11 @@ object MessageCrypto {
}
inflater.end()
String(outputStream.toByteArray(), Charsets.UTF_8)
val result = String(outputStream.toByteArray(), Charsets.UTF_8)
android.util.Log.d("MessageCrypto", "🔓 Decompressed: ${result.length} chars")
result
} catch (e: Exception) {
android.util.Log.e("MessageCrypto", "❌ decryptWithPBKDF2Key failed: ${e.message}", e)
null
}
}