mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 13:26:16 +00:00
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
This commit is contained in:
@@ -48,6 +48,7 @@
|
|||||||
A96C6B002E0C45FE00F377FE /* KeyDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A96C6AFF2E0C45FE00F377FE /* KeyDetailView.swift */; };
|
A96C6B002E0C45FE00F377FE /* KeyDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A96C6AFF2E0C45FE00F377FE /* KeyDetailView.swift */; };
|
||||||
A96C6B022E0C49E800F377FE /* CenteredLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A96C6B012E0C49E800F377FE /* CenteredLabel.swift */; };
|
A96C6B022E0C49E800F377FE /* CenteredLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A96C6B012E0C49E800F377FE /* CenteredLabel.swift */; };
|
||||||
A96C90A12E12B87A00724253 /* TextBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = A96C90A02E12B87900724253 /* TextBox.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 */; };
|
A98554552E05535F009051BD /* KeyManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98554542E05535F009051BD /* KeyManagerView.swift */; };
|
||||||
A98554592E0553AA009051BD /* KeyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98554582E0553AA009051BD /* KeyManager.swift */; };
|
A98554592E0553AA009051BD /* KeyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98554582E0553AA009051BD /* KeyManager.swift */; };
|
||||||
A985545D2E055D4D009051BD /* ConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A985545C2E055D4D009051BD /* ConnectionView.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 = "<group>"; };
|
A96C6AFF2E0C45FE00F377FE /* KeyDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyDetailView.swift; sourceTree = "<group>"; };
|
||||||
A96C6B012E0C49E800F377FE /* CenteredLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CenteredLabel.swift; sourceTree = "<group>"; };
|
A96C6B012E0C49E800F377FE /* CenteredLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CenteredLabel.swift; sourceTree = "<group>"; };
|
||||||
A96C90A02E12B87900724253 /* TextBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBox.swift; sourceTree = "<group>"; };
|
A96C90A02E12B87900724253 /* TextBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBox.swift; sourceTree = "<group>"; };
|
||||||
|
A96C90A22E12D53900724253 /* KeyType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyType.swift; sourceTree = "<group>"; };
|
||||||
A98554542E05535F009051BD /* KeyManagerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyManagerView.swift; sourceTree = "<group>"; };
|
A98554542E05535F009051BD /* KeyManagerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyManagerView.swift; sourceTree = "<group>"; };
|
||||||
A98554582E0553AA009051BD /* KeyManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyManager.swift; sourceTree = "<group>"; };
|
A98554582E0553AA009051BD /* KeyManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyManager.swift; sourceTree = "<group>"; };
|
||||||
A985545C2E055D4D009051BD /* ConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionView.swift; sourceTree = "<group>"; };
|
A985545C2E055D4D009051BD /* ConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionView.swift; sourceTree = "<group>"; };
|
||||||
@@ -374,6 +376,7 @@
|
|||||||
A98554572E055398009051BD /* Keys */ = {
|
A98554572E055398009051BD /* Keys */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
A96C90A22E12D53900724253 /* KeyType.swift */,
|
||||||
A98554582E0553AA009051BD /* KeyManager.swift */,
|
A98554582E0553AA009051BD /* KeyManager.swift */,
|
||||||
A985545E2E056EDD009051BD /* KeychainLayer.swift */,
|
A985545E2E056EDD009051BD /* KeychainLayer.swift */,
|
||||||
A96C6AFD2E0C43B600F377FE /* Keypair.swift */,
|
A96C6AFD2E0C43B600F377FE /* Keypair.swift */,
|
||||||
@@ -587,6 +590,7 @@
|
|||||||
A9DA97712E0D30ED00142DDC /* HostSymbol.swift in Sources */,
|
A9DA97712E0D30ED00142DDC /* HostSymbol.swift in Sources */,
|
||||||
A96C90A12E12B87A00724253 /* TextBox.swift in Sources */,
|
A96C90A12E12B87A00724253 /* TextBox.swift in Sources */,
|
||||||
A96BE6A82E116E2B00C0FEE9 /* SessionsListView.swift in Sources */,
|
A96BE6A82E116E2B00C0FEE9 /* SessionsListView.swift in Sources */,
|
||||||
|
A96C90A32E12D53B00724253 /* KeyType.swift in Sources */,
|
||||||
A98554612E058433009051BD /* HostsManager.swift in Sources */,
|
A98554612E058433009051BD /* HostsManager.swift in Sources */,
|
||||||
A985545D2E055D4D009051BD /* ConnectionView.swift in Sources */,
|
A985545D2E055D4D009051BD /* ConnectionView.swift in Sources */,
|
||||||
A98554592E0553AA009051BD /* KeyManager.swift in Sources */,
|
A98554592E0553AA009051BD /* KeyManager.swift in Sources */,
|
||||||
|
|||||||
@@ -185,8 +185,11 @@ class HostsManager: ObservableObject, @unchecked Sendable {
|
|||||||
func getKeys() -> [Keypair] {
|
func getKeys() -> [Keypair] {
|
||||||
var result: [Keypair] = []
|
var result: [Keypair] = []
|
||||||
for host in hosts {
|
for host in hosts {
|
||||||
guard host.privateKey != nil && host.publicKey != nil else { continue }
|
guard let publicKey = host.publicKey else { continue }
|
||||||
let keypair = Keypair(publicKey: host.publicKey, privateKey: host.privateKey)
|
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) {
|
if !result.contains(keypair) {
|
||||||
result.append(keypair)
|
result.append(keypair)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,22 @@ class KeyManager: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//MARK: generate keys
|
//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() {
|
func generateEd25519() {
|
||||||
let privateKey = Curve25519.Signing.PrivateKey()
|
let privateKey = Curve25519.Signing.PrivateKey()
|
||||||
let publicKeyData = privateKey.publicKey
|
let publicKeyData = privateKey.publicKey
|
||||||
@@ -45,13 +61,13 @@ class KeyManager: ObservableObject {
|
|||||||
print(publicKeyData.rawRepresentation)
|
print(publicKeyData.rawRepresentation)
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateRSA() throws {
|
func generateRSA(size: Int) throws -> (priv: Data, pub: Data) {
|
||||||
let type = kSecAttrKeyTypeRSA
|
let type = kSecAttrKeyTypeRSA
|
||||||
let label = Date().ISO8601Format()
|
let label = Date().ISO8601Format()
|
||||||
let tag = label.data(using: .utf8)!
|
let tag = label.data(using: .utf8)!
|
||||||
let attributes: [String: Any] =
|
let attributes: [String: Any] =
|
||||||
[kSecAttrKeyType as String: type,
|
[kSecAttrKeyType as String: type,
|
||||||
kSecAttrKeySizeInBits as String: 4096,
|
kSecAttrKeySizeInBits as String: size,
|
||||||
kSecPrivateKeyAttrs as String:
|
kSecPrivateKeyAttrs as String:
|
||||||
[kSecAttrIsPermanent as String: true,
|
[kSecAttrIsPermanent as String: true,
|
||||||
kSecAttrApplicationTag as String: tag]
|
kSecAttrApplicationTag as String: tag]
|
||||||
@@ -61,15 +77,23 @@ class KeyManager: ObservableObject {
|
|||||||
guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
|
guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
|
||||||
throw error!.takeRetainedValue() as Error
|
throw error!.takeRetainedValue() as Error
|
||||||
}
|
}
|
||||||
|
guard let pubkey = getPubkey(privateKey) else {
|
||||||
|
throw error!.takeRetainedValue() as Error
|
||||||
|
}
|
||||||
print(privateKey)
|
print(privateKey)
|
||||||
|
|
||||||
print(SecKeyCopyPublicKey(privateKey) ?? "")
|
|
||||||
print(SecKeyCopyExternalRepresentation(privateKey, nil) as Any)
|
|
||||||
// do {
|
// do {
|
||||||
// try storeKey(privateKey, label: label)
|
// try storeKey(privateKey, label: label)
|
||||||
// } catch {
|
// } catch {
|
||||||
// print(error.localizedDescription)
|
// 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? {
|
func getPubkey(_ privateKey: SecKey) -> SecKey? {
|
||||||
|
|||||||
22
ShhShell/Keys/KeyType.swift
Normal file
22
ShhShell/Keys/KeyType.swift
Normal file
@@ -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)
|
||||||
|
}
|
||||||
@@ -8,21 +8,36 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
protocol KeypairProtocol: Identifiable, Equatable, Codable, Hashable {
|
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 publicKey: Data? { get set }
|
||||||
var privateKey: Data? { get set }
|
var privateKey: Data? { get set }
|
||||||
|
var passphrase: String { get set }
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Keypair: KeypairProtocol {
|
struct Keypair: KeypairProtocol {
|
||||||
var id = UUID()
|
var id = UUID()
|
||||||
|
var type: KeyType = .rsa(4096)
|
||||||
|
var name: String = ""
|
||||||
var publicKey: Data?
|
var publicKey: Data?
|
||||||
var privateKey: Data?
|
var privateKey: Data?
|
||||||
|
var passphrase: String = ""
|
||||||
|
|
||||||
init(
|
init(
|
||||||
publicKey: Data?,
|
id: UUID = UUID(),
|
||||||
privateKey: Data?
|
type: KeyType,
|
||||||
|
name: String,
|
||||||
|
publicKey: String,
|
||||||
|
privateKey: String,
|
||||||
|
passphrase: String = ""
|
||||||
) {
|
) {
|
||||||
self.publicKey = publicKey
|
self.id = id
|
||||||
self.privateKey = privateKey
|
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 {
|
static func ==(lhs: Keypair, rhs: Keypair) -> Bool {
|
||||||
|
|||||||
@@ -184,9 +184,9 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
|
|
||||||
func ring() {
|
func ring() {
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
withAnimation { self.bell = true }
|
withAnimation(.easeIn(duration: 0.1)) { self.bell = true }
|
||||||
try? await Task.sleep(nanoseconds: 250_000_000) // 250ms
|
try? await Task.sleep(nanoseconds: 300_000_000) // 250ms
|
||||||
withAnimation { self.bell = false }
|
withAnimation(.easeOut(duration: 0.1)) { self.bell = false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,9 @@ struct KeyDetailView: View {
|
|||||||
KeyDetailView(
|
KeyDetailView(
|
||||||
hostsManager: HostsManager(),
|
hostsManager: HostsManager(),
|
||||||
keypair: Keypair(
|
keypair: Keypair(
|
||||||
publicKey: "ssh-ed25519 dskjhfajkdhfjkdashfgjkhadsjkgfbhalkjhfjkhdask user@mac".data(using: .utf8),
|
type: .rsa(4096),
|
||||||
|
name: "previewKey",
|
||||||
|
publicKey: "ssh-ed25519 dskjhfajkdhfjkdashfgjkhadsjkgfbhalkjhfjkhdask user@mac",
|
||||||
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
|
||||||
@@ -94,7 +96,6 @@ struct KeyDetailView: View {
|
|||||||
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)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,15 +29,8 @@ struct KeyManagerView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Button("ed25519") {
|
Button("genereate rsa") {
|
||||||
keyManager.generateEd25519()
|
keyManager.generateKey(type: .rsa(4096), SEPKeyTag: "", comment: "jaklsd", passphrase: "")
|
||||||
}
|
|
||||||
Button("rsa") {
|
|
||||||
do {
|
|
||||||
try keyManager.generateRSA()
|
|
||||||
} catch {
|
|
||||||
print(error.localizedDescription)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.scrollContentBackground(.hidden)
|
.scrollContentBackground(.hidden)
|
||||||
|
|||||||
Reference in New Issue
Block a user