mirror of
https://github.com/maxgoedjen/secretive.git
synced 2025-04-10 17:47:19 +00:00
Rounded out the rest of the SmartCardStore API.
This commit is contained in:
parent
f54b2a33bf
commit
d7b5cca182
@ -64,6 +64,8 @@ extension OpenSSHKeyWriter {
|
|||||||
switch algorithm {
|
switch algorithm {
|
||||||
case .ellipticCurve:
|
case .ellipticCurve:
|
||||||
return "ecdsa-sha2-nistp" + String(describing: length)
|
return "ecdsa-sha2-nistp" + String(describing: length)
|
||||||
|
case .rsa:
|
||||||
|
return "rsa-sha2-512"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +78,8 @@ extension OpenSSHKeyWriter {
|
|||||||
switch algorithm {
|
switch algorithm {
|
||||||
case .ellipticCurve:
|
case .ellipticCurve:
|
||||||
return "nistp" + String(describing: length)
|
return "nistp" + String(describing: length)
|
||||||
|
case .rsa:
|
||||||
|
return "rsa-sha2-512"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ public protocol Secret: Identifiable, Hashable {
|
|||||||
public enum Algorithm: Hashable {
|
public enum Algorithm: Hashable {
|
||||||
|
|
||||||
case ellipticCurve
|
case ellipticCurve
|
||||||
|
case rsa
|
||||||
|
|
||||||
/// Initializes the Algorithm with a secAttr representation of an algorithm.
|
/// Initializes the Algorithm with a secAttr representation of an algorithm.
|
||||||
/// - Parameter secAttr: the secAttr, represented as an NSNumber.
|
/// - Parameter secAttr: the secAttr, represented as an NSNumber.
|
||||||
@ -28,8 +29,19 @@ public enum Algorithm: Hashable {
|
|||||||
switch secAttrString {
|
switch secAttrString {
|
||||||
case kSecAttrKeyTypeEC:
|
case kSecAttrKeyTypeEC:
|
||||||
self = .ellipticCurve
|
self = .ellipticCurve
|
||||||
|
case kSecAttrKeyTypeRSA:
|
||||||
|
self = .rsa
|
||||||
default:
|
default:
|
||||||
fatalError()
|
fatalError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var secAttrKeyType: CFString {
|
||||||
|
switch self {
|
||||||
|
case .ellipticCurve:
|
||||||
|
return kSecAttrKeyTypeEC
|
||||||
|
case .rsa:
|
||||||
|
return kSecAttrKeyTypeRSA
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,10 @@ extension SmartCard {
|
|||||||
signatureAlgorithm = .ecdsaSignatureMessageX962SHA256
|
signatureAlgorithm = .ecdsaSignatureMessageX962SHA256
|
||||||
case (.ellipticCurve, 384):
|
case (.ellipticCurve, 384):
|
||||||
signatureAlgorithm = .ecdsaSignatureMessageX962SHA384
|
signatureAlgorithm = .ecdsaSignatureMessageX962SHA384
|
||||||
|
case (.rsa, 1024):
|
||||||
|
signatureAlgorithm = .rsaSignatureMessagePKCS1v15SHA512
|
||||||
|
case (.rsa, 2048):
|
||||||
|
signatureAlgorithm = .rsaSignatureMessagePKCS1v15SHA512
|
||||||
default:
|
default:
|
||||||
fatalError()
|
fatalError()
|
||||||
}
|
}
|
||||||
@ -82,6 +86,112 @@ extension SmartCard {
|
|||||||
}
|
}
|
||||||
return signature as Data
|
return signature as Data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func verify(data: Data, signature: Data, with secret: SecretType) throws -> Bool {
|
||||||
|
|
||||||
|
let attributes = KeychainDictionary([
|
||||||
|
kSecAttrKeyType: secret.algorithm.secAttrKeyType,
|
||||||
|
kSecAttrKeySizeInBits: secret.keySize,
|
||||||
|
kSecAttrKeyClass: kSecAttrKeyClassPublic
|
||||||
|
])
|
||||||
|
var encryptError: SecurityError?
|
||||||
|
var untyped: CFTypeRef? = SecKeyCreateWithData(secret.publicKey as CFData, attributes, &encryptError)
|
||||||
|
guard let untypedSafe = untyped else {
|
||||||
|
throw KeychainError(statusCode: errSecSuccess)
|
||||||
|
}
|
||||||
|
let key = untypedSafe as! SecKey
|
||||||
|
let signatureAlgorithm: SecKeyAlgorithm
|
||||||
|
switch (secret.algorithm, secret.keySize) {
|
||||||
|
case (.ellipticCurve, 256):
|
||||||
|
signatureAlgorithm = .ecdsaSignatureMessageX962SHA256
|
||||||
|
case (.ellipticCurve, 384):
|
||||||
|
signatureAlgorithm = .ecdsaSignatureMessageX962SHA384
|
||||||
|
case (.rsa, 1024):
|
||||||
|
signatureAlgorithm = .rsaSignatureMessagePKCS1v15SHA512
|
||||||
|
case (.rsa, 2048):
|
||||||
|
signatureAlgorithm = .rsaSignatureMessagePKCS1v15SHA512
|
||||||
|
default:
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
let signature = SecKeyVerifySignature(key, signatureAlgorithm, data as CFData, signature as CFData, &encryptError)
|
||||||
|
if !signature {
|
||||||
|
throw SigningError(error: encryptError)
|
||||||
|
}
|
||||||
|
return signature
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encrypt(data: Data, with secret: SecretType) throws -> Data {
|
||||||
|
let attributes = KeychainDictionary([
|
||||||
|
kSecAttrKeyType: secret.algorithm.secAttrKeyType,
|
||||||
|
kSecAttrKeySizeInBits: secret.keySize,
|
||||||
|
kSecAttrKeyClass: kSecAttrKeyClassPublic
|
||||||
|
])
|
||||||
|
var encryptError: SecurityError?
|
||||||
|
let untyped: CFTypeRef? = SecKeyCreateWithData(secret.publicKey as CFData, attributes, &encryptError)
|
||||||
|
guard let untypedSafe = untyped else {
|
||||||
|
throw KeychainError(statusCode: errSecSuccess)
|
||||||
|
}
|
||||||
|
let key = untypedSafe as! SecKey
|
||||||
|
let signatureAlgorithm: SecKeyAlgorithm
|
||||||
|
switch (secret.algorithm, secret.keySize) {
|
||||||
|
case (.ellipticCurve, 256):
|
||||||
|
signatureAlgorithm = .eciesEncryptionCofactorVariableIVX963SHA256AESGCM
|
||||||
|
case (.ellipticCurve, 384):
|
||||||
|
signatureAlgorithm = .eciesEncryptionCofactorVariableIVX963SHA256AESGCM
|
||||||
|
case (.rsa, 1024):
|
||||||
|
signatureAlgorithm = .rsaEncryptionOAEPSHA512AESGCM
|
||||||
|
case (.rsa, 2048):
|
||||||
|
signatureAlgorithm = .rsaEncryptionOAEPSHA512AESGCM
|
||||||
|
default:
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
guard let signature = SecKeyCreateEncryptedData(key, signatureAlgorithm, data as CFData, &encryptError) else {
|
||||||
|
throw SigningError(error: encryptError)
|
||||||
|
}
|
||||||
|
return signature as Data
|
||||||
|
}
|
||||||
|
|
||||||
|
public func decrypt(data: Data, with secret: SecretType) throws -> Data {
|
||||||
|
guard let tokenID = tokenID else { fatalError() }
|
||||||
|
let context = LAContext()
|
||||||
|
context.localizedReason = "decrypt a file using secret \"\(secret.name)\""
|
||||||
|
context.localizedCancelTitle = "Deny"
|
||||||
|
let attributes = KeychainDictionary([
|
||||||
|
kSecClass: kSecClassKey,
|
||||||
|
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
|
||||||
|
kSecAttrApplicationLabel: secret.id as CFData,
|
||||||
|
kSecAttrTokenID: tokenID,
|
||||||
|
kSecUseAuthenticationContext: context,
|
||||||
|
kSecReturnRef: true
|
||||||
|
])
|
||||||
|
var untyped: CFTypeRef?
|
||||||
|
let status = SecItemCopyMatching(attributes, &untyped)
|
||||||
|
if status != errSecSuccess {
|
||||||
|
throw KeychainError(statusCode: status)
|
||||||
|
}
|
||||||
|
guard let untypedSafe = untyped else {
|
||||||
|
throw KeychainError(statusCode: errSecSuccess)
|
||||||
|
}
|
||||||
|
let key = untypedSafe as! SecKey
|
||||||
|
var encryptError: SecurityError?
|
||||||
|
let signatureAlgorithm: SecKeyAlgorithm
|
||||||
|
switch (secret.algorithm, secret.keySize) {
|
||||||
|
case (.ellipticCurve, 256):
|
||||||
|
signatureAlgorithm = .eciesEncryptionStandardX963SHA256AESGCM
|
||||||
|
case (.ellipticCurve, 384):
|
||||||
|
signatureAlgorithm = .eciesEncryptionStandardX963SHA384AESGCM
|
||||||
|
case (.rsa, 1024):
|
||||||
|
signatureAlgorithm = .rsaEncryptionOAEPSHA512AESGCM
|
||||||
|
case (.rsa, 2048):
|
||||||
|
signatureAlgorithm = .rsaEncryptionOAEPSHA512AESGCM
|
||||||
|
default:
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
guard let signature = SecKeyCreateDecryptedData(key, signatureAlgorithm, data as CFData, &encryptError) else {
|
||||||
|
throw SigningError(error: encryptError)
|
||||||
|
}
|
||||||
|
return signature as Data
|
||||||
|
}
|
||||||
|
|
||||||
public func existingPersistedAuthenticationContext(secret: SmartCard.Secret) -> PersistedAuthenticationContext? {
|
public func existingPersistedAuthenticationContext(secret: SmartCard.Secret) -> PersistedAuthenticationContext? {
|
||||||
nil
|
nil
|
||||||
@ -140,7 +250,6 @@ extension SmartCard.Store {
|
|||||||
let attributes = KeychainDictionary([
|
let attributes = KeychainDictionary([
|
||||||
kSecClass: kSecClassKey,
|
kSecClass: kSecClassKey,
|
||||||
kSecAttrTokenID: tokenID,
|
kSecAttrTokenID: tokenID,
|
||||||
kSecAttrKeyType: kSecAttrKeyTypeEC, // Restrict to EC
|
|
||||||
kSecReturnRef: true,
|
kSecReturnRef: true,
|
||||||
kSecMatchLimit: kSecMatchLimitAll,
|
kSecMatchLimit: kSecMatchLimitAll,
|
||||||
kSecReturnAttributes: true
|
kSecReturnAttributes: true
|
||||||
|
Loading…
Reference in New Issue
Block a user