feat: Implement Firebase Cloud Messaging (FCM) integration documentation for push notifications docs: Outline remaining tasks for complete FCM integration in the project fix: Resolve WebSocket connection issues after user registration
289 lines
9.8 KiB
Markdown
289 lines
9.8 KiB
Markdown
# Обновление авторизации для совместимости с 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. Документирование процесса миграции для существующих пользователей
|