almost done rewritign import sshprivkey

made these static funcitons
made keypair have computed openssh format pub/priv variables that are strings
This commit is contained in:
neon443
2025-07-01 12:46:32 +01:00
parent 1f3afc9c93
commit 19c2e8f912
6 changed files with 75 additions and 48 deletions

View File

@@ -187,9 +187,7 @@ class HostsManager: ObservableObject, @unchecked Sendable {
for host in hosts { for host in hosts {
guard let publicKey = host.publicKey else { continue } guard let publicKey = host.publicKey else { continue }
guard let privateKey = host.privateKey else { continue } guard let privateKey = host.privateKey else { continue }
guard let privKeyStr = String(data: privateKey, encoding: .utf8), let keypair = Keypair(type: .rsa, name: UUID().uuidString, publicKey: publicKey, privateKey: privateKey)
let pubKeyStr = String(data: publicKey, encoding: .utf8) else { continue }
let keypair = Keypair(type: .rsa(1), name: UUID().uuidString, publicKey: pubKeyStr, privateKey: privKeyStr)
if !result.contains(keypair) { if !result.contains(keypair) {
result.append(keypair) result.append(keypair)
} }

View File

@@ -27,17 +27,17 @@ class KeyManager: ObservableObject {
let privatekeyData = key.rawRepresentation let privatekeyData = key.rawRepresentation
let publickeyData = key.publicKey.rawRepresentation let publickeyData = key.publicKey.rawRepresentation
print(publickeyData.base64EncodedString()) print(publickeyData.base64EncodedString())
let pubpem = makeSSHPubkey(pub: publickeyData, comment: "neon443@m") let pubpem = KeyManager.makeSSHPubkey(pub: publickeyData, comment: "neon443@m")
let privpem = makeSSHPrivkey(pub: publickeyData, priv: privatekeyData, comment: "neon443@m") let privpem = KeyManager.makeSSHPrivkey(pub: publickeyData, priv: privatekeyData, comment: "neon443@m")
print(String(data: pubpem, encoding: .utf8)!) print(String(data: pubpem, encoding: .utf8)!)
print() print()
print(String(data: privpem, encoding: .utf8)!) print(String(data: privpem, encoding: .utf8)!)
print() print()
print(importSSHPubkey(pub: String(data: pubpem, encoding: .utf8)!).base64EncodedString()) print(KeyManager.importSSHPubkey(pub: String(data: pubpem, encoding: .utf8)!).base64EncodedString())
print(privatekeyData.base64EncodedString()) print(privatekeyData.base64EncodedString())
print(importSSHPrivkey(priv: String(data: privpem, encoding: .utf8)!).base64EncodedString()) print(KeyManager.importSSHPrivkey(priv: String(data: privpem, encoding: .utf8)!).privateKey.base64EncodedString())
fatalError() fatalError()
} }
@@ -59,14 +59,14 @@ class KeyManager: ObservableObject {
//MARK: generate keys //MARK: generate keys
func generateKey(type: KeyType, SEPKeyTag: String, comment: String, passphrase: String) -> Keypair? { func generateKey(type: KeyType, SEPKeyTag: String, comment: String, passphrase: String) -> Keypair? {
switch type { switch type {
case .ecdsa(let inSEP): case .ecdsa:
fatalError("unimplemented") fatalError("unimplemented")
case .rsa(let rsaSize): case .rsa:
fatalError("unimplemented") fatalError("unimplemented")
} }
} }
func importSSHPubkey(pub: String) -> Data { static func importSSHPubkey(pub: String) -> Data {
let split = pub.split(separator: " ") let split = pub.split(separator: " ")
guard split.count == 3 else { return Data() } guard split.count == 3 else { return Data() }
@@ -78,7 +78,7 @@ class KeyManager: ObservableObject {
return pubdata return pubdata
} }
func makeSSHPubkey(pub: Data, comment: String) -> Data { static func makeSSHPubkey(pub: Data, comment: String) -> Data {
let header = "ssh-ed25519" let header = "ssh-ed25519"
var keyBlob: Data = Data() var keyBlob: Data = Data()
//key type bit //key type bit
@@ -91,7 +91,7 @@ class KeyManager: ObservableObject {
return Data(pubkeyline.utf8) return Data(pubkeyline.utf8)
} }
func importSSHPrivkey(priv: String) -> Data { static func importSSHPrivkey(priv: String) -> Keypair {
var split = priv.replacingOccurrences(of: "-----BEGIN OPENSSH PRIVATE KEY-----\n", with: "") var split = priv.replacingOccurrences(of: "-----BEGIN OPENSSH PRIVATE KEY-----\n", with: "")
split = split.replacingOccurrences(of: "-----BEGIN OPENSSH PRIVATE KEY-----", with: "") split = split.replacingOccurrences(of: "-----BEGIN OPENSSH PRIVATE KEY-----", with: "")
split = split.replacingOccurrences(of: "\n-----END OPENSSH PRIVATE KEY-----\n", with: "") split = split.replacingOccurrences(of: "\n-----END OPENSSH PRIVATE KEY-----\n", with: "")
@@ -102,17 +102,38 @@ class KeyManager: ObservableObject {
var dataBlob = Data(base64Encoded: split.data(using: .utf8)!)! var dataBlob = Data(base64Encoded: split.data(using: .utf8)!)!
dataBlob.removeFirst(15) //remove magik header dataBlob.removeFirst(15) //remove magik header
dataBlob.removeFirst(16) //remove none noen
dataBlob.removeFirst(4) //remove lenght header for empty data
dataBlob.removeFirst(8) //remove empty data
for _ in 0..<2 { removeField(&dataBlob) //remove key type for pubkey str
removeField(&dataBlob)
} //remove the 2 nones fro encryption and kdf
removeField(&dataBlob) //remove the empty Data()
let pubkeyData = Data((dataBlob as NSData)[0..<Int((dataBlob as NSData)[3])])
removeField(&dataBlob) //remove pubkey field
return Data() dataBlob.removeFirst(4) //remove lenght header for the privkey data blob
guard (dataBlob as NSData).subdata(with: NSRange(0...3)) == (dataBlob as NSData).subdata(with: NSRange(4...7)) else {
fatalError("checkints are different")
}
dataBlob.removeFirst(8) //remove checkints
removeField(&dataBlob) // remove pubkey type header
removeField(&dataBlob) // remove pubkey
let privatekeyData = Data((dataBlob as NSData)[0..<32])
dataBlob.removeFirst(4 + 32) //remove privkey
guard (dataBlob as NSData).subdata(with: NSRange(0...31)) == pubkeyData else {
fatalError("pubkeys dont match")
}
dataBlob.removeFirst(32) //remove pubkey
let comment = String(data: Data((dataBlob as NSData)[0..<Int((dataBlob as NSData)[3])]), encoding: .utf8)!
return Keypair(type: .ecdsa, name: comment, publicKey: pubkeyData, privateKey: privatekeyData)
} }
func makeSSHPrivkey(pub: Data, priv: Data, comment: String) -> Data { static func makeSSHPrivkey(pub: Data, priv: Data, comment: String) -> Data {
var content: Data = Data() var content: Data = Data()
var blob: Data = Data() var blob: Data = Data()
@@ -167,27 +188,26 @@ class KeyManager: ObservableObject {
return SecKeyCopyPublicKey(privateKey) return SecKeyCopyPublicKey(privateKey)
} }
func encode(str: String) -> Data { static func encode(str: String) -> Data {
guard let utf8 = str.data(using: .utf8) else { guard let utf8 = str.data(using: .utf8) else {
return Data() return Data()
} }
return encode(int: utf8.count) + utf8 return encode(int: utf8.count) + utf8
} }
func encode(data: Data) -> Data { static func encode(data: Data) -> Data {
return encode(int: data.count) + data return encode(int: data.count) + data
} }
func encode(int: Int) -> Data { static func encode(int: Int) -> Data {
var bigEndian = UInt32(int).bigEndian var bigEndian = UInt32(int).bigEndian
return Data(bytes: &bigEndian, count: 4) // 32bits / 8 bitsperbyte return Data(bytes: &bigEndian, count: 4) // 32bits / 8 bitsperbyte
} }
func removeField(_ data: inout Data) { static func removeField(_ data: inout Data) {
guard data.count >= 4 else { return } guard data.count >= 4 else { return }
let lengthBytes = data.subdata(in: 0..<4) let length = (data as NSData)[3]
let length = lengthBytes.withUnsafeBytes { $0.load(as: UInt32.self).bigEndian }
guard data.count >= 4 + Int(length) else { return } guard data.count >= 4 + Int(length) else { return }
data.removeFirst(4) data.removeFirst(4)

View File

@@ -10,13 +10,13 @@ import Foundation
enum KeyType: Codable, Equatable, Hashable, CustomStringConvertible { enum KeyType: Codable, Equatable, Hashable, CustomStringConvertible {
var description: String { var description: String {
switch self { switch self {
case .ecdsa(let inSEP): case .ecdsa:
return inSEP ? "ECDSA Secure Enclave" : "ECDSA" return "ECDSA"
case .rsa(let bits): case .rsa:
return "RSA \(bits)" return "RSA"
} }
} }
case ecdsa(inSEP: Bool) case ecdsa
case rsa(Int) case rsa
} }

View File

@@ -11,38 +11,49 @@ protocol KeypairProtocol: Identifiable, Equatable, Codable, Hashable {
var id: UUID { get } var id: UUID { get }
var type: KeyType { get set } var type: KeyType { get set }
var name: String { get set } var name: String { get set }
var publicKey: Data? { get set } var publicKey: Data { get set }
var privateKey: Data? { get set } var privateKey: Data { get set }
var passphrase: String { get set } var passphrase: String { get set }
var openSshPubkey: String { get }
var openSshPrivkey: String { get }
} }
struct Keypair: KeypairProtocol { struct Keypair: KeypairProtocol {
var id = UUID() var id = UUID()
var type: KeyType = .rsa(4096) var type: KeyType = .ecdsa
var name: String = "" var name: String = ""
var publicKey: Data? var publicKey: Data
var privateKey: Data? var privateKey: Data
var passphrase: String = "" var passphrase: String = ""
var openSshPubkey: String {
String(data: KeyManager.makeSSHPubkey(pub: publicKey, comment: name), encoding: .utf8) ?? "OpenSSH key format error"
}
var openSshPrivkey: String {
String(data: KeyManager.makeSSHPrivkey(pub: publicKey, priv: privateKey, comment: name), encoding: .utf8) ?? "OpenSSH key format error"
}
init( init(
id: UUID = UUID(), id: UUID = UUID(),
type: KeyType, type: KeyType,
name: String, name: String,
publicKey: String, publicKey: Data,
privateKey: String, privateKey: Data,
passphrase: String = "" passphrase: String = ""
) { ) {
self.id = id self.id = id
self.type = type self.type = type
self.name = name self.name = name
self.publicKey = publicKey.data(using: .utf8) self.publicKey = publicKey
self.privateKey = privateKey.data(using: .utf8) self.privateKey = privateKey
self.passphrase = passphrase self.passphrase = passphrase
} }
static func ==(lhs: Keypair, rhs: Keypair) -> Bool { static func ==(lhs: Keypair, rhs: Keypair) -> Bool {
if lhs.publicKey?.base64EncodedString() == rhs.publicKey?.base64EncodedString() if lhs.publicKey.base64EncodedString() == rhs.publicKey.base64EncodedString()
&& lhs.privateKey?.base64EncodedString() == rhs.privateKey?.base64EncodedString() { && lhs.privateKey.base64EncodedString() == rhs.privateKey.base64EncodedString() {
return true return true
} else { } else {
return false return false

View File

@@ -85,9 +85,9 @@ struct KeyDetailView: View {
KeyDetailView( KeyDetailView(
hostsManager: HostsManager(), hostsManager: HostsManager(),
keypair: Keypair( keypair: Keypair(
type: .rsa(4096), type: .rsa,
name: "previewKey", name: "previewKey",
publicKey: "ssh-ed25519 dskjhfajkdhfjkdashfgjkhadsjkgfbhalkjhfjkhdask user@mac", publicKey: "ssh-ed25519 dskjhfajkdhfjkdashfgjkhadsjkgfbhalkjhfjkhdask user@mac".data(using: .utf8)!,
privateKey: """ privateKey: """
-----BEGIN OPENSSH PRIVATE KEY----- -----BEGIN OPENSSH PRIVATE KEY-----
Lorem ipsum dolor sit amet, consectetur adipiscing elit Lorem ipsum dolor sit amet, consectetur adipiscing elit
@@ -95,7 +95,7 @@ struct KeyDetailView: View {
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat nisi ut aliquip ex ea commodo consequat
-----END OPENSSH PRIVATE KEY----- -----END OPENSSH PRIVATE KEY-----
""" """.data(using: .utf8)!
) )
) )
} }

View File

@@ -22,9 +22,7 @@ struct KeyManagerView: View {
NavigationLink { NavigationLink {
KeyDetailView(hostsManager: hostsManager, keypair: keypair) KeyDetailView(hostsManager: hostsManager, keypair: keypair)
} label: { } label: {
if let publicKey = keypair.publicKey { Text(String(data: keypair.publicKey, encoding: .utf8) ?? "nil")
Text(String(data: publicKey, encoding: .utf8) ?? "nil")
}
} }
} }
} }