passforios/passKit/Crypto/PGPAgent.swift

149 lines
5 KiB
Swift
Raw Normal View History

//
// PGPAgent.swift
// passKit
//
// Created by Yishi Lin on 2019/7/17.
// Copyright © 2019 Bob Sun. All rights reserved.
//
public class PGPAgent {
public static let shared = PGPAgent()
private let keyStore: KeyStore
2020-04-19 15:41:30 +02:00
private var pgpInterface: PGPInterface?
2021-03-06 15:26:42 +01:00
private var latestDecryptStatus = true
public init(keyStore: KeyStore = AppKeychain.shared) {
self.keyStore = keyStore
}
init(keyStore: KeyStore, pgpInterface: PGPInterface) {
self.keyStore = keyStore
self.pgpInterface = pgpInterface
}
public func initKeys() throws {
guard let publicKey: String = keyStore.get(for: PGPKey.PUBLIC.getKeychainKey()),
let privateKey: String = keyStore.get(for: PGPKey.PRIVATE.getKeychainKey()) else {
pgpInterface = nil
throw AppError.keyImport
}
do {
2020-04-19 15:41:30 +02:00
pgpInterface = try GopenPGPInterface(publicArmoredKey: publicKey, privateArmoredKey: privateKey)
} catch {
2020-04-19 15:41:30 +02:00
pgpInterface = try ObjectivePGPInterface(publicArmoredKey: publicKey, privateArmoredKey: privateKey)
}
}
public func uninitKeys() {
pgpInterface = nil
}
2026-03-09 00:34:34 +01:00
public func isInitialized() -> Bool {
pgpInterface != nil
}
public func getKeyID() throws -> [String] {
2019-10-01 01:19:41 +08:00
try checkAndInit()
return pgpInterface?.keyID ?? []
}
public func getShortKeyID() throws -> [String] {
2020-04-11 23:23:38 -07:00
try checkAndInit()
return pgpInterface?.shortKeyID.sorted() ?? []
2020-04-11 23:23:38 -07:00
}
public func decrypt(encryptedData: Data, keyID: String, requestPGPKeyPassphrase: @escaping (String) -> String) throws -> Data? {
// Init keys.
try checkAndInit()
guard let pgpInterface else {
throw AppError.decryption
}
var keyID = keyID
if !pgpInterface.containsPrivateKey(with: keyID) {
if pgpInterface.keyID.count == 1 {
keyID = pgpInterface.keyID.first!
} else {
throw AppError.pgpPrivateKeyNotFound(keyID: keyID)
}
}
// Remember the previous status and set the current status
let previousDecryptStatus = latestDecryptStatus
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)
}
// Decrypt.
guard let result = try pgpInterface.decrypt(encryptedData: encryptedData, keyID: keyID, passPhraseForKey: providePassPhraseForKey) else {
return nil
}
// The decryption step has succeed.
latestDecryptStatus = true
return result
}
public func encrypt(plainData: Data, keyID: String) throws -> Data {
try checkAndInit()
guard let pgpInterface else {
throw AppError.encryption
}
var keyID = keyID
if !pgpInterface.containsPublicKey(with: keyID) {
if pgpInterface.keyID.count == 1 {
keyID = pgpInterface.keyID.first!
} else {
throw AppError.pgpPublicKeyNotFound(keyID: keyID)
}
}
return try pgpInterface.encrypt(plainData: plainData, keyID: keyID)
}
public func decrypt(encryptedData: Data, requestPGPKeyPassphrase: @escaping (String) -> String) throws -> Data? {
2021-01-07 21:58:38 -08:00
// Remember the previous status and set the current status
2021-01-31 13:17:37 +01:00
let previousDecryptStatus = latestDecryptStatus
latestDecryptStatus = false
2021-01-07 21:58:38 -08:00
// 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)
2021-01-07 21:58:38 -08:00
}
// Decrypt.
guard let result = try pgpInterface!.decrypt(encryptedData: encryptedData, keyID: nil, passPhraseForKey: providePassPhraseForKey) else {
2021-01-07 21:58:38 -08:00
return nil
}
// The decryption step has succeed.
2021-01-31 13:17:37 +01:00
latestDecryptStatus = true
2021-01-07 21:58:38 -08:00
return result
}
public func encrypt(plainData: Data) throws -> Data {
try checkAndInit()
guard let pgpInterface else {
2021-01-07 21:58:38 -08:00
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())
}
private func checkAndInit() throws {
if pgpInterface == nil || !keyStore.contains(key: Globals.pgpKeyPassphrase) {
try initKeys()
}
}
}