2019-09-08 23:00:46 +02:00
|
|
|
//
|
|
|
|
|
// GopenPgp.swift
|
|
|
|
|
// passKit
|
|
|
|
|
//
|
|
|
|
|
// Created by Danny Moesch on 08.09.19.
|
|
|
|
|
// Copyright © 2019 Bob Sun. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import Crypto
|
|
|
|
|
|
|
|
|
|
struct GopenPgp: PgpInterface {
|
|
|
|
|
|
2019-10-20 12:14:51 +02:00
|
|
|
private static let errorMapping: [String: Error] = [
|
|
|
|
|
"openpgp: invalid data: private key checksum failure": AppError.WrongPassphrase,
|
|
|
|
|
"openpgp: incorrect key": AppError.KeyExpiredOrIncompatible,
|
|
|
|
|
]
|
|
|
|
|
|
2019-09-08 23:00:46 +02:00
|
|
|
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? {
|
2019-10-20 12:14:51 +02:00
|
|
|
do {
|
|
|
|
|
try privateKey.unlock(withPassphrase: passphrase)
|
|
|
|
|
} catch {
|
|
|
|
|
throw Self.errorMapping[error.localizedDescription, default: error]
|
|
|
|
|
}
|
2019-09-08 23:00:46 +02:00
|
|
|
let message = createPgpMessage(from: encryptedData)
|
2019-10-20 12:14:51 +02:00
|
|
|
do {
|
|
|
|
|
return try privateKey.decrypt(message, verifyKey: nil, verifyTime: 0).data
|
|
|
|
|
} catch {
|
|
|
|
|
throw Self.errorMapping[error.localizedDescription, default: error]
|
|
|
|
|
}
|
2019-09-08 23:00:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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? {
|
2019-09-30 00:12:54 +08:00
|
|
|
// Important note:
|
|
|
|
|
// Even if SharedDefaults[.encryptInArmored] is true now, it could be different during the encryption.
|
|
|
|
|
var error: NSError?
|
|
|
|
|
let message = CryptoNewPGPMessageFromArmored(String(data: encryptedData, encoding: .ascii), &error)
|
|
|
|
|
if error == nil {
|
|
|
|
|
return message
|
2019-09-08 23:00:46 +02:00
|
|
|
}
|
|
|
|
|
return CryptoNewPGPMessage(encryptedData.mutable as Data)
|
|
|
|
|
}
|
|
|
|
|
}
|