From 80b83644b4867502cff10ef81e7019020ec91315 Mon Sep 17 00:00:00 2001 From: neon443 <69979447+neon443@users.noreply.github.com> Date: Mon, 30 Jun 2025 16:28:58 +0100 Subject: [PATCH] updated keypair data structure to have an name, passphrase and type added generateKy to generate a key, currently only rsa update generateRSA to return the Data for pub and priv, and take a custom size bell animation better, slightly longer in total and easeinout added new generate button hardcoded to a rsa 4096 added keytype to define key types (duh) update getKeys to use the new keypair structure --- ShhShell.xcodeproj/project.pbxproj | 4 +++ ShhShell/Host/HostsManager.swift | 7 ++++-- ShhShell/Keys/KeyManager.swift | 32 +++++++++++++++++++++--- ShhShell/Keys/KeyType.swift | 22 ++++++++++++++++ ShhShell/Keys/Keypair.swift | 23 ++++++++++++++--- ShhShell/SSH/SSHHandler.swift | 6 ++--- ShhShell/Views/Keys/KeyDetailView.swift | 5 ++-- ShhShell/Views/Keys/KeyManagerView.swift | 11 ++------ 8 files changed, 86 insertions(+), 24 deletions(-) create mode 100644 ShhShell/Keys/KeyType.swift diff --git a/ShhShell.xcodeproj/project.pbxproj b/ShhShell.xcodeproj/project.pbxproj index fa7e8e0..7049005 100644 --- a/ShhShell.xcodeproj/project.pbxproj +++ b/ShhShell.xcodeproj/project.pbxproj @@ -48,6 +48,7 @@ A96C6B002E0C45FE00F377FE /* KeyDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A96C6AFF2E0C45FE00F377FE /* KeyDetailView.swift */; }; A96C6B022E0C49E800F377FE /* CenteredLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A96C6B012E0C49E800F377FE /* CenteredLabel.swift */; }; A96C90A12E12B87A00724253 /* TextBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = A96C90A02E12B87900724253 /* TextBox.swift */; }; + A96C90A32E12D53B00724253 /* KeyType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A96C90A22E12D53900724253 /* KeyType.swift */; }; A98554552E05535F009051BD /* KeyManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98554542E05535F009051BD /* KeyManagerView.swift */; }; A98554592E0553AA009051BD /* KeyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98554582E0553AA009051BD /* KeyManager.swift */; }; A985545D2E055D4D009051BD /* ConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A985545C2E055D4D009051BD /* ConnectionView.swift */; }; @@ -145,6 +146,7 @@ A96C6AFF2E0C45FE00F377FE /* KeyDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyDetailView.swift; sourceTree = ""; }; A96C6B012E0C49E800F377FE /* CenteredLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CenteredLabel.swift; sourceTree = ""; }; A96C90A02E12B87900724253 /* TextBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBox.swift; sourceTree = ""; }; + A96C90A22E12D53900724253 /* KeyType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyType.swift; sourceTree = ""; }; A98554542E05535F009051BD /* KeyManagerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyManagerView.swift; sourceTree = ""; }; A98554582E0553AA009051BD /* KeyManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyManager.swift; sourceTree = ""; }; A985545C2E055D4D009051BD /* ConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionView.swift; sourceTree = ""; }; @@ -374,6 +376,7 @@ A98554572E055398009051BD /* Keys */ = { isa = PBXGroup; children = ( + A96C90A22E12D53900724253 /* KeyType.swift */, A98554582E0553AA009051BD /* KeyManager.swift */, A985545E2E056EDD009051BD /* KeychainLayer.swift */, A96C6AFD2E0C43B600F377FE /* Keypair.swift */, @@ -587,6 +590,7 @@ A9DA97712E0D30ED00142DDC /* HostSymbol.swift in Sources */, A96C90A12E12B87A00724253 /* TextBox.swift in Sources */, A96BE6A82E116E2B00C0FEE9 /* SessionsListView.swift in Sources */, + A96C90A32E12D53B00724253 /* KeyType.swift in Sources */, A98554612E058433009051BD /* HostsManager.swift in Sources */, A985545D2E055D4D009051BD /* ConnectionView.swift in Sources */, A98554592E0553AA009051BD /* KeyManager.swift in Sources */, diff --git a/ShhShell/Host/HostsManager.swift b/ShhShell/Host/HostsManager.swift index 4a69887..d1e4398 100644 --- a/ShhShell/Host/HostsManager.swift +++ b/ShhShell/Host/HostsManager.swift @@ -185,8 +185,11 @@ class HostsManager: ObservableObject, @unchecked Sendable { func getKeys() -> [Keypair] { var result: [Keypair] = [] for host in hosts { - guard host.privateKey != nil && host.publicKey != nil else { continue } - let keypair = Keypair(publicKey: host.publicKey, privateKey: host.privateKey) + guard let publicKey = host.publicKey else { continue } + guard let privateKey = host.privateKey else { continue } + guard let privKeyStr = String(data: privateKey, encoding: .utf8), + 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) { result.append(keypair) } diff --git a/ShhShell/Keys/KeyManager.swift b/ShhShell/Keys/KeyManager.swift index 10bbc65..86a0e9f 100644 --- a/ShhShell/Keys/KeyManager.swift +++ b/ShhShell/Keys/KeyManager.swift @@ -38,6 +38,22 @@ class KeyManager: ObservableObject { } //MARK: generate keys + func generateKey(type: KeyType, SEPKeyTag: String, comment: String, passphrase: String) -> Keypair? { + switch type { + case .ecdsa(let inSEP): + fatalError() + case .rsa(let rsaSize): + guard let keyData = try? generateRSA(size: rsaSize) else { return nil } + return Keypair( + type: .rsa(rsaSize), + name: comment, + publicKey: String(data: keyData.pub, encoding: .utf8) ?? "", + privateKey: String(data: keyData.priv, encoding: .utf8) ?? "", + passphrase: "" + ) + } + } + func generateEd25519() { let privateKey = Curve25519.Signing.PrivateKey() let publicKeyData = privateKey.publicKey @@ -45,13 +61,13 @@ class KeyManager: ObservableObject { print(publicKeyData.rawRepresentation) } - func generateRSA() throws { + func generateRSA(size: Int) throws -> (priv: Data, pub: Data) { let type = kSecAttrKeyTypeRSA let label = Date().ISO8601Format() let tag = label.data(using: .utf8)! let attributes: [String: Any] = [kSecAttrKeyType as String: type, - kSecAttrKeySizeInBits as String: 4096, + kSecAttrKeySizeInBits as String: size, kSecPrivateKeyAttrs as String: [kSecAttrIsPermanent as String: true, kSecAttrApplicationTag as String: tag] @@ -61,15 +77,23 @@ class KeyManager: ObservableObject { guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else { throw error!.takeRetainedValue() as Error } + guard let pubkey = getPubkey(privateKey) else { + throw error!.takeRetainedValue() as Error + } print(privateKey) - print(SecKeyCopyPublicKey(privateKey) ?? "") - print(SecKeyCopyExternalRepresentation(privateKey, nil) as Any) // do { // try storeKey(privateKey, label: label) // } catch { // print(error.localizedDescription) // } + guard let privKeyData = SecKeyCopyExternalRepresentation(privateKey, &error) else { + throw error!.takeRetainedValue() as Error + } + guard let pubKeyData = SecKeyCopyExternalRepresentation(pubkey, &error) else { + throw error!.takeRetainedValue() as Error + } + return (privKeyData as Data, pubKeyData as Data) } func getPubkey(_ privateKey: SecKey) -> SecKey? { diff --git a/ShhShell/Keys/KeyType.swift b/ShhShell/Keys/KeyType.swift new file mode 100644 index 0000000..ef0b27c --- /dev/null +++ b/ShhShell/Keys/KeyType.swift @@ -0,0 +1,22 @@ +// +// KeyType.swift +// ShhShell +// +// Created by neon443 on 30/06/2025. +// + +import Foundation + +enum KeyType: Codable, Equatable, Hashable, CustomStringConvertible { + var description: String { + switch self { + case .ecdsa(let inSEP): + return inSEP ? "ECDSA Secure Enclave" : "ECDSA" + case .rsa(let bits): + return "RSA \(bits)" + } + } + + case ecdsa(inSEP: Bool) + case rsa(Int) +} diff --git a/ShhShell/Keys/Keypair.swift b/ShhShell/Keys/Keypair.swift index eca81ba..d109a17 100644 --- a/ShhShell/Keys/Keypair.swift +++ b/ShhShell/Keys/Keypair.swift @@ -8,21 +8,36 @@ import Foundation protocol KeypairProtocol: Identifiable, Equatable, Codable, Hashable { + var id: UUID { get } + var type: KeyType { get set } + var name: String { get set } var publicKey: Data? { get set } var privateKey: Data? { get set } + var passphrase: String { get set } } struct Keypair: KeypairProtocol { var id = UUID() + var type: KeyType = .rsa(4096) + var name: String = "" var publicKey: Data? var privateKey: Data? + var passphrase: String = "" init( - publicKey: Data?, - privateKey: Data? + id: UUID = UUID(), + type: KeyType, + name: String, + publicKey: String, + privateKey: String, + passphrase: String = "" ) { - self.publicKey = publicKey - self.privateKey = privateKey + self.id = id + self.type = type + self.name = name + self.publicKey = publicKey.data(using: .utf8) + self.privateKey = privateKey.data(using: .utf8) + self.passphrase = passphrase } static func ==(lhs: Keypair, rhs: Keypair) -> Bool { diff --git a/ShhShell/SSH/SSHHandler.swift b/ShhShell/SSH/SSHHandler.swift index 08d79df..b3537d6 100644 --- a/ShhShell/SSH/SSHHandler.swift +++ b/ShhShell/SSH/SSHHandler.swift @@ -184,9 +184,9 @@ class SSHHandler: @unchecked Sendable, ObservableObject { func ring() { Task { @MainActor in - withAnimation { self.bell = true } - try? await Task.sleep(nanoseconds: 250_000_000) // 250ms - withAnimation { self.bell = false } + withAnimation(.easeIn(duration: 0.1)) { self.bell = true } + try? await Task.sleep(nanoseconds: 300_000_000) // 250ms + withAnimation(.easeOut(duration: 0.1)) { self.bell = false } } } diff --git a/ShhShell/Views/Keys/KeyDetailView.swift b/ShhShell/Views/Keys/KeyDetailView.swift index 81669bc..ba46b9c 100644 --- a/ShhShell/Views/Keys/KeyDetailView.swift +++ b/ShhShell/Views/Keys/KeyDetailView.swift @@ -85,7 +85,9 @@ struct KeyDetailView: View { KeyDetailView( hostsManager: HostsManager(), keypair: Keypair( - publicKey: "ssh-ed25519 dskjhfajkdhfjkdashfgjkhadsjkgfbhalkjhfjkhdask user@mac".data(using: .utf8), + type: .rsa(4096), + name: "previewKey", + publicKey: "ssh-ed25519 dskjhfajkdhfjkdashfgjkhadsjkgfbhalkjhfjkhdask user@mac", privateKey: """ -----BEGIN OPENSSH PRIVATE KEY----- Lorem ipsum dolor sit amet, consectetur adipiscing elit @@ -94,7 +96,6 @@ struct KeyDetailView: View { nisi ut aliquip ex ea commodo consequat -----END OPENSSH PRIVATE KEY----- """ - .data(using: .utf8) ) ) } diff --git a/ShhShell/Views/Keys/KeyManagerView.swift b/ShhShell/Views/Keys/KeyManagerView.swift index e8cf15d..3a91230 100644 --- a/ShhShell/Views/Keys/KeyManagerView.swift +++ b/ShhShell/Views/Keys/KeyManagerView.swift @@ -29,15 +29,8 @@ struct KeyManagerView: View { } } - Button("ed25519") { - keyManager.generateEd25519() - } - Button("rsa") { - do { - try keyManager.generateRSA() - } catch { - print(error.localizedDescription) - } + Button("genereate rsa") { + keyManager.generateKey(type: .rsa(4096), SEPKeyTag: "", comment: "jaklsd", passphrase: "") } } .scrollContentBackground(.hidden)