feat: Add fallback transport server and enhance file download handling with blurhash support
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user