Files
mobile-android/docs/ATTACHMENT_DECRYPTION_FIX.md

5.6 KiB
Raw Blame History

Исправление расшифровки вложений (Desktop → Android)

Дата

27 января 2026

Проблема

Входящие фотографии от Desktop на Android не расшифровывались. При попытке открыть изображение возникала ошибка:

javax.crypto.BadPaddingException: error:1e000065:Cipher functions:OPENSSL_internal:BAD_DECRYPT

Все варианты расшифровки (V1-V6) падали с этой ошибкой, несмотря на то что:

  • ChaCha ключ расшифровывался правильно (56 байт)
  • UTF-8 конверсия работала корректно
  • Данные передавались без повреждений

Причина

crypto-js использует PBKDF2 с SHA256 по умолчанию, а не SHA1!

Детали

  1. Desktop (crypto.worker.ts) использует:

    const key = crypto.PBKDF2(password, "rosetta", {
      keySize: 256 / 32,
      iterations: 1000,
    });
    

    Без явного указания hasher, crypto-js использует SHA256.

  2. Android (MessageCrypto.kt) использовал:

    val mac = javax.crypto.Mac.getInstance("HmacSHA1")  // ❌ SHA1
    

Тестовое подтверждение

Проверка с простым паролем "test":

crypto-js PBKDF2 (default):  103af158b41bb86784d953ef50b32c54230086946cf9ebb81616b004d78c15db
crypto-js PBKDF2 (SHA1):     1343ea25240fff22b2f3278fd7e20f8b67f2f92d194ae98c71cbdcaf526fe4e4
crypto-js PBKDF2 (SHA256):   103af158b41bb86784d953ef50b32c54230086946cf9ebb81616b004d78c15db
Node.js PBKDF2 (SHA1):       1343ea25240fff22b2f3278fd7e20f8b67f2f92d194ae98c71cbdcaf526fe4e4
Node.js PBKDF2 (SHA256):     103af158b41bb86784d953ef50b32c54230086946cf9ebb81616b004d78c15db

Вывод: crypto-js PBKDF2 по умолчанию = SHA256 ≠ SHA1

Решение

Изменены все функции PBKDF2 в Android с SHA1 на SHA256:

1. generatePBKDF2KeyFromBytes()

Было:

// PBKDF2-HMAC-SHA1 ручная реализация
val mac = javax.crypto.Mac.getInstance("HmacSHA1")
val keySpec = javax.crypto.spec.SecretKeySpec(passwordBytes, "HmacSHA1")

Стало:

// PBKDF2-HMAC-SHA256 ручная реализация для совместимости с crypto-js
// ВАЖНО: crypto-js PBKDF2 по умолчанию использует SHA256, НЕ SHA1!
val mac = javax.crypto.Mac.getInstance("HmacSHA256")
val keySpec = javax.crypto.spec.SecretKeySpec(passwordBytes, "HmacSHA256")

2. generatePBKDF2KeyJava()

Было:

val factory = javax.crypto.SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")

Стало:

val factory = javax.crypto.SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")

3. encryptReplyBlob()

Также исправлена функция шифрования для отправки вложений:

Было:

// CRITICAL: Must use SHA1 to match crypto-js default (not SHA256!)
val factory = javax.crypto.SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")

Стало:

// CRITICAL: crypto-js PBKDF2 uses SHA256 by default (NOT SHA1!)
val factory = javax.crypto.SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")

Измененные файлы

  • rosetta-android/app/src/main/java/com/rosetta/messenger/crypto/MessageCrypto.kt
    • generatePBKDF2KeyFromBytes() - изменен с SHA1 на SHA256
    • generatePBKDF2KeyJava() - изменен с SHA1 на SHA256
    • encryptReplyBlob() - изменен с SHA1 на SHA256
    • Обновлены комментарии для корректного указания алгоритма

Результат

Расшифровка вложений Desktop → Android теперь работает корректно Шифрование вложений Android → Desktop также будет совместимо Все варианты (V1-V6) теперь используют правильный PBKDF2-HMAC-SHA256

Технические детали

Алгоритм расшифровки attachment blob

  1. Расшифровка ChaCha ключа (56 bytes = 32 key + 24 nonce)

    • Через ECDH + AES-256-CBC
    • Конверсия UTF-8 bytes → UTF-8 string (с заменой невалидных на U+FFFD)
  2. PBKDF2 key derivation

    • Password: UTF-8 string из step 1
    • Salt: "rosetta"
    • Iterations: 1000
    • Key size: 256 bits (32 bytes)
    • Hash: SHA256 (было SHA1 )
  3. AES-256-CBC расшифровка

    • Формат: ivBase64:ciphertextBase64
    • IV: 16 bytes
    • Padding: PKCS5/PKCS7
  4. Zlib декомпрессия

    • Результат: base64 изображение

Проверка

После установки исправленной версии:

  1. Отправить фото с Desktop на Android
  2. Открыть диалог на Android
  3. Нажать на изображение для загрузки
  4. Изображение должно успешно расшифроваться и отобразиться

Примечания

  • Эта проблема затрагивает только входящие вложения от Desktop
  • Android → Android вложения могли работать с разными алгоритмами PBKDF2
  • Ошибочный комментарий "crypto-js uses SHA1 by default" был исправлен по всему коду