Security settings improvements

This commit is contained in:
Jake-B 2025-06-16 17:24:54 -04:00
parent 86d4e4728a
commit b026650435
2 changed files with 52 additions and 7 deletions

View file

@ -12,19 +12,28 @@ struct SecureInput: View {
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
@Binding private var text: String
@Binding private var isValid: Bool
@State var isSecure: Bool = true
private var title: String
init(_ title: String, text: Binding<String>, isValid: Binding<Bool>) {
// Local state to store the value of iSSecure, or optionally a binding
private var isSecureBinding: Binding<Bool>?
@State private var isSecureLocal: Bool = true
private var isSecure: Binding<Bool> {
// Use the binding if we have one, otherwise fallback to the local state variable
isSecureBinding ?? $isSecureLocal
}
init(_ title: String, text: Binding<String>, isValid: Binding<Bool>, isSecure: Binding<Bool>? = nil) {
self.title = title
self._text = text
self._isValid = isValid
self.isSecureBinding = isSecure
}
var body: some View {
ZStack(alignment: .trailing) {
Group {
if isSecure {
if isSecure.wrappedValue {
SecureField(title, text: $text)
.font(idiom == .phone ? .caption : .callout)
.allowsTightening(true)
@ -51,9 +60,9 @@ struct SecureInput: View {
if !text.isEmpty {
Button(action: {
isSecure.toggle()
isSecure.wrappedValue.toggle()
}) {
Image(systemName: self.isSecure ? "eye.slash" : "eye")
Image(systemName: self.isSecure.wrappedValue ? "eye.slash" : "eye")
.accentColor(.secondary)
}.buttonStyle(BorderlessButtonStyle())
}

View file

@ -10,6 +10,7 @@ import SwiftUI
import CoreData
import MeshtasticProtobufs
import OSLog
import CryptoKit
struct SecurityConfig: View {
@ -33,6 +34,15 @@ struct SecurityConfig: View {
@State var isManaged = false
@State var serialEnabled = false
@State var debugLogApiEnabled = false
@State var privateKeyIsSecure = true
private var isValidKeyPair: Bool {
if let privateKeyBytes = Data(base64Encoded: privateKey),
let calculatedPublicKey = generatePublicKey(from: privateKeyBytes) {
return calculatedPublicKey.base64EncodedString() == publicKey
}
return false
}
var body: some View {
VStack {
@ -51,12 +61,16 @@ struct SecurityConfig: View {
.foregroundStyle(.tertiary)
.disableAutocorrection(true)
.textSelection(.enabled)
.background(
RoundedRectangle(cornerRadius: 10.0)
.stroke(isValidKeyPair ? Color.clear : Color.red, lineWidth: 2.0)
)
Text("Sent out to other nodes on the mesh to allow them to compute a shared secret key.")
.foregroundStyle(.secondary)
.font(idiom == .phone ? .caption : .callout)
Divider()
Label("Private Key", systemImage: "key.fill")
SecureInput("Private Key", text: $privateKey, isValid: $hasValidPrivateKey)
SecureInput("Private Key", text: $privateKey, isValid: $hasValidPrivateKey, isSecure: $privateKeyIsSecure)
.background(
RoundedRectangle(cornerRadius: 10.0)
.stroke(hasValidPrivateKey ? Color.clear : Color.red, lineWidth: 2.0)
@ -70,6 +84,7 @@ struct SecurityConfig: View {
Button {
if let keyBytes = generatePrivateKey(count: 32) {
privateKey = keyBytes.base64EncodedString()
self.privateKeyIsSecure = false
}
} label: {
Image(systemName: "lock.rotation")
@ -156,6 +171,10 @@ struct SecurityConfig: View {
let tempKey = Data(base64Encoded: privateKey) ?? Data()
if tempKey.count == 32 {
hasValidPrivateKey = true
if let privateKeyBytes = Data(base64Encoded: privateKey), privateKeyBytes.count == 32 {
// Valid private key -- generate the public key
publicKey = generatePublicKey(from: privateKeyBytes)?.base64EncodedString() ?? ""
}
} else {
hasValidPrivateKey = false
}
@ -287,7 +306,24 @@ struct SecurityConfig: View {
return randomBytes
} else {
// Handle error, perhaps by logging or throwing an exception
print("Error generating random bytes: \(status)")
Logger.mesh.debug("Error generating random bytes: \(status)")
return nil
}
}
func generatePublicKey(from privateKeyData: Data) -> Data? {
guard privateKeyData.count == 32 else {
Logger.mesh.debug("Invalid private key length. Must be 32 bytes for Curve25519.")
return nil
}
do {
// Create a Curve25519 private key from raw representation
let privateKey = try Curve25519.KeyAgreement.PrivateKey(rawRepresentation: privateKeyData)
let publicKey = privateKey.publicKey
return publicKey.rawRepresentation
} catch {
Logger.mesh.debug("Failed to create Curve25519 key: \(error)")
return nil
}
}