From 7adc5da26f725ecdf19cb9623f99204597583cc5 Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sat, 11 Mar 2023 15:35:07 -0800 Subject: [PATCH] Comments and shuffling around --- .../SecretKit/OpenSSH/OpenSSHKeyWriter.swift | 3 + .../SmartCardSecretKit/SmartCardStore.swift | 180 ++++++++++-------- Sources/Secretive/Views/EmptyStoreView.swift | 2 +- 3 files changed, 103 insertions(+), 82 deletions(-) diff --git a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHKeyWriter.swift b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHKeyWriter.swift index ef69b0c..da8c4b1 100644 --- a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHKeyWriter.swift +++ b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHKeyWriter.swift @@ -65,6 +65,8 @@ extension OpenSSHKeyWriter { case .ellipticCurve: return "ecdsa-sha2-nistp" + String(describing: length) case .rsa: + // All RSA keys use the same 512 bit hash function, per + // https://security.stackexchange.com/questions/255074/why-are-rsa-sha2-512-and-rsa-sha2-256-supported-but-not-reported-by-ssh-q-key return "rsa-sha2-512" } } @@ -79,6 +81,7 @@ extension OpenSSHKeyWriter { case .ellipticCurve: return "nistp" + String(describing: length) case .rsa: + // All RSA keys use the same 512 bit hash function return "rsa-sha2-512" } } diff --git a/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift b/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift index 25f8509..c6ea705 100644 --- a/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift +++ b/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift @@ -45,7 +45,7 @@ extension SmartCard { fatalError("Keys must be deleted on the smart card.") } - public func sign(data: Data, with secret: SecretType, for provenance: SigningRequestProvenance) throws -> Data { + public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance) throws -> Data { guard let tokenID = tokenID else { fatalError() } let context = LAContext() context.localizedReason = "sign a request from \"\(provenance.origin.displayName)\" using secret \"\(secret.name)\"" @@ -86,16 +86,14 @@ extension SmartCard { } return signature as Data } - - public func verify(data: Data, signature: Data, with secret: SecretType) throws -> Bool { - + public func verify(data: Data, signature: Data, with secret: Secret) 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) + var verifyError: SecurityError? + let untyped: CFTypeRef? = SecKeyCreateWithData(secret.publicKey as CFData, attributes, &verifyError) guard let untypedSafe = untyped else { throw KeychainError(statusCode: errSecSuccess) } @@ -113,85 +111,12 @@ extension SmartCard { default: fatalError() } - let signature = SecKeyVerifySignature(key, signatureAlgorithm, data as CFData, signature as CFData, &encryptError) + let signature = SecKeyVerifySignature(key, signatureAlgorithm, data as CFData, signature as CFData, &verifyError) if !signature { - throw SigningError(error: encryptError) + throw SigningError(error: verifyError) } 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? { nil @@ -273,6 +198,99 @@ extension SmartCard.Store { } + +// MARK: Smart Card specific encryption/decryption/verification +extension SmartCard.Store { + + /// Encrypts a payload with a specified key. + /// - Parameters: + /// - data: The payload to encrypt. + /// - secret: The secret to encrypt with. + /// - Returns: The encrypted data. + /// - Warning: Encryption functions are deliberately only exposed on a library level, and are not exposed in Secretive itself to prevent users from data loss. Any pull requests which expose this functionality in the app will not be merged. + public func encrypt(data: Data, with secret: SecretType) throws -> Data { + let context = LAContext() + context.localizedReason = "encrypt data using secret \"\(secret.name)\"" + context.localizedCancelTitle = "Deny" + let attributes = KeychainDictionary([ + kSecAttrKeyType: secret.algorithm.secAttrKeyType, + kSecAttrKeySizeInBits: secret.keySize, + kSecAttrKeyClass: kSecAttrKeyClassPublic, + kSecUseAuthenticationContext: context + ]) + var encryptError: SmartCard.SecurityError? + let untyped: CFTypeRef? = SecKeyCreateWithData(secret.publicKey as CFData, attributes, &encryptError) + guard let untypedSafe = untyped else { + throw SmartCard.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 SmartCard.SigningError(error: encryptError) + } + return signature as Data + } + + /// Decrypts a payload with a specified key. + /// - Parameters: + /// - data: The payload to decrypt. + /// - secret: The secret to decrypt with. + /// - Returns: The decrypted data. + /// - Warning: Encryption functions are deliberately only exposed on a library level, and are not exposed in Secretive itself to prevent users from data loss. Any pull requests which expose this functionality in the app will not be merged. + public func decrypt(data: Data, with secret: SecretType) throws -> Data { + guard let tokenID = tokenID else { fatalError() } + let context = LAContext() + context.localizedReason = "decrypt data 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 SmartCard.KeychainError(statusCode: status) + } + guard let untypedSafe = untyped else { + throw SmartCard.KeychainError(statusCode: errSecSuccess) + } + let key = untypedSafe as! SecKey + var encryptError: SmartCard.SecurityError? + let signatureAlgorithm: SecKeyAlgorithm + switch (secret.algorithm, secret.keySize) { + case (.ellipticCurve, 256): + signatureAlgorithm = .eciesEncryptionStandardX963SHA256AESGCM + case (.ellipticCurve, 384): + signatureAlgorithm = .eciesEncryptionStandardX963SHA384AESGCM + case (.rsa, 1024), (.rsa, 2048): + signatureAlgorithm = .rsaEncryptionOAEPSHA512AESGCM + default: + fatalError() + } + guard let signature = SecKeyCreateDecryptedData(key, signatureAlgorithm, data as CFData, &encryptError) else { + throw SmartCard.SigningError(error: encryptError) + } + return signature as Data + } + +} + extension TKTokenWatcher { /// All available tokens, excluding the Secure Enclave. diff --git a/Sources/Secretive/Views/EmptyStoreView.swift b/Sources/Secretive/Views/EmptyStoreView.swift index 689b00b..5bd48c1 100644 --- a/Sources/Secretive/Views/EmptyStoreView.swift +++ b/Sources/Secretive/Views/EmptyStoreView.swift @@ -34,7 +34,7 @@ struct EmptyStoreImmutableView: View { VStack { Text("No Secrets").bold() Text("Use your Smart Card's management tool to create a secret.") - Text("Secretive only supports Elliptic Curve keys.") + Text("Secretive supports EC256, EC384, RSA1024, and RSA2048 keys.") }.frame(maxWidth: .infinity, maxHeight: .infinity) }