passforios/passKitTests/Crypto/PGPAgentTest.swift

168 lines
7.1 KiB
Swift
Raw Normal View History

//
// PGPAgent.swift
// passKitTests
//
// Created by Yishi Lin on 2019/7/17.
// Copyright © 2019 Bob Sun. All rights reserved.
//
2019-09-30 00:12:54 +08:00
import SwiftyUserDefaults
import XCTest
@testable import passKit
class PGPAgentTest: XCTestCase {
private var keychain: KeyStore!
private var pgpAgent: PGPAgent!
private let testData = "Hello World!".data(using: .utf8)!
override func setUp() {
super.setUp()
keychain = DictBasedKeychain()
pgpAgent = PGPAgent(keyStore: keychain)
2019-09-30 00:12:54 +08:00
UserDefaults().removePersistentDomain(forName: "SharedDefaultsForPGPAgentTest")
passKit.Defaults = DefaultsAdapter(defaults: UserDefaults(suiteName: "SharedDefaultsForPGPAgentTest")!, keyStore: DefaultsKeys())
}
override func tearDown() {
keychain.removeAllContent()
2019-09-30 00:12:54 +08:00
UserDefaults().removePersistentDomain(forName: "SharedDefaultsForPGPAgentTest")
super.tearDown()
}
2020-11-10 22:43:44 +01:00
private func basicEncryptDecrypt(using pgpAgent: PGPAgent, keyID: String, encryptKeyID: String? = nil, requestPassphrase: @escaping (String) -> String = requestPGPKeyPassphrase, encryptInArmored: Bool = true, decryptFromArmored: Bool = true) throws -> Data? {
passKit.Defaults.encryptInArmored = encryptInArmored
let encryptedData = try pgpAgent.encrypt(plainData: testData, keyID: keyID)
2020-04-19 15:43:13 +02:00
passKit.Defaults.encryptInArmored = decryptFromArmored
2020-04-13 10:25:01 -07:00
return try pgpAgent.decrypt(encryptedData: encryptedData, keyID: encryptKeyID ?? keyID, requestPGPKeyPassphrase: requestPassphrase)
}
func testMultiKeys() throws {
try [
2020-04-13 21:06:19 -07:00
RSA2048_RSA4096,
2020-04-19 15:43:13 +02:00
ED25519_NISTP384,
2020-04-13 21:06:19 -07:00
].forEach { testKeyInfo in
2020-04-19 15:43:13 +02:00
keychain.removeAllContent()
try importKeys(testKeyInfo.publicKeys, testKeyInfo.privateKeys)
XCTAssert(pgpAgent.isPrepared)
try pgpAgent.initKeys()
try [
2020-04-19 15:43:13 +02:00
(true, true),
(true, false),
(false, true),
(false, false),
].forEach { encryptInArmored, decryptFromArmored in
for id in testKeyInfo.fingerprints {
XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent, keyID: id, encryptInArmored: encryptInArmored, decryptFromArmored: decryptFromArmored), testData)
}
}
}
}
func testBasicEncryptDecrypt() throws {
try [
RSA2048,
2020-04-12 18:24:03 -07:00
RSA2048_SUB,
2020-04-12 19:32:58 -07:00
RSA4096,
RSA4096_SUB,
ED25519,
2020-04-12 18:24:03 -07:00
ED25519_SUB,
2020-04-13 21:06:19 -07:00
NISTP384,
].forEach { testKeyInfo in
2020-04-19 15:43:13 +02:00
keychain.removeAllContent()
try importKeys(testKeyInfo.publicKey, testKeyInfo.privateKey)
XCTAssert(pgpAgent.isPrepared)
try pgpAgent.initKeys()
2020-04-13 21:06:19 -07:00
XCTAssert(try pgpAgent.getKeyID().first!.lowercased().hasSuffix(testKeyInfo.fingerprint))
2019-09-30 00:12:54 +08:00
try [
2020-04-19 15:43:13 +02:00
(true, true),
(true, false),
(false, true),
(false, false),
].forEach { encryptInArmored, decryptFromArmored in
XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent, keyID: testKeyInfo.fingerprint, encryptInArmored: encryptInArmored, decryptFromArmored: decryptFromArmored), testData)
2019-09-30 00:12:54 +08:00
}
}
}
func testNoPrivateKey() throws {
try KeyFileManager(keyType: PgpKey.PUBLIC, keyPath: "", keyHandler: keychain.add).importKey(from: RSA2048.publicKey)
XCTAssertFalse(pgpAgent.isPrepared)
XCTAssertThrowsError(try pgpAgent.initKeys()) {
XCTAssertEqual($0 as! AppError, AppError.keyImport)
}
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint)) {
XCTAssertEqual($0 as! AppError, AppError.keyImport)
}
}
func testInterchangePublicAndPrivateKey() throws {
try importKeys(RSA2048.privateKey, RSA2048.publicKey)
XCTAssert(pgpAgent.isPrepared)
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint)) {
2020-04-11 23:23:38 -07:00
XCTAssert($0.localizedDescription.contains("gopenpgp: unable to add locked key to a keyring"))
}
}
func testIncompatibleKeyTypes() throws {
try importKeys(ED25519.publicKey, RSA2048.privateKey)
XCTAssert(pgpAgent.isPrepared)
2020-04-13 10:25:01 -07:00
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: ED25519.fingerprint, encryptKeyID: RSA2048.fingerprint)) {
XCTAssertEqual($0 as! AppError, AppError.keyExpiredOrIncompatible)
}
}
func testCorruptedKey() throws {
try importKeys(RSA2048.publicKey.replacingOccurrences(of: "1", with: ""), RSA2048.privateKey)
XCTAssert(pgpAgent.isPrepared)
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint)) {
XCTAssert($0.localizedDescription.contains("Can't read keys. Invalid input."))
}
}
2020-04-19 15:42:00 +02:00
func testUnsetKeys() throws {
try importKeys(ED25519.publicKey, ED25519.privateKey)
XCTAssert(pgpAgent.isPrepared)
XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent, keyID: ED25519.fingerprint), testData)
keychain.removeContent(for: PgpKey.PUBLIC.getKeychainKey())
keychain.removeContent(for: PgpKey.PRIVATE.getKeychainKey())
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: ED25519.fingerprint)) {
XCTAssertEqual($0 as! AppError, AppError.keyImport)
}
}
2019-09-16 21:35:07 +02:00
func testNoDecryptionWithIncorrectPassphrase() throws {
try importKeys(RSA2048.publicKey, RSA2048.privateKey)
var passphraseRequestCalledCount = 0
let provideCorrectPassphrase: (String) -> String = { _ in
2020-04-19 15:43:13 +02:00
passphraseRequestCalledCount += 1
2020-04-13 21:06:19 -07:00
return requestPGPKeyPassphrase(keyID: RSA2048.fingerprint)
2019-09-16 21:35:07 +02:00
}
let provideIncorrectPassphrase: (String) -> String = { _ in
2020-04-19 15:43:13 +02:00
passphraseRequestCalledCount += 1
2019-09-16 21:35:07 +02:00
return "incorrect passphrase"
}
// Provide the correct passphrase.
XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint, requestPassphrase: provideCorrectPassphrase), testData)
XCTAssertEqual(passphraseRequestCalledCount, 1)
// Provide the wrong passphrase.
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint, requestPassphrase: provideIncorrectPassphrase)) {
XCTAssertEqual($0 as! AppError, AppError.wrongPassphrase)
2019-09-16 21:35:07 +02:00
}
XCTAssertEqual(passphraseRequestCalledCount, 2)
// Ask for the passphrase because the previous decryption has failed.
XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint, requestPassphrase: provideCorrectPassphrase), testData)
XCTAssertEqual(passphraseRequestCalledCount, 3)
2019-09-16 21:35:07 +02:00
}
private func importKeys(_ publicKey: String, _ privateKey: String) throws {
try KeyFileManager(keyType: PgpKey.PUBLIC, keyPath: "", keyHandler: keychain.add).importKey(from: publicKey)
try KeyFileManager(keyType: PgpKey.PRIVATE, keyPath: "", keyHandler: keychain.add).importKey(from: privateKey)
}
}