9.8 KiB
Обновление авторизации для совместимости с crypto_new
Дата: 16 января 2026
Статус: ✅ Реализовано
Обзор изменений
Обновлена логика авторизации в Android приложении для полной совместимости с новым методом шифрования из crypto_new (TypeScript/JavaScript). Основные изменения касаются генерации ключевых пар и формата публичных ключей.
Основные изменения
1. Метод генерации приватного ключа
Старый метод (BIP39):
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):
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):
const privateKey = sha256.create().update(seed).digest().toHex().toString();
2. Формат публичного ключа
Старый метод (несжатый):
val publicKeyPoint = ecSpec.g.multiply(privateKeyBigInt)
val publicKeyHex = publicKeyPoint.getEncoded(false) // 65 bytes (04 + x + y)
Новый метод (сжатый):
val publicKeyPoint = ecSpec.g.multiply(privateKeyBigInt)
val publicKeyHex = publicKeyPoint.getEncoded(true) // 33 bytes (02/03 + x)
JavaScript эквивалент (crypto_new/crypto.ts):
const publicKey = secp256k1.getPublicKey(Buffer.from(privateKey, "hex"), true);
3. Метод генерации privateKeyHash
Этот метод НЕ ИЗМЕНИЛСЯ и уже был совместим с crypto_new:
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):
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
Изменённые функции:
seedPhraseToPrivateKey()- теперь использует SHA256 вместо BIP39generateKeyPairFromSeed()- генерирует сжатый публичный ключ (33 байта)
Влияние на авторизацию
Процесс авторизации
-
Создание аккаунта (
AuthState.kt -> createAccount()):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") -
Подключение к серверу (
Protocol.kt -> startHandshake()):val handshake = PacketHandshake().apply { this.publicKey = keyPair.publicKey // 33 bytes сжатый this.privateKey = privateKeyHash // SHA256 hash } -
Сервер проверяет:
- Публичный ключ в сжатом формате (33 байта)
- privateKeyHash = SHA256(privateKey + "rosetta")
Совместимость
✅ Совместимо с crypto_new
- Генерация ключей: SHA256(seedPhrase) → privateKey
- Публичный ключ: Сжатый формат (33 байта)
- privateKeyHash: SHA256(privateKey + "rosetta")
- ECDH: Поддерживает сжатые ключи через
decodePoint()
⚠️ Несовместимость со старыми аккаунтами
ВАЖНО: Аккаунты, созданные со старым методом (BIP39 + несжатый ключ), больше НЕ СМОГУТ авторизоваться!
Причины:
- Другой приватный ключ (BIP39 vs SHA256)
- Другой публичный ключ (65 байт vs 33 байта)
- Другой privateKeyHash (из-за другого privateKey)
Миграция
Для поддержки старых аккаунтов потребуется:
-
Определить формат ключа при загрузке:
fun isOldFormat(publicKey: String): Boolean { return publicKey.length == 130 // 65 bytes = 130 hex chars } -
Использовать соответствующий метод генерации
НО: Рекомендуется создать новые аккаунты с новым методом шифрования!
Тестирование
Проверка совместимости
-
Создать тестовый seed phrase:
test seed phrase for crypto new compatibility check here now -
JavaScript (crypto_new):
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)); -
Kotlin (Android):
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") -
Результаты должны совпадать на 100%!
Проверка авторизации
- Создать новый аккаунт в Android приложении
- Сохранить seed phrase
- Импортировать тот же seed phrase в React Native версии
- Убедиться что оба приложения:
- Генерируют одинаковые ключи
- Успешно авторизуются на сервере
- Могут отправлять/получать сообщения друг другу
Преимущества нового метода
1. Простота
- Один SHA256 вместо сложной BIP39 генерации
- Меньше зависимостей
2. Совместимость
- 100% совместимость с JavaScript crypto_new
- Одинаковые ключи на всех платформах
3. Размер
- Сжатые публичные ключи: 33 байта вместо 65
- Экономия трафика и места в БД
4. Производительность
- SHA256 быстрее чем BIP39 derivation
- Кэширование результатов
Потенциальные проблемы
1. Миграция существующих пользователей
Решение: Требуется создание новых аккаунтов с новым seed phrase.
2. Обратная совместимость
Решение: Можно добавить проверку формата ключа и поддержку обоих методов:
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:
// Более безопасная версия
const privateKey = crypto
.PBKDF2(seed, "rosetta", {
keySize: 256 / 32,
iterations: 2048,
})
.toString();
Заключение
Авторизация полностью обновлена для совместимости с crypto_new. Все ключи генерируются одинаково на Android и JavaScript платформах, что обеспечивает:
- ✅ Единую базу кода для криптографии
- ✅ Совместимость между платформами
- ✅ Уменьшение размера ключей
- ✅ Улучшение производительности
Следующие шаги:
- Тестирование авторизации на реальном сервере
- Проверка обмена сообщениями между Android и React Native
- Документирование процесса миграции для существующих пользователей