mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 13:26:16 +00:00
162 lines
4.2 KiB
Swift
162 lines
4.2 KiB
Swift
//
|
|
// KeyManager.swift
|
|
// ShhShell
|
|
//
|
|
// Created by neon443 on 20/06/2025.
|
|
//
|
|
|
|
import Foundation
|
|
import CryptoKit
|
|
import Security
|
|
|
|
struct Key: Identifiable, Hashable {
|
|
var id = UUID()
|
|
var privateKey: SecKey
|
|
var publicKey: SecKey {
|
|
SecKeyCopyPublicKey(privateKey)!
|
|
}
|
|
}
|
|
|
|
class KeyManager: ObservableObject {
|
|
private let userdefaults = NSUbiquitousKeyValueStore.default
|
|
|
|
var tags: [String] = []
|
|
|
|
init() {
|
|
let key = Curve25519.Signing.PrivateKey()
|
|
let privatekeyData = key.rawRepresentation
|
|
let publickeyData = key.publicKey.rawRepresentation
|
|
print(publickeyData.base64EncodedString())
|
|
let pubpem = makeSSHPubkey(pub: publickeyData, comment: "neon443@m")
|
|
let privpem = makeSSHPrivkey(pub: publickeyData, priv: privatekeyData, comment: "neon443@m")
|
|
print(String(data: pubpem, encoding: .utf8)!)
|
|
print()
|
|
print(String(data: privpem, encoding: .utf8)!)
|
|
print()
|
|
|
|
print(importSSHPubkey(pub: String(data: pubpem, encoding: .utf8)!).base64EncodedString())
|
|
}
|
|
|
|
func loadTags() {
|
|
userdefaults.synchronize()
|
|
let decoder = JSONDecoder()
|
|
guard let data = userdefaults.data(forKey: "keyTags") else { return }
|
|
guard let decoded = try? decoder.decode([String].self, from: data) else { return }
|
|
tags = decoded
|
|
}
|
|
|
|
func saveTags() {
|
|
let encoder = JSONEncoder()
|
|
guard let encoded = try? encoder.encode(tags) else { return }
|
|
userdefaults.set(encoded, forKey: "keyTags")
|
|
userdefaults.synchronize()
|
|
}
|
|
|
|
//MARK: generate keys
|
|
func generateKey(type: KeyType, SEPKeyTag: String, comment: String, passphrase: String) -> Keypair? {
|
|
switch type {
|
|
case .ecdsa(let inSEP):
|
|
fatalError("unimplemented")
|
|
case .rsa(let rsaSize):
|
|
fatalError("unimplemented")
|
|
}
|
|
}
|
|
|
|
func importSSHPubkey(pub: String) -> Data {
|
|
let split = pub.split(separator: " ")
|
|
guard split.count == 3 else { return Data() }
|
|
|
|
var pubdata = Data(base64Encoded: String(split[1]))!
|
|
while pubdata.count != 36 {
|
|
let lengthOfField = Int(pubdata[3])
|
|
pubdata.removeFirst(4 + lengthOfField)
|
|
}
|
|
pubdata.removeFirst(4)
|
|
return pubdata
|
|
}
|
|
|
|
func makeSSHPubkey(pub: Data, comment: String) -> Data {
|
|
let header = "ssh-ed25519"
|
|
var keyBlob: Data = Data()
|
|
//key type bit
|
|
keyBlob += encode(str: header)
|
|
//base64 blob bit
|
|
keyBlob += encode(data: pub)
|
|
|
|
let b64key = keyBlob.base64EncodedString()
|
|
let pubkeyline = "\(header) \(b64key) \(comment)\n"
|
|
return Data(pubkeyline.utf8)
|
|
}
|
|
|
|
func makeSSHPrivkey(pub: Data, priv: Data, comment: String) -> Data {
|
|
var content: Data = Data()
|
|
var blob: Data = Data()
|
|
|
|
let header = "-----BEGIN OPENSSH PRIVATE KEY-----\n"
|
|
let footer = "\n-----END OPENSSH PRIVATE KEY-----\n"
|
|
|
|
//add header
|
|
content += header.data(using: .utf8)!
|
|
|
|
//add the magik prefix
|
|
blob += Data("openssh-key-v1\0".utf8)
|
|
//add encryption info
|
|
blob += encode(str: "none")
|
|
//add kdf info
|
|
blob += encode(str: "none") + encode(data: Data())
|
|
//add key count
|
|
blob += encode(int: 1)
|
|
|
|
//add atual key
|
|
var pubkeyBlob = Data()
|
|
let keyType = "ssh-ed25519"
|
|
pubkeyBlob += encode(str: keyType)
|
|
pubkeyBlob += encode(data: pub)
|
|
blob += encode(data: pubkeyBlob)
|
|
|
|
//priv
|
|
var privBlob = Data()
|
|
let checkint = UInt32.random(in: UInt32.min...UInt32.max)
|
|
privBlob.append(contentsOf: withUnsafeBytes(of: checkint.bigEndian, Array.init))
|
|
privBlob.append(contentsOf: withUnsafeBytes(of: checkint.bigEndian, Array.init))
|
|
privBlob += encode(str: keyType)
|
|
privBlob += encode(data: pub)
|
|
privBlob += encode(data: priv + pub)
|
|
privBlob += encode(str: comment)
|
|
|
|
let padLegth = (8 - (privBlob.count % 8)) % 8
|
|
if padLegth > 0 {
|
|
privBlob.append(contentsOf: (1...padLegth).map { UInt8($0) } )
|
|
}
|
|
|
|
blob += encode(data: privBlob)
|
|
|
|
content += blob.base64EncodedData(options: .lineLength64Characters)
|
|
|
|
//footer
|
|
content += footer.data(using: .utf8)!
|
|
|
|
return content
|
|
}
|
|
|
|
func getPubkey(_ privateKey: SecKey) -> SecKey? {
|
|
return SecKeyCopyPublicKey(privateKey)
|
|
}
|
|
|
|
func encode(str: String) -> Data {
|
|
guard let utf8 = str.data(using: .utf8) else {
|
|
return Data()
|
|
}
|
|
return encode(int: utf8.count) + utf8
|
|
}
|
|
|
|
func encode(data: Data) -> Data {
|
|
return encode(int: data.count) + data
|
|
}
|
|
|
|
func encode(int: Int) -> Data {
|
|
var bigEndian = UInt32(int).bigEndian
|
|
return Data(bytes: &bigEndian, count: 4) // 32bits / 8 bitsperbyte
|
|
}
|
|
}
|