# Исправление расшифровки вложений (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" был исправлен по всему коду
