mirror of
				https://github.com/maxgoedjen/secretive.git
				synced 2025-11-04 09:20:56 +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