feat: Update authorization logic for compatibility with crypto_new; enhance key generation and public key format

This commit is contained in:
k1ngsterr1
2026-01-16 04:53:48 +05:00
parent 306e854646
commit caf1d246d3
7 changed files with 774 additions and 15 deletions

288
CRYPTO_NEW_AUTH_UPDATE.md Normal file
View 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. Документирование процесса миграции для существующих пользователей