Files
mobile-android/CRYPTO_NEW_AUTH_UPDATE.md

289 lines
9.8 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.
# Обновление авторизации для совместимости с crypto_new
## Дата: 16 января 2026
## Статус: ✅ Реализовано
## Обзор изменений
Обновлена логика авторизации в Android приложении для полной совместимости с новым методом шифрования из `crypto_new` (TypeScript/JavaScript). Основные изменения касаются генерации ключевых пар и формата публичных ключей.
## Основные изменения
### 1. Метод генерации приватного ключа
#### Старый метод (BIP39):
```kotlin
fun seedPhraseToPrivateKey(seedPhrase: List<String>): String {
val mnemonicCode = MnemonicCode.INSTANCE
val seed = MnemonicCode.toSeed(seedPhrase, "") // 64 bytes
return seed.joinToString("") { "%02x".format(it) } // 128 hex chars
}
```
#### Новый метод (crypto_new):
```kotlin
fun seedPhraseToPrivateKey(seedPhrase: List<String>): String {
val seedString = seedPhrase.joinToString(" ")
val digest = MessageDigest.getInstance("SHA-256")
val hash = digest.digest(seedString.toByteArray(Charsets.UTF_8)) // 32 bytes
return hash.joinToString("") { "%02x".format(it) } // 64 hex chars
}
```
**JavaScript эквивалент (crypto_new/crypto.ts):**
```javascript
const privateKey = sha256.create().update(seed).digest().toHex().toString();
```
### 2. Формат публичного ключа
#### Старый метод (несжатый):
```kotlin
val publicKeyPoint = ecSpec.g.multiply(privateKeyBigInt)
val publicKeyHex = publicKeyPoint.getEncoded(false) // 65 bytes (04 + x + y)
```
#### Новый метод (сжатый):
```kotlin
val publicKeyPoint = ecSpec.g.multiply(privateKeyBigInt)
val publicKeyHex = publicKeyPoint.getEncoded(true) // 33 bytes (02/03 + x)
```
**JavaScript эквивалент (crypto_new/crypto.ts):**
```javascript
const publicKey = secp256k1.getPublicKey(Buffer.from(privateKey, "hex"), true);
```
### 3. Метод генерации privateKeyHash
Этот метод **НЕ ИЗМЕНИЛСЯ** и уже был совместим с crypto_new:
```kotlin
fun generatePrivateKeyHash(privateKey: String): String {
val data = (privateKey + "rosetta").toByteArray()
val digest = MessageDigest.getInstance("SHA-256")
val hash = digest.digest(data)
return hash.joinToString("") { "%02x".format(it) }
}
```
**JavaScript эквивалент (crypto_new/crypto.ts):**
```javascript
export const generateHashFromPrivateKey = async (privateKey: string) => {
return sha256
.create()
.update(privateKey + "rosetta")
.digest()
.toHex()
.toString();
};
```
## Изменённые файлы
### CryptoManager.kt
**Файл:** `/app/src/main/java/com/rosetta/messenger/crypto/CryptoManager.kt`
**Изменённые функции:**
1. `seedPhraseToPrivateKey()` - теперь использует SHA256 вместо BIP39
2. `generateKeyPairFromSeed()` - генерирует сжатый публичный ключ (33 байта)
## Влияние на авторизацию
### Процесс авторизации
1. **Создание аккаунта (`AuthState.kt -> createAccount()`):**
```kotlin
val keyPair = CryptoManager.generateKeyPairFromSeed(seedPhrase)
// keyPair.privateKey - 32 bytes (64 hex chars) через SHA256
// keyPair.publicKey - 33 bytes (66 hex chars) сжатый формат
val privateKeyHash = CryptoManager.generatePrivateKeyHash(keyPair.privateKey)
// SHA256(privateKey + "rosetta")
```
2. **Подключение к серверу (`Protocol.kt -> startHandshake()`):**
```kotlin
val handshake = PacketHandshake().apply {
this.publicKey = keyPair.publicKey // 33 bytes сжатый
this.privateKey = privateKeyHash // SHA256 hash
}
```
3. **Сервер проверяет:**
- Публичный ключ в сжатом формате (33 байта)
- privateKeyHash = SHA256(privateKey + "rosetta")
## Совместимость
### ✅ Совместимо с crypto_new
- **Генерация ключей:** SHA256(seedPhrase) → privateKey
- **Публичный ключ:** Сжатый формат (33 байта)
- **privateKeyHash:** SHA256(privateKey + "rosetta")
- **ECDH:** Поддерживает сжатые ключи через `decodePoint()`
### ⚠️ Несовместимость со старыми аккаунтами
**ВАЖНО:** Аккаунты, созданные со старым методом (BIP39 + несжатый ключ), больше НЕ СМОГУТ авторизоваться!
Причины:
1. Другой приватный ключ (BIP39 vs SHA256)
2. Другой публичный ключ (65 байт vs 33 байта)
3. Другой privateKeyHash (из-за другого privateKey)
### Миграция
Для поддержки старых аккаунтов потребуется:
1. **Определить формат ключа при загрузке:**
```kotlin
fun isOldFormat(publicKey: String): Boolean {
return publicKey.length == 130 // 65 bytes = 130 hex chars
}
```
2. **Использовать соответствующий метод генерации**
**НО:** Рекомендуется создать новые аккаунты с новым методом шифрования!
## Тестирование
### Проверка совместимости
1. **Создать тестовый seed phrase:**
```
test seed phrase for crypto new compatibility check here now
```
2. **JavaScript (crypto_new):**
```javascript
const keyPair = await generateKeyPairFromSeed(
"test seed phrase for crypto new compatibility check here now"
);
console.log("Private:", keyPair.privateKey);
console.log("Public:", keyPair.publicKey);
console.log("Hash:", await generateHashFromPrivateKey(keyPair.privateKey));
```
3. **Kotlin (Android):**
```kotlin
val seedPhrase = listOf("test", "seed", "phrase", "for", "crypto", "new", "compatibility", "check", "here", "now")
val keyPair = CryptoManager.generateKeyPairFromSeed(seedPhrase)
val hash = CryptoManager.generatePrivateKeyHash(keyPair.privateKey)
Log.d("Test", "Private: ${keyPair.privateKey}")
Log.d("Test", "Public: ${keyPair.publicKey}")
Log.d("Test", "Hash: $hash")
```
4. **Результаты должны совпадать на 100%!**
### Проверка авторизации
1. Создать новый аккаунт в Android приложении
2. Сохранить seed phrase
3. Импортировать тот же seed phrase в React Native версии
4. Убедиться что оба приложения:
- Генерируют одинаковые ключи
- Успешно авторизуются на сервере
- Могут отправлять/получать сообщения друг другу
## Преимущества нового метода
### 1. Простота
- Один SHA256 вместо сложной BIP39 генерации
- Меньше зависимостей
### 2. Совместимость
- 100% совместимость с JavaScript crypto_new
- Одинаковые ключи на всех платформах
### 3. Размер
- Сжатые публичные ключи: 33 байта вместо 65
- Экономия трафика и места в БД
### 4. Производительность
- SHA256 быстрее чем BIP39 derivation
- Кэширование результатов
## Потенциальные проблемы
### 1. Миграция существующих пользователей
**Решение:** Требуется создание новых аккаунтов с новым seed phrase.
### 2. Обратная совместимость
**Решение:** Можно добавить проверку формата ключа и поддержку обоих методов:
```kotlin
fun generateKeyPairFromSeed(
seedPhrase: List<String>,
useNewMethod: Boolean = true
): KeyPairData {
return if (useNewMethod) {
// Новый метод: SHA256 + compressed
generateKeyPairFromSeedNew(seedPhrase)
} else {
// Старый метод: BIP39 + uncompressed
generateKeyPairFromSeedLegacy(seedPhrase)
}
}
```
### 3. Безопасность
**SHA256(seedPhrase) vs BIP39:**
- BIP39 использует PBKDF2 с 2048 итераций
- SHA256 - один проход
**Рекомендация:** Для production рассмотреть использование PBKDF2 в crypto_new:
```javascript
// Более безопасная версия
const privateKey = crypto
.PBKDF2(seed, "rosetta", {
keySize: 256 / 32,
iterations: 2048,
})
.toString();
```
## Заключение
Авторизация полностью обновлена для совместимости с crypto_new. Все ключи генерируются одинаково на Android и JavaScript платформах, что обеспечивает:
- ✅ Единую базу кода для криптографии
- ✅ Совместимость между платформами
- ✅ Уменьшение размера ключей
- ✅ Улучшение производительности
**Следующие шаги:**
1. Тестирование авторизации на реальном сервере
2. Проверка обмена сообщениями между Android и React Native
3. Документирование процесса миграции для существующих пользователей