Partially implement multikeys support (decryption)

This commit is contained in:
Mingshen Sun 2020-04-13 01:30:00 -07:00
parent 7f6e3f1909
commit b7ee00815c
7 changed files with 165 additions and 40 deletions

View file

@ -51,7 +51,6 @@ class CryptoFrameworkTest: XCTestCase {
return
}
XCTAssertNil(error)
XCTAssert(publicKey.getHexKeyID().hasSuffix(keyTriple.fingerprint))
XCTAssertNil(error)

View file

@ -31,11 +31,31 @@ class PGPAgentTest: XCTestCase {
super.tearDown()
}
func basicEncryptDecrypt(using pgpAgent: PGPAgent, requestPassphrase: () -> String = requestPGPKeyPassphrase, encryptInArmored: Bool = true, encryptInArmoredNow: Bool = true) throws -> Data? {
func basicEncryptDecrypt(using pgpAgent: PGPAgent, keyID: String, requestPassphrase: () -> String = requestPGPKeyPassphrase, encryptInArmored: Bool = true, encryptInArmoredNow: Bool = true) throws -> Data? {
passKit.Defaults.encryptInArmored = encryptInArmored
let encryptedData = try pgpAgent.encrypt(plainData: testData)
let encryptedData = try pgpAgent.encrypt(plainData: testData, keyID: keyID)
passKit.Defaults.encryptInArmored = encryptInArmoredNow
return try pgpAgent.decrypt(encryptedData: encryptedData, requestPGPKeyPassphrase: requestPassphrase)
return try pgpAgent.decrypt(encryptedData: encryptedData, keyID: keyID, requestPGPKeyPassphrase: requestPassphrase)
}
func testMultiKeys() throws {
try [
RSA2048_RSA4096
].forEach { keyTriple in
let keychain = DictBasedKeychain()
let pgpAgent = PGPAgent(keyStore: keychain)
try KeyFileManager(keyType: PgpKey.PUBLIC, keyPath: "", keyHandler: keychain.add).importKey(from: keyTriple.publicKey)
try KeyFileManager(keyType: PgpKey.PRIVATE, keyPath: "", keyHandler: keychain.add).importKey(from: keyTriple.privateKey)
XCTAssert(pgpAgent.isPrepared)
try pgpAgent.initKeys()
try [
(true, true), (true, false), (false, true), (false, false)
].forEach{ a, b in
for id in keyTriple.fingerprint {
XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent, keyID: id, encryptInArmored: a, encryptInArmoredNow: b), testData)
}
}
}
}
func testBasicEncryptDecrypt() throws {
@ -57,7 +77,7 @@ class PGPAgentTest: XCTestCase {
try [
(true, true), (true, false), (false, true), (false, false)
].forEach{ a, b in
XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent, encryptInArmored: a, encryptInArmoredNow: b), testData)
XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent, keyID: keyTriple.fingerprint, encryptInArmored: a, encryptInArmoredNow: b), testData)
}
}
}
@ -68,7 +88,7 @@ class PGPAgentTest: XCTestCase {
XCTAssertThrowsError(try pgpAgent.initKeys()) {
XCTAssertEqual($0 as! AppError, AppError.KeyImport)
}
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent)) {
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint)) {
XCTAssertEqual($0 as! AppError, AppError.KeyImport)
}
}
@ -76,7 +96,7 @@ class PGPAgentTest: XCTestCase {
func testInterchangePublicAndPrivateKey() throws {
try importKeys(RSA2048.privateKey, RSA2048.publicKey)
XCTAssert(pgpAgent.isPrepared)
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent)) {
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint)) {
XCTAssert($0.localizedDescription.contains("gopenpgp: unable to add locked key to a keyring"))
}
}
@ -84,7 +104,7 @@ class PGPAgentTest: XCTestCase {
func testIncompatibleKeyTypes() throws {
try importKeys(ED25519.publicKey, RSA2048.privateKey)
XCTAssert(pgpAgent.isPrepared)
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent)) {
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint)) {
XCTAssertEqual($0 as! AppError, AppError.KeyExpiredOrIncompatible)
}
}
@ -92,7 +112,7 @@ class PGPAgentTest: XCTestCase {
func testCorruptedKey() throws {
try importKeys(RSA2048.publicKey.replacingOccurrences(of: "1", with: ""), RSA2048.privateKey)
XCTAssert(pgpAgent.isPrepared)
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent)) {
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint)) {
XCTAssert($0.localizedDescription.contains("Can't read keys. Invalid input."))
}
}
@ -100,10 +120,10 @@ class PGPAgentTest: XCTestCase {
func testUnsettKeys() throws {
try importKeys(ED25519.publicKey, ED25519.privateKey)
XCTAssert(pgpAgent.isPrepared)
XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent), testData)
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)) {
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: ED25519.fingerprint)) {
XCTAssertEqual($0 as! AppError, AppError.KeyImport)
}
}
@ -122,17 +142,17 @@ class PGPAgentTest: XCTestCase {
}
// Provide the correct passphrase.
XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent, requestPassphrase: provideCorrectPassphrase), testData)
XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint, requestPassphrase: provideCorrectPassphrase), testData)
XCTAssertEqual(passphraseRequestCalledCount, 1)
// Provide the wrong passphrase.
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, requestPassphrase: provideIncorrectPassphrase)) {
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint, requestPassphrase: provideIncorrectPassphrase)) {
XCTAssertEqual($0 as! AppError, AppError.WrongPassphrase)
}
XCTAssertEqual(passphraseRequestCalledCount, 2)
// Ask for the passphrase because the previous decryption has failed.
XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent, requestPassphrase: provideCorrectPassphrase), testData)
XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint, requestPassphrase: provideCorrectPassphrase), testData)
XCTAssertEqual(passphraseRequestCalledCount, 3)
}

View file

@ -20,17 +20,49 @@ class PasswordStoreTest: XCTestCase {
}()
let remoteRepoURL = URL(string: "https://github.com/mssun/passforios-password-store.git")!
func testClone() throws {
func testCloneAndDecryptMultiKeys() throws {
let url = URL(fileURLWithPath: "\(Globals.repositoryPath)-test")
let passwordStore = PasswordStore(url: url)
let expectation = self.expectation(description: "clone")
try passwordStore.cloneRepository(
remoteRepoURL: remoteRepoURL,
options: cloneOptions,
branchName: "master",
transferProgressBlock: { _, _ in },
checkoutProgressBlock: { _, _, _ in }
)
) {
expectation.fulfill()
}
waitForExpectations(timeout: 3, handler: nil)
[
("work/github.com", "4712286271220DB299883EA7062E678DA1024DAE"),
("personal/github.com", "787EAE1A5FA3E749AA34CC6AA0645EBED862027E")
].forEach {(path, id) in
let keyID = findGPGID(from: url.appendingPathComponent(path))
XCTAssertEqual(keyID, id)
}
let keychain = AppKeychain.shared
try KeyFileManager(keyType: PgpKey.PUBLIC, keyPath: "", keyHandler: keychain.add).importKey(from: RSA2048_RSA4096.publicKey)
try KeyFileManager(keyType: PgpKey.PRIVATE, keyPath: "", keyHandler: keychain.add).importKey(from: RSA2048_RSA4096.privateKey)
try PGPAgent.shared.initKeys()
let personal = try decrypt(passwordStore: passwordStore, path: "personal/github.com.gpg", passphrase: "passforios")
XCTAssertEqual(personal.plainText, "passwordforpersonal\n")
let work = try decrypt(passwordStore: passwordStore, path: "work/github.com.gpg", passphrase: "passforios")
XCTAssertEqual(work.plainText, "passwordforwork\n")
passwordStore.erase()
}
private func decrypt(passwordStore: PasswordStore, path: String, passphrase: String) throws -> Password {
let entity = passwordStore.getPasswordEntity(by: path, isDir: false)!
return try passwordStore.decrypt(passwordEntity: entity, requestPGPKeyPassphrase: { passphrase } )!
}
}

View file

@ -18,6 +18,13 @@ struct PGPKeyTestTriple {
let passphrase = "passforios"
}
struct MultiPGPKeyTestTriple {
let publicKey: String
let privateKey: String
let fingerprint: [String]
let passphrase: [String]
}
let RSA2048 = PGPKeyTestTriple(
publicKey: PGP_RSA2048_PUBLIC_KEY,
privateKey: PGP_RSA2048_PRIVATE_KEY,
@ -54,6 +61,13 @@ let ED25519_SUB = PGPKeyTestTriple(
fingerprint: "e9444483"
)
let RSA2048_RSA4096 = MultiPGPKeyTestTriple(
publicKey: PGP_RSA2048_PUBLIC_KEY + "\n" + PGP_RSA4096_PUBLIC_KEY,
privateKey: PGP_RSA2048_PRIVATE_KEY + "\n" + PGP_RSA4096_PRIVATE_KEY,
fingerprint: ["a1024dae", "d862027e"],
passphrase: ["passforios", "passforios"]
)
func requestPGPKeyPassphrase() -> String {
return "passforios"
}