mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 04:45:21 +00:00
peerid computed from noise fingerprint (#413)
This commit is contained in:
@@ -5,7 +5,6 @@ import android.content.SharedPreferences
|
|||||||
import androidx.security.crypto.EncryptedSharedPreferences
|
import androidx.security.crypto.EncryptedSharedPreferences
|
||||||
import androidx.security.crypto.MasterKey
|
import androidx.security.crypto.MasterKey
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.security.SecureRandom
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,7 +12,6 @@ import android.util.Log
|
|||||||
*
|
*
|
||||||
* Handles:
|
* Handles:
|
||||||
* - Static identity key persistence across app sessions
|
* - Static identity key persistence across app sessions
|
||||||
* - Peer ID rotation timing (5-15 minute random intervals)
|
|
||||||
* - Secure storage using Android EncryptedSharedPreferences
|
* - Secure storage using Android EncryptedSharedPreferences
|
||||||
* - Fingerprint calculation and identity validation
|
* - Fingerprint calculation and identity validation
|
||||||
*/
|
*/
|
||||||
@@ -26,16 +24,9 @@ class SecureIdentityStateManager(private val context: Context) {
|
|||||||
private const val KEY_STATIC_PUBLIC_KEY = "static_public_key"
|
private const val KEY_STATIC_PUBLIC_KEY = "static_public_key"
|
||||||
private const val KEY_SIGNING_PRIVATE_KEY = "signing_private_key"
|
private const val KEY_SIGNING_PRIVATE_KEY = "signing_private_key"
|
||||||
private const val KEY_SIGNING_PUBLIC_KEY = "signing_public_key"
|
private const val KEY_SIGNING_PUBLIC_KEY = "signing_public_key"
|
||||||
private const val KEY_LAST_ROTATION = "last_rotation"
|
|
||||||
private const val KEY_NEXT_ROTATION_INTERVAL = "next_rotation_interval"
|
|
||||||
|
|
||||||
// Rotation intervals (same as iOS)
|
|
||||||
private const val MIN_ROTATION_INTERVAL = 5 * 60 * 1000L // 5 minutes
|
|
||||||
private const val MAX_ROTATION_INTERVAL = 15 * 60 * 1000L // 15 minutes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val prefs: SharedPreferences
|
private val prefs: SharedPreferences
|
||||||
private val random = SecureRandom()
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// Create master key for encryption
|
// Create master key for encryption
|
||||||
@@ -188,70 +179,9 @@ class SecureIdentityStateManager(private val context: Context) {
|
|||||||
return fingerprint.matches(Regex("^[a-fA-F0-9]{64}$"))
|
return fingerprint.matches(Regex("^[a-fA-F0-9]{64}$"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Peer ID Rotation Management
|
// MARK: - Peer ID Rotation Management (removed)
|
||||||
|
// Android now derives peer ID from the persisted Noise identity fingerprint.
|
||||||
/**
|
// No timed peer ID rotation is performed here.
|
||||||
* Check if peer ID should be rotated based on random interval
|
|
||||||
*/
|
|
||||||
fun shouldRotatePeerID(): Boolean {
|
|
||||||
val lastRotation = prefs.getLong(KEY_LAST_ROTATION, 0L)
|
|
||||||
val nextInterval = prefs.getLong(KEY_NEXT_ROTATION_INTERVAL, 0L)
|
|
||||||
val now = System.currentTimeMillis()
|
|
||||||
|
|
||||||
if (lastRotation == 0L || nextInterval == 0L) {
|
|
||||||
// First run or missing data - schedule next rotation and don't rotate now
|
|
||||||
scheduleNextRotation()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
val shouldRotate = (now - lastRotation) >= nextInterval
|
|
||||||
if (shouldRotate) {
|
|
||||||
Log.d(TAG, "Peer ID rotation due: ${(now - lastRotation) / 1000}s since last rotation")
|
|
||||||
}
|
|
||||||
|
|
||||||
return shouldRotate
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark rotation as completed and schedule next one
|
|
||||||
*/
|
|
||||||
fun markRotationCompleted() {
|
|
||||||
val now = System.currentTimeMillis()
|
|
||||||
prefs.edit()
|
|
||||||
.putLong(KEY_LAST_ROTATION, now)
|
|
||||||
.apply()
|
|
||||||
|
|
||||||
scheduleNextRotation()
|
|
||||||
|
|
||||||
Log.d(TAG, "Peer ID rotation marked as completed")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedule the next rotation with random interval (5-15 minutes)
|
|
||||||
*/
|
|
||||||
private fun scheduleNextRotation() {
|
|
||||||
val nextInterval = MIN_ROTATION_INTERVAL + random.nextLong(MAX_ROTATION_INTERVAL - MIN_ROTATION_INTERVAL)
|
|
||||||
|
|
||||||
prefs.edit()
|
|
||||||
.putLong(KEY_NEXT_ROTATION_INTERVAL, nextInterval)
|
|
||||||
.apply()
|
|
||||||
|
|
||||||
Log.d(TAG, "Next peer ID rotation scheduled in ${nextInterval / 60000} minutes")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get time until next rotation (for debugging)
|
|
||||||
*/
|
|
||||||
fun getTimeUntilNextRotation(): Long {
|
|
||||||
val lastRotation = prefs.getLong(KEY_LAST_ROTATION, 0L)
|
|
||||||
val nextInterval = prefs.getLong(KEY_NEXT_ROTATION_INTERVAL, 0L)
|
|
||||||
val now = System.currentTimeMillis()
|
|
||||||
|
|
||||||
if (lastRotation == 0L || nextInterval == 0L) return -1
|
|
||||||
|
|
||||||
val elapsed = now - lastRotation
|
|
||||||
return maxOf(0L, nextInterval - elapsed)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Identity Validation
|
// MARK: - Identity Validation
|
||||||
|
|
||||||
@@ -305,14 +235,6 @@ class SecureIdentityStateManager(private val context: Context) {
|
|||||||
appendLine("Has identity: $hasIdentity")
|
appendLine("Has identity: $hasIdentity")
|
||||||
|
|
||||||
if (hasIdentity) {
|
if (hasIdentity) {
|
||||||
val lastRotation = prefs.getLong(KEY_LAST_ROTATION, 0L)
|
|
||||||
val nextInterval = prefs.getLong(KEY_NEXT_ROTATION_INTERVAL, 0L)
|
|
||||||
val timeUntilNext = getTimeUntilNextRotation()
|
|
||||||
|
|
||||||
appendLine("Last rotation: ${if (lastRotation > 0) "${(System.currentTimeMillis() - lastRotation) / 1000}s ago" else "never"}")
|
|
||||||
appendLine("Next rotation in: ${if (timeUntilNext >= 0) "${timeUntilNext / 1000}s" else "not scheduled"}")
|
|
||||||
appendLine("Rotation interval: ${nextInterval / 1000}s")
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val keyPair = loadStaticKey()
|
val keyPair = loadStaticKey()
|
||||||
if (keyPair != null) {
|
if (keyPair != null) {
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ class BluetoothMeshService(private val context: Context) {
|
|||||||
private const val MAX_TTL: UByte = 7u
|
private const val MAX_TTL: UByte = 7u
|
||||||
}
|
}
|
||||||
|
|
||||||
// My peer identification - same format as iOS
|
|
||||||
val myPeerID: String = generateCompatiblePeerID()
|
|
||||||
|
|
||||||
// Core components - each handling specific responsibilities
|
// Core components - each handling specific responsibilities
|
||||||
private val encryptionService = EncryptionService(context)
|
private val encryptionService = EncryptionService(context)
|
||||||
|
|
||||||
|
// My peer identification - derived from persisted Noise identity fingerprint (first 16 hex chars)
|
||||||
|
val myPeerID: String = encryptionService.getIdentityFingerprint().take(16)
|
||||||
private val peerManager = PeerManager()
|
private val peerManager = PeerManager()
|
||||||
private val fragmentManager = FragmentManager()
|
private val fragmentManager = FragmentManager()
|
||||||
private val securityManager = SecurityManager(encryptionService, myPeerID)
|
private val securityManager = SecurityManager(encryptionService, myPeerID)
|
||||||
@@ -904,15 +904,6 @@ class BluetoothMeshService(private val context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate peer ID compatible with iOS - exactly 8 bytes (16 hex characters)
|
|
||||||
*/
|
|
||||||
private fun generateCompatiblePeerID(): String {
|
|
||||||
val randomBytes = ByteArray(8) // 8 bytes = 16 hex characters (like iOS)
|
|
||||||
Random.nextBytes(randomBytes)
|
|
||||||
return randomBytes.joinToString("") { "%02x".format(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert hex string peer ID to binary data (8 bytes) - exactly same as iOS
|
* Convert hex string peer ID to binary data (8 bytes) - exactly same as iOS
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user