From f906dc9cf872369b118fbbc6d21f547353e8cb3c Mon Sep 17 00:00:00 2001 From: k1ngsterr1 Date: Tue, 27 Jan 2026 00:22:34 +0500 Subject: [PATCH] feat: Add detailed logging for encryptReplyBlob function in MessageCrypto --- .../rosetta/messenger/crypto/MessageCrypto.kt | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/rosetta/messenger/crypto/MessageCrypto.kt b/app/src/main/java/com/rosetta/messenger/crypto/MessageCrypto.kt index 814efe7..1c17957 100644 --- a/app/src/main/java/com/rosetta/messenger/crypto/MessageCrypto.kt +++ b/app/src/main/java/com/rosetta/messenger/crypto/MessageCrypto.kt @@ -731,29 +731,40 @@ object MessageCrypto { */ fun encryptReplyBlob(replyJson: String, plainKeyAndNonce: ByteArray): String { return try { + android.util.Log.d("MessageCrypto", "🔐 encryptReplyBlob START") + android.util.Log.d("MessageCrypto", "🔐 Input length: ${replyJson.length} chars") + android.util.Log.d("MessageCrypto", "🔐 Input first 100: ${replyJson.take(100)}") + android.util.Log.d("MessageCrypto", "🔐 plainKeyAndNonce length: ${plainKeyAndNonce.size} bytes") // Convert plainKeyAndNonce to string - simulate JS Buffer.toString('utf-8') behavior // which replaces invalid UTF-8 sequences with U+FFFD val password = bytesToJsUtf8String(plainKeyAndNonce) + android.util.Log.d("MessageCrypto", "🔐 Password length: ${password.length} chars") + android.util.Log.d("MessageCrypto", "🔐 Password first 50 chars: ${password.take(50)}") - // Compress with raw deflate (NO zlib header) - matching pako.deflate() - // CRITICAL: nowrap=true for raw deflate (pako default) - val deflater = java.util.zip.Deflater(java.util.zip.Deflater.DEFAULT_COMPRESSION, true) + // Compress with zlib format (WITH header) - matching pako.deflate() + // CRITICAL: nowrap=false for zlib format (pako.deflate default) + val deflater = java.util.zip.Deflater(java.util.zip.Deflater.DEFAULT_COMPRESSION, false) deflater.setInput(replyJson.toByteArray(Charsets.UTF_8)) deflater.finish() val compressedBuffer = ByteArray(replyJson.length * 2 + 100) val compressedSize = deflater.deflate(compressedBuffer) deflater.end() val compressed = compressedBuffer.copyOf(compressedSize) + android.util.Log.d("MessageCrypto", "🔐 Original size: ${replyJson.length}, Compressed size: ${compressed.size}") // PBKDF2 key derivation (matching crypto-js) // CRITICAL: Use our custom implementation that properly handles UTF-8! // Java's PBEKeySpec uses UTF-16, but crypto-js uses UTF-8 val keyBytes = generatePBKDF2Key(password) + android.util.Log.d("MessageCrypto", "🔐 PBKDF2 key generated: ${keyBytes.size} bytes") + android.util.Log.d("MessageCrypto", "🔐 Key first 16 bytes (hex): ${keyBytes.take(16).joinToString("") { "%02x".format(it) }}") // Generate random IV (16 bytes) val iv = ByteArray(16) java.security.SecureRandom().nextBytes(iv) + android.util.Log.d("MessageCrypto", "🔐 IV generated: ${iv.size} bytes") + android.util.Log.d("MessageCrypto", "🔐 IV (hex): ${iv.joinToString("") { "%02x".format(it) }}") // AES-CBC encryption val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") @@ -761,14 +772,19 @@ object MessageCrypto { val ivSpec = IvParameterSpec(iv) cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec) val ciphertext = cipher.doFinal(compressed) + android.util.Log.d("MessageCrypto", "🔐 AES encrypted: ${ciphertext.size} bytes") // Format: "ivBase64:ciphertextBase64" (same as RN new format) val ivBase64 = Base64.encodeToString(iv, Base64.NO_WRAP) val ctBase64 = Base64.encodeToString(ciphertext, Base64.NO_WRAP) val result = "$ivBase64:$ctBase64" + android.util.Log.d("MessageCrypto", "🔐 Final encrypted length: ${result.length} chars") + android.util.Log.d("MessageCrypto", "🔐 Final format check - contains colon: ${result.contains(":")}") + android.util.Log.d("MessageCrypto", "🔐 encryptReplyBlob END") result } catch (e: Exception) { + android.util.Log.e("MessageCrypto", "❌ encryptReplyBlob failed: ${e.message}", e) // Fallback: return plaintext (for backwards compatibility) replyJson }