mirror of
https://github.com/maxgoedjen/secretive.git
synced 2026-04-09 18:57:22 +02:00
86 lines
3.0 KiB
Swift
86 lines
3.0 KiB
Swift
import Foundation
|
|
import CryptoKit
|
|
import SecretKit
|
|
|
|
/// Generates OpenSSH representations of Secrets.
|
|
public struct OpenSSHSignatureWriter: Sendable {
|
|
|
|
/// Initializes the writer.
|
|
public init() {
|
|
}
|
|
|
|
/// Generates an OpenSSH data payload identifying the secret.
|
|
/// - Returns: OpenSSH data payload identifying the secret.
|
|
public func data<SecretType: Secret>(secret: SecretType, signature: Data) -> Data {
|
|
switch secret.keyType.algorithm {
|
|
case .ecdsa:
|
|
// https://datatracker.ietf.org/doc/html/rfc5656#section-3.1
|
|
ecdsaSignature(signature, keyType: secret.keyType)
|
|
case .mldsa:
|
|
// https://datatracker.ietf.org/doc/html/draft-sfluhrer-ssh-mldsa-05
|
|
mldsaSignature(signature, keyType: secret.keyType)
|
|
case .rsa:
|
|
// https://datatracker.ietf.org/doc/html/rfc4253#section-6.6
|
|
rsaSignature(signature)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
extension OpenSSHSignatureWriter {
|
|
|
|
/// Converts a fixed-width big-endian integer (e.g. r/s from CryptoKit rawRepresentation) into an SSH mpint.
|
|
/// Strips unnecessary leading zeros and prefixes `0x00` if needed to keep the value positive.
|
|
private func mpint(fromFixedWidthPositiveBytes bytes: Data) -> Data {
|
|
// mpint zero is encoded as a string with zero bytes of data.
|
|
guard let firstNonZeroIndex = bytes.firstIndex(where: { $0 != 0x00 }) else {
|
|
return Data()
|
|
}
|
|
|
|
let trimmed = Data(bytes[firstNonZeroIndex...])
|
|
|
|
if let first = trimmed.first, first >= 0x80 {
|
|
var prefixed = Data([0x00])
|
|
prefixed.append(trimmed)
|
|
return prefixed
|
|
}
|
|
return trimmed
|
|
}
|
|
|
|
func ecdsaSignature(_ rawRepresentation: Data, keyType: KeyType) -> Data {
|
|
let rawLength = rawRepresentation.count/2
|
|
let r = mpint(fromFixedWidthPositiveBytes: Data(rawRepresentation[0..<rawLength]))
|
|
let s = mpint(fromFixedWidthPositiveBytes: Data(rawRepresentation[rawLength...]))
|
|
|
|
var signatureChunk = Data()
|
|
signatureChunk.append(r.lengthAndData)
|
|
signatureChunk.append(s.lengthAndData)
|
|
var mutSignedData = Data()
|
|
var sub = Data()
|
|
sub.append(OpenSSHPublicKeyWriter().openSSHIdentifier(for: keyType).lengthAndData)
|
|
sub.append(signatureChunk.lengthAndData)
|
|
mutSignedData.append(sub.lengthAndData)
|
|
return mutSignedData
|
|
}
|
|
|
|
func mldsaSignature(_ rawRepresentation: Data, keyType: KeyType) -> Data {
|
|
var mutSignedData = Data()
|
|
var sub = Data()
|
|
sub.append(OpenSSHPublicKeyWriter().openSSHIdentifier(for: keyType).lengthAndData)
|
|
sub.append(rawRepresentation.lengthAndData)
|
|
mutSignedData.append(sub.lengthAndData)
|
|
return mutSignedData
|
|
}
|
|
|
|
func rsaSignature(_ rawRepresentation: Data) -> Data {
|
|
var mutSignedData = Data()
|
|
var sub = Data()
|
|
sub.append("rsa-sha2-512".lengthAndData)
|
|
sub.append(rawRepresentation.lengthAndData)
|
|
mutSignedData.append(sub.lengthAndData)
|
|
return mutSignedData
|
|
}
|
|
|
|
}
|