Separate encryption/decryption logic for different frameworks used
This commit is contained in:
parent
e2201ffa52
commit
730542d5bb
24 changed files with 428 additions and 414 deletions
|
|
@ -63,6 +63,9 @@
|
|||
30C25DD721F4834D00BB27BB /* UILocalizedLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C25DD521F4834D00BB27BB /* UILocalizedLabel.swift */; };
|
||||
30C25DD821F4834D00BB27BB /* UICodeHighlightingLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C25DD621F4834D00BB27BB /* UICodeHighlightingLabel.swift */; };
|
||||
30CCA90B2325119C0048CA51 /* Data+Mutable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCA90A2325119C0048CA51 /* Data+Mutable.swift */; };
|
||||
30CCA91623258C380048CA51 /* PgpInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCA91523258C380048CA51 /* PgpInterface.swift */; };
|
||||
30CCA91823258E760048CA51 /* GopenPgp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCA91723258E760048CA51 /* GopenPgp.swift */; };
|
||||
30CCA91A232591320048CA51 /* ObjectivePgp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCA919232591320048CA51 /* ObjectivePgp.swift */; };
|
||||
30FD2F78214D9E0E005E0A92 /* ParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30FD2F77214D9E0E005E0A92 /* ParserTest.swift */; };
|
||||
3EA2386CD0E9CE2A702A0B3E /* Pods_pass.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FE627E8F3DACEDD8FA220081 /* Pods_pass.framework */; };
|
||||
556EC3D322335C5F00934F9C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30BF5ECA21EA8FB5000E4154 /* Localizable.strings */; };
|
||||
|
|
@ -280,6 +283,9 @@
|
|||
30C25DD521F4834D00BB27BB /* UILocalizedLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UILocalizedLabel.swift; sourceTree = "<group>"; };
|
||||
30C25DD621F4834D00BB27BB /* UICodeHighlightingLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UICodeHighlightingLabel.swift; sourceTree = "<group>"; };
|
||||
30CCA90A2325119C0048CA51 /* Data+Mutable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Mutable.swift"; sourceTree = "<group>"; };
|
||||
30CCA91523258C380048CA51 /* PgpInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PgpInterface.swift; sourceTree = "<group>"; };
|
||||
30CCA91723258E760048CA51 /* GopenPgp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GopenPgp.swift; sourceTree = "<group>"; };
|
||||
30CCA919232591320048CA51 /* ObjectivePgp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectivePgp.swift; sourceTree = "<group>"; };
|
||||
30FD2F77214D9E0E005E0A92 /* ParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParserTest.swift; sourceTree = "<group>"; };
|
||||
3B2B2F844061EFA534FE9506 /* Pods_passKitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_passKitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
62DEE9943E0F2B8C79E3FC5B /* Pods-passExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-passExtension.release.xcconfig"; path = "Pods/Target Support Files/Pods-passExtension/Pods-passExtension.release.xcconfig"; sourceTree = "<group>"; };
|
||||
|
|
@ -469,6 +475,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
30A86F94230F237000F821A4 /* CryptoFrameworkTest.swift */,
|
||||
A2AA934522DE3A8000D79A00 /* PGPAgentTest.swift */,
|
||||
);
|
||||
path = Crypto;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -525,7 +532,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
30B0485F209A5141001013CA /* PasswordTest.swift */,
|
||||
A2AA934522DE3A8000D79A00 /* PGPAgentTest.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -540,6 +546,17 @@
|
|||
path = UserInterface;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
30CCA90C232584560048CA51 /* Crypto */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
30CCA91723258E760048CA51 /* GopenPgp.swift */,
|
||||
30CCA919232591320048CA51 /* ObjectivePgp.swift */,
|
||||
A2AA934322DE30DD00D79A00 /* PGPAgent.swift */,
|
||||
30CCA91523258C380048CA51 /* PgpInterface.swift */,
|
||||
);
|
||||
path = Crypto;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A2168A801EFD431A005EA873 /* Controllers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -580,6 +597,7 @@
|
|||
A26075791EEC6F34005DB03E /* passKit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
30CCA90C232584560048CA51 /* Crypto */,
|
||||
A2C532B9201DD07500DB9F53 /* Controllers */,
|
||||
30B6AABA21F49095006B352D /* Extensions */,
|
||||
A2F4E20F1EED7F0A0011986E /* Helpers */,
|
||||
|
|
@ -638,7 +656,6 @@
|
|||
30697C4021F63CAB0064FCAC /* Password.swift */,
|
||||
30697C3F21F63CAA0064FCAC /* PasswordEntity.swift */,
|
||||
30697C4321F63CAB0064FCAC /* PasswordStore.swift */,
|
||||
A2AA934322DE30DD00D79A00 /* PGPAgent.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -1293,10 +1310,12 @@
|
|||
A2AA934422DE30DD00D79A00 /* PGPAgent.swift in Sources */,
|
||||
30697C3B21F63C990064FCAC /* String+Localization.swift in Sources */,
|
||||
302E85612125ECC70031BA64 /* Parser.swift in Sources */,
|
||||
30CCA91A232591320048CA51 /* ObjectivePgp.swift in Sources */,
|
||||
30697C4621F63CAB0064FCAC /* GitCredential.swift in Sources */,
|
||||
30A1D2A621B2D46100E2D1F7 /* OtpType.swift in Sources */,
|
||||
3032328E22CBD4CD009EBD9C /* CryptographicKeys.swift in Sources */,
|
||||
30697C2A21F63C5A0064FCAC /* NotificationNames.swift in Sources */,
|
||||
30CCA91623258C380048CA51 /* PgpInterface.swift in Sources */,
|
||||
30697C4721F63CAB0064FCAC /* PasscodeLock.swift in Sources */,
|
||||
30697C3421F63C8B0064FCAC /* PasscodeLockViewController.swift in Sources */,
|
||||
30697C2C21F63C5A0064FCAC /* FileManagerExtension.swift in Sources */,
|
||||
|
|
@ -1304,6 +1323,7 @@
|
|||
30697C3D21F63C990064FCAC /* UIViewExtension.swift in Sources */,
|
||||
30697C3A21F63C990064FCAC /* UIViewControllerExtension.swift in Sources */,
|
||||
30697C2E21F63C5A0064FCAC /* Utils.swift in Sources */,
|
||||
30CCA91823258E760048CA51 /* GopenPgp.swift in Sources */,
|
||||
30697C4521F63CAB0064FCAC /* Password.swift in Sources */,
|
||||
30697C4421F63CAB0064FCAC /* PasswordEntity.swift in Sources */,
|
||||
30BAC8CD22E3BB9700438475 /* KeyStore.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class AddPasswordTableViewController: PasswordEditorTableViewController {
|
|||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
if identifier == "saveAddPasswordSegue" {
|
||||
// check PGP key
|
||||
guard passwordStore.pgpAgent.isImported else {
|
||||
guard PGPAgent.shared.isPrepared else {
|
||||
let alertTitle = "CannotAddPassword".localize()
|
||||
let alertMessage = "PgpKeyNotSet.".localize()
|
||||
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
@objc func rememberPGPPassphraseSwitchAction(_ sender: Any?) {
|
||||
SharedDefaults[.isRememberPGPPassphraseOn] = rememberPGPPassphraseSwitch.isOn
|
||||
if rememberPGPPassphraseSwitch.isOn == false {
|
||||
passwordStore.pgpAgent.passphrase = nil
|
||||
AppKeychain.shared.removeContent(for: Globals.pgpKeyPassphrase)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ class PGPKeyArmorSettingTableViewController: AutoCellHeightUITableViewController
|
|||
@IBOutlet weak var scanPublicKeyCell: UITableViewCell!
|
||||
@IBOutlet weak var scanPrivateKeyCell: UITableViewCell!
|
||||
|
||||
var pgpPassphrase: String?
|
||||
let passwordStore = PasswordStore.shared
|
||||
let keychain = AppKeychain.shared
|
||||
|
||||
class ScannedPGPKey {
|
||||
static let maxNumberOfGif = 100
|
||||
|
|
@ -91,8 +91,6 @@ class PGPKeyArmorSettingTableViewController: AutoCellHeightUITableViewController
|
|||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
pgpPassphrase = passwordStore.pgpAgent.passphrase
|
||||
|
||||
scanPublicKeyCell?.textLabel?.text = "ScanPublicKeyQrCodes".localize()
|
||||
scanPublicKeyCell?.textLabel?.textColor = Globals.blue
|
||||
scanPublicKeyCell?.selectionStyle = .default
|
||||
|
|
@ -116,7 +114,7 @@ class PGPKeyArmorSettingTableViewController: AutoCellHeightUITableViewController
|
|||
let savePassphraseAlert = UIAlertController(title: "Passphrase".localize(), message: "WantToSavePassphrase?".localize(), preferredStyle: UIAlertController.Style.alert)
|
||||
// no
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: UIAlertAction.Style.default) { _ in
|
||||
self.pgpPassphrase = nil
|
||||
self.keychain.removeContent(for: Globals.pgpKeyPassphrase)
|
||||
SharedDefaults[.isRememberPGPPassphraseOn] = false
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
})
|
||||
|
|
@ -125,12 +123,12 @@ class PGPKeyArmorSettingTableViewController: AutoCellHeightUITableViewController
|
|||
// ask for the passphrase
|
||||
let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertController.Style.alert)
|
||||
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertAction.Style.default, handler: {_ in
|
||||
self.pgpPassphrase = alert.textFields?.first?.text
|
||||
self.keychain.add(string: alert.textFields?.first?.text, for: Globals.pgpKeyPassphrase)
|
||||
SharedDefaults[.isRememberPGPPassphraseOn] = true
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
}))
|
||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = self.pgpPassphrase
|
||||
textField.text = self.keychain.get(for: Globals.pgpKeyPassphrase)
|
||||
textField.isSecureTextEntry = true
|
||||
})
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
|
|
|
|||
|
|
@ -13,14 +13,14 @@ class PGPKeySettingTableViewController: AutoCellHeightUITableViewController {
|
|||
|
||||
@IBOutlet weak var pgpPublicKeyURLTextField: UITextField!
|
||||
@IBOutlet weak var pgpPrivateKeyURLTextField: UITextField!
|
||||
var pgpPassphrase: String?
|
||||
|
||||
let passwordStore = PasswordStore.shared
|
||||
let keychain = AppKeychain.shared
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
pgpPublicKeyURLTextField.text = SharedDefaults[.pgpPublicKeyURL]?.absoluteString
|
||||
pgpPrivateKeyURLTextField.text = SharedDefaults[.pgpPrivateKeyURL]?.absoluteString
|
||||
pgpPassphrase = passwordStore.pgpAgent.passphrase
|
||||
}
|
||||
|
||||
private func validatePGPKeyURL(input: String?) -> Bool {
|
||||
|
|
@ -43,7 +43,7 @@ class PGPKeySettingTableViewController: AutoCellHeightUITableViewController {
|
|||
let savePassphraseAlert = UIAlertController(title: "Passphrase".localize(), message: "WantToSavePassphrase?".localize(), preferredStyle: UIAlertController.Style.alert)
|
||||
// no
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: UIAlertAction.Style.default) { _ in
|
||||
self.pgpPassphrase = nil
|
||||
self.keychain.removeContent(for: Globals.pgpKeyPassphrase)
|
||||
SharedDefaults[.isRememberPGPPassphraseOn] = false
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
})
|
||||
|
|
@ -52,12 +52,12 @@ class PGPKeySettingTableViewController: AutoCellHeightUITableViewController {
|
|||
// ask for the passphrase
|
||||
let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertController.Style.alert)
|
||||
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertAction.Style.default, handler: {_ in
|
||||
self.pgpPassphrase = alert.textFields?.first?.text
|
||||
self.keychain.add(string: alert.textFields?.first?.text, for: Globals.pgpKeyPassphrase)
|
||||
SharedDefaults[.isRememberPGPPassphraseOn] = true
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
}))
|
||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = self.pgpPassphrase
|
||||
textField.text = self.keychain.get(for: Globals.pgpKeyPassphrase)
|
||||
textField.isSecureTextEntry = true
|
||||
})
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
let _ = sem.wait(timeout: DispatchTime.distantFuture)
|
||||
if SharedDefaults[.isRememberPGPPassphraseOn] {
|
||||
self.passwordStore.pgpAgent.passphrase = passphrase
|
||||
AppKeychain.shared.add(string: passphrase, for: Globals.pgpKeyPassphrase)
|
||||
}
|
||||
return passphrase
|
||||
}
|
||||
|
|
@ -122,7 +122,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
// remove the wrong passphrase so that users could enter it next time
|
||||
self.passwordStore.pgpAgent.passphrase = nil
|
||||
AppKeychain.shared.removeContent(for: Globals.pgpKeyPassphrase)
|
||||
// alert: cancel or try again
|
||||
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: error.localizedDescription, preferredStyle: UIAlertController.Style.alert)
|
||||
alert.addAction(UIAlertAction(title: "Cancel".localize(), style: UIAlertAction.Style.default) { _ in
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
private var filteredPasswordsTableEntries: [PasswordsTableEntry] = []
|
||||
private var parentPasswordEntity: PasswordEntity? = nil
|
||||
private let passwordStore = PasswordStore.shared
|
||||
private let keychain = AppKeychain.shared
|
||||
|
||||
private var tapTabBarTime: TimeInterval = 0
|
||||
|
||||
|
|
@ -385,13 +386,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
SVProgressHUD.show(withStatus: "Decrypting".localize())
|
||||
}
|
||||
if SharedDefaults[.isRememberPGPPassphraseOn] {
|
||||
self.passwordStore.pgpAgent.passphrase = passphrase
|
||||
keychain.add(string: passphrase, for: Globals.pgpKeyPassphrase)
|
||||
}
|
||||
return passphrase
|
||||
}
|
||||
|
||||
private func decryptThenCopyPassword(from indexPath: IndexPath) {
|
||||
guard self.passwordStore.pgpAgent.isImported else {
|
||||
guard PGPAgent.shared.isPrepared else {
|
||||
Utils.alert(title: "CannotCopyPassword".localize(), message: "SetPgpKey.".localize(), controller: self, completion: nil)
|
||||
return
|
||||
}
|
||||
|
|
@ -412,7 +413,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
// remove the wrong passphrase so that users could enter it next time
|
||||
self.passwordStore.pgpAgent.passphrase = nil
|
||||
self.keychain.removeContent(for: Globals.pgpKeyPassphrase)
|
||||
Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||
}
|
||||
}
|
||||
|
|
@ -453,7 +454,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
if identifier == "showPasswordDetail" {
|
||||
guard self.passwordStore.pgpAgent.isImported else {
|
||||
guard PGPAgent.shared.isPrepared else {
|
||||
Utils.alert(title: "CannotShowPassword".localize(), message: "SetPgpKey.".localize(), controller: self, completion: nil)
|
||||
if let s = sender as? UITableViewCell {
|
||||
let selectedIndexPath = tableView.indexPath(for: s)!
|
||||
|
|
@ -462,7 +463,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
return false
|
||||
}
|
||||
} else if identifier == "addPasswordSegue" {
|
||||
guard self.passwordStore.pgpAgent.isImported && self.passwordStore.storeRepository != nil else {
|
||||
guard PGPAgent.shared.isPrepared && self.passwordStore.storeRepository != nil else {
|
||||
Utils.alert(title: "CannotAddPassword".localize(), message: "MakeSurePgpAndGitProperlySet.".localize(), controller: self, completion: nil)
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
var setPasscodeLockAlert: UIAlertController?
|
||||
|
||||
let passwordStore = PasswordStore.shared
|
||||
let keychain = AppKeychain.shared
|
||||
var passcodeLock = PasscodeLock.shared
|
||||
|
||||
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
|
||||
|
|
@ -28,9 +29,6 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
if let controller = segue.source as? PGPKeySettingTableViewController {
|
||||
SharedDefaults[.pgpPrivateKeyURL] = URL(string: controller.pgpPrivateKeyURLTextField.text!.trimmed)
|
||||
SharedDefaults[.pgpPublicKeyURL] = URL(string: controller.pgpPublicKeyURLTextField.text!.trimmed)
|
||||
if SharedDefaults[.isRememberPGPPassphraseOn] {
|
||||
self.passwordStore.pgpAgent.passphrase = controller.pgpPassphrase
|
||||
}
|
||||
SharedDefaults[.pgpKeySource] = "url"
|
||||
|
||||
SVProgressHUD.setDefaultMaskType(.black)
|
||||
|
|
@ -38,10 +36,11 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
SVProgressHUD.show(withStatus: "FetchingPgpKey".localize())
|
||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||
do {
|
||||
try self.passwordStore.pgpAgent.initPGPKey(from: SharedDefaults[.pgpPublicKeyURL]!, keyType: .PUBLIC)
|
||||
try self.passwordStore.pgpAgent.initPGPKey(from: SharedDefaults[.pgpPrivateKeyURL]!, keyType: .PRIVATE)
|
||||
try KeyFileManager.PublicPgp.importKey(from: SharedDefaults[.pgpPublicKeyURL]!)
|
||||
try KeyFileManager.PrivatePgp.importKey(from: SharedDefaults[.pgpPrivateKeyURL]!)
|
||||
try PGPAgent.shared.initKeys()
|
||||
DispatchQueue.main.async {
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpAgent.pgpKeyID
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = PGPAgent.shared.keyId
|
||||
SVProgressHUD.showSuccess(withStatus: "Success".localize())
|
||||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
Utils.alert(title: "RememberToRemoveKey".localize(), message: "RememberToRemoveKeyFromServer.".localize(), controller: self, completion: nil)
|
||||
|
|
@ -56,18 +55,17 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
|
||||
} else if let controller = segue.source as? PGPKeyArmorSettingTableViewController {
|
||||
SharedDefaults[.pgpKeySource] = "armor"
|
||||
if SharedDefaults[.isRememberPGPPassphraseOn] {
|
||||
self.passwordStore.pgpAgent.passphrase = controller.pgpPassphrase
|
||||
}
|
||||
|
||||
SVProgressHUD.setDefaultMaskType(.black)
|
||||
SVProgressHUD.setDefaultStyle(.light)
|
||||
SVProgressHUD.show(withStatus: "FetchingPgpKey".localize())
|
||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||
do {
|
||||
try self.passwordStore.pgpAgent.initPGPKey(with: controller.armorPublicKeyTextView.text ?? "", keyType: .PUBLIC)
|
||||
try self.passwordStore.pgpAgent.initPGPKey(with: controller.armorPrivateKeyTextView.text ?? "", keyType: .PRIVATE)
|
||||
try KeyFileManager.PublicPgp.importKey(from: controller.armorPublicKeyTextView.text ?? "")
|
||||
try KeyFileManager.PrivatePgp.importKey(from: controller.armorPrivateKeyTextView.text ?? "")
|
||||
try PGPAgent.shared.initKeys()
|
||||
DispatchQueue.main.async {
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpAgent.pgpKeyID
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = PGPAgent.shared.keyId
|
||||
SVProgressHUD.showSuccess(withStatus: "Success".localize())
|
||||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
}
|
||||
|
|
@ -89,9 +87,11 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
SVProgressHUD.show(withStatus: "FetchingPgpKey".localize())
|
||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||
do {
|
||||
try self.passwordStore.pgpAgent.initPGPKeyFromFileSharing()
|
||||
try KeyFileManager.PublicPgp.importKeyFromFileSharing()
|
||||
try KeyFileManager.PrivatePgp.importKeyFromFileSharing()
|
||||
try PGPAgent.shared.initKeys()
|
||||
DispatchQueue.main.async {
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpAgent.pgpKeyID
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = PGPAgent.shared.keyId
|
||||
SVProgressHUD.showSuccess(withStatus: "Imported".localize())
|
||||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
}
|
||||
|
|
@ -135,11 +135,8 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
}
|
||||
|
||||
private func setPGPKeyTableViewCellDetailText() {
|
||||
if let pgpKeyID = self.passwordStore.pgpAgent.pgpKeyID {
|
||||
pgpKeyTableViewCell.detailTextLabel?.text = pgpKeyID
|
||||
} else {
|
||||
pgpKeyTableViewCell.detailTextLabel?.text = "NotSet".localize()
|
||||
}
|
||||
try? PGPAgent.shared.initKeys()
|
||||
pgpKeyTableViewCell.detailTextLabel?.text = PGPAgent.shared.keyId ?? "NotSet".localize()
|
||||
}
|
||||
|
||||
private func setPasswordRepositoryTableViewCellDetailText() {
|
||||
|
|
@ -192,14 +189,14 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
optionMenu.addAction(urlAction)
|
||||
optionMenu.addAction(armorAction)
|
||||
|
||||
if passwordStore.pgpAgent.isFileSharingReady {
|
||||
if KeyFileManager.PublicPgp.doesKeyFileExist() && KeyFileManager.PrivatePgp.doesKeyFileExist() {
|
||||
fileActionTitle.append(" (\("Import".localize()))")
|
||||
let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
||||
// passphrase related
|
||||
let savePassphraseAlert = UIAlertController(title: "Passphrase".localize(), message: "WantToSavePassphrase?".localize(), preferredStyle: UIAlertController.Style.alert)
|
||||
// no
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: UIAlertAction.Style.default) { _ in
|
||||
self.passwordStore.pgpAgent.passphrase = nil
|
||||
self.keychain.removeContent(for: Globals.pgpKeyPassphrase)
|
||||
SharedDefaults[.isRememberPGPPassphraseOn] = false
|
||||
self.saveImportedPGPKey()
|
||||
})
|
||||
|
|
@ -208,7 +205,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
// ask for the passphrase
|
||||
let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertController.Style.alert)
|
||||
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertAction.Style.default, handler: {_ in
|
||||
self.passwordStore.pgpAgent.passphrase = alert.textFields?.first?.text
|
||||
self.keychain.add(string: alert.textFields?.first?.text, for: Globals.pgpKeyPassphrase)
|
||||
SharedDefaults[.isRememberPGPPassphraseOn] = true
|
||||
self.saveImportedPGPKey()
|
||||
}))
|
||||
|
|
@ -234,7 +231,9 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
|
||||
if SharedDefaults[.pgpKeySource] != nil {
|
||||
let deleteAction = UIAlertAction(title: "RemovePgpKeys".localize(), style: .destructive) { _ in
|
||||
self.passwordStore.removePGPKeys()
|
||||
self.keychain.removeContent(for: PgpKey.PUBLIC.getKeychainKey())
|
||||
self.keychain.removeContent(for: PgpKey.PRIVATE.getKeychainKey())
|
||||
PGPAgent.shared.uninitKeys()
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = "NotSet".localize()
|
||||
}
|
||||
optionMenu.addAction(deleteAction)
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@
|
|||
"PGPPublicKeyNotExistError." = "Der öffentliche PGP-Schlüssen existiert nicht";
|
||||
"WrongPasswordFilename." = "Schreiben der Passwort-Datei nicht möglich .";
|
||||
"DecryptionError." = "Passwort kann nicht entschlüsselt werden.";
|
||||
"EncodingError." = "Schlüssel ist nicht in ASCII kodiert.";
|
||||
"UnknownError." = "Ein unbekannter Fehler ist aufgetreten.";
|
||||
"PrepareRepository" = "Repository vorbereiten";
|
||||
"CheckingOutBranch" = "Branch '%@' wird ausgecheckt";
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@
|
|||
"PgpPublicKeyNotExistError." = "PGP public key doesn't exist.";
|
||||
"WrongPasswordFilenameError." = "Cannot write to the password file.";
|
||||
"DecryptionError." = "Cannot decrypt password.";
|
||||
"EncodingError." = "Key is not ASCII encoded.";
|
||||
"UnknownError." = "Unknown error.";
|
||||
"PrepareRepository" = "Prepare Repository";
|
||||
"CheckingOutBranch" = "Checking out branch '%@'";
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa
|
|||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let entry = getPasswordEntry(by: indexPath)
|
||||
|
||||
guard self.passwordStore.pgpAgent.isImported else {
|
||||
guard PGPAgent.shared.isPrepared else {
|
||||
Utils.alert(title: "CannotCopyPassword".localize(), message: "PgpKeyNotSet.".localize(), controller: self, completion: nil)
|
||||
return
|
||||
}
|
||||
|
|
@ -165,7 +165,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa
|
|||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
// remove the wrong passphrase so that users could enter it next time
|
||||
self.passwordStore.pgpAgent.passphrase = nil
|
||||
AppKeychain.shared.removeContent(for: Globals.pgpKeyPassphrase)
|
||||
Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||
}
|
||||
}
|
||||
|
|
@ -200,7 +200,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa
|
|||
}
|
||||
let _ = sem.wait(timeout: DispatchTime.distantFuture)
|
||||
if SharedDefaults[.isRememberPGPPassphraseOn] {
|
||||
self.passwordStore.pgpAgent.passphrase = passphrase
|
||||
AppKeychain.shared.add(string: passphrase, for: Globals.pgpKeyPassphrase)
|
||||
}
|
||||
return passphrase
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
@IBOutlet weak var tableView: UITableView!
|
||||
|
||||
private let passwordStore = PasswordStore.shared
|
||||
private let keychain = AppKeychain.shared
|
||||
|
||||
private var searchActive = false
|
||||
private var passwordsTableEntries: [PasswordsTableEntry] = []
|
||||
|
|
@ -153,7 +154,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let entry = getPasswordEntry(by: indexPath)
|
||||
|
||||
guard self.passwordStore.pgpAgent.isImported else {
|
||||
guard PGPAgent.shared.isPrepared else {
|
||||
Utils.alert(title: "CannotCopyPassword".localize(), message: "PgpKeyNotSet.".localize(), controller: self, completion: nil)
|
||||
return
|
||||
}
|
||||
|
|
@ -191,7 +192,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
// remove the wrong passphrase so that users could enter it next time
|
||||
self.passwordStore.pgpAgent.passphrase = nil
|
||||
self.keychain.removeContent(for: Globals.pgpKeyPassphrase)
|
||||
Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||
}
|
||||
}
|
||||
|
|
@ -227,7 +228,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
let _ = sem.wait(timeout: DispatchTime.distantFuture)
|
||||
if SharedDefaults[.isRememberPGPPassphraseOn] {
|
||||
self.passwordStore.pgpAgent.passphrase = passphrase
|
||||
self.keychain.add(string: passphrase, for: Globals.pgpKeyPassphrase)
|
||||
}
|
||||
return passphrase
|
||||
}
|
||||
|
|
|
|||
57
passKit/Crypto/GopenPgp.swift
Normal file
57
passKit/Crypto/GopenPgp.swift
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// GopenPgp.swift
|
||||
// passKit
|
||||
//
|
||||
// Created by Danny Moesch on 08.09.19.
|
||||
// Copyright © 2019 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import Crypto
|
||||
|
||||
struct GopenPgp: PgpInterface {
|
||||
|
||||
private let publicKey: CryptoKeyRing
|
||||
private let privateKey: CryptoKeyRing
|
||||
|
||||
init(publicArmoredKey: String, privateArmoredKey: String) throws {
|
||||
guard let pgp = CryptoGetGopenPGP() else {
|
||||
throw AppError.KeyImport
|
||||
}
|
||||
publicKey = try pgp.buildKeyRingArmored(publicArmoredKey)
|
||||
privateKey = try pgp.buildKeyRingArmored(privateArmoredKey)
|
||||
}
|
||||
|
||||
func decrypt(encryptedData: Data, passphrase: String) throws -> Data? {
|
||||
try privateKey.unlock(withPassphrase: passphrase)
|
||||
let message = createPgpMessage(from: encryptedData)
|
||||
return try privateKey.decrypt(message, verifyKey: nil, verifyTime: 0).data
|
||||
}
|
||||
|
||||
func encrypt(plainData: Data) throws -> Data {
|
||||
let encryptedData = try publicKey.encrypt(CryptoNewPlainMessage(plainData.mutable as Data), privateKey: nil)
|
||||
if SharedDefaults[.encryptInArmored] {
|
||||
var error: NSError?
|
||||
let armor = encryptedData.getArmored(&error)
|
||||
guard error == nil else {
|
||||
throw error!
|
||||
}
|
||||
return armor.data(using: .ascii)!
|
||||
}
|
||||
return encryptedData.getBinary()!
|
||||
}
|
||||
|
||||
var keyId: String {
|
||||
var error: NSError?
|
||||
let fingerprint = publicKey.getFingerprint(&error)
|
||||
return error == nil ? String(fingerprint.suffix(8)).uppercased() : ""
|
||||
}
|
||||
|
||||
private func createPgpMessage(from encryptedData: Data) -> CryptoPGPMessage? {
|
||||
if SharedDefaults[.encryptInArmored] {
|
||||
var error: NSError?
|
||||
let message = CryptoNewPGPMessageFromArmored(String(data: encryptedData, encoding: .ascii), &error)
|
||||
return error == nil ? message : nil
|
||||
}
|
||||
return CryptoNewPGPMessage(encryptedData.mutable as Data)
|
||||
}
|
||||
}
|
||||
48
passKit/Crypto/ObjectivePgp.swift
Normal file
48
passKit/Crypto/ObjectivePgp.swift
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
//
|
||||
// ObjectivePgp.swift
|
||||
// passKit
|
||||
//
|
||||
// Created by Danny Moesch on 08.09.19.
|
||||
// Copyright © 2019 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import ObjectivePGP
|
||||
|
||||
struct ObjectivePgp: PgpInterface {
|
||||
|
||||
private let publicKey: Key
|
||||
private let privateKey: Key
|
||||
|
||||
private let keyring = ObjectivePGP.defaultKeyring
|
||||
|
||||
init(publicArmoredKey: String, privateArmoredKey: String) throws {
|
||||
guard let publicKeyData = publicArmoredKey.data(using: .ascii), let privateKeyData = privateArmoredKey.data(using: .ascii) else {
|
||||
throw AppError.KeyImport
|
||||
}
|
||||
let publicKeys = try ObjectivePGP.readKeys(from: publicKeyData)
|
||||
let privateKeys = try ObjectivePGP.readKeys(from: privateKeyData)
|
||||
keyring.import(keys: publicKeys)
|
||||
keyring.import(keys: privateKeys)
|
||||
guard let publicKey = publicKeys.first, let privateKey = privateKeys.first else {
|
||||
throw AppError.KeyImport
|
||||
}
|
||||
self.publicKey = publicKey
|
||||
self.privateKey = privateKey
|
||||
}
|
||||
|
||||
func decrypt(encryptedData: Data, passphrase: String) throws -> Data? {
|
||||
return try ObjectivePGP.decrypt(encryptedData, andVerifySignature: false, using: keyring.keys) { _ in passphrase }
|
||||
}
|
||||
|
||||
func encrypt(plainData: Data) throws -> Data {
|
||||
let encryptedData = try ObjectivePGP.encrypt(plainData, addSignature: false, using: keyring.keys, passphraseForKey: nil)
|
||||
if SharedDefaults[.encryptInArmored] {
|
||||
return Armor.armored(encryptedData, as: .message).data(using: .ascii)!
|
||||
}
|
||||
return encryptedData
|
||||
}
|
||||
|
||||
var keyId: String {
|
||||
return publicKey.keyID.shortIdentifier
|
||||
}
|
||||
}
|
||||
64
passKit/Crypto/PGPAgent.swift
Normal file
64
passKit/Crypto/PGPAgent.swift
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// 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 = PGPAgent()
|
||||
|
||||
private let keyStore: KeyStore
|
||||
private var pgpInterface: PgpInterface?
|
||||
|
||||
public init(keyStore: KeyStore = AppKeychain.shared) {
|
||||
self.keyStore = keyStore
|
||||
}
|
||||
|
||||
public func initKeys() throws {
|
||||
guard let publicKey: String = keyStore.get(for: PgpKey.PUBLIC.getKeychainKey()),
|
||||
let privateKey: String = keyStore.get(for: PgpKey.PRIVATE.getKeychainKey()) else {
|
||||
throw AppError.KeyImport
|
||||
}
|
||||
do {
|
||||
pgpInterface = try GopenPgp(publicArmoredKey: publicKey, privateArmoredKey: privateKey)
|
||||
} catch {
|
||||
pgpInterface = try ObjectivePgp(publicArmoredKey: publicKey, privateArmoredKey: privateKey)
|
||||
}
|
||||
}
|
||||
|
||||
public func uninitKeys() {
|
||||
pgpInterface = nil
|
||||
}
|
||||
|
||||
public var keyId: String? {
|
||||
return pgpInterface?.keyId
|
||||
}
|
||||
|
||||
public func decrypt(encryptedData: Data, requestPGPKeyPassphrase: () -> String) throws -> Data? {
|
||||
try checkAndInit()
|
||||
let passphrase = keyStore.get(for: Globals.pgpKeyPassphrase) ?? requestPGPKeyPassphrase()
|
||||
return try pgpInterface!.decrypt(encryptedData: encryptedData, passphrase: passphrase)
|
||||
}
|
||||
|
||||
public func encrypt(plainData: Data) throws -> Data {
|
||||
try checkAndInit()
|
||||
guard let pgpInterface = pgpInterface else {
|
||||
throw AppError.Encryption
|
||||
}
|
||||
return try pgpInterface.encrypt(plainData: plainData)
|
||||
}
|
||||
|
||||
public var isPrepared: Bool {
|
||||
return 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
16
passKit/Crypto/PgpInterface.swift
Normal file
16
passKit/Crypto/PgpInterface.swift
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// PgpInterface.swift
|
||||
// passKit
|
||||
//
|
||||
// Created by Danny Moesch on 08.09.19.
|
||||
// Copyright © 2019 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
protocol PgpInterface {
|
||||
|
||||
func decrypt(encryptedData: Data, passphrase: String) throws -> Data?
|
||||
|
||||
func encrypt(plainData: Data) throws -> Data
|
||||
|
||||
var keyId: String { get }
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ public enum AppError: Error, Equatable {
|
|||
case WrongPasswordFilename
|
||||
case Decryption
|
||||
case Encryption
|
||||
case Encoding
|
||||
case Unknown
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ public class Globals {
|
|||
public static let iTunesFileSharingPGPPrivate = iTunesFileSharingPath + "/gpg_key"
|
||||
public static let iTunesFileSharingSSHPrivate = iTunesFileSharingPath + "/ssh_key"
|
||||
|
||||
public static let pgpKeyPassphrase = "pgpKeyPassphrase"
|
||||
|
||||
public static let gitSignatureDefaultName = "Pass for iOS"
|
||||
public static let gitSignatureDefaultEmail = "user@passforios"
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
//
|
||||
|
||||
public class KeyFileManager {
|
||||
public typealias KeyHandler = (Data, String) -> ()
|
||||
public typealias KeyHandler = (String, String) -> Void
|
||||
|
||||
public static let PublicPgp = KeyFileManager(keyType: PgpKey.PUBLIC)
|
||||
public static let PrivatePgp = KeyFileManager(keyType: PgpKey.PRIVATE)
|
||||
|
|
@ -15,24 +15,35 @@ public class KeyFileManager {
|
|||
|
||||
private let keyType: CryptographicKey
|
||||
private let keyPath: String
|
||||
private let keyHandler: KeyHandler
|
||||
|
||||
private convenience init(keyType: CryptographicKey) {
|
||||
self.init(keyType: keyType, keyPath: keyType.getFileSharingPath())
|
||||
}
|
||||
|
||||
public init(keyType: CryptographicKey, keyPath: String) {
|
||||
public init(keyType: CryptographicKey, keyPath: String, keyHandler: @escaping KeyHandler = AppKeychain.shared.add) {
|
||||
self.keyType = keyType
|
||||
self.keyPath = keyPath
|
||||
self.keyHandler = keyHandler
|
||||
}
|
||||
|
||||
public func importKeyAndDeleteFile(keyHandler: KeyHandler = AppKeychain.shared.add) throws {
|
||||
guard let keyFileContent = FileManager.default.contents(atPath: keyPath) else {
|
||||
throw AppError.ReadingFile(URL(fileURLWithPath: keyPath).lastPathComponent)
|
||||
}
|
||||
keyHandler(keyFileContent, keyType.getKeychainKey())
|
||||
public func importKeyFromFileSharing() throws {
|
||||
let keyFileContent = try String(contentsOfFile: keyPath, encoding: .ascii)
|
||||
try importKey(from: keyFileContent)
|
||||
try FileManager.default.removeItem(atPath: keyPath)
|
||||
}
|
||||
|
||||
public func importKey(from string: String) throws {
|
||||
guard string.unicodeScalars.allSatisfy({ $0.isASCII }) else {
|
||||
throw AppError.Encoding
|
||||
}
|
||||
keyHandler(string, keyType.getKeychainKey())
|
||||
}
|
||||
|
||||
public func importKey(from url: URL) throws {
|
||||
try importKey(from: String(contentsOf: url, encoding: .ascii))
|
||||
}
|
||||
|
||||
public func doesKeyFileExist() -> Bool {
|
||||
return FileManager.default.fileExists(atPath: keyPath)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,223 +0,0 @@
|
|||
//
|
||||
// PGPAgent.swift
|
||||
// passKit
|
||||
//
|
||||
// Created by Yishi Lin on 2019/7/17.
|
||||
// Copyright © 2019 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ObjectivePGP
|
||||
import KeychainAccess
|
||||
import Crypto
|
||||
|
||||
public class PGPAgent {
|
||||
|
||||
private let keyStore: KeyStore
|
||||
|
||||
public init(keyStore: KeyStore = AppKeychain.shared) {
|
||||
self.keyStore = keyStore
|
||||
}
|
||||
|
||||
public var pgpKeyID: String?
|
||||
// PGP passphrase
|
||||
public var passphrase: String? {
|
||||
set {
|
||||
keyStore.add(string: newValue, for: "pgpKeyPassphrase")
|
||||
}
|
||||
get {
|
||||
return keyStore.get(for: "pgpKeyPassphrase")
|
||||
}
|
||||
}
|
||||
|
||||
// Gopenpgpwrapper
|
||||
private var publicKey: CryptoKeyRing? {
|
||||
didSet {
|
||||
var err: NSError? = nil
|
||||
let fp = publicKey?.getFingerprint(&err)
|
||||
if err == nil && fp != nil {
|
||||
pgpKeyID = String(fp!.suffix(8)).uppercased()
|
||||
} else {
|
||||
pgpKeyID = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
private var privateKey: CryptoKeyRing?
|
||||
// ObjectivePGP
|
||||
private let keyring = ObjectivePGP.defaultKeyring
|
||||
private var publicKeyV2: Key? {
|
||||
didSet {
|
||||
pgpKeyID = publicKeyV2?.keyID.shortIdentifier
|
||||
}
|
||||
}
|
||||
private var privateKeyV2: Key?
|
||||
|
||||
public var isImported: Bool {
|
||||
get {
|
||||
return (publicKey != nil || publicKeyV2 != nil) && (privateKey != nil || privateKeyV2 != nil)
|
||||
}
|
||||
}
|
||||
public var isFileSharingReady: Bool {
|
||||
get {
|
||||
return KeyFileManager.PublicPgp.doesKeyFileExist() && KeyFileManager.PrivatePgp.doesKeyFileExist()
|
||||
}
|
||||
}
|
||||
|
||||
public func initPGPKeys() throws {
|
||||
try initPGPKey(.PUBLIC)
|
||||
try initPGPKey(.PRIVATE)
|
||||
}
|
||||
|
||||
public func initPGPKey(_ keyType: PgpKey) throws {
|
||||
// Clean up the previously set public/private key.
|
||||
switch keyType {
|
||||
case .PUBLIC:
|
||||
self.publicKey = nil
|
||||
self.publicKeyV2 = nil
|
||||
case .PRIVATE:
|
||||
self.privateKey = nil
|
||||
self.privateKeyV2 = nil
|
||||
}
|
||||
|
||||
// Read the key data from keychain.
|
||||
guard let pgpKeyData: Data = keyStore.get(for: keyType.getKeychainKey()) else {
|
||||
throw AppError.KeyImport
|
||||
}
|
||||
|
||||
// Remove the key data from keychain temporary, in case the following step crashes repeatedly.
|
||||
keyStore.removeContent(for: keyType.getKeychainKey())
|
||||
|
||||
// Try GopenPGP first.
|
||||
let pgp = CryptoGetGopenPGP()
|
||||
|
||||
// Treat keys as binary first
|
||||
if let key = try? pgp?.buildKeyRing(pgpKeyData) {
|
||||
switch keyType {
|
||||
case .PUBLIC:
|
||||
self.publicKey = key
|
||||
case .PRIVATE:
|
||||
self.privateKey = key
|
||||
}
|
||||
keyStore.add(data: pgpKeyData, for: keyType.getKeychainKey())
|
||||
return
|
||||
}
|
||||
|
||||
// Treat key as ASCII armored keys if binary fails
|
||||
if let key = try? pgp?.buildKeyRingArmored(String(data: pgpKeyData, encoding: .ascii)) {
|
||||
switch keyType {
|
||||
case .PUBLIC:
|
||||
self.publicKey = key
|
||||
case .PRIVATE:
|
||||
self.privateKey = key
|
||||
}
|
||||
keyStore.add(data: pgpKeyData, for: keyType.getKeychainKey())
|
||||
return
|
||||
}
|
||||
|
||||
// Try ObjectivePGP as a backup plan.
|
||||
// [ObjectivePGP.readKeys MAY CRASH!!!]
|
||||
if let keys = try? ObjectivePGP.readKeys(from: pgpKeyData),
|
||||
let key = keys.first {
|
||||
keyring.import(keys: keys)
|
||||
switch keyType {
|
||||
case .PUBLIC:
|
||||
self.publicKeyV2 = key
|
||||
case .PRIVATE:
|
||||
self.privateKeyV2 = key
|
||||
}
|
||||
keyStore.add(data: pgpKeyData, for: keyType.getKeychainKey())
|
||||
return
|
||||
}
|
||||
|
||||
throw AppError.KeyImport
|
||||
}
|
||||
|
||||
public func initPGPKey(from url: URL, keyType: PgpKey) throws {
|
||||
let pgpKeyData = try Data(contentsOf: url)
|
||||
keyStore.add(data: pgpKeyData, for: keyType.getKeychainKey())
|
||||
try initPGPKey(keyType)
|
||||
}
|
||||
|
||||
public func initPGPKey(with armorKey: String, keyType: PgpKey) throws {
|
||||
let pgpKeyData = armorKey.data(using: .ascii)!
|
||||
keyStore.add(data: pgpKeyData, for: keyType.getKeychainKey())
|
||||
try initPGPKey(keyType)
|
||||
}
|
||||
|
||||
public func initPGPKeyFromFileSharing() throws {
|
||||
try KeyFileManager.PublicPgp.importKeyAndDeleteFile(keyHandler: keyStore.add)
|
||||
try KeyFileManager.PrivatePgp.importKeyAndDeleteFile(keyHandler: keyStore.add)
|
||||
try initPGPKeys()
|
||||
}
|
||||
|
||||
public func decrypt(encryptedData: Data, requestPGPKeyPassphrase: () -> String) throws -> Data? {
|
||||
guard privateKey != nil || privateKeyV2 != nil else {
|
||||
throw AppError.PgpPublicKeyNotExist
|
||||
}
|
||||
let passphrase = self.passphrase ?? requestPGPKeyPassphrase()
|
||||
// Try Gopenpgp.
|
||||
if privateKey != nil {
|
||||
try privateKey?.unlock(withPassphrase: passphrase)
|
||||
|
||||
var err : NSError? = nil
|
||||
var message = CryptoNewPGPMessageFromArmored(String(data: encryptedData, encoding: .ascii), &err)
|
||||
if err != nil {
|
||||
message = CryptoNewPGPMessage(encryptedData)
|
||||
}
|
||||
|
||||
if let decryptedData = try? privateKey?.decrypt(message, verifyKey: nil, verifyTime: 0) {
|
||||
return decryptedData.data
|
||||
}
|
||||
}
|
||||
// Try ObjectivePGP.
|
||||
if privateKeyV2 != nil {
|
||||
if let decryptedData = try? ObjectivePGP.decrypt(encryptedData, andVerifySignature: false, using: keyring.keys, passphraseForKey: {(_) in passphrase}) {
|
||||
return decryptedData
|
||||
}
|
||||
}
|
||||
throw AppError.Decryption
|
||||
}
|
||||
|
||||
public func encrypt(plainData: Data) throws -> Data {
|
||||
guard publicKey != nil || publicKeyV2 != nil else {
|
||||
throw AppError.PgpPublicKeyNotExist
|
||||
}
|
||||
// Try Gopenpgp.
|
||||
if publicKey != nil {
|
||||
if let encryptedData = try? publicKey?.encrypt(CryptoNewPlainMessageFromString(String(data: plainData, encoding: .utf8)), privateKey: nil) {
|
||||
if SharedDefaults[.encryptInArmored] {
|
||||
var err : NSError? = nil
|
||||
let armor = encryptedData.getArmored(&err)
|
||||
if err == nil {
|
||||
return armor.data(using: .ascii)!
|
||||
}
|
||||
} else {
|
||||
return encryptedData.getBinary()!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try ObjectivePGP.
|
||||
if publicKeyV2 != nil {
|
||||
if let encryptedData = try? ObjectivePGP.encrypt(plainData, addSignature: false, using: keyring.keys, passphraseForKey: nil) {
|
||||
if SharedDefaults[.encryptInArmored] {
|
||||
return Armor.armored(encryptedData, as: .message).data(using: .utf8)!
|
||||
} else {
|
||||
return encryptedData
|
||||
}
|
||||
}
|
||||
}
|
||||
throw AppError.Encryption
|
||||
}
|
||||
|
||||
public func removePGPKeys() {
|
||||
keyStore.removeContent(for: PgpKey.PUBLIC.getKeychainKey())
|
||||
keyStore.removeContent(for: PgpKey.PRIVATE.getKeychainKey())
|
||||
passphrase = nil
|
||||
publicKey = nil
|
||||
privateKey = nil
|
||||
publicKeyV2 = nil
|
||||
privateKeyV2 = nil
|
||||
keyring.deleteAll()
|
||||
}
|
||||
}
|
||||
|
|
@ -25,8 +25,6 @@ public class PasswordStore {
|
|||
public let storeURL = URL(fileURLWithPath: "\(Globals.repositoryPath)")
|
||||
public let tempStoreURL = URL(fileURLWithPath: "\(Globals.repositoryPath)-temp")
|
||||
|
||||
public let pgpAgent = PGPAgent()
|
||||
|
||||
public var storeRepository: GTRepository?
|
||||
|
||||
public var gitSignatureForNow: GTSignature? {
|
||||
|
|
@ -111,7 +109,6 @@ public class PasswordStore {
|
|||
if fm.fileExists(atPath: storeURL.path) {
|
||||
try storeRepository = GTRepository.init(url: storeURL)
|
||||
}
|
||||
try self.pgpAgent.initPGPKeys()
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
|
|
@ -119,9 +116,9 @@ public class PasswordStore {
|
|||
|
||||
private func importExistingKeysIntoKeychain() {
|
||||
// App Store update: v0.5.1 -> v0.6.0
|
||||
try? KeyFileManager(keyType: PgpKey.PUBLIC, keyPath: Globals.pgpPublicKeyPath).importKeyAndDeleteFile()
|
||||
try? KeyFileManager(keyType: PgpKey.PRIVATE, keyPath: Globals.pgpPrivateKeyPath).importKeyAndDeleteFile()
|
||||
try? KeyFileManager(keyType: SshKey.PRIVATE, keyPath: Globals.gitSSHPrivateKeyPath).importKeyAndDeleteFile()
|
||||
try? KeyFileManager(keyType: PgpKey.PUBLIC, keyPath: Globals.pgpPublicKeyPath).importKeyFromFileSharing()
|
||||
try? KeyFileManager(keyType: PgpKey.PRIVATE, keyPath: Globals.pgpPrivateKeyPath).importKeyFromFileSharing()
|
||||
try? KeyFileManager(keyType: SshKey.PRIVATE, keyPath: Globals.gitSSHPrivateKeyPath).importKeyFromFileSharing()
|
||||
SharedDefaults.remove(.pgpPublicKeyArmor)
|
||||
SharedDefaults.remove(.pgpPrivateKeyArmor)
|
||||
SharedDefaults.remove(.gitSSHPrivateKeyArmor)
|
||||
|
|
@ -638,7 +635,8 @@ public class PasswordStore {
|
|||
|
||||
try? fm.removeItem(atPath: Globals.gitSSHPrivateKeyPath)
|
||||
|
||||
self.pgpAgent.removePGPKeys()
|
||||
AppKeychain.shared.removeContent(for: PgpKey.PUBLIC.getKeychainKey())
|
||||
AppKeychain.shared.removeContent(for: PgpKey.PRIVATE.getKeychainKey())
|
||||
|
||||
AppKeychain.shared.removeAllContent()
|
||||
|
||||
|
|
@ -699,7 +697,7 @@ public class PasswordStore {
|
|||
public func decrypt(passwordEntity: PasswordEntity, requestPGPKeyPassphrase: () -> String) throws -> Password? {
|
||||
let encryptedDataPath = storeURL.appendingPathComponent(passwordEntity.getPath())
|
||||
let encryptedData = try Data(contentsOf: encryptedDataPath)
|
||||
guard let decryptedData = try self.pgpAgent.decrypt(encryptedData: encryptedData, requestPGPKeyPassphrase: requestPGPKeyPassphrase) else {
|
||||
guard let decryptedData = try PGPAgent.shared.decrypt(encryptedData: encryptedData, requestPGPKeyPassphrase: requestPGPKeyPassphrase) else {
|
||||
throw AppError.Decryption
|
||||
}
|
||||
let plainText = String(data: decryptedData, encoding: .utf8) ?? ""
|
||||
|
|
@ -708,11 +706,7 @@ public class PasswordStore {
|
|||
}
|
||||
|
||||
public func encrypt(password: Password) throws -> Data {
|
||||
return try self.pgpAgent.encrypt(plainData: password.plainData)
|
||||
}
|
||||
|
||||
public func removePGPKeys() {
|
||||
self.pgpAgent.removePGPKeys()
|
||||
return try PGPAgent.shared.encrypt(plainData: password.plainData)
|
||||
}
|
||||
|
||||
public func removeGitSSHKeys() {
|
||||
|
|
@ -725,6 +719,6 @@ public class PasswordStore {
|
|||
}
|
||||
|
||||
public func gitSSHKeyImportFromFileSharing() throws {
|
||||
try KeyFileManager.PrivateSsh.importKeyAndDeleteFile()
|
||||
try KeyFileManager.PrivateSsh.importKeyFromFileSharing()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
105
passKitTests/Crypto/PGPAgentTest.swift
Normal file
105
passKitTests/Crypto/PGPAgentTest.swift
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
//
|
||||
// PGPAgent.swift
|
||||
// passKitTests
|
||||
//
|
||||
// Created by Yishi Lin on 2019/7/17.
|
||||
// Copyright © 2019 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
keychain.removeAllContent()
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func basicEncryptDecrypt(using pgpAgent: PGPAgent) throws -> Data? {
|
||||
let encryptedData = try pgpAgent.encrypt(plainData: testData)
|
||||
return try pgpAgent.decrypt(encryptedData: encryptedData, requestPGPKeyPassphrase: requestPGPKeyPassphrase)
|
||||
}
|
||||
|
||||
func testBasicEncryptDecrypt() throws {
|
||||
try [
|
||||
RSA2048,
|
||||
RSA2048_SUB,
|
||||
ED25519,
|
||||
//ED25519_SUB,
|
||||
].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()
|
||||
XCTAssert(pgpAgent.keyId!.lowercased().hasSuffix(keyTriple.fingerprint))
|
||||
XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent), testData)
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
XCTAssertEqual($0 as! AppError, AppError.KeyImport)
|
||||
}
|
||||
}
|
||||
|
||||
func testInterchangePublicAndPrivateKey() throws {
|
||||
try importKeys(RSA2048.privateKey, RSA2048.publicKey)
|
||||
XCTAssert(pgpAgent.isPrepared)
|
||||
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent)) {
|
||||
XCTAssert($0.localizedDescription.contains("gopenpgp: cannot unlock key ring, no private key available"))
|
||||
}
|
||||
}
|
||||
|
||||
func testIncompatibleKeyTypes() throws {
|
||||
try importKeys(ED25519.publicKey, RSA2048.privateKey)
|
||||
XCTAssert(pgpAgent.isPrepared)
|
||||
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent)) {
|
||||
XCTAssert($0.localizedDescription.contains("openpgp: incorrect key"))
|
||||
}
|
||||
}
|
||||
|
||||
func testCorruptedKey() throws {
|
||||
try importKeys(RSA2048.publicKey.replacingOccurrences(of: "1", with: ""), RSA2048.privateKey)
|
||||
XCTAssert(pgpAgent.isPrepared)
|
||||
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent)) {
|
||||
XCTAssert($0.localizedDescription.contains("Can't read keys. Invalid input."))
|
||||
}
|
||||
}
|
||||
|
||||
func testUnsettKeys() throws {
|
||||
try importKeys(ED25519.publicKey, ED25519.privateKey)
|
||||
XCTAssert(pgpAgent.isPrepared)
|
||||
XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent), testData)
|
||||
keychain.removeContent(for: PgpKey.PUBLIC.getKeychainKey())
|
||||
keychain.removeContent(for: PgpKey.PRIVATE.getKeychainKey())
|
||||
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent)) {
|
||||
XCTAssertEqual($0 as! AppError, AppError.KeyImport)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -12,28 +12,54 @@ import XCTest
|
|||
|
||||
class KeyFileManagerTest: XCTestCase {
|
||||
private static let filePath = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("test.txt").path
|
||||
private static let keyFileManager = KeyFileManager(keyType: PgpKey.PUBLIC, keyPath: filePath)
|
||||
private static let keyFileManager = KeyFileManager(keyType: PgpKey.PUBLIC, keyPath: filePath) { _, _ in }
|
||||
|
||||
override func tearDown() {
|
||||
try? FileManager.default.removeItem(atPath: KeyFileManagerTest.filePath)
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testImportKeyAndDeleteFile() throws {
|
||||
func testImportKeyFromFileSharing() throws {
|
||||
let fileContent = "content".data(using: .ascii)
|
||||
var storage: [String: Data] = [:]
|
||||
let keyFileManager = KeyFileManager(keyType: PgpKey.PRIVATE, keyPath: KeyFileManagerTest.filePath)
|
||||
var storage: [String: String] = [:]
|
||||
let keyFileManager = KeyFileManager(keyType: PgpKey.PRIVATE, keyPath: KeyFileManagerTest.filePath) { storage[$1] = $0 }
|
||||
|
||||
FileManager.default.createFile(atPath: KeyFileManagerTest.filePath, contents: fileContent, attributes: nil)
|
||||
try keyFileManager.importKeyAndDeleteFile { storage[$1] = $0 }
|
||||
try keyFileManager.importKeyFromFileSharing()
|
||||
|
||||
XCTAssertFalse(FileManager.default.fileExists(atPath: KeyFileManagerTest.filePath))
|
||||
XCTAssertTrue(storage[PgpKey.PRIVATE.getKeychainKey()] == fileContent)
|
||||
XCTAssertEqual(storage[PgpKey.PRIVATE.getKeychainKey()], "content")
|
||||
}
|
||||
|
||||
func testErrorReadingFile() throws {
|
||||
XCTAssertThrowsError(try KeyFileManagerTest.keyFileManager.importKeyAndDeleteFile { _, _ in }) {
|
||||
XCTAssertEqual($0 as! AppError, AppError.ReadingFile("test.txt"))
|
||||
XCTAssertThrowsError(try KeyFileManagerTest.keyFileManager.importKeyFromFileSharing())
|
||||
}
|
||||
|
||||
func testImportKeyFromUrl() throws {
|
||||
let fileContent = "content".data(using: .ascii)
|
||||
let url = URL(fileURLWithPath: KeyFileManagerTest.filePath)
|
||||
var storage: [String: String] = [:]
|
||||
let keyFileManager = KeyFileManager(keyType: PgpKey.PRIVATE, keyPath: KeyFileManagerTest.filePath) { storage[$1] = $0 }
|
||||
|
||||
FileManager.default.createFile(atPath: KeyFileManagerTest.filePath, contents: fileContent, attributes: nil)
|
||||
try keyFileManager.importKey(from: url)
|
||||
|
||||
XCTAssertEqual(storage[PgpKey.PRIVATE.getKeychainKey()], "content")
|
||||
}
|
||||
|
||||
func testImportKeyFromString() throws {
|
||||
let string = "content"
|
||||
var storage: [String: String] = [:]
|
||||
let keyFileManager = KeyFileManager(keyType: PgpKey.PRIVATE, keyPath: KeyFileManagerTest.filePath) { storage[$1] = $0 }
|
||||
|
||||
try keyFileManager.importKey(from: string)
|
||||
|
||||
XCTAssertEqual(storage[PgpKey.PRIVATE.getKeychainKey()], string)
|
||||
}
|
||||
|
||||
func testImportKeyFromNonAsciiString() throws {
|
||||
XCTAssertThrowsError(try KeyFileManagerTest.keyFileManager.importKey(from: "≠")) {
|
||||
XCTAssertEqual($0 as! AppError, AppError.Encoding)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,108 +0,0 @@
|
|||
//
|
||||
// PGPAgent.swift
|
||||
// passKitTests
|
||||
//
|
||||
// Created by Yishi Lin on 2019/7/17.
|
||||
// Copyright © 2019 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
@testable import passKit
|
||||
|
||||
class PGPAgentTest: XCTestCase {
|
||||
|
||||
private let keychain = DictBasedKeychain()
|
||||
|
||||
func basicEncryptDecrypt(pgpAgent: PGPAgent) -> Bool {
|
||||
// Encrypt and decrypt.
|
||||
let plainData = "Hello World!".data(using: .utf8)!
|
||||
guard let encryptedData = try? pgpAgent.encrypt(plainData: plainData) else {
|
||||
return false
|
||||
}
|
||||
guard let decryptedData = try? pgpAgent.decrypt(encryptedData: encryptedData, requestPGPKeyPassphrase: requestPGPKeyPassphrase) else {
|
||||
return false
|
||||
}
|
||||
return plainData == decryptedData
|
||||
}
|
||||
|
||||
func testInitPGPKey() {
|
||||
let pgpAgent = PGPAgent(keyStore: keychain)
|
||||
|
||||
// [RSA2048] Setup keys.
|
||||
try? pgpAgent.initPGPKey(with: PGP_RSA2048_PUBLIC_KEY, keyType: .PUBLIC)
|
||||
try? pgpAgent.initPGPKey(with: PGP_RSA2048_PRIVATE_KEY, keyType: .PRIVATE)
|
||||
XCTAssertTrue(pgpAgent.isImported)
|
||||
XCTAssertEqual(pgpAgent.pgpKeyID, "A1024DAE")
|
||||
XCTAssertTrue(self.basicEncryptDecrypt(pgpAgent: pgpAgent))
|
||||
let pgpAgent2 = PGPAgent(keyStore: keychain)
|
||||
try? pgpAgent2.initPGPKeys() // load from the keychain
|
||||
XCTAssertTrue(self.basicEncryptDecrypt(pgpAgent: pgpAgent2))
|
||||
pgpAgent.removePGPKeys()
|
||||
|
||||
// [RSA2048] Setup keys. The private key is a subkey.
|
||||
try? pgpAgent.initPGPKey(with: PGP_RSA2048_PUBLIC_KEY, keyType: .PUBLIC)
|
||||
try? pgpAgent.initPGPKey(with: PGP_RSA2048_PRIVATE_SUBKEY, keyType: .PRIVATE)
|
||||
XCTAssertTrue(pgpAgent.isImported)
|
||||
XCTAssertEqual(pgpAgent.pgpKeyID, "A1024DAE")
|
||||
XCTAssertTrue(self.basicEncryptDecrypt(pgpAgent: pgpAgent))
|
||||
pgpAgent.removePGPKeys()
|
||||
|
||||
// [ED25519] Setup keys.
|
||||
try? pgpAgent.initPGPKey(with: PGP_ED25519_PUBLIC_KEY, keyType: .PUBLIC)
|
||||
try? pgpAgent.initPGPKey(with: PGP_ED25519_PRIVATE_KEY, keyType: .PRIVATE)
|
||||
XCTAssertTrue(pgpAgent.isImported)
|
||||
XCTAssertEqual(pgpAgent.pgpKeyID, "E9444483")
|
||||
XCTAssertTrue(self.basicEncryptDecrypt(pgpAgent: pgpAgent))
|
||||
pgpAgent.removePGPKeys()
|
||||
|
||||
// [RSA2048] Setup keys from URL.
|
||||
let publicKeyURL = URL(fileURLWithPath: PgpKey.PUBLIC.getFileSharingPath())
|
||||
let privateKeyURL = URL(fileURLWithPath: PgpKey.PRIVATE.getFileSharingPath())
|
||||
try? PGP_RSA2048_PUBLIC_KEY.write(to: publicKeyURL, atomically: false, encoding: .utf8)
|
||||
try? PGP_RSA2048_PRIVATE_KEY.write(to: privateKeyURL, atomically: false, encoding: .utf8)
|
||||
try? pgpAgent.initPGPKey(from: publicKeyURL, keyType: .PUBLIC)
|
||||
try? pgpAgent.initPGPKey(from: privateKeyURL, keyType: .PRIVATE)
|
||||
XCTAssertTrue(pgpAgent.isImported)
|
||||
XCTAssertEqual(pgpAgent.pgpKeyID, "A1024DAE")
|
||||
XCTAssertTrue(self.basicEncryptDecrypt(pgpAgent: pgpAgent))
|
||||
pgpAgent.removePGPKeys()
|
||||
|
||||
// [RSA2048] Setup keys from iTunes file sharing.
|
||||
try? PGP_RSA2048_PUBLIC_KEY.write(to: publicKeyURL, atomically: false, encoding: .utf8)
|
||||
try? PGP_RSA2048_PRIVATE_KEY.write(to: privateKeyURL, atomically: false, encoding: .utf8)
|
||||
XCTAssertTrue(pgpAgent.isFileSharingReady)
|
||||
try? pgpAgent.initPGPKeyFromFileSharing()
|
||||
XCTAssertTrue(pgpAgent.isImported)
|
||||
XCTAssertEqual(pgpAgent.pgpKeyID, "A1024DAE")
|
||||
XCTAssertTrue(self.basicEncryptDecrypt(pgpAgent: pgpAgent))
|
||||
XCTAssertFalse(FileManager.default.fileExists(atPath: publicKeyURL.absoluteString))
|
||||
XCTAssertFalse(FileManager.default.fileExists(atPath: privateKeyURL.absoluteString))
|
||||
pgpAgent.removePGPKeys()
|
||||
}
|
||||
|
||||
func testInitPGPKeyBadPrivateKeys() {
|
||||
let pgpAgent = PGPAgent(keyStore: keychain)
|
||||
let plainData = "Hello World!".data(using: .utf8)!
|
||||
|
||||
// [RSA2048] Setup the public key.
|
||||
try? pgpAgent.initPGPKey(with: PGP_RSA2048_PUBLIC_KEY, keyType: .PUBLIC)
|
||||
let encryptedData = try? pgpAgent.encrypt(plainData: plainData)
|
||||
XCTAssertNotNil(encryptedData)
|
||||
XCTAssertThrowsError(try pgpAgent.decrypt(encryptedData: encryptedData!, requestPGPKeyPassphrase: requestPGPKeyPassphrase))
|
||||
|
||||
// Wrong private key: a public key.
|
||||
try? pgpAgent.initPGPKey(with: PGP_RSA2048_PUBLIC_KEY, keyType: .PRIVATE)
|
||||
XCTAssertThrowsError(try pgpAgent.decrypt(encryptedData: encryptedData!, requestPGPKeyPassphrase: requestPGPKeyPassphrase))
|
||||
|
||||
// Wrong private key: an unmatched private key.
|
||||
try? pgpAgent.initPGPKey(with: PGP_ED25519_PRIVATE_KEY, keyType: .PRIVATE)
|
||||
XCTAssertThrowsError(try pgpAgent.decrypt(encryptedData: encryptedData!, requestPGPKeyPassphrase: requestPGPKeyPassphrase))
|
||||
|
||||
/// Wrong private key: a corrupted private key.
|
||||
try? pgpAgent.initPGPKey(with: PGP_RSA2048_PRIVATE_KEY.replacingOccurrences(of: "1", with: ""), keyType: .PRIVATE)
|
||||
XCTAssertThrowsError(try pgpAgent.decrypt(encryptedData: encryptedData!, requestPGPKeyPassphrase: requestPGPKeyPassphrase))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue