import 'dart:convert'; import 'dart:ffi'; import 'dart:io'; import 'dart:math'; import 'dart:typed_data'; import 'package:ffi/ffi.dart'; import 'package:path_provider/path_provider.dart'; // TODO: 让_Block的size可以设置 class Block16 extends Struct { @Array(16) external Array buf; } class Block32 extends Struct { @Array(32) external Array buf; } extension ExBlock16 on Pointer { Pointer get p => Pointer.fromAddress(address); Uint8List get list => p.asTypedList(16); } extension ExBlock32 on Pointer { Pointer get p => Pointer.fromAddress(address); Uint8List get list => p.asTypedList(32); void copy(Pointer key) { for (int i=0; i<32; ++i) { key.ref.buf[i]=1; } } } class SM2Point extends Struct { external Block32 x, y; } extension ExSM2Point on Pointer { Pointer get x => Pointer.fromAddress(address); Pointer get y => x.elementAt(1); } class Block { Block(this.size): p = malloc.allocate(size); final int size; final Pointer p; Uint8List get list => p.asTypedList(size); // Pointer elementAt(int index) => p.elementAt(index); // int operator[](int index) => p[index]; // void operator[]=(int index, int value) => p[index] = value; } class SM2Key extends Struct { external SM2Point publicKey; external Block32 privateKey; } extension ExSM2Key on Pointer { Pointer get publicKey => Pointer.fromAddress(address); Pointer get privateKey => Pointer.fromAddress(address + 64); void generate() { assert(gm.sm2KeyGenerate(this) == 1); } void copy(Pointer key) { } } class SM4cbcCtx extends Struct { @Array(32) external Array sm4Key; external Block16 iv, block; @Size() external int blockNBytes; } extension ExSM4CBCCtx on Pointer { Pointer get sm4Key => Pointer.fromAddress(address); Pointer get iv => Pointer.fromAddress(sm4Key.elementAt(32).address); Pointer get block => iv.elementAt(1); int get size => ref.blockNBytes; } final _lib = DynamicLibrary.open("libgmssl.so"); final gm = GmSSL._(); final stderrAddress = _lib.lookup("stderr").value; final stdoutAddress = _lib.lookup("stdout").value; final _fputs = _lib.lookupFunction, UintPtr), int Function(Pointer, int)>("fputs"); int fputs(String str, int stream) { return _fputs(str.toNativeUtf8(), stream); } final _puts = _lib.lookupFunction), int Function(Pointer)>("puts"); int puts(String str) { return _puts(str.toNativeUtf8()); } final _freopen = _lib.lookupFunction< UintPtr Function(Pointer, Pointer, UintPtr), int Function(Pointer, Pointer, int)>("freopen"); int freopen(String path, String mode, int stream) { return _freopen(path.toNativeUtf8(), mode.toNativeUtf8(), stream); } const sm2MaxPlainText = 255; const sm2MaxCipherTextSize = 366; class GmSSL { GmSSL._(); Pointer newSM2Key() => malloc(); final _fopen = _lib.lookupFunction< UintPtr Function(Pointer, Pointer), int Function(Pointer, Pointer) >("fopen"); final fflush = _lib.lookupFunction("fflush"); final fclose = _lib.lookupFunction("fclose"); int fopen(String path, String mode) { return _fopen(path.toNativeUtf8(), mode.toNativeUtf8()); } final sm2KeyGenerate = _lib.lookupFunction), int Function(Pointer)>("sm2_key_generate"); // TODO: something wrong ... final sm2PrivateKeyInfoEncryptToDER = _lib.lookupFunction< Int Function(SM2Key, Pointer, Pointer>, Pointer), int Function(SM2Key, Pointer, Pointer>, Pointer) >("sm2_private_key_info_encrypt_to_der"); // TODO: unimplemented ... final sm2PrivateKeyInfoDecryptFromDER = _lib.lookupFunction< Int Function(SM2Key, Pointer>, Pointer, Pointer, Pointer>, Pointer), int Function(SM2Key, Pointer>, Pointer, Pointer, Pointer>, Pointer) >("sm2_private_key_info_decrypt_from_der"); final sm2PrivateKeyInfoEncryptToPEM = _lib.lookupFunction< Int Function(Pointer, Pointer, UintPtr), int Function(Pointer, Pointer, int) >("sm2_private_key_info_encrypt_to_pem"); final sm2PrivateKeyInfoDecryptFromPEM = _lib.lookupFunction< Int Function(Pointer, Pointer, UintPtr), int Function(Pointer, Pointer, int) >("sm2_private_key_info_decrypt_from_pem"); final sm2PublicKeyInfoToPEM = _lib.lookupFunction< Int Function(Pointer, UintPtr), int Function(Pointer, int) >("sm2_public_key_info_to_pem"); final sm2PublicKeyInfoFromPEM = _lib.lookupFunction< Int Function(Pointer, UintPtr), int Function(Pointer, int) >("sm2_public_key_info_from_pem"); final sm2PublicKeyInfoToDER = _lib.lookupFunction< Int Function(Pointer, Pointer, Pointer), int Function(Pointer, Pointer, Pointer) >("sm2_public_key_info_to_der"); final sm2PublicKeyInfoFromDER = _lib.lookupFunction< Int Function(Pointer, Pointer>, Pointer), int Function(Pointer, Pointer>, Pointer) >("sm2_public_key_info_from_der"); final sm2Encrypt = _lib.lookupFunction< Int Function(Pointer, Pointer, Size, Pointer, Pointer), int Function(Pointer, Pointer, int, Pointer, Pointer) >("sm2_encrypt"); final sm2Decrypt = _lib.lookupFunction< Int Function(Pointer, Pointer, Size, Pointer, Pointer), int Function(Pointer, Pointer, int, Pointer, Pointer) >("sm2_decrypt"); final sm4cbcEncryptInit = _lib.lookupFunction< Int Function(Pointer, Pointer, Pointer), int Function(Pointer, Pointer, Pointer) >("sm4_cbc_encrypt_init"); final sm4cbcEncryptUpdate = _lib.lookupFunction< Int Function(Pointer, Pointer, Size, Pointer, Pointer), int Function(Pointer, Pointer, int, Pointer, Pointer) >("sm4_cbc_encrypt_update"); final sm4cbcEncryptFinish = _lib.lookupFunction< Int Function(Pointer, Pointer, Pointer), int Function(Pointer, Pointer, Pointer) >("sm4_cbc_encrypt_finish"); final sm4cbcDecryptInit = _lib.lookupFunction< Int Function(Pointer, Pointer, Pointer), int Function(Pointer, Pointer, Pointer) >("sm4_cbc_decrypt_init"); final sm4cbcDecryptUpdate = _lib.lookupFunction< Int Function(Pointer, Pointer, Size, Pointer, Pointer), int Function(Pointer, Pointer, int, Pointer, Pointer) >("sm4_cbc_decrypt_update"); final sm4cbcDecryptFinish = _lib.lookupFunction< Int Function(Pointer, Pointer, Pointer), int Function(Pointer, Pointer, Pointer) >("sm4_cbc_decrypt_finish"); } Uint8List sm4cbcEncrypt(Uint8List input, Uint8List sm4key, Uint8List iv) { assert(sm4key.length == 16, "key length error"); assert(iv.length == 16, "key length error"); // print("sm4cbcEncrypt start..."); // print("malloc..."); final ctx = malloc(); final key = malloc(); final civ = malloc(); final inBuf = malloc(4096); final outBuf = malloc(4196); final outLen = malloc(); final output = []; // print("copy..."); for (int i=0; i<16; ++i) { key.p[i] = sm4key[i]; } for (int i=0; i<16; ++i) { civ.p[i] = iv[i]; } // print("init..."); assert(gm.sm4cbcEncryptInit(ctx, key, civ) == 1, "sm4cbcEncryptInit error"); // print("encrypt..."); for (int i=0; i(); final key = malloc(); final civ = malloc(); final inBuf = malloc(4096); final outBuf = malloc(4196); final outLen = malloc(); final output = []; for (int i=0; i<16; ++i) { key.p[i] = sm4key[i]; } for (int i=0; i<16; ++i) { civ.p[i] = iv[i]; } assert(gm.sm4cbcDecryptInit(ctx, key, civ) == 1, "sm4cbcDecryptInit error"); for (int i=0; i key) { final buf = malloc(512); final p = malloc(1); p.value = buf.address; final len = malloc(1); len.value = 0; assert(gm.sm2PublicKeyInfoToDER(key, p, len) == 1); assert(len.value >= 0 && len.value < 512, "error: len.value == ${len.value}"); final res = buf.asTypedList(len.value); malloc.free(buf); malloc.free(len); malloc.free(p); return res; } int sm2PublicKeyInfoFromDER(Pointer key, Uint8List der) { final buf = malloc(512); final len = malloc(); len.value = der.length; final p = malloc>(); p.value = buf; for (int i=0; i get _tempPemPath async => // "${(await getTemporaryDirectory()).path}/temp.pem"; // Future sm2PublicKeyInfoToPEMString(SM2Key key) async { // final path = await _tempPemPath; // final res = sm2PublicKeyInfoToPEM(key, path); // assert(res == 1); // return File(path).readAsStringSync(); // } int sm2PublicKeyInfoToPEM(Pointer key, String path) { final pf = gm.fopen(path, "w"); final res = gm.sm2PublicKeyInfoToPEM(key, pf); // TODO: 封装一个file类隐式执行fflush & fclose gm.fflush(pf); gm.fclose(pf); return res; } int sm2PublicKeyInfoFromPEM(Pointer key, String path) { final pf = gm.fopen(path, "r"); assert(pf != 0, "fopen $path failed"); final res = gm.sm2PublicKeyInfoFromPEM(key, pf); gm.fflush(pf); gm.fclose(pf); return res; } // Future sm2PublicKeyInfoFromPEMString(SM2Key key, String pem) async { // final path = await _tempPemPath; // File file = File(path); // file.writeAsStringSync(pem); // return sm2PublicKeyInfoFromPEM(key, path); // } // Future sm2PrivateKeyInfoEncryptToPEMString( // SM2Key key, Pointer pass) async { // final path = await _tempPemPath; // final res = sm2PrivateKeyInfoEncryptToPEM(key, pass, path); // return File(path).readAsStringSync(); // // pf = gm.fopen(savePath, "r"); // // assert(gm.sm2PrivateKeyInfoDecryptFromPEM(key, pass, pf) == 1); // } void sm2PrivateKeyInfoEncryptToPEM(Pointer key, Pointer pass, String path) { final pf = gm.fopen(path, "w"); assert(pf != 0, "fopen $path failed"); final res = gm.sm2PrivateKeyInfoEncryptToPEM(key, pass, pf); gm.fflush(pf); gm.fclose(pf); assert(res == 1); } int sm2PrivateKeyInfoDecryptFromPEM(Pointer key, Pointer pass, String path) { final pf = gm.fopen(path, "r"); assert(pf != 0, "fopen $path failed"); final res = gm.sm2PrivateKeyInfoDecryptFromPEM(key, pass, pf); gm.fflush(pf); gm.fclose(pf); return res; } Uint8List sm2Encrypt(Pointer key, Uint8List plaintext) { final inLen = plaintext.length; assert(inLen <= sm2MaxPlainText, "plaintext length > $sm2MaxPlainText"); Pointer input = malloc(sm2MaxPlainText + 1); Pointer output = malloc(sm2MaxCipherTextSize); Pointer outLen = malloc(); for (int i=0; i key, Uint8List ciphertext) { final inLen = ciphertext.length; assert(inLen <= sm2MaxCipherTextSize, "ciphertext length > $sm2MaxCipherTextSize"); Pointer input = malloc(sm2MaxCipherTextSize); Pointer output = malloc(sm2MaxCipherTextSize); Pointer outLen = malloc(); for (int i=0; i pass) { // throw UnimplementedError("this method run incorrectly"); // TODO: something wrong... // TODO: 检查使用完成后是否需要清理&释放内存 Pointer buf = malloc.allocate(1024 * sizeOf()); Pointer> p = malloc.allocate(sizeOf()); p.value = buf; Pointer len = calloc.allocate(sizeOf()); final res = gm.sm2PrivateKeyInfoEncryptToDER(key, pass, p, len); assert(res == 1); final list = buf.asTypedList(len.value); // TODO: safety clean malloc.free(buf); malloc.free(p); malloc.free(len); return list; }