perf(ios): optimize swift code
This commit is contained in:
parent
142dd17ad2
commit
2ed8aab69f
@ -3,93 +3,144 @@ import UIKit
|
|||||||
|
|
||||||
@available(iOS 13.0, *)
|
@available(iOS 13.0, *)
|
||||||
public class SwiftNativeCryptoIosPlugin: NSObject, FlutterPlugin {
|
public class SwiftNativeCryptoIosPlugin: NSObject, FlutterPlugin {
|
||||||
|
static let name: String = "plugins.hugop.cl/native_crypto"
|
||||||
|
|
||||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||||
let channel = FlutterMethodChannel(name: "plugins.hugop.cl/native_crypto", binaryMessenger: registrar.messenger())
|
let channel = FlutterMethodChannel(name: name, binaryMessenger: registrar.messenger())
|
||||||
let instance = SwiftNativeCryptoIosPlugin()
|
let instance = SwiftNativeCryptoIosPlugin()
|
||||||
registrar.addMethodCallDelegate(instance, channel: channel)
|
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||||
switch call.method {
|
switch call.method {
|
||||||
case "digest":
|
case "digest": _call(task: handleDigest(call: call), result: result)
|
||||||
|
case "generateSecretKey": _call(task: handleGenerateSecretKey(call: call), result: result)
|
||||||
|
case "pbkdf2": _call(task: handlePbkdf2(call: call), result: result)
|
||||||
|
case "encryptAsList": _call(task: handleEncryptAsList(call: call), result: result)
|
||||||
|
case "decryptAsList": _call(task: handleDecryptAsList(call: call), result: result)
|
||||||
|
case "encrypt": _call(task: handleCrypt(call: call, forEncryption: true), result: result)
|
||||||
|
case "decrypt": _call(task: handleCrypt(call: call, forEncryption: false), result: result)
|
||||||
|
default: result(FlutterMethodNotImplemented)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func _call<T>(task: Task<T>, result: @escaping FlutterResult) {
|
||||||
|
task.call()
|
||||||
|
task.finalize(callback: {(task: Task<T>) in
|
||||||
|
if (task.isSuccessful()) {
|
||||||
|
result(task.getResult()!)
|
||||||
|
} else {
|
||||||
|
let exception: Error = task.getException()
|
||||||
|
let message = exception.localizedDescription
|
||||||
|
result(FlutterError(code: "native_crypto", message: message, details: nil))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleDigest(call: FlutterMethodCall) -> Task<FlutterStandardTypedData> {
|
||||||
|
return Task(task: {
|
||||||
let args : NSDictionary = call.arguments as! NSDictionary
|
let args : NSDictionary = call.arguments as! NSDictionary
|
||||||
|
|
||||||
let data : Data = (args["data"] as! FlutterStandardTypedData).data
|
let data : Data = (args["data"] as! FlutterStandardTypedData).data
|
||||||
let algo : String = args["algorithm"] as! String
|
let algorithm : String = args["algorithm"] as! String
|
||||||
let algorithm : HashAlgorithm? = HashAlgorithm.init(rawValue: algo)
|
|
||||||
// TODO(hpcl): check if algorithm is null
|
return FlutterStandardTypedData.init(bytes: try HashAlgorithm.digest(data: data, algorithm: algorithm))
|
||||||
// TODO(hpcl): check if digest is null
|
})
|
||||||
result(FlutterStandardTypedData.init(bytes: Hash.digest(data: data, algorithm: algorithm!)))
|
}
|
||||||
case "generateSecretKey":
|
|
||||||
|
private func handleGenerateSecretKey(call: FlutterMethodCall) -> Task<FlutterStandardTypedData> {
|
||||||
|
return Task(task: {
|
||||||
let args : NSDictionary = call.arguments as! NSDictionary
|
let args : NSDictionary = call.arguments as! NSDictionary
|
||||||
|
|
||||||
let bitsCount : NSNumber = args["bitsCount"] as! NSNumber
|
let bitsCount : NSNumber = args["bitsCount"] as! NSNumber
|
||||||
// TODO(hpcl): check if secure random is null
|
|
||||||
result(FlutterStandardTypedData.init(bytes: Key.fromSecureRandom(bitsCount: bitsCount.intValue)))
|
return FlutterStandardTypedData.init(bytes: SecretKey(fromSecureRandom: bitsCount.intValue).bytes)
|
||||||
case "generateKeyPair":
|
})
|
||||||
result(FlutterStandardTypedData.init(bytes: KeyPair.fromCurve()))
|
}
|
||||||
case "pbkdf2":
|
|
||||||
|
private func handlePbkdf2(call: FlutterMethodCall) -> Task<FlutterStandardTypedData> {
|
||||||
|
return Task(task: {
|
||||||
let args : NSDictionary = call.arguments as! NSDictionary
|
let args : NSDictionary = call.arguments as! NSDictionary
|
||||||
|
|
||||||
let password : String = args["password"] as! String
|
let password : String = args["password"] as! String
|
||||||
let salt : String = args["salt"] as! String
|
let salt : String = args["salt"] as! String
|
||||||
let keyBytesCount : NSNumber = args["keyBytesCount"] as! NSNumber
|
let keyBytesCount : NSNumber = args["keyBytesCount"] as! NSNumber
|
||||||
let iterations : NSNumber = args["iterations"] as! NSNumber
|
let iterations : NSNumber = args["iterations"] as! NSNumber
|
||||||
let algo : String = args["algorithm"] as! String
|
let algorithm : String = args["algorithm"] as! String
|
||||||
let algorithm : HashAlgorithm? = HashAlgorithm.init(rawValue: algo)
|
|
||||||
// TODO(hpcl): check if algorithm is null
|
let pbkdf2 : Pbkdf2 = Pbkdf2(keyBytesCount: keyBytesCount.intValue, iterations: iterations.intValue)
|
||||||
// TODO(hpcl): check if derivation is null
|
pbkdf2.hash = HashAlgorithm.init(rawValue: algorithm) ?? pbkdf2.hash
|
||||||
result(FlutterStandardTypedData.init(bytes: Key.fromPBKDF2(password: password, salt: salt, keyBytesCount: keyBytesCount.intValue, iterations: iterations.intValue, algorithm: algorithm!)!))
|
pbkdf2.initialize(password: password, salt: salt)
|
||||||
case "encrypt":
|
|
||||||
|
return FlutterStandardTypedData.init(bytes: try pbkdf2.derive().bytes)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleEncryptAsList(call: FlutterMethodCall) -> Task<Array<Data>> {
|
||||||
|
return Task(task: {
|
||||||
let args : NSDictionary = call.arguments as! NSDictionary
|
let args : NSDictionary = call.arguments as! NSDictionary
|
||||||
|
|
||||||
let data : Data = (args["data"] as! FlutterStandardTypedData).data
|
let data : Data = (args["data"] as! FlutterStandardTypedData).data
|
||||||
let key : Data = (args["key"] as! FlutterStandardTypedData).data
|
let key : Data = (args["key"] as! FlutterStandardTypedData).data
|
||||||
let algo : String = args["algorithm"] as! String
|
let algorithm : String = args["algorithm"] as! String
|
||||||
// TODO(hpcl): check if algorithm is null
|
|
||||||
// TODO(hpcl): check if ciphertext is null
|
let cipherAlgorithm : CipherAlgorithm? = CipherAlgorithm.init(rawValue: algorithm)
|
||||||
var ciphertext : Data
|
var cipher : Cipher
|
||||||
switch algo {
|
if (cipherAlgorithm != nil) {
|
||||||
case "aes":
|
cipher = cipherAlgorithm!.getCipher
|
||||||
ciphertext = AESCipher.encrypt(plaintext: data, key: key)!
|
} else {
|
||||||
case "chachapoly":
|
throw NativeCryptoError.cipherError
|
||||||
ciphertext = CHACHACipher.encrypt(plaintext: data, key: key)!
|
|
||||||
default:
|
|
||||||
ciphertext = Data.init();
|
|
||||||
}
|
}
|
||||||
result(FlutterStandardTypedData.init(bytes: ciphertext))
|
|
||||||
case "decrypt":
|
return try cipher.encryptAsList(data: data, key: key)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleDecryptAsList(call: FlutterMethodCall) -> Task<FlutterStandardTypedData> {
|
||||||
|
return Task(task: {
|
||||||
|
let args : NSDictionary = call.arguments as! NSDictionary
|
||||||
|
|
||||||
|
let data = args["data"] as! NSArray
|
||||||
|
let key : Data = (args["key"] as! FlutterStandardTypedData).data
|
||||||
|
let algorithm : String = args["algorithm"] as! String
|
||||||
|
|
||||||
|
let iv = (data[0] as! FlutterStandardTypedData).data
|
||||||
|
let encrypted = (data[1] as! FlutterStandardTypedData).data
|
||||||
|
|
||||||
|
let cipherAlgorithm : CipherAlgorithm? = CipherAlgorithm.init(rawValue: algorithm)
|
||||||
|
var cipher : Cipher
|
||||||
|
if (cipherAlgorithm != nil) {
|
||||||
|
cipher = cipherAlgorithm!.getCipher
|
||||||
|
} else {
|
||||||
|
throw NativeCryptoError.cipherError
|
||||||
|
}
|
||||||
|
|
||||||
|
return FlutterStandardTypedData.init(bytes: try cipher.decryptAsList(data: [iv, encrypted], key: key))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleCrypt(call: FlutterMethodCall, forEncryption: Bool) -> Task<FlutterStandardTypedData> {
|
||||||
|
return Task(task: {
|
||||||
let args : NSDictionary = call.arguments as! NSDictionary
|
let args : NSDictionary = call.arguments as! NSDictionary
|
||||||
|
|
||||||
let data : Data = (args["data"] as! FlutterStandardTypedData).data
|
let data : Data = (args["data"] as! FlutterStandardTypedData).data
|
||||||
let key : Data = (args["key"] as! FlutterStandardTypedData).data
|
let key : Data = (args["key"] as! FlutterStandardTypedData).data
|
||||||
let algo : String = args["algorithm"] as! String
|
let algorithm : String = args["algorithm"] as! String
|
||||||
// TODO(hpcl): check if algorithm is null
|
|
||||||
// TODO(hpcl): check if ciphertext is null
|
|
||||||
var ciphertext : Data
|
|
||||||
switch algo {
|
|
||||||
case "aes":
|
|
||||||
ciphertext = AESCipher.decrypt(ciphertext: data, key: key)!
|
|
||||||
case "chachapoly":
|
|
||||||
ciphertext = CHACHACipher.decrypt(ciphertext: data, key: key)!
|
|
||||||
default:
|
|
||||||
ciphertext = Data.init();
|
|
||||||
}
|
|
||||||
result(FlutterStandardTypedData.init(bytes: ciphertext))
|
|
||||||
case "generateSharedSecretKey":
|
|
||||||
let args : NSDictionary = call.arguments as! NSDictionary
|
|
||||||
|
|
||||||
let salt : Data = (args["salt"] as! FlutterStandardTypedData).data
|
let cipherAlgorithm : CipherAlgorithm? = CipherAlgorithm.init(rawValue: algorithm)
|
||||||
let keyBytesCount : NSNumber = args["keyBytesCount"] as! NSNumber
|
var cipher : Cipher
|
||||||
let ephemeralPrivateKey : Data = (args["ephemeralPrivateKey"] as! FlutterStandardTypedData).data
|
if (cipherAlgorithm != nil) {
|
||||||
let otherPublicKey : Data = (args["otherPublicKey"] as! FlutterStandardTypedData).data
|
cipher = cipherAlgorithm!.getCipher
|
||||||
let hkdfAlgorithm : String = args["hkdfAlgorithm"] as! String
|
} else {
|
||||||
let algorithm : HashAlgorithm? = HashAlgorithm.init(rawValue: hkdfAlgorithm)
|
throw NativeCryptoError.cipherError
|
||||||
// TODO(hpcl): check if algorithm is null
|
}
|
||||||
// TODO(hpcl): check if generated key is null
|
|
||||||
result(FlutterStandardTypedData.init(bytes: ECDH.generateSharedSecretKey(salt: salt, hash: algorithm!, keyBytesCount: keyBytesCount.intValue, privateKey: ephemeralPrivateKey, publicKey: otherPublicKey)!))
|
|
||||||
|
|
||||||
default: result(FlutterMethodNotImplemented)
|
if (forEncryption) {
|
||||||
|
return FlutterStandardTypedData.init(bytes: try cipher.encrypt(data: data, key: key))
|
||||||
|
} else {
|
||||||
|
return FlutterStandardTypedData.init(bytes: try cipher.decrypt(data: data, key: key))
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,57 @@
|
|||||||
//
|
//
|
||||||
// AES.swift
|
// AESCipher.swift
|
||||||
// native_crypto_ios
|
// native_crypto_ios
|
||||||
//
|
//
|
||||||
// Created by Hugo Pointcheval on 25/05/2022.
|
// Created by Hugo Pointcheval on 25/05/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import CryptoKit
|
||||||
|
|
||||||
|
class AESCipher : Cipher {
|
||||||
|
var algorithm: CipherAlgorithm = CipherAlgorithm.aes
|
||||||
|
|
||||||
class AES : Cipher {
|
|
||||||
/// Encrypts plaintext with key using AES GCM
|
/// Encrypts plaintext with key using AES GCM
|
||||||
@available(iOS 13.0, *)
|
@available(iOS 13.0, *)
|
||||||
static func encrypt(plaintext: Data, key: Data) -> Data? {
|
func encrypt(data: Data, key: Data) throws -> Data {
|
||||||
let symmetricKey = SymmetricKey.init(data: key)
|
let symmetricKey : SymmetricKey = SymmetricKey.init(data: key)
|
||||||
let encrypted = try? AES.GCM.seal(plaintext, using: symmetricKey)
|
let encrypted : AES.GCM.SealedBox? = try? AES.GCM.seal(data, using: symmetricKey)
|
||||||
return encrypted?.combined
|
|
||||||
|
let encryptedData : Data? = encrypted?.combined
|
||||||
|
if (encryptedData == nil) {
|
||||||
|
throw NativeCryptoError.encryptionError
|
||||||
|
}
|
||||||
|
return encryptedData!
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decrypts ciphertext with key using AES GCM
|
/// Decrypts ciphertext with key using AES GCM
|
||||||
@available(iOS 13.0, *)
|
@available(iOS 13.0, *)
|
||||||
static func decrypt(ciphertext: Data, key: Data) -> Data? {
|
func decrypt(data: Data, key: Data) throws -> Data {
|
||||||
let symmetricKey = SymmetricKey.init(data: key)
|
let symmetricKey = SymmetricKey.init(data: key)
|
||||||
let sealedBox = try? AES.GCM.SealedBox(combined: ciphertext)
|
let sealedBox = try? AES.GCM.SealedBox(combined: data)
|
||||||
if (sealedBox == nil) { return nil }
|
if (sealedBox == nil) { return Data.init() }
|
||||||
let decryptedData = try? AES.GCM.open(sealedBox!, using: symmetricKey)
|
let decryptedData = try? AES.GCM.open(sealedBox!, using: symmetricKey)
|
||||||
|
if (decryptedData == nil) {
|
||||||
|
throw NativeCryptoError.decryptionError
|
||||||
|
}
|
||||||
|
return decryptedData!
|
||||||
|
}
|
||||||
|
|
||||||
|
func encryptAsList(data: Data, key: Data) throws -> [Data] {
|
||||||
|
let encryptedData = try encrypt(data: data, key: key)
|
||||||
|
|
||||||
|
let iv = encryptedData.prefix(12)
|
||||||
|
let data = encryptedData.suffix(from: 12)
|
||||||
|
|
||||||
|
return [iv, data]
|
||||||
|
}
|
||||||
|
|
||||||
|
func decryptAsList(data: [Data], key: Data) throws -> Data {
|
||||||
|
var encryptedData = data.first!
|
||||||
|
let data = data.last!
|
||||||
|
encryptedData.append(data)
|
||||||
|
|
||||||
|
let decryptedData = try decrypt(data: encryptedData, key: key)
|
||||||
return decryptedData
|
return decryptedData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,3 +6,58 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import CommonCrypto
|
||||||
|
|
||||||
|
class Pbkdf2 : KeyDerivation {
|
||||||
|
var algorithm: KdfAlgorithm = KdfAlgorithm.pbkdf2
|
||||||
|
|
||||||
|
var keyBytesCount: Int
|
||||||
|
var iterations: Int
|
||||||
|
var hash: HashAlgorithm = HashAlgorithm.HashSHA256
|
||||||
|
|
||||||
|
var password: String? = nil
|
||||||
|
var salt: String? = nil
|
||||||
|
|
||||||
|
init(keyBytesCount: Int, iterations: Int) {
|
||||||
|
self.keyBytesCount = keyBytesCount
|
||||||
|
self.iterations = iterations
|
||||||
|
}
|
||||||
|
|
||||||
|
func initialize(password: String, salt: String) {
|
||||||
|
self.password = password
|
||||||
|
self.salt = salt
|
||||||
|
}
|
||||||
|
|
||||||
|
func derive() throws -> SecretKey {
|
||||||
|
if (password == nil || salt == nil) {
|
||||||
|
throw NativeCryptoError.pbkdf2Error
|
||||||
|
}
|
||||||
|
|
||||||
|
let passwordData = password!.data(using: .utf8)!
|
||||||
|
let saltData = salt!.data(using: .utf8)!
|
||||||
|
|
||||||
|
var derivedKeyData = Data(repeating: 0, count: keyBytesCount)
|
||||||
|
let localDerivedKeyData = derivedKeyData
|
||||||
|
|
||||||
|
let status = derivedKeyData.withUnsafeMutableBytes { (derivedKeyBytes: UnsafeMutableRawBufferPointer) in
|
||||||
|
saltData.withUnsafeBytes { (saltBytes: UnsafeRawBufferPointer) in
|
||||||
|
CCKeyDerivationPBKDF(
|
||||||
|
CCPBKDFAlgorithm(kCCPBKDF2),
|
||||||
|
password,
|
||||||
|
passwordData.count,
|
||||||
|
saltBytes.bindMemory(to: UInt8.self).baseAddress,
|
||||||
|
saltData.count,
|
||||||
|
hash.pbkdf2identifier,
|
||||||
|
UInt32(iterations),
|
||||||
|
derivedKeyBytes.bindMemory(to: UInt8.self).baseAddress,
|
||||||
|
localDerivedKeyData.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != kCCSuccess) {
|
||||||
|
throw NativeCryptoError.pbkdf2Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return SecretKey(derivedKeyData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,3 +6,20 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import CryptoKit
|
||||||
|
|
||||||
|
class SecretKey : Key {
|
||||||
|
var bytes: Data
|
||||||
|
|
||||||
|
init(_ bytes: Data) {
|
||||||
|
self.bytes = bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
init(fromSecureRandom bitsCount: Int) {
|
||||||
|
let symmetricKey = SymmetricKey.init(size: SymmetricKeySize(bitCount: bitsCount))
|
||||||
|
bytes = symmetricKey.withUnsafeBytes
|
||||||
|
{
|
||||||
|
return Data(Array($0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,3 +6,11 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
protocol Cipher {
|
||||||
|
var algorithm: CipherAlgorithm { get }
|
||||||
|
func encrypt(data: Data, key: Data) throws -> Data
|
||||||
|
func decrypt(data: Data, key: Data) throws -> Data
|
||||||
|
func encryptAsList(data: Data, key: Data) throws -> [Data]
|
||||||
|
func decryptAsList(data: [Data], key: Data) throws-> Data
|
||||||
|
}
|
||||||
|
@ -6,3 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
protocol Key {
|
||||||
|
var bytes: Data { get set }
|
||||||
|
}
|
||||||
|
@ -6,3 +6,8 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
protocol KeyDerivation {
|
||||||
|
var algorithm : KdfAlgorithm { get }
|
||||||
|
func derive() throws -> SecretKey
|
||||||
|
}
|
||||||
|
@ -6,3 +6,13 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
enum CipherAlgorithm : String {
|
||||||
|
case aes = "aes"
|
||||||
|
|
||||||
|
var getCipher: Cipher {
|
||||||
|
switch self {
|
||||||
|
case .aes: return AESCipher()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,3 +6,40 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import CommonCrypto
|
||||||
|
import CryptoKit
|
||||||
|
|
||||||
|
enum HashAlgorithm: String {
|
||||||
|
case HashSHA256 = "sha256"
|
||||||
|
case HashSHA384 = "sha384"
|
||||||
|
case HashSHA512 = "sha512"
|
||||||
|
|
||||||
|
var pbkdf2identifier: UInt32 {
|
||||||
|
switch self {
|
||||||
|
case .HashSHA256: return CCPBKDFAlgorithm(kCCPRFHmacAlgSHA256)
|
||||||
|
case .HashSHA384: return CCPBKDFAlgorithm(kCCPRFHmacAlgSHA384)
|
||||||
|
case .HashSHA512: return CCPBKDFAlgorithm(kCCPRFHmacAlgSHA512)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 13.0, *)
|
||||||
|
func digest(data: Data) -> Data {
|
||||||
|
switch self {
|
||||||
|
case .HashSHA256:
|
||||||
|
return Data(SHA256.hash(data: data))
|
||||||
|
case .HashSHA384:
|
||||||
|
return Data(SHA384.hash(data: data))
|
||||||
|
case .HashSHA512:
|
||||||
|
return Data(SHA512.hash(data: data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 13.0, *)
|
||||||
|
static func digest(data: Data, algorithm: String) throws -> Data {
|
||||||
|
let algo = HashAlgorithm.init(rawValue: algorithm)
|
||||||
|
if (algo == nil) {
|
||||||
|
throw NativeCryptoError.messageDigestError
|
||||||
|
}
|
||||||
|
return algo!.digest(data: data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,3 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
enum KdfAlgorithm {
|
||||||
|
case pbkdf2
|
||||||
|
}
|
||||||
|
@ -6,3 +6,13 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
enum NativeCryptoError : Error {
|
||||||
|
case decryptionError
|
||||||
|
case encryptionError
|
||||||
|
case messageDigestError
|
||||||
|
case pbkdf2Error
|
||||||
|
case cipherError
|
||||||
|
case resultError
|
||||||
|
case exceptionError
|
||||||
|
}
|
||||||
|
@ -6,3 +6,47 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
class Task<T> {
|
||||||
|
|
||||||
|
var task: () throws -> T
|
||||||
|
private var successful: Bool = false
|
||||||
|
private var result: T? = nil
|
||||||
|
private var exception: Error? = nil
|
||||||
|
|
||||||
|
init(task: @escaping () throws -> T) {
|
||||||
|
self.task = task
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSuccessful() -> Bool {
|
||||||
|
return successful
|
||||||
|
}
|
||||||
|
|
||||||
|
func getResult() -> T? {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func getException() -> Error {
|
||||||
|
if (exception != nil) {
|
||||||
|
return exception!
|
||||||
|
} else {
|
||||||
|
return NativeCryptoError.exceptionError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func call() {
|
||||||
|
do {
|
||||||
|
result = try task()
|
||||||
|
exception = nil
|
||||||
|
successful = true
|
||||||
|
} catch {
|
||||||
|
exception = error
|
||||||
|
result = nil
|
||||||
|
successful = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func finalize(callback: (_ task: Task<T>) -> Void) {
|
||||||
|
callback(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user