Check existence of PGP keys before encrypt/decrypt
This commit is contained in:
parent
50dec23b02
commit
0cae6af60d
6 changed files with 41 additions and 4 deletions
|
|
@ -136,6 +136,8 @@
|
||||||
"PgpCopyPublicAndPrivateKeyToPass." = "Copy your ASCII-armored public and private keys to Pass with names \"gpg_key.pub\" and \"gpg_key\" (without quotes) via iTunes. Then come back and click \"iTunes File Sharing\" to finish.";
|
"PgpCopyPublicAndPrivateKeyToPass." = "Copy your ASCII-armored public and private keys to Pass with names \"gpg_key.pub\" and \"gpg_key\" (without quotes) via iTunes. Then come back and click \"iTunes File Sharing\" to finish.";
|
||||||
"KeyExpiredOrIncompatibleError." = "PGP public key may be expired or incompatible with the private key.";
|
"KeyExpiredOrIncompatibleError." = "PGP public key may be expired or incompatible with the private key.";
|
||||||
"WrongPassphraseError." = "Passphrase of your PGP secret key is wrong.";
|
"WrongPassphraseError." = "Passphrase of your PGP secret key is wrong.";
|
||||||
|
"PgpPublicKeyNotFoundError." = "PGP public key (%@) not found.";
|
||||||
|
"PgpPrivateKeyNotFoundError." = "PGP private key (%@) not found.";
|
||||||
"CannotImportFile" = "Cannot Import File";
|
"CannotImportFile" = "Cannot Import File";
|
||||||
"LoadFromFiles" = "Load From File";
|
"LoadFromFiles" = "Load From File";
|
||||||
"FileCannotBeImported." = "An error occurred importing the file '%@'. Please make sure its location is readable.";
|
"FileCannotBeImported." = "An error occurred importing the file '%@'. Please make sure its location is readable.";
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ struct GopenPgp: PgpInterface {
|
||||||
}
|
}
|
||||||
throw AppError.KeyImport
|
throw AppError.KeyImport
|
||||||
}
|
}
|
||||||
publicKeys[k.getFingerprint()] = k
|
publicKeys[k.getFingerprint().lowercased()] = k
|
||||||
}
|
}
|
||||||
|
|
||||||
for key in prvKeys {
|
for key in prvKeys {
|
||||||
|
|
@ -41,7 +41,7 @@ struct GopenPgp: PgpInterface {
|
||||||
}
|
}
|
||||||
throw AppError.KeyImport
|
throw AppError.KeyImport
|
||||||
}
|
}
|
||||||
privateKeys[k.getFingerprint()] = k
|
privateKeys[k.getFingerprint().lowercased()] = k
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -64,6 +64,14 @@ struct GopenPgp: PgpInterface {
|
||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func containsPublicKey(with keyID: String) -> Bool {
|
||||||
|
publicKeys.keys.contains(where: { key in key.hasSuffix(keyID.lowercased()) })
|
||||||
|
}
|
||||||
|
|
||||||
|
func containsPrivateKey(with keyID: String) -> Bool {
|
||||||
|
privateKeys.keys.contains(where: { key in key.hasSuffix(keyID.lowercased()) })
|
||||||
|
}
|
||||||
|
|
||||||
func decrypt(encryptedData: Data, keyID: String, passphrase: String) throws -> Data? {
|
func decrypt(encryptedData: Data, keyID: String, passphrase: String) throws -> Data? {
|
||||||
guard let e = privateKeys.first(where: { (key, _) in key.hasSuffix(keyID.lowercased()) }),
|
guard let e = privateKeys.first(where: { (key, _) in key.hasSuffix(keyID.lowercased()) }),
|
||||||
let privateKey = privateKeys[e.key] else {
|
let privateKey = privateKeys[e.key] else {
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,14 @@ struct ObjectivePgp: PgpInterface {
|
||||||
return encryptedData
|
return encryptedData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func containsPublicKey(with keyID: String) -> Bool {
|
||||||
|
keyring.findKey(keyID)?.isPublic ?? false
|
||||||
|
}
|
||||||
|
|
||||||
|
func containsPrivateKey(with keyID: String) -> Bool {
|
||||||
|
keyring.findKey(keyID)?.isSecret ?? false
|
||||||
|
}
|
||||||
|
|
||||||
var keyID: [String] {
|
var keyID: [String] {
|
||||||
return keyring.keys.map({ $0.keyID.longIdentifier })
|
return keyring.keys.map({ $0.keyID.longIdentifier })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,15 @@ public class PGPAgent {
|
||||||
self.latestDecryptStatus = false
|
self.latestDecryptStatus = false
|
||||||
// Init keys.
|
// Init keys.
|
||||||
try checkAndInit()
|
try checkAndInit()
|
||||||
|
|
||||||
|
guard let pgpInterface = pgpInterface else {
|
||||||
|
throw AppError.Decryption
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pgpInterface.containsPrivateKey(with: keyID) {
|
||||||
|
throw AppError.PgpPrivateKeyNotFound(keyID: keyID)
|
||||||
|
}
|
||||||
|
|
||||||
// Get the PGP key passphrase.
|
// Get the PGP key passphrase.
|
||||||
var passphrase = ""
|
var passphrase = ""
|
||||||
if previousDecryptStatus == false {
|
if previousDecryptStatus == false {
|
||||||
|
|
@ -59,7 +68,7 @@ public class PGPAgent {
|
||||||
passphrase = keyStore.get(for: AppKeychain.getPGPKeyPassphraseKey(keyID: keyID)) ?? requestPGPKeyPassphrase(keyID)
|
passphrase = keyStore.get(for: AppKeychain.getPGPKeyPassphraseKey(keyID: keyID)) ?? requestPGPKeyPassphrase(keyID)
|
||||||
}
|
}
|
||||||
// Decrypt.
|
// Decrypt.
|
||||||
guard let result = try pgpInterface!.decrypt(encryptedData: encryptedData, keyID: keyID, passphrase: passphrase) else {
|
guard let result = try pgpInterface.decrypt(encryptedData: encryptedData, keyID: keyID, passphrase: passphrase) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// The decryption step has succeed.
|
// The decryption step has succeed.
|
||||||
|
|
@ -72,6 +81,9 @@ public class PGPAgent {
|
||||||
guard let pgpInterface = pgpInterface else {
|
guard let pgpInterface = pgpInterface else {
|
||||||
throw AppError.Encryption
|
throw AppError.Encryption
|
||||||
}
|
}
|
||||||
|
if !pgpInterface.containsPublicKey(with: keyID) {
|
||||||
|
throw AppError.PgpPublicKeyNotFound(keyID: keyID)
|
||||||
|
}
|
||||||
return try pgpInterface.encrypt(plainData: plainData, keyID: keyID)
|
return try pgpInterface.encrypt(plainData: plainData, keyID: keyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@ protocol PgpInterface {
|
||||||
|
|
||||||
func encrypt(plainData: Data, keyID: String) throws -> Data
|
func encrypt(plainData: Data, keyID: String) throws -> Data
|
||||||
|
|
||||||
|
func containsPublicKey(with keyID: String) -> Bool
|
||||||
|
|
||||||
|
func containsPrivateKey(with keyID: String) -> Bool
|
||||||
|
|
||||||
var keyID: [String] { get }
|
var keyID: [String] { get }
|
||||||
|
|
||||||
var shortKeyID: [String] { get }
|
var shortKeyID: [String] { get }
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ public enum AppError: Error, Equatable {
|
||||||
case GitReset
|
case GitReset
|
||||||
case GitCommit
|
case GitCommit
|
||||||
case PasswordEntity
|
case PasswordEntity
|
||||||
case PgpPublicKeyNotExist
|
case PgpPublicKeyNotFound(keyID: String)
|
||||||
|
case PgpPrivateKeyNotFound(keyID: String)
|
||||||
case KeyExpiredOrIncompatible
|
case KeyExpiredOrIncompatible
|
||||||
case WrongPassphrase
|
case WrongPassphrase
|
||||||
case WrongPasswordFilename
|
case WrongPasswordFilename
|
||||||
|
|
@ -32,6 +33,8 @@ extension AppError: LocalizedError {
|
||||||
switch self {
|
switch self {
|
||||||
case let .RepositoryRemoteBranchNotFound(name), let .RepositoryBranchNotFound(name), let .ReadingFile(name):
|
case let .RepositoryRemoteBranchNotFound(name), let .RepositoryBranchNotFound(name), let .ReadingFile(name):
|
||||||
return localizationKey.localize(name)
|
return localizationKey.localize(name)
|
||||||
|
case let .PgpPublicKeyNotFound(keyID), let .PgpPrivateKeyNotFound(keyID):
|
||||||
|
return localizationKey.localize(keyID)
|
||||||
default:
|
default:
|
||||||
return localizationKey.localize()
|
return localizationKey.localize()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue