mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 18:45:20 +00:00
std lib for noise
This commit is contained in:
@@ -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")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user