std lib for noise

This commit is contained in:
callebtc
2025-07-17 13:39:22 +02:00
parent 176ceab044
commit 02ea3771b5
2 changed files with 64 additions and 24 deletions
+2 -2
View File
@@ -76,8 +76,8 @@ dependencies {
// Cryptography // Cryptography
implementation(libs.bundles.cryptography) implementation(libs.bundles.cryptography)
// Noise Protocol Framework // Noise Protocol Framework - Standard Implementation
implementation("org.signal.forks:noise-java:0.1.1") implementation("com.github.auties00:noise-java:1.2")
// JSON // JSON
implementation(libs.gson) implementation(libs.gson)
@@ -4,6 +4,7 @@ import android.util.Log
import com.southernstorm.noise.protocol.* import com.southernstorm.noise.protocol.*
import java.security.SecureRandom import java.security.SecureRandom
/** /**
* Individual Noise session for a specific peer - REAL IMPLEMENTATION with noise-java * Individual Noise session for a specific peer - REAL IMPLEMENTATION with noise-java
* 100% compatible with iOS bitchat Noise Protocol * 100% compatible with iOS bitchat Noise Protocol
@@ -80,7 +81,8 @@ class NoiseSession(
init { init {
try { try {
initializeNoiseHandshake() // Validate static keys
validateStaticKeys()
Log.d(TAG, "Created ${if (isInitiator) "initiator" else "responder"} session for $peerID") Log.d(TAG, "Created ${if (isInitiator) "initiator" else "responder"} session for $peerID")
} catch (e: Exception) { } catch (e: Exception) {
state = NoiseSessionState.Failed(e) state = NoiseSessionState.Failed(e)
@@ -89,30 +91,65 @@ class NoiseSession(
} }
/** /**
* Initialize the real Noise handshake state using noise-java * Validate static keys before using them
* Fixed to match iOS static key handling exactly
*/ */
private fun initializeNoiseHandshake() { private fun validateStaticKeys() {
val role = if (isInitiator) HandshakeState.INITIATOR else HandshakeState.RESPONDER if (localStaticPrivateKey.size != 32) {
handshakeState = HandshakeState(PROTOCOL_NAME, role) throw IllegalArgumentException("Local static private key must be 32 bytes, got ${localStaticPrivateKey.size}")
}
if (localStaticPublicKey.size != 32) {
throw IllegalArgumentException("Local static public key must be 32 bytes, got ${localStaticPublicKey.size}")
}
// CRITICAL FIX: Proper static key setup to match iOS implementation // Check for all-zero keys (invalid)
// The static key needs to be set BEFORE starting the handshake if (localStaticPrivateKey.all { it == 0.toByte() }) {
throw IllegalArgumentException("Local static private key cannot be all zeros")
}
if (localStaticPublicKey.all { it == 0.toByte() }) {
throw IllegalArgumentException("Local static public key cannot be all zeros")
}
Log.d(TAG, "Static keys validated successfully - private: ${localStaticPrivateKey.size} bytes, public: ${localStaticPublicKey.size} bytes")
}
/**
* Initialize the Noise handshake with proper static key injection
* FIXED: Uses standard noise-java library that supports manual key setting
*/
private fun initializeNoiseHandshake(role: Int) {
try {
Log.d(TAG, "Creating HandshakeState with role: ${if (role == HandshakeState.INITIATOR) "INITIATOR" else "RESPONDER"}")
handshakeState = HandshakeState(PROTOCOL_NAME, role)
Log.d(TAG, "HandshakeState created successfully")
if (handshakeState?.needsLocalKeyPair() == true) {
Log.d(TAG, "Local key pair is needed")
val localKeyPair = handshakeState?.getLocalKeyPair() val localKeyPair = handshakeState?.getLocalKeyPair()
if (localKeyPair != null) { if (localKeyPair != null) {
// Set both private and public keys properly // FIXED: Set our persistent static keys directly (standard noise-java supports this)
localKeyPair.setPrivateKey(localStaticPrivateKey, 0) localKeyPair.setPrivateKey(localStaticPrivateKey, 0)
localKeyPair.setPublicKey(localStaticPublicKey, 0) localKeyPair.setPublicKey(localStaticPublicKey, 0)
Log.d(TAG, "Set local static key pair for handshake state") Log.d(TAG, "Set persistent static key pair (private: ${localStaticPrivateKey.size} bytes, public: ${localStaticPublicKey.size} bytes)")
} else { } else {
Log.w(TAG, "Warning: Could not get local key pair from handshake state") Log.e(TAG, "Failed to get local key pair even though it's needed")
throw IllegalStateException("Failed to get local key pair")
}
} else {
Log.d(TAG, "Local key pair not needed for this handshake pattern/role")
} }
// Start the handshake
handshakeState?.start() handshakeState?.start()
Log.d(TAG, "Handshake state started successfully")
Log.d(TAG, "Initialized real Noise handshake state for $peerID") } catch (e: Exception) {
Log.e(TAG, "Exception during handshake initialization: ${e.message}", e)
throw e
} }
}
// MARK: - Real Handshake Implementation // MARK: - Real Handshake Implementation
@@ -133,6 +170,8 @@ class NoiseSession(
Log.d(TAG, "Starting real XX handshake with $peerID as initiator") Log.d(TAG, "Starting real XX handshake with $peerID as initiator")
try { try {
// Initialize handshake as initiator
initializeNoiseHandshake(HandshakeState.INITIATOR)
state = NoiseSessionState.Handshaking state = NoiseSessionState.Handshaking
handshakeMessageCount = 1 handshakeMessageCount = 1
@@ -168,6 +207,7 @@ class NoiseSession(
try { try {
// Initialize as responder if receiving first message // Initialize as responder if receiving first message
if (state == NoiseSessionState.Uninitialized && !isInitiator) { if (state == NoiseSessionState.Uninitialized && !isInitiator) {
initializeNoiseHandshake(HandshakeState.RESPONDER)
state = NoiseSessionState.Handshaking state = NoiseSessionState.Handshaking
handshakeMessageCount = 1 handshakeMessageCount = 1
Log.d(TAG, "Initialized as responder for real XX handshake with $peerID") Log.d(TAG, "Initialized as responder for real XX handshake with $peerID")
@@ -427,8 +467,7 @@ class NoiseSession(
// Destroy existing state // Destroy existing state
destroy() destroy()
// Reinitialize // Reset to uninitialized state (handshake will be initialized when needed)
initializeNoiseHandshake()
state = NoiseSessionState.Uninitialized state = NoiseSessionState.Uninitialized
messagesSent = 0 messagesSent = 0
messagesReceived = 0 messagesReceived = 0
@@ -484,4 +523,5 @@ sealed class SessionError(message: String, cause: Throwable? = null) : Exception
object HandshakeFailed : SessionError("Handshake failed") object HandshakeFailed : SessionError("Handshake failed")
object EncryptionFailed : SessionError("Encryption failed") object EncryptionFailed : SessionError("Encryption failed")
object DecryptionFailed : SessionError("Decryption failed") object DecryptionFailed : SessionError("Decryption failed")
class HandshakeInitializationFailed(message: String) : SessionError("Handshake initialization failed: $message")
} }