Add cipher class and cipher algorithm in swift
This commit is contained in:
parent
5545badfc5
commit
9007fded56
135
ios/Classes/Cipher.swift
Normal file
135
ios/Classes/Cipher.swift
Normal file
@ -0,0 +1,135 @@
|
||||
//
|
||||
// Cipher.swift
|
||||
//
|
||||
// NativeCryptoPlugin
|
||||
//
|
||||
// Copyright (c) 2020
|
||||
// Author: Hugo Pointcheval
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CommonCrypto
|
||||
|
||||
enum CipherAlgorithm: String {
|
||||
case AES = "aes"
|
||||
case BlowFish = "blowfish"
|
||||
|
||||
var instance: Int {
|
||||
switch self {
|
||||
case .AES: return kCCAlgorithmAES
|
||||
case .BlowFish: return kCCAlgorithmBlowfish
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum BlockCipherMode: String {
|
||||
case ECB = "ecb"
|
||||
case CBC = "cbc"
|
||||
|
||||
var instance: Int {
|
||||
switch self {
|
||||
case .CBC: return 0
|
||||
case .ECB: return kCCOptionECBMode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Padding: String {
|
||||
case PKCS5 = "pkcs5"
|
||||
case None = "none"
|
||||
|
||||
var instance: Int {
|
||||
switch self {
|
||||
case .PKCS5: return kCCOptionPKCS7Padding
|
||||
case .None: return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Cipher {
|
||||
func encrypt(data : Data, key : Data, algorithm : CipherAlgorithm, mode : BlockCipherMode, padding : Padding) -> [Data]? {
|
||||
// Calculate Mac
|
||||
let mac = Hash().digest(data: key + data, algorithm: .SHA256)
|
||||
let payload = mac! + data
|
||||
|
||||
// Generate IV
|
||||
let ivBytes = UnsafeMutableRawPointer.allocate(byteCount: kCCBlockSizeAES128, alignment: 1)
|
||||
defer { ivBytes.deallocate() }
|
||||
let ivStatus = CCRandomGenerateBytes(ivBytes, kCCBlockSizeAES128)
|
||||
if (ivStatus != kCCSuccess) {
|
||||
return nil
|
||||
}
|
||||
let ivData = Data(bytes: ivBytes, count: kCCBlockSizeAES128)
|
||||
|
||||
let algo = algorithm.instance
|
||||
let options: CCOptions = UInt32(mode.instance + padding.instance)
|
||||
|
||||
|
||||
guard var ciphertext = crypt(operation: kCCEncrypt,
|
||||
algorithm: algo,
|
||||
options: options,
|
||||
key: key,
|
||||
initializationVector: ivData,
|
||||
dataIn: payload) else { return nil }
|
||||
|
||||
return [ciphertext, ivData]
|
||||
}
|
||||
|
||||
func decrypt(payload : [Data], key : Data, algorithm : CipherAlgorithm, mode : BlockCipherMode, padding : Padding) -> Data? {
|
||||
let encrypted = payload[1] + payload[0]
|
||||
|
||||
guard encrypted.count > kCCBlockSizeAES128 else { return nil }
|
||||
let iv = encrypted.prefix(kCCBlockSizeAES128)
|
||||
let ciphertext = encrypted.suffix(from: kCCBlockSizeAES128)
|
||||
|
||||
let algo = algorithm.instance
|
||||
let options: CCOptions = UInt32(mode.instance + padding.instance)
|
||||
|
||||
guard var decrypted = crypt(operation: kCCDecrypt,
|
||||
algorithm: algo,
|
||||
options: options,
|
||||
key: key,
|
||||
initializationVector: iv,
|
||||
dataIn: ciphertext) else {return nil}
|
||||
|
||||
|
||||
// Create a range based on the length of data to return
|
||||
let range = 0..<32
|
||||
|
||||
// Get a new copy of data
|
||||
let mac = decrypted.subdata(in: range)
|
||||
decrypted.removeSubrange(range)
|
||||
|
||||
let vmac = Hash().digest(data: key + decrypted, algorithm: .SHA256)
|
||||
|
||||
if (mac.base64EncodedData() == vmac!.base64EncodedData()) {
|
||||
return decrypted
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private func crypt(operation: Int, algorithm: Int, options: UInt32, key: Data,
|
||||
initializationVector: Data, dataIn: Data) -> Data? {
|
||||
|
||||
return key.withUnsafeBytes { keyUnsafeRawBufferPointer in
|
||||
return dataIn.withUnsafeBytes { dataInUnsafeRawBufferPointer in
|
||||
return initializationVector.withUnsafeBytes { ivUnsafeRawBufferPointer in
|
||||
let dataOutSize: Int = dataIn.count + kCCBlockSizeAES128*2
|
||||
let dataOut = UnsafeMutableRawPointer.allocate(byteCount: dataOutSize,
|
||||
alignment: 1)
|
||||
defer { dataOut.deallocate() }
|
||||
var dataOutMoved: Int = 0
|
||||
let status = CCCrypt(CCOperation(operation), CCAlgorithm(algorithm),
|
||||
CCOptions(options),
|
||||
keyUnsafeRawBufferPointer.baseAddress, key.count,
|
||||
ivUnsafeRawBufferPointer.baseAddress,
|
||||
dataInUnsafeRawBufferPointer.baseAddress, dataIn.count,
|
||||
dataOut, dataOutSize, &dataOutMoved)
|
||||
guard status == kCCSuccess else { return nil }
|
||||
return Data(bytes: dataOut, count: dataOutMoved)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user