Compare commits
No commits in common. "ee80f0dbe865b8f32aba9846957a73b80498adfe" and "f0c21dd880fd4fbe1457365bfcc7482ff37813bb" have entirely different histories.
ee80f0dbe8
...
f0c21dd880
7 changed files with 76 additions and 261 deletions
|
|
@ -16,7 +16,6 @@ struct GopenPGPInterface: PGPInterface {
|
|||
|
||||
private var publicKeys: [String: CryptoKey] = [:]
|
||||
private var privateKeys: [String: CryptoKey] = [:]
|
||||
private var privateSubkeyToKeyIDMapping: [String: String] = [:] // value is the key in privateKeys map
|
||||
|
||||
init(publicArmoredKey: String, privateArmoredKey: String) throws {
|
||||
let pubKeys = extractKeysFromArmored(str: publicArmoredKey)
|
||||
|
|
@ -41,24 +40,7 @@ struct GopenPGPInterface: PGPInterface {
|
|||
}
|
||||
throw AppError.keyImport
|
||||
}
|
||||
|
||||
let keyID = cryptoKey.getFingerprint().lowercased()
|
||||
privateKeys[keyID] = cryptoKey
|
||||
|
||||
guard let subkeyIDsJSON = HelperPassGetHexSubkeyIDsJSON(cryptoKey) else {
|
||||
guard error == nil else {
|
||||
throw error!
|
||||
}
|
||||
throw AppError.keyImport
|
||||
}
|
||||
do {
|
||||
let subkeyIDs = try JSONDecoder().decode([String].self, from: subkeyIDsJSON)
|
||||
for subkeyID in subkeyIDs {
|
||||
privateSubkeyToKeyIDMapping[subkeyID] = keyID
|
||||
}
|
||||
} catch {
|
||||
throw AppError.keyImport
|
||||
}
|
||||
privateKeys[cryptoKey.getFingerprint().lowercased()] = cryptoKey
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -88,13 +70,15 @@ struct GopenPGPInterface: PGPInterface {
|
|||
privateKeys.keys.contains { key in key.hasSuffix(keyID.lowercased()) }
|
||||
}
|
||||
|
||||
func decrypt(encryptedData: Data, keyIDHint: String?, passPhraseForKey: @escaping (String) -> String) throws -> Data? {
|
||||
let message = createPGPMessage(from: encryptedData)
|
||||
guard let message else {
|
||||
throw AppError.decryption
|
||||
}
|
||||
func decrypt(encryptedData: Data, keyID: String?, passphrase: String) throws -> Data? {
|
||||
let key: CryptoKey? = {
|
||||
if let keyID {
|
||||
return privateKeys.first(where: { key, _ in key.hasSuffix(keyID.lowercased()) })?.value
|
||||
}
|
||||
return privateKeys.first?.value
|
||||
}()
|
||||
|
||||
guard let privateKey: CryptoKey = try findDecryptionKey(message: message, keyIDHint: keyIDHint) else {
|
||||
guard let privateKey = key else {
|
||||
throw AppError.decryption
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +87,6 @@ struct GopenPGPInterface: PGPInterface {
|
|||
try privateKey.isLocked(&isLocked)
|
||||
var unlockedKey: CryptoKey!
|
||||
if isLocked.boolValue {
|
||||
let passphrase = passPhraseForKey(privateKey.getFingerprint())
|
||||
unlockedKey = try privateKey.unlock(passphrase.data(using: .utf8))
|
||||
} else {
|
||||
unlockedKey = privateKey
|
||||
|
|
@ -117,52 +100,33 @@ struct GopenPGPInterface: PGPInterface {
|
|||
throw AppError.decryption
|
||||
}
|
||||
|
||||
let message = createPGPMessage(from: encryptedData)
|
||||
return try keyRing.decrypt(message, verifyKey: nil, verifyTime: 0).data
|
||||
} catch {
|
||||
throw Self.errorMapping[error.localizedDescription, default: error]
|
||||
}
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use encrypt(plainData:keyIDs:) instead.")
|
||||
func encrypt(plainData: Data, keyID: String?) throws -> Data {
|
||||
guard let keyID = keyID ?? publicKeys.keys.first else {
|
||||
// this is invalid, but we want the new function to throw the error for us
|
||||
return try encrypt(plainData: plainData, keyIDs: [])
|
||||
}
|
||||
return try encrypt(plainData: plainData, keyIDs: [keyID])
|
||||
}
|
||||
|
||||
func encryptWithAllKeys(plainData: Data) throws -> Data {
|
||||
let keyIDs = publicKeys.keys.filter { key in privateKeys.keys.contains(key) }
|
||||
return try encrypt(plainData: plainData, keyIDs: keyIDs)
|
||||
}
|
||||
|
||||
func encrypt(plainData: Data, keyIDs: [String]) throws -> Data {
|
||||
let keys: [CryptoKey] = try keyIDs.map { keyID in
|
||||
guard let key = publicKeys.first(where: { key, _ in key.hasSuffix(keyID.lowercased()) })?.value else {
|
||||
throw AppError.pgpPublicKeyNotFound(keyID: keyID)
|
||||
let key: CryptoKey? = {
|
||||
if let keyID {
|
||||
return publicKeys.first(where: { key, _ in key.hasSuffix(keyID.lowercased()) })?.value
|
||||
}
|
||||
return key
|
||||
}
|
||||
guard let firstKey = keys.first else {
|
||||
return publicKeys.first?.value
|
||||
}()
|
||||
|
||||
guard let publicKey = key else {
|
||||
throw AppError.encryption
|
||||
}
|
||||
let otherKeys = keys.dropFirst()
|
||||
|
||||
var error: NSError?
|
||||
guard let keyRing = CryptoNewKeyRing(firstKey, &error) else {
|
||||
|
||||
guard let keyRing = CryptoNewKeyRing(publicKey, &error) else {
|
||||
guard error == nil else {
|
||||
throw error!
|
||||
}
|
||||
throw AppError.encryption
|
||||
}
|
||||
do {
|
||||
try otherKeys.forEach { key in
|
||||
try keyRing.add(key)
|
||||
}
|
||||
} catch {
|
||||
throw AppError.encryption
|
||||
}
|
||||
|
||||
let encryptedData = try keyRing.encrypt(CryptoNewPlainMessage(plainData.mutable as Data), privateKey: nil)
|
||||
if Defaults.encryptInArmored {
|
||||
|
|
@ -183,33 +147,6 @@ struct GopenPGPInterface: PGPInterface {
|
|||
var shortKeyID: [String] {
|
||||
publicKeys.keys.map { $0.suffix(8).uppercased() }
|
||||
}
|
||||
|
||||
private func findDecryptionKey(message: CryptoPGPMessage, keyIDHint: String?) throws -> CryptoKey? {
|
||||
var keyIDCandidates: any Collection<String> = privateKeys.keys
|
||||
do {
|
||||
if let encryptionKeysJSON = message.getHexEncryptionKeyIDsJson() {
|
||||
// these are the subkeys (encryption keys), not the primaries keys (whose fingerprints we have in the privateKeys map),
|
||||
// so we need to map them back to the primary keyIDs using privateSubkeyToKeyIDMapping
|
||||
let validSubkeys = try JSONDecoder().decode([String].self, from: encryptionKeysJSON)
|
||||
let validKeyIDs = validSubkeys.compactMap { privateSubkeyToKeyIDMapping[$0] }
|
||||
if #available(iOSApplicationExtension 16.0, *) {
|
||||
assert(validKeyIDs.isEmpty || !Set(keyIDCandidates).isDisjoint(with: validKeyIDs))
|
||||
}
|
||||
keyIDCandidates = validKeyIDs
|
||||
}
|
||||
} catch {
|
||||
// fall back to legacy approach of trying first in privateKeys (or preferring hint)
|
||||
}
|
||||
|
||||
if let keyIDHint {
|
||||
keyIDCandidates = keyIDCandidates.filter { key in key.hasSuffix(keyIDHint.lowercased()) }
|
||||
}
|
||||
guard let selectedKeyID = keyIDCandidates.first else {
|
||||
throw keyIDHint != nil ? AppError.keyExpiredOrIncompatible : AppError.decryption
|
||||
}
|
||||
|
||||
return privateKeys[selectedKeyID]
|
||||
}
|
||||
}
|
||||
|
||||
public func createPGPMessage(from encryptedData: Data) -> CryptoPGPMessage? {
|
||||
|
|
|
|||
|
|
@ -24,34 +24,12 @@ struct ObjectivePGPInterface: PGPInterface {
|
|||
}
|
||||
}
|
||||
|
||||
func decrypt(encryptedData: Data, keyIDHint _: String?, passPhraseForKey: @escaping (String) -> String) throws -> Data? {
|
||||
try ObjectivePGP.decrypt(encryptedData, andVerifySignature: false, using: keyring.keys) { selectedKey in
|
||||
guard let selectedKey else {
|
||||
return nil
|
||||
}
|
||||
return passPhraseForKey(selectedKey.keyID.longIdentifier)
|
||||
}
|
||||
func decrypt(encryptedData: Data, keyID _: String?, passphrase: String) throws -> Data? {
|
||||
try ObjectivePGP.decrypt(encryptedData, andVerifySignature: false, using: keyring.keys) { _ in passphrase }
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use encrypt(plainData:keyIDs:) instead.")
|
||||
func encrypt(plainData: Data, keyID _: String?) throws -> Data {
|
||||
// Backwards compatibility: ignore keyID parameter and encrypted with all keys in the keyring
|
||||
try encryptWithAllKeys(plainData: plainData)
|
||||
}
|
||||
|
||||
func encryptWithAllKeys(plainData: Data) throws -> Data {
|
||||
try encrypt(plainData: plainData, keyIDs: keyID)
|
||||
}
|
||||
|
||||
func encrypt(plainData: Data, keyIDs: [String]) throws -> Data {
|
||||
let keys = try keyIDs.map { keyID in
|
||||
guard let key = keyring.findKey(keyID) else {
|
||||
throw AppError.pgpPublicKeyNotFound(keyID: keyID)
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
let encryptedData = try ObjectivePGP.encrypt(plainData, addSignature: false, using: keys, passphraseForKey: nil)
|
||||
let encryptedData = try ObjectivePGP.encrypt(plainData, addSignature: false, using: keyring.keys, passphraseForKey: nil)
|
||||
if Defaults.encryptInArmored {
|
||||
return Armor.armored(encryptedData, as: .message).data(using: .ascii)!
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,14 +69,14 @@ public class PGPAgent {
|
|||
latestDecryptStatus = false
|
||||
|
||||
// Get the PGP key passphrase.
|
||||
let providePassPhraseForKey = { (selectedKeyID: String) -> String in
|
||||
if previousDecryptStatus == false {
|
||||
return requestPGPKeyPassphrase(selectedKeyID)
|
||||
}
|
||||
return self.keyStore.get(for: AppKeychain.getPGPKeyPassphraseKey(keyID: selectedKeyID)) ?? requestPGPKeyPassphrase(selectedKeyID)
|
||||
var passphrase = ""
|
||||
if previousDecryptStatus == false {
|
||||
passphrase = requestPGPKeyPassphrase(keyID)
|
||||
} else {
|
||||
passphrase = keyStore.get(for: AppKeychain.getPGPKeyPassphraseKey(keyID: keyID)) ?? requestPGPKeyPassphrase(keyID)
|
||||
}
|
||||
// Decrypt.
|
||||
guard let result = try pgpInterface.decrypt(encryptedData: encryptedData, keyIDHint: keyID, passPhraseForKey: providePassPhraseForKey) else {
|
||||
guard let result = try pgpInterface.decrypt(encryptedData: encryptedData, keyID: keyID, passphrase: passphrase) else {
|
||||
return nil
|
||||
}
|
||||
// The decryption step has succeed.
|
||||
|
|
@ -84,7 +84,6 @@ public class PGPAgent {
|
|||
return result
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use encrypt(plainData:keyIDs:) instead.")
|
||||
public func encrypt(plainData: Data, keyID: String) throws -> Data {
|
||||
try checkAndInit()
|
||||
guard let pgpInterface else {
|
||||
|
|
@ -98,49 +97,24 @@ public class PGPAgent {
|
|||
throw AppError.pgpPublicKeyNotFound(keyID: keyID)
|
||||
}
|
||||
}
|
||||
return try pgpInterface.encrypt(plainData: plainData, keyIDs: [keyID])
|
||||
return try pgpInterface.encrypt(plainData: plainData, keyID: keyID)
|
||||
}
|
||||
|
||||
public func encrypt(plainData: Data, keyIDs: [String]) throws -> Data {
|
||||
try checkAndInit()
|
||||
guard let pgpInterface else {
|
||||
throw AppError.encryption
|
||||
}
|
||||
return try pgpInterface.encrypt(plainData: plainData, keyIDs: keyIDs)
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use encrypt(plainData:keyIDs:) or encryptWithAllKeys(plainData:) instead.")
|
||||
public func encrypt(plainData: Data) throws -> Data {
|
||||
try checkAndInit()
|
||||
guard let pgpInterface else {
|
||||
throw AppError.encryption
|
||||
}
|
||||
return try pgpInterface.encrypt(plainData: plainData, keyID: nil)
|
||||
}
|
||||
|
||||
public func encryptWithAllKeys(plainData: Data) throws -> Data {
|
||||
try checkAndInit()
|
||||
guard let pgpInterface else {
|
||||
throw AppError.encryption
|
||||
}
|
||||
return try pgpInterface.encryptWithAllKeys(plainData: plainData)
|
||||
}
|
||||
|
||||
public func decrypt(encryptedData: Data, requestPGPKeyPassphrase: @escaping (String) -> String) throws -> Data? {
|
||||
public func decrypt(encryptedData: Data, requestPGPKeyPassphrase: (String) -> String) throws -> Data? {
|
||||
// Remember the previous status and set the current status
|
||||
let previousDecryptStatus = latestDecryptStatus
|
||||
latestDecryptStatus = false
|
||||
// Init keys.
|
||||
try checkAndInit()
|
||||
// Get the PGP key passphrase.
|
||||
let providePassPhraseForKey = { (selectedKeyID: String) -> String in
|
||||
if previousDecryptStatus == false {
|
||||
return requestPGPKeyPassphrase(selectedKeyID)
|
||||
}
|
||||
return self.keyStore.get(for: AppKeychain.getPGPKeyPassphraseKey(keyID: selectedKeyID)) ?? requestPGPKeyPassphrase(selectedKeyID)
|
||||
var passphrase = ""
|
||||
if previousDecryptStatus == false {
|
||||
passphrase = requestPGPKeyPassphrase("")
|
||||
} else {
|
||||
passphrase = keyStore.get(for: AppKeychain.getPGPKeyPassphraseKey(keyID: "")) ?? requestPGPKeyPassphrase("")
|
||||
}
|
||||
// Decrypt.
|
||||
guard let result = try pgpInterface!.decrypt(encryptedData: encryptedData, keyIDHint: nil, passPhraseForKey: providePassPhraseForKey) else {
|
||||
guard let result = try pgpInterface!.decrypt(encryptedData: encryptedData, keyID: nil, passphrase: passphrase) else {
|
||||
return nil
|
||||
}
|
||||
// The decryption step has succeed.
|
||||
|
|
@ -148,6 +122,14 @@ public class PGPAgent {
|
|||
return result
|
||||
}
|
||||
|
||||
public func encrypt(plainData: Data) throws -> Data {
|
||||
try checkAndInit()
|
||||
guard let pgpInterface else {
|
||||
throw AppError.encryption
|
||||
}
|
||||
return try pgpInterface.encrypt(plainData: plainData, keyID: nil)
|
||||
}
|
||||
|
||||
public var isPrepared: Bool {
|
||||
keyStore.contains(key: PGPKey.PUBLIC.getKeychainKey())
|
||||
&& keyStore.contains(key: PGPKey.PRIVATE.getKeychainKey())
|
||||
|
|
|
|||
|
|
@ -7,13 +7,9 @@
|
|||
//
|
||||
|
||||
protocol PGPInterface {
|
||||
func decrypt(encryptedData: Data, keyIDHint: String?, passPhraseForKey: @escaping (String) -> String) throws -> Data?
|
||||
func decrypt(encryptedData: Data, keyID: String?, passphrase: String) throws -> Data?
|
||||
|
||||
@available(*, deprecated, message: "Use encrypt(plainData:keyIDs:) instead.")
|
||||
func encrypt(plainData: Data, keyID: String?) throws -> Data
|
||||
// encrypt with all public keys for which we also have a private key
|
||||
func encryptWithAllKeys(plainData: Data) throws -> Data
|
||||
func encrypt(plainData: Data, keyIDs: [String]) throws -> Data
|
||||
|
||||
func containsPublicKey(with keyID: String) -> Bool
|
||||
|
||||
|
|
|
|||
|
|
@ -420,9 +420,9 @@ public class PasswordStore {
|
|||
}
|
||||
|
||||
public func encrypt(password: Password, keyID: String? = nil) throws -> Data {
|
||||
let encryptedDataPath = password.fileURL(in: storeURL)
|
||||
let keyID = keyID ?? findGPGID(from: encryptedDataPath)
|
||||
if Defaults.isEnableGPGIDOn {
|
||||
let encryptedDataPath = password.fileURL(in: storeURL)
|
||||
let keyID = keyID ?? findGPGID(from: encryptedDataPath)
|
||||
return try PGPAgent.shared.encrypt(plainData: password.plainData, keyID: keyID)
|
||||
}
|
||||
return try PGPAgent.shared.encrypt(plainData: password.plainData)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,34 @@ final class PGPAgentTest: XCTestCase {
|
|||
super.tearDown()
|
||||
}
|
||||
|
||||
// - MARK: Basic encrypt and decrypt tests
|
||||
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)
|
||||
passKit.Defaults.encryptInArmored = decryptFromArmored
|
||||
return try pgpAgent.decrypt(encryptedData: encryptedData, keyID: encryptKeyID ?? keyID, requestPGPKeyPassphrase: requestPassphrase)
|
||||
}
|
||||
|
||||
func testMultiKeys() throws {
|
||||
try [
|
||||
RSA2048_RSA4096,
|
||||
ED25519_NISTP384,
|
||||
].forEach { testKeyInfo in
|
||||
keychain.removeAllContent()
|
||||
try importKeys(testKeyInfo.publicKeys, testKeyInfo.privateKeys)
|
||||
XCTAssert(pgpAgent.isPrepared)
|
||||
try pgpAgent.initKeys()
|
||||
try [
|
||||
(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 [
|
||||
|
|
@ -134,113 +161,8 @@ final class PGPAgentTest: XCTestCase {
|
|||
XCTAssertEqual(passphraseRequestCalledCount, 3)
|
||||
}
|
||||
|
||||
func testMultipleKeysLoaded() throws {
|
||||
try [
|
||||
RSA2048_RSA4096,
|
||||
ED25519_NISTP384,
|
||||
].forEach { testKeyInfo in
|
||||
keychain.removeAllContent()
|
||||
try importKeys(testKeyInfo.publicKeys, testKeyInfo.privateKeys)
|
||||
XCTAssert(pgpAgent.isPrepared)
|
||||
try pgpAgent.initKeys()
|
||||
try [
|
||||
(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 testMultiKeysSelectMatchingPrivateKeyToDecrypt() throws {
|
||||
keychain.removeAllContent()
|
||||
try importKeys(RSA2048_RSA4096.publicKeys, RSA2048_RSA4096.privateKeys)
|
||||
try pgpAgent.initKeys()
|
||||
try [
|
||||
(true, true),
|
||||
(true, false),
|
||||
(false, true),
|
||||
(false, false),
|
||||
].forEach { encryptInArmored, decryptFromArmored in
|
||||
passKit.Defaults.encryptInArmored = encryptInArmored
|
||||
let encryptedData = try pgpAgent.encrypt(plainData: testData, keyIDs: [RSA2048.fingerprint])
|
||||
passKit.Defaults.encryptInArmored = decryptFromArmored
|
||||
// Note: not specifying the keyID to decrypt, so that the agent needs to find the matching private key by itself.
|
||||
let decryptedData = try pgpAgent.decrypt(encryptedData: encryptedData, requestPGPKeyPassphrase: requestPGPKeyPassphrase)
|
||||
XCTAssertEqual(decryptedData, testData)
|
||||
}
|
||||
}
|
||||
|
||||
// - MARK: Encrypt with multiple keys
|
||||
|
||||
func testEncryptWithMultipleKeys() throws {
|
||||
keychain.removeAllContent()
|
||||
// no private key for ED25519
|
||||
try importKeys(RSA2048_RSA4096.publicKeys | ED25519.publicKey, RSA2048_RSA4096.privateKeys)
|
||||
try pgpAgent.initKeys()
|
||||
|
||||
let encryptedData = try pgpAgent.encrypt(plainData: testData, keyIDs: RSA2048_RSA4096.fingerprints + [ED25519.fingerprint])
|
||||
|
||||
try [RSA2048.fingerprint, RSA4096.fingerprint].forEach { keyID in
|
||||
let decryptedData = try pgpAgent.decrypt(encryptedData: encryptedData, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase)
|
||||
XCTAssertEqual(decryptedData, testData)
|
||||
}
|
||||
|
||||
XCTAssertThrowsError(try pgpAgent.decrypt(encryptedData: encryptedData, keyID: ED25519.fingerprint, requestPGPKeyPassphrase: requestPGPKeyPassphrase)) {
|
||||
XCTAssertEqual($0 as! AppError, AppError.pgpPrivateKeyNotFound(keyID: ED25519.fingerprint))
|
||||
}
|
||||
|
||||
// load private key for ED25519
|
||||
try importKeys(RSA2048_RSA4096.publicKeys | ED25519.publicKey, RSA2048_RSA4096.privateKeys | ED25519.privateKey)
|
||||
try pgpAgent.initKeys()
|
||||
let decryptedData = try pgpAgent.decrypt(encryptedData: encryptedData, keyID: ED25519.fingerprint, requestPGPKeyPassphrase: requestPGPKeyPassphrase)
|
||||
XCTAssertEqual(decryptedData, testData)
|
||||
}
|
||||
|
||||
func testEncryptWithAllKeys() throws {
|
||||
// When multiple keys are imported, the agent should be able to encrypt without specifying the keyID.
|
||||
// It should use all public keys for which we also have private keys, and the encrypted message should be able to be decrypted by any of the private keys.
|
||||
|
||||
keychain.removeAllContent()
|
||||
// no private key for ED25519
|
||||
try importKeys(RSA2048_RSA4096.publicKeys | ED25519.publicKey, RSA2048_RSA4096.privateKeys)
|
||||
try pgpAgent.initKeys()
|
||||
|
||||
let encryptedData = try pgpAgent.encryptWithAllKeys(plainData: testData)
|
||||
|
||||
try [RSA2048.fingerprint, RSA4096.fingerprint].forEach { keyID in
|
||||
let decryptedData = try pgpAgent.decrypt(encryptedData: encryptedData, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase)
|
||||
XCTAssertEqual(decryptedData, testData)
|
||||
}
|
||||
|
||||
XCTAssertThrowsError(try pgpAgent.decrypt(encryptedData: encryptedData, keyID: ED25519.fingerprint, requestPGPKeyPassphrase: requestPGPKeyPassphrase)) {
|
||||
XCTAssertEqual($0 as! AppError, AppError.pgpPrivateKeyNotFound(keyID: ED25519.fingerprint))
|
||||
}
|
||||
|
||||
// load private key for ED25519
|
||||
try importKeys(RSA2048_RSA4096.publicKeys | ED25519.publicKey, RSA2048_RSA4096.privateKeys | ED25519.privateKey)
|
||||
try pgpAgent.initKeys()
|
||||
|
||||
XCTAssertThrowsError(try pgpAgent.decrypt(encryptedData: encryptedData, keyID: ED25519.fingerprint, requestPGPKeyPassphrase: requestPGPKeyPassphrase)) {
|
||||
XCTAssertEqual($0 as! AppError, AppError.keyExpiredOrIncompatible)
|
||||
}
|
||||
}
|
||||
|
||||
// - MARK: Helpers
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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, keyIDs: [keyID])
|
||||
passKit.Defaults.encryptInArmored = decryptFromArmored
|
||||
return try pgpAgent.decrypt(encryptedData: encryptedData, keyID: encryptKeyID ?? keyID, requestPGPKeyPassphrase: requestPassphrase)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ GOPENPGP_PATH="$CHECKOUT_PATH/gopenpgp"
|
|||
mkdir -p "$OUTPUT_PATH"
|
||||
mkdir -p "$CHECKOUT_PATH"
|
||||
|
||||
git clone --depth 1 --branch "$GOPENPGP_VERSION" https://forgejo.tranvouez.eu/lysann/passforios-gopenpgp.git "$GOPENPGP_PATH"
|
||||
git clone --depth 1 --branch "$GOPENPGP_VERSION" https://github.com/mssun/gopenpgp.git "$GOPENPGP_PATH"
|
||||
|
||||
pushd "$GOPENPGP_PATH"
|
||||
mkdir -p dist
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue