Files
mobile-android/docs/ATTACHMENT_DECRYPTION_FIX.md

163 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Исправление расшифровки вложений (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)** использует:
```typescript
const key = crypto.PBKDF2(password, "rosetta", {
keySize: 256 / 32,
iterations: 1000,
});
```
Без явного указания `hasher`, crypto-js использует **SHA256**.
2. **Android (MessageCrypto.kt)** использовал:
```kotlin
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()`
**Было:**
```kotlin
// PBKDF2-HMAC-SHA1 ручная реализация
val mac = javax.crypto.Mac.getInstance("HmacSHA1")
val keySpec = javax.crypto.spec.SecretKeySpec(passwordBytes, "HmacSHA1")
```
**Стало:**
```kotlin
// 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()`
**Было:**
```kotlin
val factory = javax.crypto.SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
```
**Стало:**
```kotlin
val factory = javax.crypto.SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
```
### 3. `encryptReplyBlob()`
Также исправлена функция шифрования для отправки вложений:
**Было:**
```kotlin
// CRITICAL: Must use SHA1 to match crypto-js default (not SHA256!)
val factory = javax.crypto.SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
```
**Стало:**
```kotlin
// 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" был исправлен по всему коду