encryptIos_until.dart
import 'encrypt_ios_platform_interface.dart';
export 'package:encrypt_ios/encrypt_ios_until.dart';
class EncryptIosUntil {
String KEY;
String IV;
EncryptIosUntil({this.KEY = "xxxxxxxxxxxxxxxx", this.IV = "vvvvvvvvvvvvvvvv"});//这里是配置默认的key和iv,各16字节
Future<String?> encryptStr({required String str,String? key, String? iv}){
return EncryptIosPlatform.instance.encryptStr(key??KEY,iv??IV,str);
}
Future<String?> decryptStr({required String str,String? key, String? iv}){
return EncryptIosPlatform.instance.decryptStr(key??KEY,iv??IV,str);
}
Future<bool?> encryptFile({required String src,required String desc,String? key, String? iv}){
return EncryptIosPlatform.instance.encryptFile(key??KEY,iv??IV, src, desc);
}
Future<bool?> decryptFile({required String src,required String desc,String? key, String? iv}){
return EncryptIosPlatform.instance.decryptFile(key??KEY,iv??IV, src, desc);
}
}
encrypt_ios_platform_interface.dart
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'encrypt_ios_method_channel.dart';
abstract class EncryptIosPlatform extends PlatformInterface {
EncryptIosPlatform() : super(token: _token);
static final Object _token = Object();
static EncryptIosPlatform _instance = MethodChannelEncryptIos();
static EncryptIosPlatform get instance => _instance;
static set instance(EncryptIosPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
Future<String?> encryptStr(String key,String iv,String str){
throw UnimplementedError('encryptStr() has not been implemented.');
}
Future<String?> decryptStr(String key,String iv,String str){
throw UnimplementedError('decryptStr() has not been implemented.');
}
Future<bool?> encryptFile(String key,String iv,String src,String desc){
throw UnimplementedError('encryptFile() has not been implemented.');
}
Future<bool?> decryptFile(String key,String iv,String src,String desc){
throw UnimplementedError('decryptFile() has not been implemented.');
}
}
encrypt_ios_method_channel.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'encrypt_ios_platform_interface.dart';
/// An implementation of [EncryptIosPlatform] that uses method channels.
class MethodChannelEncryptIos extends EncryptIosPlatform {
/// The method channel used to interact with the native platform.
final methodChannel = const MethodChannel('encrypt_ios');
Future<String?> encryptStr(String key,String iv,String str) async {
final enStr = await methodChannel.invokeMethod<String>('encryptStr',<String, dynamic>{
'key': key,
'iv': iv,
'str': str
});
return enStr;
}
Future<String?> decryptStr(String key,String iv,String str) async {
final deStr = await methodChannel.invokeMethod<String>('decryptStr',<String, dynamic>{
'key': key,
'iv': iv,
'str': str
});
return deStr;
}
Future<bool?> decryptFile(String key, String iv, String src, String desc) async {
final result = await methodChannel.invokeMethod<bool>('decryptFile',<String, dynamic>{
'key': key,
'iv': iv,
'src': src,
'desc': desc
});
return result;
}
Future<bool?> encryptFile(String key, String iv, String src, String desc) async {
final result = await methodChannel.invokeMethod<bool>('encryptFile',<String, dynamic>{
'key': key,
'iv': iv,
'src': src,
'desc': desc
});
return result;
}
}
添加 s.dependency ‘CommonCryptoModule’
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint encrypt.podspec` to validate before publishing.
#
Pod::Spec.new do |s|
s.name = 'encrypt'
s.version = '0.0.1'
s.summary = 'A new Flutter project.'
s.description = <<-DESC
A new Flutter project.
DESC
s.homepage = 'http://example.com'
s.license = { :file => '../LICENSE' }
s.author = { 'Your Company' => '[email protected]' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.dependency 'Flutter'
s.dependency 'CommonCryptoModule'
s.platform = :ios, '9.0'
# Flutter.framework does not contain a i386 slice.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
s.swift_version = '5.0'
end
搜索Swift找到对应的.swift文件进行修改
SwiftEncrypIosPlugin.swift
import Flutter
import UIKit
import CryptoSwift
import CommonCrypto
public class SwiftEncryptIosPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "encrypt_ios", binaryMessenger: registrar.messenger())
let instance = SwiftEncryptIosPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
//传入参数
let arg = call.arguments
//获取必要的key与iv
if let args = arg as? [String: Any],
let key = args["key"] as? String,
let iv = args["iv"] as? String
{
let keyData = Data(bytes: key, count: key.count)
let ivData = Data(bytes: iv, count: iv.count)
switch call.method {//区分调用方法
case "encryptStr":
if let str = args["str"] as? String{
debugPrint("encryptStr->str:"+str)
let deData = aesCBC(operation: kCCEncrypt, data: Data(bytes: str.bytes, count: str.count), keyData: keyData, ivData: ivData)
debugPrint("encryptStr->destr:"+deData.base64EncodedString())
result(deData.base64EncodedString())//编码base64返回,与Android端相同
}else{
result(FlutterError(code: "-1", message: "iOS could not extract " +
"flutter arguments in method: (encryptStr),missing parameter 'str'", details: nil))
}
case "decryptStr":
if let str = args["str"] as? String{
debugPrint("decryptStr->str:"+str)
let strData = Data(base64Encoded: str)//需要先解码base64,再进行解密
let deData = aesCBC(operation: kCCDecrypt, data:strData!, keyData: keyData, ivData: ivData)
let deStr = String(bytes: deData.bytes,encoding: String.Encoding.utf8)//转utf-8输出
debugPrint("decryptStr->destr:",deStr)
result(deStr)
}else{
result(FlutterError(code: "-1", message: "iOS could not extract " +
"flutter arguments in method: (encryptStr),missing parameter 'str'", details: nil))
}
case "encryptFile":
if let src = args["src"] as? String,
let desc = args["desc"] as? String{
var isSuccess = false
do{
isSuccess = try aesCBCFile(operation: kCCEncrypt, keyData: keyData, ivData: ivData, _srcPath: src, _descPath: desc)
result(isSuccess)
}catch{
result(FlutterError(code: "-1", message: error.localizedDescription, details: nil))
}
}else{
result(FlutterError(code: "-1", message: "iOS could not extract " +
"flutter arguments in method: (encryptFile),missing parameter 'src/desc'", details: nil))
}
case "decryptFile":
if let src = args["src"] as? String,
let desc = args["desc"] as? String{
var isSuccess = false
do{
isSuccess = try aesCBCFile(operation: kCCDecrypt, keyData: keyData, ivData: ivData, _srcPath: src, _descPath: desc)
result(isSuccess)
}catch{
result(FlutterError(code: "-1", message: error.localizedDescription, details: nil))
}
}else{
result(FlutterError(code: "-1", message: "iOS could not extract " +
"flutter arguments in method: (decryptFile),missing parameter 'src/desc'", details: nil))
}
default :
result("iOS " + UIDevice.current.systemVersion)
}
}else{
result(FlutterError(code: "-1", message: "iOS could not extract " +
"flutter arguments in : missing parameter(key or iv)", details: nil))
}
}
// AES加解密
public func aesCBC(operation: Int, data:Data, keyData: Data, ivData: Data) -> Data {
let dataLength = data.count
let cryptLength = size_t(dataLength + kCCBlockSizeAES128)
var cryptData = Data(count:cryptLength)
let keyLength = size_t(kCCKeySizeAES128)
let options = CCOptions(kCCOptionPKCS7Padding)
var numBytesEncrypted :size_t = 0
let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
data.withUnsafeBytes {dataBytes in
ivData.withUnsafeBytes {ivBytes in
keyData.withUnsafeBytes {keyBytes in
CCCrypt(CCOperation(operation),
CCAlgorithm(kCCAlgorithmAES),
options,
keyBytes, keyLength,
ivBytes,
dataBytes, dataLength,
cryptBytes, cryptLength,
&numBytesEncrypted)
}
}
}
}
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.removeSubrange(numBytesEncrypted..<cryptData.count)
} else {
print("Error: \(cryptStatus)")
}
return cryptData;
}
public func aesCBCFile(operation: Int, keyData: Data, ivData: Data, _srcPath:String,_descPath:String) throws -> Bool{
debugPrint("FileSrc:"+_srcPath)
debugPrint("FileDesc:"+_descPath)
let startTime = CFAbsoluteTimeGetCurrent()//记录方法开始时间
if !(FileManager.default.fileExists(atPath: _srcPath)) {//判断源文件是否存在
throw URLError(URLError.cannotWriteToFile,userInfo: ["message":"can't find file by srcPath"])
}
let inputStream = InputStream(fileAtPath: _srcPath)
if inputStream == nil {//判断源文件流是否存在
throw URLError(URLError.cannotWriteToFile,userInfo: ["message":"can't find file by srcPath"])
}
var srcFileSize : Int = 0
let src = try FileManager.default.attributesOfItem(atPath: _srcPath)
srcFileSize = Int(src[FileAttributeKey.size] as! UInt64)
debugPrint("Begin,SrcFileSize:",srcFileSize)
//初始化目标文件流,如果存在目标文件,进行移除
if(FileManager.default.fileExists(atPath: _descPath)){
try FileManager.default.removeItem(atPath: _descPath)
}
FileManager.default.createFile(atPath: _descPath, contents: nil)
let outputStream = OutputStream(toFileAtPath: _descPath, append: true)!
outputStream.open()
//初始化加解密
let keyLength = size_t(kCCKeySizeAES128)
let options = CCOptions(kCCOptionPKCS7Padding)
var cryptor: CCCryptorRef?
// defer {
// CCCryptorRelease(cryptor)
// }
let status = keyData.withUnsafeBytes {keyBytes in
ivData.withUnsafeBytes {ivBytes in
CCCryptorCreate(CCOperation(operation), CCAlgorithm(kCCAlgorithmAES), options, keyBytes, keyLength, ivBytes, &cryptor)
}
}//创建加解密对象
inputStream?.open()//开启输入流
var bufused = 0//bufused为实际加解密所进行的字符个数
var finalPointer:UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8>.allocate(capacity: 1)//保存CCCryptorUpdate的结果
let bufferSize = 1024*1024//缓冲区大小
while inputStream!.hasBytesAvailable{
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)//缓冲区
let read = inputStream!.read(buffer, maxLength: bufferSize)//读取数据流到缓冲区
if (read == 0){
buffer.deallocate()//清空缓冲区
break
}
var readData = Data(bytes: buffer, count: read)
var readLength = readData.count
let resultLength = size_t(readData.count + kCCBlockSizeAES128)//保存加解密后数组的长度
var updateData = [UInt8](repeating: 0, count: resultLength)//保存加解密后的数据
var cryptStatus = readData.withUnsafeBytes {readBytes in
CCCryptorUpdate(cryptor, readBytes, readLength, &updateData, resultLength , &bufused)//进行加解密
}
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
updateData.removeSubrange(bufused..<resultLength)//保存实际进行的加解密个数,去除原本多余的字符
} else {
print("Error: \(cryptStatus)")
}
outputStream.write(updateData, maxLength: updateData.count)//写入文件
finalPointer.initialize(from: updateData, count: 1)//记录修改,直接地址相连接,避免了内存溢出
buffer.deallocate()//清空缓冲区
}
//数据读取完毕,关闭读取文件流
inputStream!.close()
CCCryptorFinal(cryptor, finalPointer, srcFileSize, &bufused)//通过CCCryptorFinal可以获得srcFileSize-updateResult.count大小的且合并后不影响updateResult的数组
CCCryptorRelease(cryptor)//释放内存
let bufferPointer = UnsafeMutableBufferPointer(start: finalPointer, count: bufused)//截取有效地址
let result = outputStream.write(Array(bufferPointer), maxLength: bufused)//转为数组并写入文件
//数据写入完毕,关闭写入文件流
outputStream.close()
var descFileSize : Int = 0
let desc = try FileManager.default.attributesOfItem(atPath: _descPath)
descFileSize = Int(desc[FileAttributeKey.size] as! UInt64)
debugPrint("Finish,DescFileSize:",descFileSize)
//记录结束时间
let endTime = CFAbsoluteTimeGetCurrent()
debugPrint(String(format:"aesCBCFile Function usage time :%.2f second", (endTime - startTime)))
return true
}
}
pubspec.yaml
flutter:
plugin:
platforms:
# android:
# package: com.handcent.encrypt
# pluginClass: EncryptUntil
ios:
pluginClass: SwiftEncrypIosPlugin
转载请注明出处