signing noise id

This commit is contained in:
callebtc
2025-07-30 12:17:47 +02:00
parent 70589b1fe7
commit 73af5ded50
2 changed files with 104 additions and 12 deletions
@@ -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()