feat: Add comprehensive encryption architecture documentation for Rosette Messenger
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
This commit is contained in:
288
docs/CRYPTO_NEW_AUTH_UPDATE.md
Normal file
288
docs/CRYPTO_NEW_AUTH_UPDATE.md
Normal file
@@ -0,0 +1,288 @@
|
||||
# Обновление авторизации для совместимости с 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. Документирование процесса миграции для существующих пользователей
|
||||
Reference in New Issue
Block a user