Remove CryptoKit and add pbkdf2 in swift

This commit is contained in:
Hugo Pointcheval 2020-04-18 15:26:06 +02:00
parent 9ea2b5247e
commit 2a5c719c2e

View File

@ -1,6 +1,5 @@
import Flutter import Flutter
import UIKit import UIKit
import CryptoKit
import CommonCrypto import CommonCrypto
extension FlutterStandardTypedData { extension FlutterStandardTypedData {
@ -14,16 +13,6 @@ extension FlutterStandardTypedData {
} }
} }
// CryptoKit.Digest utils
@available(iOS 13.0, *)
extension Digest {
var bytes: [UInt8] { Array(makeIterator()) }
var data: Data { Data(bytes) }
var hexStr: String {
bytes.map { String(format: "%02X", $0) }.joined()
}
}
func crypt(operation: Int, algorithm: Int, options: Int, key: Data, func crypt(operation: Int, algorithm: Int, options: Int, key: Data,
initializationVector: Data, dataIn: Data) -> Data? { initializationVector: Data, dataIn: Data) -> Data? {
@ -49,6 +38,37 @@ func crypt(operation: Int, algorithm: Int, options: Int, key: Data,
} }
} }
func pbkdf2(hash: CCPBKDFAlgorithm, password: String, salt: String, keyByteCount: Int, rounds: Int) -> Data? {
let passwordData = password.data(using: .utf8)!
let saltData = salt.data(using: .utf8)!
var derivedKeyData = Data(repeating: 0, count: keyByteCount)
var localDerivedKeyData = derivedKeyData
let derivationStatus = derivedKeyData.withUnsafeMutableBytes { derivedKeyBytes in
saltData.withUnsafeBytes { saltBytes in
CCKeyDerivationPBKDF(
CCPBKDFAlgorithm(kCCPBKDF2),
password, passwordData.count,
saltBytes, saltData.count,
hash,
UInt32(rounds),
derivedKeyBytes, localDerivedKeyData.count)
}
}
if (derivationStatus != kCCSuccess) {
print("Error: \(derivationStatus)")
return nil;
}
return derivedKeyData
}
func pbkdf2sha256(password: String, salt: String, keyByteCount: Int, rounds: Int) -> Data? {
return pbkdf2(hash: CCPBKDFAlgorithm(kCCPRFHmacAlgSHA256), password: password, salt: salt, keyByteCount: keyByteCount, rounds: rounds)
}
func randomGenerateBytes(count: Int) -> Data? { func randomGenerateBytes(count: Int) -> Data? {
let bytes = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: 1) let bytes = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: 1)
defer { bytes.deallocate() } defer { bytes.deallocate() }
@ -85,9 +105,32 @@ extension Data {
options: kCCOptionPKCS7Padding, key: key, initializationVector: iv, options: kCCOptionPKCS7Padding, key: key, initializationVector: iv,
dataIn: ciphertext) dataIn: ciphertext)
} }
enum Algorithm {
case sha256
var digestLength: Int {
switch self {
case .sha256: return Int(CC_SHA256_DIGEST_LENGTH)
}
}
}
func hash(for algorithm: Algorithm) -> Data {
let hashBytes = UnsafeMutablePointer<UInt8>.allocate(capacity: algorithm.digestLength)
defer { hashBytes.deallocate() }
switch algorithm {
case .sha256:
withUnsafeBytes { (buffer) -> Void in
CC_SHA256(buffer.baseAddress!, CC_LONG(buffer.count), hashBytes)
}
}
return Data(bytes: hashBytes, count: algorithm.digestLength)
}
} }
@available(iOS 13.0, *)
public class SwiftNativeCryptoPlugin: NSObject, FlutterPlugin { public class SwiftNativeCryptoPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) { public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "native.crypto.helper", binaryMessenger: registrar.messenger()) let channel = FlutterMethodChannel(name: "native.crypto.helper", binaryMessenger: registrar.messenger())
@ -97,13 +140,37 @@ public class SwiftNativeCryptoPlugin: NSObject, FlutterPlugin {
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method { switch call.method {
case "pbkdf2":
let args = call.arguments as! NSDictionary
let password = args["password"] as! String
let salt = args["salt"] as! String
let keyLength = args["keyLength"] as! NSNumber
let iteration = args["iteration"] as! NSNumber
let keyBytes = pbkdf2sha256(password: password, salt: salt, keyByteCount: keyLength.intValue, rounds: iteration.intValue)
if keyBytes != nil {
result(FlutterStandardTypedData.init(bytes: keyBytes!))
} else {
result(FlutterError(code: "PBKDF2ERROR",
message: "PBKDF2 KEY IS NIL.",
details: nil))
}
case "symKeygen": case "symKeygen":
let args = call.arguments as! NSDictionary let args = call.arguments as! NSDictionary
let keySize = args["size"] as! NSNumber let keySize = args["size"] as! NSNumber
let keyBytes = symKeygen(keySize: keySize)! let keyBytes = symKeygen(keySize: keySize)
result(FlutterStandardTypedData.init(bytes: keyBytes)) if keyBytes != nil {
result(FlutterStandardTypedData.init(bytes: keyBytes!))
} else {
result(FlutterError(code: "SYMKEYGENERROR",
message: "GENERATED KEY IS NIL.",
details: nil))
}
case "symEncrypt": case "symEncrypt":
let args = call.arguments as! NSDictionary let args = call.arguments as! NSDictionary
@ -124,9 +191,15 @@ public class SwiftNativeCryptoPlugin: NSObject, FlutterPlugin {
let aesKey = (args["aesKey"] as! FlutterStandardTypedData).data let aesKey = (args["aesKey"] as! FlutterStandardTypedData).data
let decryptedPayload = symDecrypt(payload: encryptedPayload, aesKey: aesKey)! let decryptedPayload = symDecrypt(payload: encryptedPayload, aesKey: aesKey)
result(decryptedPayload) if decryptedPayload != nil {
result(FlutterStandardTypedData.init(bytes: decryptedPayload!))
} else {
result(FlutterError(code: "DECRYPTIONERROR",
message: "DECRYPTED PAYLOAD IS NIL. MAYBE VERIFICATION MAC IS UNVALID.",
details: nil))
}
default: result(FlutterMethodNotImplemented) default: result(FlutterMethodNotImplemented)
@ -134,8 +207,8 @@ public class SwiftNativeCryptoPlugin: NSObject, FlutterPlugin {
} }
func digest(input : Data) -> Data { func digest(input : Data) -> Data {
let hashed = SHA256.hash(data: input) let hashed = input.hash(for: .sha256)
return hashed.data return hashed
} }
func symKeygen(keySize : NSNumber) -> Data? { func symKeygen(keySize : NSNumber) -> Data? {