mirror of
https://github.com/maxgoedjen/secretive.git
synced 2025-04-10 17:47:19 +00:00
Comments and shuffling around
This commit is contained in:
parent
d7b5cca182
commit
7adc5da26f
@ -65,6 +65,8 @@ extension OpenSSHKeyWriter {
|
|||||||
case .ellipticCurve:
|
case .ellipticCurve:
|
||||||
return "ecdsa-sha2-nistp" + String(describing: length)
|
return "ecdsa-sha2-nistp" + String(describing: length)
|
||||||
case .rsa:
|
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"
|
return "rsa-sha2-512"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,6 +81,7 @@ extension OpenSSHKeyWriter {
|
|||||||
case .ellipticCurve:
|
case .ellipticCurve:
|
||||||
return "nistp" + String(describing: length)
|
return "nistp" + String(describing: length)
|
||||||
case .rsa:
|
case .rsa:
|
||||||
|
// All RSA keys use the same 512 bit hash function
|
||||||
return "rsa-sha2-512"
|
return "rsa-sha2-512"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ extension SmartCard {
|
|||||||
fatalError("Keys must be deleted on the smart card.")
|
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() }
|
guard let tokenID = tokenID else { fatalError() }
|
||||||
let context = LAContext()
|
let context = LAContext()
|
||||||
context.localizedReason = "sign a request from \"\(provenance.origin.displayName)\" using secret \"\(secret.name)\""
|
context.localizedReason = "sign a request from \"\(provenance.origin.displayName)\" using secret \"\(secret.name)\""
|
||||||
@ -86,16 +86,14 @@ extension SmartCard {
|
|||||||
}
|
}
|
||||||
return signature as Data
|
return signature as Data
|
||||||
}
|
}
|
||||||
|
public func verify(data: Data, signature: Data, with secret: Secret) throws -> Bool {
|
||||||
public func verify(data: Data, signature: Data, with secret: SecretType) throws -> Bool {
|
|
||||||
|
|
||||||
let attributes = KeychainDictionary([
|
let attributes = KeychainDictionary([
|
||||||
kSecAttrKeyType: secret.algorithm.secAttrKeyType,
|
kSecAttrKeyType: secret.algorithm.secAttrKeyType,
|
||||||
kSecAttrKeySizeInBits: secret.keySize,
|
kSecAttrKeySizeInBits: secret.keySize,
|
||||||
kSecAttrKeyClass: kSecAttrKeyClassPublic
|
kSecAttrKeyClass: kSecAttrKeyClassPublic
|
||||||
])
|
])
|
||||||
var encryptError: SecurityError?
|
var verifyError: SecurityError?
|
||||||
var untyped: CFTypeRef? = SecKeyCreateWithData(secret.publicKey as CFData, attributes, &encryptError)
|
let untyped: CFTypeRef? = SecKeyCreateWithData(secret.publicKey as CFData, attributes, &verifyError)
|
||||||
guard let untypedSafe = untyped else {
|
guard let untypedSafe = untyped else {
|
||||||
throw KeychainError(statusCode: errSecSuccess)
|
throw KeychainError(statusCode: errSecSuccess)
|
||||||
}
|
}
|
||||||
@ -113,85 +111,12 @@ extension SmartCard {
|
|||||||
default:
|
default:
|
||||||
fatalError()
|
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 {
|
if !signature {
|
||||||
throw SigningError(error: encryptError)
|
throw SigningError(error: verifyError)
|
||||||
}
|
}
|
||||||
return signature
|
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
|
||||||
@ -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 {
|
extension TKTokenWatcher {
|
||||||
|
|
||||||
/// All available tokens, excluding the Secure Enclave.
|
/// All available tokens, excluding the Secure Enclave.
|
||||||
|
@ -34,7 +34,7 @@ struct EmptyStoreImmutableView: View {
|
|||||||
VStack {
|
VStack {
|
||||||
Text("No Secrets").bold()
|
Text("No Secrets").bold()
|
||||||
Text("Use your Smart Card's management tool to create a secret.")
|
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)
|
}.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user