mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 05:05:20 +00:00
signing noise id
This commit is contained in:
@@ -3,6 +3,12 @@ package com.bitchat.android.crypto
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.bitchat.android.noise.NoiseEncryptionService
|
import com.bitchat.android.noise.NoiseEncryptionService
|
||||||
|
import org.bouncycastle.crypto.AsymmetricCipherKeyPair
|
||||||
|
import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator
|
||||||
|
import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters
|
||||||
|
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters
|
||||||
|
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters
|
||||||
|
import org.bouncycastle.crypto.signers.Ed25519Signer
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
@@ -17,6 +23,7 @@ class EncryptionService(private val context: Context) {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "EncryptionService"
|
private const val TAG = "EncryptionService"
|
||||||
|
private const val ED25519_PRIVATE_KEY_PREF = "ed25519_signing_private_key"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Core Noise encryption service
|
// Core Noise encryption service
|
||||||
@@ -25,12 +32,23 @@ class EncryptionService(private val context: Context) {
|
|||||||
// Session tracking for established connections
|
// Session tracking for established connections
|
||||||
private val establishedSessions = ConcurrentHashMap<String, String>() // peerID -> fingerprint
|
private val establishedSessions = ConcurrentHashMap<String, String>() // peerID -> fingerprint
|
||||||
|
|
||||||
|
// Ed25519 signing keys (separate from Noise static keys)
|
||||||
|
private val ed25519PrivateKey: Ed25519PrivateKeyParameters
|
||||||
|
private val ed25519PublicKey: Ed25519PublicKeyParameters
|
||||||
|
|
||||||
// Callbacks for UI state updates
|
// Callbacks for UI state updates
|
||||||
var onSessionEstablished: ((String) -> Unit)? = null // peerID
|
var onSessionEstablished: ((String) -> Unit)? = null // peerID
|
||||||
var onSessionLost: ((String) -> Unit)? = null // peerID
|
var onSessionLost: ((String) -> Unit)? = null // peerID
|
||||||
var onHandshakeRequired: ((String) -> Unit)? = null // peerID
|
var onHandshakeRequired: ((String) -> Unit)? = null // peerID
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
// Initialize or load Ed25519 signing keys
|
||||||
|
val keyPair = loadOrCreateEd25519KeyPair()
|
||||||
|
ed25519PrivateKey = keyPair.private as Ed25519PrivateKeyParameters
|
||||||
|
ed25519PublicKey = keyPair.public as Ed25519PublicKeyParameters
|
||||||
|
|
||||||
|
Log.d(TAG, "✅ Ed25519 signing keys initialized")
|
||||||
|
|
||||||
// Set up NoiseEncryptionService callbacks
|
// Set up NoiseEncryptionService callbacks
|
||||||
noiseService.onPeerAuthenticated = { peerID, fingerprint ->
|
noiseService.onPeerAuthenticated = { peerID, fingerprint ->
|
||||||
Log.d(TAG, "✅ Noise session established with $peerID, fingerprint: ${fingerprint.take(16)}...")
|
Log.d(TAG, "✅ Noise session established with $peerID, fingerprint: ${fingerprint.take(16)}...")
|
||||||
@@ -63,24 +81,26 @@ class EncryptionService(private val context: Context) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get our signing public key for Ed25519 signatures (for identity announcements)
|
* Get our signing public key for Ed25519 signatures (for identity announcements)
|
||||||
* Note: In the current implementation, this returns the same as static key
|
|
||||||
* In a full implementation, this would be a separate Ed25519 key
|
|
||||||
*/
|
*/
|
||||||
fun getSigningPublicKey(): ByteArray? {
|
fun getSigningPublicKey(): ByteArray? {
|
||||||
// For now, return the static public key as placeholder
|
return ed25519PublicKey.encoded
|
||||||
// In a full implementation, this would be a separate Ed25519 signing key
|
|
||||||
return noiseService.getStaticPublicKeyData()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign data using our signing key (for identity announcements)
|
* Sign data using our Ed25519 signing key (for identity announcements)
|
||||||
* Note: In the current simplified implementation, this returns empty signature
|
|
||||||
* In a full implementation, this would use Ed25519 signing
|
|
||||||
*/
|
*/
|
||||||
fun signData(data: ByteArray): ByteArray? {
|
fun signData(data: ByteArray): ByteArray? {
|
||||||
// For now, return empty signature as placeholder
|
return try {
|
||||||
// In a full implementation, this would use Ed25519 to sign the data
|
val signer = Ed25519Signer()
|
||||||
return ByteArray(64) // Ed25519 signature length placeholder
|
signer.init(true, ed25519PrivateKey)
|
||||||
|
signer.update(data, 0, data.size)
|
||||||
|
val signature = signer.generateSignature()
|
||||||
|
Log.d(TAG, "✅ Generated Ed25519 signature (${signature.size} bytes)")
|
||||||
|
signature
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "❌ Failed to sign data with Ed25519: ${e.message}")
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -112,6 +132,15 @@ class EncryptionService(private val context: Context) {
|
|||||||
fun clearPersistentIdentity() {
|
fun clearPersistentIdentity() {
|
||||||
noiseService.clearPersistentIdentity()
|
noiseService.clearPersistentIdentity()
|
||||||
establishedSessions.clear()
|
establishedSessions.clear()
|
||||||
|
|
||||||
|
// Clear Ed25519 signing key from preferences
|
||||||
|
try {
|
||||||
|
val prefs = context.getSharedPreferences("bitchat_crypto", Context.MODE_PRIVATE)
|
||||||
|
prefs.edit().remove(ED25519_PRIVATE_KEY_PREF).apply()
|
||||||
|
Log.d(TAG, "🗑️ Cleared Ed25519 signing keys from preferences")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "❌ Failed to clear Ed25519 keys: ${e.message}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -321,4 +350,67 @@ class EncryptionService(private val context: Context) {
|
|||||||
noiseService.shutdown()
|
noiseService.shutdown()
|
||||||
Log.d(TAG, "🔌 EncryptionService shut down")
|
Log.d(TAG, "🔌 EncryptionService shut down")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Ed25519 Signature Verification
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify Ed25519 signature against data using a public key
|
||||||
|
*/
|
||||||
|
fun verifyEd25519Signature(signature: ByteArray, data: ByteArray, publicKeyBytes: ByteArray): Boolean {
|
||||||
|
return try {
|
||||||
|
val publicKey = Ed25519PublicKeyParameters(publicKeyBytes, 0)
|
||||||
|
val verifier = Ed25519Signer()
|
||||||
|
verifier.init(false, publicKey)
|
||||||
|
verifier.update(data, 0, data.size)
|
||||||
|
val isValid = verifier.verifySignature(signature)
|
||||||
|
Log.d(TAG, "✅ Ed25519 signature verification: $isValid")
|
||||||
|
isValid
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "❌ Failed to verify Ed25519 signature: ${e.message}")
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private Key Management
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load existing Ed25519 key pair from preferences or create a new one
|
||||||
|
*/
|
||||||
|
private fun loadOrCreateEd25519KeyPair(): AsymmetricCipherKeyPair {
|
||||||
|
try {
|
||||||
|
val prefs = context.getSharedPreferences("bitchat_crypto", Context.MODE_PRIVATE)
|
||||||
|
val storedKey = prefs.getString(ED25519_PRIVATE_KEY_PREF, null)
|
||||||
|
|
||||||
|
if (storedKey != null) {
|
||||||
|
// Load existing key
|
||||||
|
val privateKeyBytes = android.util.Base64.decode(storedKey, android.util.Base64.DEFAULT)
|
||||||
|
val privateKey = Ed25519PrivateKeyParameters(privateKeyBytes, 0)
|
||||||
|
val publicKey = privateKey.generatePublicKey()
|
||||||
|
Log.d(TAG, "✅ Loaded existing Ed25519 signing key pair")
|
||||||
|
return AsymmetricCipherKeyPair(publicKey, privateKey)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "⚠️ Failed to load existing Ed25519 key, creating new one: ${e.message}")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new key pair
|
||||||
|
val keyGen = Ed25519KeyPairGenerator()
|
||||||
|
keyGen.init(Ed25519KeyGenerationParameters(SecureRandom()))
|
||||||
|
val keyPair = keyGen.generateKeyPair()
|
||||||
|
|
||||||
|
// Store private key in preferences
|
||||||
|
try {
|
||||||
|
val privateKey = keyPair.private as Ed25519PrivateKeyParameters
|
||||||
|
val privateKeyBytes = privateKey.encoded
|
||||||
|
val encodedKey = android.util.Base64.encodeToString(privateKeyBytes, android.util.Base64.DEFAULT)
|
||||||
|
|
||||||
|
val prefs = context.getSharedPreferences("bitchat_crypto", Context.MODE_PRIVATE)
|
||||||
|
prefs.edit().putString(ED25519_PRIVATE_KEY_PREF, encodedKey).apply()
|
||||||
|
Log.d(TAG, "✅ Created and stored new Ed25519 signing key pair")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "❌ Failed to store Ed25519 private key: ${e.message}")
|
||||||
|
}
|
||||||
|
|
||||||
|
return keyPair
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class NoiseEncryptionService(private val context: Context) {
|
|||||||
if (loadedKeyPair != null) {
|
if (loadedKeyPair != null) {
|
||||||
staticIdentityPrivateKey = loadedKeyPair.first
|
staticIdentityPrivateKey = loadedKeyPair.first
|
||||||
staticIdentityPublicKey = loadedKeyPair.second
|
staticIdentityPublicKey = loadedKeyPair.second
|
||||||
Log.d(TAG, "Loaded existing static identity key")
|
Log.d(TAG, "Loaded existing static identity key: ${calculateFingerprint(staticIdentityPublicKey)}")
|
||||||
} else {
|
} else {
|
||||||
// Generate new identity key pair
|
// Generate new identity key pair
|
||||||
val keyPair = generateKeyPair()
|
val keyPair = generateKeyPair()
|
||||||
|
|||||||
Reference in New Issue
Block a user