1,修改SM4加密源文件 解决SM4加密不一致问题
This commit is contained in:
parent
83daf04a11
commit
b6bafc9a47
@ -1,6 +1,7 @@
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:star_lock/blue/sm4Encipher/sm4.dart';
|
||||
|
||||
import '../../tools/storage.dart';
|
||||
import '../io_tool/io_tool.dart';
|
||||
import 'io_reply.dart';
|
||||
@ -9,10 +10,8 @@ import 'io_type.dart';
|
||||
|
||||
import 'package:crypto/crypto.dart' as a;
|
||||
import 'package:convert/convert.dart';
|
||||
import 'package:sm_crypto/sm_crypto.dart';
|
||||
|
||||
class GetPrivateKeyCommand extends SenderProtocol {
|
||||
|
||||
String? lockID;
|
||||
String? keyID; // 钥匙ID
|
||||
String? authUserID; // 钥匙授权人ID
|
||||
@ -34,9 +33,9 @@ class GetPrivateKeyCommand extends SenderProtocol {
|
||||
|
||||
// 指令类型
|
||||
int type = commandType!.typeValue;
|
||||
double typeDouble = type/256;
|
||||
double typeDouble = type / 256;
|
||||
int type1 = typeDouble.toInt();
|
||||
int type2 = type%256;
|
||||
int type2 = type % 256;
|
||||
data.add(type1);
|
||||
data.add(type2);
|
||||
print("type:$type");
|
||||
@ -67,9 +66,9 @@ class GetPrivateKeyCommand extends SenderProtocol {
|
||||
data.add((d1 & 0xff00) >> 8);
|
||||
data.add((d1 & 0xff));
|
||||
|
||||
if(needAuthor == 0){
|
||||
if (needAuthor == 0) {
|
||||
data.add(0);
|
||||
}else{
|
||||
} else {
|
||||
List<int> authCodeData = [];
|
||||
|
||||
//KeyID
|
||||
@ -100,21 +99,24 @@ class GetPrivateKeyCommand extends SenderProtocol {
|
||||
|
||||
// 把KeyID、authUserID、时间戳、公钥通过md5加密之后就是authCode
|
||||
var authCode = a.md5.convert(authCodeData);
|
||||
print("authCodeData:$authCodeData \nauthCode:$authCode \nauthCodeBytes:${authCode.bytes}");
|
||||
print(
|
||||
"authCodeData:$authCodeData \nauthCode:$authCode \nauthCodeBytes:${authCode.bytes}");
|
||||
|
||||
data.add(authCode.bytes.length);
|
||||
data.addAll(authCode.bytes);
|
||||
}
|
||||
|
||||
if((data.length % 16) != 0){
|
||||
if ((data.length % 16) != 0) {
|
||||
int add = (16 - data.length % 16);
|
||||
for(int i = 0; i<add; i++){
|
||||
for (int i = 0; i < add; i++) {
|
||||
data.add(0);
|
||||
}
|
||||
}
|
||||
print("SM4Data:$data");
|
||||
// 拿到数据之后通过LockId进行SM4 ECB加密
|
||||
ebcData = utf8.encode(getSM4Str(data, "TMH_c3570480da8d"));
|
||||
// 拿到数据之后通过LockId进行SM4 ECB加密 key:544d485f633335373034383064613864
|
||||
String key = SM4.createHexKey(key: 'TMH_c3570480da8d');
|
||||
ebcData = SM4.encrypt(data, key: key, mode: SM4CryptoMode.ECB);
|
||||
// ebcData = utf8.encode(getSM4Str(data, "TMH_c3570480da8d"));
|
||||
print("ebcData:$ebcData");
|
||||
// String cbcEncryptData = SM4.encrypt(data: data, key: "TMH_c3570480da8d", mode: SM4CryptoMode.CBC, iv: iv,);
|
||||
return ebcData;
|
||||
@ -122,7 +124,7 @@ class GetPrivateKeyCommand extends SenderProtocol {
|
||||
}
|
||||
|
||||
class GetPrivateKeyReply extends Reply {
|
||||
GetPrivateKeyReply.parseData(CommandType commandType, List<int> dataDetail)
|
||||
GetPrivateKeyReply.parseData(CommandType commandType, List<int> dataDetail)
|
||||
: super.parseData(commandType, dataDetail) {
|
||||
print('获取私钥');
|
||||
int index = 0;
|
||||
@ -134,4 +136,4 @@ class GetPrivateKeyReply extends Reply {
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,38 +4,38 @@ import 'dart:typed_data';
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:encrypt/encrypt.dart' as ddd;
|
||||
import 'package:sm_crypto/sm_crypto.dart';
|
||||
// import 'package:sm_crypto/sm_crypto.dart';
|
||||
|
||||
String getSM4Str(List<int>data, String key) {
|
||||
String dataStr = radixString(data);
|
||||
String iv = SM4.createHexKey(key: key);
|
||||
// String getSM4Str(List<int>data, String key) {
|
||||
// String dataStr = radixString(data);
|
||||
// String iv = SM4.createHexKey(key: key);
|
||||
|
||||
String cbcEncryptData = SM4.encrypt(
|
||||
data: dataStr,
|
||||
key: iv,
|
||||
mode: SM4CryptoMode.ECB,
|
||||
iv: iv,
|
||||
);
|
||||
// String cbcEncryptData = SM4.encrypt(
|
||||
// data: dataStr,
|
||||
// key: iv,
|
||||
// mode: SM4CryptoMode.ECB,
|
||||
// iv: iv,
|
||||
// );
|
||||
|
||||
print("getDNSAPIStrData:$data \ngetDNSAPIStrkey:$key \ngetDNSAPIStrDataStr:$dataStr \niv:$iv\ncbcEncryptData:$cbcEncryptData");
|
||||
return cbcEncryptData;
|
||||
// print("getDNSAPIStrData:$data \ngetDNSAPIStrkey:$key \ngetDNSAPIStrDataStr:$dataStr \niv:$iv\ncbcEncryptData:$cbcEncryptData");
|
||||
// return cbcEncryptData;
|
||||
|
||||
// final iv = ddd.IV.fromLength(32);
|
||||
// final encrypter = ddd.Encrypter(ddd.AES(ddd.Key.fromUtf8(key), mode: ddd.AESMode.ecb, padding: 'PKCS7'));
|
||||
// final encrypted = encrypter.encrypt(key, iv: iv);
|
||||
//
|
||||
// return encrypted;
|
||||
}
|
||||
// // final iv = ddd.IV.fromLength(32);
|
||||
// // final encrypter = ddd.Encrypter(ddd.AES(ddd.Key.fromUtf8(key), mode: ddd.AESMode.ecb, padding: 'PKCS7'));
|
||||
// // final encrypted = encrypter.encrypt(key, iv: iv);
|
||||
// //
|
||||
// // return encrypted;
|
||||
// }
|
||||
|
||||
String md5Crypto(List<int> data){
|
||||
String md5Crypto(List<int> data) {
|
||||
final dig = md5.convert(data);
|
||||
var keyStr = dig.toString();
|
||||
return keyStr.substring(0, 16).toLowerCase();
|
||||
}
|
||||
|
||||
// 获取固定长度的数组
|
||||
List<int> getFixedLengthList(List<int>data, int length) {
|
||||
for(int i = 0; i<length; i++){
|
||||
List<int> getFixedLengthList(List<int> data, int length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
data.add(0);
|
||||
}
|
||||
return data;
|
||||
@ -55,7 +55,24 @@ String uint8ToHex(Uint8List byteArr) {
|
||||
return "";
|
||||
}
|
||||
Uint8List result = Uint8List(byteArr.length << 1);
|
||||
var hexTable = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']; //16进制字符表
|
||||
var hexTable = [
|
||||
'0',
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'A',
|
||||
'B',
|
||||
'C',
|
||||
'D',
|
||||
'E',
|
||||
'F'
|
||||
]; //16进制字符表
|
||||
for (var i = 0; i < byteArr.length; i++) {
|
||||
var bit = byteArr[i]; //取传入的byteArr的每一位
|
||||
var index = bit >> 4 & 15; //右移4位,取剩下四位
|
||||
|
||||
535
star_lock/lib/blue/sm4Encipher/sm4.dart
Normal file
535
star_lock/lib/blue/sm4Encipher/sm4.dart
Normal file
@ -0,0 +1,535 @@
|
||||
import 'dart:convert';
|
||||
import 'utils/utils.dart';
|
||||
|
||||
enum SM4CryptoMode { ECB, CBC }
|
||||
|
||||
class SM4 {
|
||||
static const List<int> S_BOX = [
|
||||
0xd6,
|
||||
0x90,
|
||||
0xe9,
|
||||
0xfe,
|
||||
0xcc,
|
||||
0xe1,
|
||||
0x3d,
|
||||
0xb7,
|
||||
0x16,
|
||||
0xb6,
|
||||
0x14,
|
||||
0xc2,
|
||||
0x28,
|
||||
0xfb,
|
||||
0x2c,
|
||||
0x05,
|
||||
0x2b,
|
||||
0x67,
|
||||
0x9a,
|
||||
0x76,
|
||||
0x2a,
|
||||
0xbe,
|
||||
0x04,
|
||||
0xc3,
|
||||
0xaa,
|
||||
0x44,
|
||||
0x13,
|
||||
0x26,
|
||||
0x49,
|
||||
0x86,
|
||||
0x06,
|
||||
0x99,
|
||||
0x9c,
|
||||
0x42,
|
||||
0x50,
|
||||
0xf4,
|
||||
0x91,
|
||||
0xef,
|
||||
0x98,
|
||||
0x7a,
|
||||
0x33,
|
||||
0x54,
|
||||
0x0b,
|
||||
0x43,
|
||||
0xed,
|
||||
0xcf,
|
||||
0xac,
|
||||
0x62,
|
||||
0xe4,
|
||||
0xb3,
|
||||
0x1c,
|
||||
0xa9,
|
||||
0xc9,
|
||||
0x08,
|
||||
0xe8,
|
||||
0x95,
|
||||
0x80,
|
||||
0xdf,
|
||||
0x94,
|
||||
0xfa,
|
||||
0x75,
|
||||
0x8f,
|
||||
0x3f,
|
||||
0xa6,
|
||||
0x47,
|
||||
0x07,
|
||||
0xa7,
|
||||
0xfc,
|
||||
0xf3,
|
||||
0x73,
|
||||
0x17,
|
||||
0xba,
|
||||
0x83,
|
||||
0x59,
|
||||
0x3c,
|
||||
0x19,
|
||||
0xe6,
|
||||
0x85,
|
||||
0x4f,
|
||||
0xa8,
|
||||
0x68,
|
||||
0x6b,
|
||||
0x81,
|
||||
0xb2,
|
||||
0x71,
|
||||
0x64,
|
||||
0xda,
|
||||
0x8b,
|
||||
0xf8,
|
||||
0xeb,
|
||||
0x0f,
|
||||
0x4b,
|
||||
0x70,
|
||||
0x56,
|
||||
0x9d,
|
||||
0x35,
|
||||
0x1e,
|
||||
0x24,
|
||||
0x0e,
|
||||
0x5e,
|
||||
0x63,
|
||||
0x58,
|
||||
0xd1,
|
||||
0xa2,
|
||||
0x25,
|
||||
0x22,
|
||||
0x7c,
|
||||
0x3b,
|
||||
0x01,
|
||||
0x21,
|
||||
0x78,
|
||||
0x87,
|
||||
0xd4,
|
||||
0x00,
|
||||
0x46,
|
||||
0x57,
|
||||
0x9f,
|
||||
0xd3,
|
||||
0x27,
|
||||
0x52,
|
||||
0x4c,
|
||||
0x36,
|
||||
0x02,
|
||||
0xe7,
|
||||
0xa0,
|
||||
0xc4,
|
||||
0xc8,
|
||||
0x9e,
|
||||
0xea,
|
||||
0xbf,
|
||||
0x8a,
|
||||
0xd2,
|
||||
0x40,
|
||||
0xc7,
|
||||
0x38,
|
||||
0xb5,
|
||||
0xa3,
|
||||
0xf7,
|
||||
0xf2,
|
||||
0xce,
|
||||
0xf9,
|
||||
0x61,
|
||||
0x15,
|
||||
0xa1,
|
||||
0xe0,
|
||||
0xae,
|
||||
0x5d,
|
||||
0xa4,
|
||||
0x9b,
|
||||
0x34,
|
||||
0x1a,
|
||||
0x55,
|
||||
0xad,
|
||||
0x93,
|
||||
0x32,
|
||||
0x30,
|
||||
0xf5,
|
||||
0x8c,
|
||||
0xb1,
|
||||
0xe3,
|
||||
0x1d,
|
||||
0xf6,
|
||||
0xe2,
|
||||
0x2e,
|
||||
0x82,
|
||||
0x66,
|
||||
0xca,
|
||||
0x60,
|
||||
0xc0,
|
||||
0x29,
|
||||
0x23,
|
||||
0xab,
|
||||
0x0d,
|
||||
0x53,
|
||||
0x4e,
|
||||
0x6f,
|
||||
0xd5,
|
||||
0xdb,
|
||||
0x37,
|
||||
0x45,
|
||||
0xde,
|
||||
0xfd,
|
||||
0x8e,
|
||||
0x2f,
|
||||
0x03,
|
||||
0xff,
|
||||
0x6a,
|
||||
0x72,
|
||||
0x6d,
|
||||
0x6c,
|
||||
0x5b,
|
||||
0x51,
|
||||
0x8d,
|
||||
0x1b,
|
||||
0xaf,
|
||||
0x92,
|
||||
0xbb,
|
||||
0xdd,
|
||||
0xbc,
|
||||
0x7f,
|
||||
0x11,
|
||||
0xd9,
|
||||
0x5c,
|
||||
0x41,
|
||||
0x1f,
|
||||
0x10,
|
||||
0x5a,
|
||||
0xd8,
|
||||
0x0a,
|
||||
0xc1,
|
||||
0x31,
|
||||
0x88,
|
||||
0xa5,
|
||||
0xcd,
|
||||
0x7b,
|
||||
0xbd,
|
||||
0x2d,
|
||||
0x74,
|
||||
0xd0,
|
||||
0x12,
|
||||
0xb8,
|
||||
0xe5,
|
||||
0xb4,
|
||||
0xb0,
|
||||
0x89,
|
||||
0x69,
|
||||
0x97,
|
||||
0x4a,
|
||||
0x0c,
|
||||
0x96,
|
||||
0x77,
|
||||
0x7e,
|
||||
0x65,
|
||||
0xb9,
|
||||
0xf1,
|
||||
0x09,
|
||||
0xc5,
|
||||
0x6e,
|
||||
0xc6,
|
||||
0x84,
|
||||
0x18,
|
||||
0xf0,
|
||||
0x7d,
|
||||
0xec,
|
||||
0x3a,
|
||||
0xdc,
|
||||
0x4d,
|
||||
0x20,
|
||||
0x79,
|
||||
0xee,
|
||||
0x5f,
|
||||
0x3e,
|
||||
0xd7,
|
||||
0xcb,
|
||||
0x39,
|
||||
0x48
|
||||
];
|
||||
|
||||
static const List<int> FK = [0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC];
|
||||
|
||||
static const List<int> CK = [
|
||||
0x00070e15,
|
||||
0x1c232a31,
|
||||
0x383f464d,
|
||||
0x545b6269,
|
||||
0x70777e85,
|
||||
0x8c939aa1,
|
||||
0xa8afb6bd,
|
||||
0xc4cbd2d9,
|
||||
0xe0e7eef5,
|
||||
0xfc030a11,
|
||||
0x181f262d,
|
||||
0x343b4249,
|
||||
0x50575e65,
|
||||
0x6c737a81,
|
||||
0x888f969d,
|
||||
0xa4abb2b9,
|
||||
0xc0c7ced5,
|
||||
0xdce3eaf1,
|
||||
0xf8ff060d,
|
||||
0x141b2229,
|
||||
0x30373e45,
|
||||
0x4c535a61,
|
||||
0x686f767d,
|
||||
0x848b9299,
|
||||
0xa0a7aeb5,
|
||||
0xbcc3cad1,
|
||||
0xd8dfe6ed,
|
||||
0xf4fb0209,
|
||||
0x10171e25,
|
||||
0x2c333a41,
|
||||
0x484f565d,
|
||||
0x646b7279
|
||||
];
|
||||
|
||||
static const int SM4_ENCRYPT = 1;
|
||||
|
||||
static const int SM4_DECRYPT = 0;
|
||||
|
||||
static const int blockSize = 16;
|
||||
|
||||
static final _encryptKey = List<int>.filled(32, 0);
|
||||
static final _decryptKey = List<int>.filled(32, 0);
|
||||
|
||||
static int _readUint32BE(List<int> b, int i) {
|
||||
return ((b[i] & 0xff) << 24) |
|
||||
((b[i + 1] & 0xff) << 16) |
|
||||
((b[i + 2] & 0xff) << 8) |
|
||||
(b[i + 3] & 0xff);
|
||||
}
|
||||
|
||||
static void _writeUint32BE(int n, List<int> b, int i) {
|
||||
b[i] = ((n >> 24) & 0xff);
|
||||
b[i + 1] = ((n >> 16) & 0xff);
|
||||
b[i + 2] = ((n >> 8) & 0xff);
|
||||
b[i + 3] = n & 0xff;
|
||||
}
|
||||
|
||||
static int _Sbox(int inch) => S_BOX[inch & 0xFF];
|
||||
|
||||
static int _sm4F(int x0, int x1, int x2, int x3, int rk) {
|
||||
final x = x1 ^ x2 ^ x3 ^ rk;
|
||||
int bb = 0;
|
||||
int c = 0;
|
||||
List<int> a = List<int>.filled(4, 0);
|
||||
List<int> b = List<int>.filled(4, 0);
|
||||
_writeUint32BE(x, a, 0);
|
||||
b[0] = _Sbox(a[0]);
|
||||
b[1] = _Sbox(a[1]);
|
||||
b[2] = _Sbox(a[2]);
|
||||
b[3] = _Sbox(a[3]);
|
||||
bb = _readUint32BE(b, 0);
|
||||
|
||||
c = bb ^
|
||||
SMUtils.leftShift(bb, 2) ^
|
||||
SMUtils.leftShift(bb, 10) ^
|
||||
SMUtils.leftShift(bb, 18) ^
|
||||
SMUtils.leftShift(bb, 24);
|
||||
return x0 ^ c;
|
||||
}
|
||||
|
||||
static int _calculateRoundKey(int key) {
|
||||
int roundKey = 0;
|
||||
List<int> keyBytes = List<int>.filled(4, 0);
|
||||
List<int> sboxBytes = List<int>.filled(4, 0);
|
||||
_writeUint32BE(key, keyBytes, 0);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
sboxBytes[i] = _Sbox(keyBytes[i]);
|
||||
}
|
||||
int temp = _readUint32BE(sboxBytes, 0);
|
||||
roundKey = temp ^ SMUtils.leftShift(temp, 13) ^ SMUtils.leftShift(temp, 23);
|
||||
return roundKey;
|
||||
}
|
||||
|
||||
static void setKey(String key) {
|
||||
List<int> keyBytes = SMUtils.hexStringToBytes(key);
|
||||
List<int> intermediateKeys = List<int>.filled(36, 0);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
intermediateKeys[i] = _readUint32BE(keyBytes, i * 4) ^ FK[i];
|
||||
}
|
||||
for (int i = 0; i < 32; i++) {
|
||||
intermediateKeys[i + 4] = intermediateKeys[i] ^
|
||||
_calculateRoundKey(intermediateKeys[i + 1] ^
|
||||
intermediateKeys[i + 2] ^
|
||||
intermediateKeys[i + 3] ^
|
||||
CK[i]);
|
||||
_encryptKey[i] = intermediateKeys[i + 4];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
int temp = _encryptKey[i];
|
||||
_decryptKey[i] = _encryptKey[31 - i];
|
||||
_decryptKey[31 - i] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
static void _round(List<int> sk, List<int> input, List<int> output) {
|
||||
int i = 0;
|
||||
List<int> ulbuf = List<int>.filled(36, 0);
|
||||
ulbuf[0] = _readUint32BE(input, 0);
|
||||
ulbuf[1] = _readUint32BE(input, 4);
|
||||
ulbuf[2] = _readUint32BE(input, 8);
|
||||
ulbuf[3] = _readUint32BE(input, 12);
|
||||
while (i < 32) {
|
||||
ulbuf[i + 4] =
|
||||
_sm4F(ulbuf[i], ulbuf[i + 1], ulbuf[i + 2], ulbuf[i + 3], sk[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
_writeUint32BE(ulbuf[35], output, 0);
|
||||
_writeUint32BE(ulbuf[34], output, 4);
|
||||
_writeUint32BE(ulbuf[33], output, 8);
|
||||
_writeUint32BE(ulbuf[32], output, 12);
|
||||
}
|
||||
|
||||
static List<int> _padding(List<int> input, int mode) {
|
||||
final int padLen = blockSize - (input.length % blockSize);
|
||||
|
||||
if (mode == SM4_ENCRYPT) {
|
||||
final paddedList = List<int>.filled(input.length + padLen, 0);
|
||||
paddedList.setRange(0, input.length, input);
|
||||
for (int i = input.length; i < paddedList.length; i++) {
|
||||
paddedList[i] = padLen;
|
||||
}
|
||||
return paddedList;
|
||||
} else {
|
||||
final lastByte = input.last;
|
||||
final cutLen = input.length - lastByte;
|
||||
return input.sublist(0, cutLen);
|
||||
}
|
||||
}
|
||||
|
||||
static List<int> _crypto(
|
||||
List<int> data, int flag, SM4CryptoMode mode, String? iv) {
|
||||
late List<int> lastVector;
|
||||
if (mode == SM4CryptoMode.CBC) {
|
||||
if (iv == null || iv.length != 32)
|
||||
throw Exception("IV must be a string of length 16");
|
||||
else
|
||||
lastVector = SMUtils.hexStringToBytes(iv);
|
||||
}
|
||||
final key = (flag == SM4_ENCRYPT) ? _encryptKey : _decryptKey;
|
||||
if (flag == SM4_ENCRYPT) {
|
||||
data = _padding(data, SM4_ENCRYPT);
|
||||
}
|
||||
final length = data.length;
|
||||
final List<int> output = [];
|
||||
|
||||
for (int offset = 0; offset < length; offset += blockSize) {
|
||||
final outData = List<int>.filled(blockSize, 0);
|
||||
final copyLen =
|
||||
(offset + blockSize <= length) ? blockSize : length - offset;
|
||||
final input = data.sublist(offset, offset + copyLen);
|
||||
if (mode == SM4CryptoMode.CBC && flag == SM4_ENCRYPT) {
|
||||
for (int i = 0; i < blockSize; i++) {
|
||||
input[i] = input[i] ^ lastVector[i];
|
||||
}
|
||||
}
|
||||
_round(key, input, outData);
|
||||
|
||||
if (mode == SM4CryptoMode.CBC && flag == SM4_DECRYPT) {
|
||||
for (int i = 0; i < blockSize; i++) {
|
||||
outData[i] ^= lastVector[i];
|
||||
}
|
||||
}
|
||||
output.addAll(outData);
|
||||
|
||||
if (mode == SM4CryptoMode.CBC) {
|
||||
if (flag == SM4_ENCRYPT) {
|
||||
lastVector = outData;
|
||||
} else {
|
||||
lastVector = input;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag == SM4_DECRYPT) {
|
||||
return _padding(output, SM4_DECRYPT);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/// Utf8 to byte list
|
||||
static List<int> _utf8ToArray(String str) {
|
||||
return utf8.encode(str);
|
||||
}
|
||||
|
||||
// /// auto add 0x00
|
||||
static List<int> _autoAddZero(List<int> list) {
|
||||
/// supplementary list
|
||||
List<int> supplementList = List.filled(16, 0x00);
|
||||
|
||||
/// complete list
|
||||
List<int> completeList = [...list, ...supplementList].sublist(0, 16);
|
||||
return completeList;
|
||||
}
|
||||
|
||||
/// hex byte list to hex string
|
||||
static String _listToHex(List<int> arr) {
|
||||
String hexString = arr
|
||||
.map((item) {
|
||||
String itemHexString = item.toRadixString(16);
|
||||
// The hexadecimal notation is 0123456789ABCDEF
|
||||
//if there is a single one, add 0
|
||||
if (itemHexString.length == 1) {
|
||||
return '0$itemHexString';
|
||||
} else {
|
||||
return itemHexString;
|
||||
}
|
||||
})
|
||||
.toList()
|
||||
.join('');
|
||||
|
||||
return hexString;
|
||||
}
|
||||
|
||||
static String createHexKey({
|
||||
required String key,
|
||||
autoPushZero = true,
|
||||
}) {
|
||||
List<int> keyList = _utf8ToArray(key);
|
||||
|
||||
if (autoPushZero) {
|
||||
if (keyList.length < 128 / 8) {
|
||||
keyList = _autoAddZero(keyList);
|
||||
}
|
||||
if (keyList.length > 128 / 8) {
|
||||
keyList = keyList.sublist(0, 16);
|
||||
}
|
||||
}
|
||||
return _listToHex(keyList);
|
||||
}
|
||||
|
||||
static List<int> encrypt(List<int> data,
|
||||
{String? key, SM4CryptoMode mode = SM4CryptoMode.ECB, String? iv}) {
|
||||
if (key != null) setKey(key);
|
||||
List<int> input = data;
|
||||
List<int> output = _crypto(input, SM4_ENCRYPT, mode, iv);
|
||||
return output;
|
||||
}
|
||||
|
||||
static decrypt(String cipherText,
|
||||
{String? key, SM4CryptoMode mode = SM4CryptoMode.ECB, String? iv}) {
|
||||
if (key != null) setKey(key);
|
||||
List<int> input = SMUtils.hexStringToBytes(cipherText);
|
||||
List<int> output = _crypto(input, SM4_DECRYPT, mode, iv);
|
||||
return utf8.decode(output);
|
||||
}
|
||||
}
|
||||
150
star_lock/lib/blue/sm4Encipher/utils/asn1.dart
Normal file
150
star_lock/lib/blue/sm4Encipher/utils/asn1.dart
Normal file
@ -0,0 +1,150 @@
|
||||
|
||||
|
||||
class _ASN1Object {
|
||||
String? tlv;
|
||||
String t = '00';
|
||||
String l = '00';
|
||||
String v = '';
|
||||
|
||||
_ASN1Object() {
|
||||
tlv = null;
|
||||
}
|
||||
|
||||
/// 获取 der 编码比特流16进制串
|
||||
String getEncodedHex() {
|
||||
if (tlv == null) {
|
||||
v = getValue();
|
||||
l = getLength();
|
||||
tlv = t + l + v;
|
||||
}
|
||||
return tlv!;
|
||||
}
|
||||
|
||||
String getLength() {
|
||||
int n = v.length ~/ 2; // 字节数
|
||||
String nHex = n.toRadixString(16);
|
||||
if (nHex.length % 2 == 1) nHex = '0$nHex';
|
||||
|
||||
if (n < 128) {
|
||||
return nHex;
|
||||
} else {
|
||||
int head = 128 + nHex.length ~/ 2;
|
||||
return head.toRadixString(16) + nHex;
|
||||
}
|
||||
}
|
||||
|
||||
String getValue() {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
class _DERInteger extends _ASN1Object {
|
||||
_DERInteger(BigInt? bigint) : super() {
|
||||
t = '02'; // 整型标签说明
|
||||
if (bigint != null) v = bigintToValue(bigint);
|
||||
}
|
||||
|
||||
@override
|
||||
String getValue() {
|
||||
return v;
|
||||
}
|
||||
|
||||
String bigintToValue(BigInt inputBigInt) {
|
||||
String hexString = inputBigInt.toRadixString(16);
|
||||
if (!hexString.startsWith('-')) {
|
||||
if (hexString.length % 2 == 1) {
|
||||
hexString = '0$hexString';
|
||||
} else if (!RegExp(r'^[0-7]').hasMatch(hexString)) {
|
||||
hexString = '00$hexString';
|
||||
}
|
||||
} else {
|
||||
// Negative number
|
||||
hexString = hexString.substring(1);
|
||||
|
||||
int paddedLength = hexString.length;
|
||||
if (paddedLength % 2 == 1) {
|
||||
paddedLength += 1; // Pad to a whole byte
|
||||
} else if (!RegExp(r'^[0-7]').hasMatch(hexString)) {
|
||||
paddedLength += 2;
|
||||
}
|
||||
|
||||
String bitmask = '';
|
||||
for (int i = 0; i < paddedLength; i++) {
|
||||
bitmask += 'f';
|
||||
}
|
||||
BigInt bitmaskBigInt = BigInt.parse(bitmask, radix: 16);
|
||||
|
||||
BigInt twosComplementBigInt = bitmaskBigInt ^ inputBigInt;
|
||||
twosComplementBigInt = twosComplementBigInt + BigInt.one;
|
||||
hexString = twosComplementBigInt.toRadixString(16).replaceAll(RegExp(r'^-'), '');
|
||||
}
|
||||
return hexString;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class _DERSequence extends _ASN1Object {
|
||||
List<_ASN1Object> asn1Array;
|
||||
|
||||
_DERSequence(this.asn1Array) : super() {
|
||||
t = '30'; // 序列标签说明
|
||||
}
|
||||
|
||||
@override
|
||||
String getValue() {
|
||||
v = asn1Array.map((asn1Object) => asn1Object.getEncodedHex()).join('');
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
int getLenOfL(String str, int start) {
|
||||
if (int.parse(str[start + 2]) < 8) return 1;
|
||||
return int.parse(str.substring(start + 2, start + 4)) & 0x7f + 1;
|
||||
}
|
||||
|
||||
int getL(String str, int start) {
|
||||
// 获取 l
|
||||
int len = getLenOfL(str, start);
|
||||
String l = str.substring(start + 2, start + 2 + len * 2);
|
||||
|
||||
if (l.isEmpty) return -1;
|
||||
BigInt bigint = int.parse(l[0]) < 8
|
||||
? BigInt.parse(l, radix: 16)
|
||||
: BigInt.parse(l.substring(2), radix: 16);
|
||||
|
||||
return bigint.toInt();
|
||||
}
|
||||
|
||||
int getStartOfV(String str, int start) {
|
||||
int len = getLenOfL(str, start);
|
||||
return start + (len + 1) * 2;
|
||||
}
|
||||
|
||||
class ASN1Utils {
|
||||
/// ASN.1 der 编码,针对 sm2 签名
|
||||
static String encodeDer(BigInt r, BigInt s) {
|
||||
final derR = _DERInteger(r);
|
||||
final derS = _DERInteger(s);
|
||||
final derSeq = _DERSequence([derR, derS]);
|
||||
return derSeq.getEncodedHex();
|
||||
}
|
||||
|
||||
/// 解析 ASN.1 der,针对 sm2 验签
|
||||
static Map<String, BigInt> decodeDer(String input) {
|
||||
int start = getStartOfV(input, 0);
|
||||
|
||||
int vIndexR = getStartOfV(input, start);
|
||||
int lR = getL(input, start);
|
||||
String vR = input.substring(vIndexR, vIndexR + lR * 2);
|
||||
|
||||
int nextStart = vIndexR + vR.length;
|
||||
int vIndexS = getStartOfV(input, nextStart);
|
||||
int lS = getL(input, nextStart);
|
||||
String vS = input.substring(vIndexS, vIndexS + lS * 2);
|
||||
|
||||
BigInt r = BigInt.parse(vR, radix: 16);
|
||||
BigInt s = BigInt.parse(vS, radix: 16);
|
||||
|
||||
return {'r': r, 's': s};
|
||||
}
|
||||
}
|
||||
248
star_lock/lib/blue/sm4Encipher/utils/ec.dart
Normal file
248
star_lock/lib/blue/sm4Encipher/utils/ec.dart
Normal file
@ -0,0 +1,248 @@
|
||||
class ECFieldElementFp {
|
||||
final BigInt x;
|
||||
final BigInt q;
|
||||
|
||||
ECFieldElementFp(this.q, this.x) {
|
||||
// TODO if (x.compareTo(q) >= 0) error
|
||||
}
|
||||
|
||||
/// 判断相等
|
||||
bool equals(ECFieldElementFp other) {
|
||||
if (other == this) return true;
|
||||
return (q == other.q && x == other.x);
|
||||
}
|
||||
|
||||
/// 返回具体数值
|
||||
BigInt toBigInteger() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/// 取反
|
||||
ECFieldElementFp negate() {
|
||||
return ECFieldElementFp(q, (-x) % q);
|
||||
}
|
||||
|
||||
/// 相加
|
||||
ECFieldElementFp add(ECFieldElementFp b) {
|
||||
return ECFieldElementFp(q, (x + b.toBigInteger()) % q);
|
||||
}
|
||||
|
||||
/// 相减
|
||||
ECFieldElementFp subtract(ECFieldElementFp b) {
|
||||
return ECFieldElementFp(q, (x - b.toBigInteger()) % q);
|
||||
}
|
||||
|
||||
/// 相乘
|
||||
ECFieldElementFp multiply(ECFieldElementFp b) {
|
||||
return ECFieldElementFp(q, (x * b.toBigInteger()) % q);
|
||||
}
|
||||
|
||||
/// 相除
|
||||
ECFieldElementFp divide(ECFieldElementFp b) {
|
||||
return ECFieldElementFp(q, (x * b.toBigInteger().modInverse(q)) % q);
|
||||
}
|
||||
|
||||
/// 平方
|
||||
ECFieldElementFp square() {
|
||||
return ECFieldElementFp(q, (x * x) % q);
|
||||
}
|
||||
}
|
||||
|
||||
class ECPointFp {
|
||||
final ECCurveFp curve;
|
||||
late final ECFieldElementFp? x;
|
||||
late final ECFieldElementFp? y;
|
||||
late final BigInt z;
|
||||
BigInt? zinv;
|
||||
|
||||
ECPointFp(this.curve, this.x, this.y, [BigInt? z]) {
|
||||
this.z = z ?? BigInt.one;
|
||||
zinv = null;
|
||||
}
|
||||
|
||||
ECFieldElementFp getX() {
|
||||
zinv ??= z.modInverse(curve.q);
|
||||
return curve.fromBigInteger(x!.toBigInteger() * zinv! % curve.q);
|
||||
}
|
||||
|
||||
ECFieldElementFp getY() {
|
||||
zinv ??= z.modInverse(curve.q);
|
||||
return curve.fromBigInteger(y!.toBigInteger() * zinv! % curve.q);
|
||||
}
|
||||
|
||||
bool equals(ECPointFp other) {
|
||||
if (other == this) return true;
|
||||
if (isInfinity()) return other.isInfinity();
|
||||
if (other.isInfinity()) return isInfinity();
|
||||
|
||||
final u = (other.y!.toBigInteger() * z - y!.toBigInteger() * other.z) % curve.q;
|
||||
if (u != BigInt.zero) return false;
|
||||
|
||||
final v = (other.x!.toBigInteger() * z - x!.toBigInteger() * other.z) % curve.q;
|
||||
return v == BigInt.zero;
|
||||
}
|
||||
|
||||
bool isInfinity() {
|
||||
if (x == null && y == null) return true;
|
||||
return z == BigInt.zero && y!.toBigInteger() != BigInt.zero;
|
||||
}
|
||||
|
||||
ECPointFp negate() {
|
||||
return ECPointFp(curve, x, y!.negate(), z);
|
||||
}
|
||||
|
||||
ECPointFp add(ECPointFp b) {
|
||||
if (isInfinity()) return b;
|
||||
if (b.isInfinity()) return this;
|
||||
final x1 = x!.toBigInteger();
|
||||
final y1 = y!.toBigInteger();
|
||||
final z1 = z;
|
||||
final x2 = b.x!.toBigInteger();
|
||||
final y2 = b.y!.toBigInteger();
|
||||
final z2 = b.z;
|
||||
final q = curve.q;
|
||||
final w1 = (x1 * z2) % q;
|
||||
final w2 = (x2 * z1) % q;
|
||||
final w3 = (w1 - w2) % q;
|
||||
final w4 = (y1 * z2) % q;
|
||||
final w5 = (y2 * z1) % q;
|
||||
final w6 = (w4 - w5) % q;
|
||||
|
||||
if (w3 == BigInt.zero) {
|
||||
if (w6 == BigInt.zero) {
|
||||
return twice();
|
||||
}
|
||||
return curve.infinity;
|
||||
}
|
||||
|
||||
final w7 = (w1 + w2) % q;
|
||||
final w8 = (z1 * z2) % q;
|
||||
final w9 = (w3 * w3) % q;
|
||||
final w10 = (w3 * w9) % q;
|
||||
final w11 = (w8 * (w6 * w6) % q - w7 * w9) % q;
|
||||
|
||||
final x3 = (w3 * w11) % q;
|
||||
final y3 = (w6 * (w9 * w1 % q - w11) - w4 * w10) % q;
|
||||
final z3 = (w10 * w8) % q;
|
||||
|
||||
return ECPointFp(curve, curve.fromBigInteger(x3), curve.fromBigInteger(y3), z3);
|
||||
}
|
||||
|
||||
ECPointFp twice() {
|
||||
if (isInfinity()) return this;
|
||||
if (y!.toBigInteger().sign == 0) return curve.infinity;
|
||||
|
||||
final x1 = x!.toBigInteger();
|
||||
final y1 = y!.toBigInteger();
|
||||
final z1 = z;
|
||||
final q = curve.q;
|
||||
final a = curve.a.toBigInteger();
|
||||
|
||||
final w1 = (x1 * x1 * BigInt.from(3) + a * (z1 * z1)) % q;
|
||||
final w2 = (y1 * BigInt.from(2) * z1) % q;
|
||||
final w3 = (y1 * y1) % q;
|
||||
final w4 = (w3 * x1 * z1) % q;
|
||||
final w5 = (w2 * w2) % q;
|
||||
final w6 = (w1 * w1 - w4 * BigInt.from(8)) % q;
|
||||
|
||||
final x3 = (w2 * w6) % q;
|
||||
final y3 = (w1 * (w4 * BigInt.from(4) - w6) - w5 * BigInt.from(2) * w3) % q;
|
||||
final z3 = (w2 * w5) % q;
|
||||
|
||||
return ECPointFp(curve, curve.fromBigInteger(x3), curve.fromBigInteger(y3), z3);
|
||||
}
|
||||
|
||||
ECPointFp multiply(BigInt k) {
|
||||
if (isInfinity()) return this;
|
||||
if (k.sign == 0) return curve.infinity;
|
||||
|
||||
final k3 = k * BigInt.from(3);
|
||||
final neg = negate();
|
||||
ECPointFp Q = this;
|
||||
|
||||
for (int i = k3.bitLength - 2; i > 0; i--) {
|
||||
Q = Q.twice();
|
||||
|
||||
/*final k3Bit = (k3 >> i) & BigInt.one == BigInt.one;
|
||||
final kBit = (k >> i) & BigInt.one == BigInt.zero;*/
|
||||
|
||||
final k3Bit = (k3 >> i).isOdd;
|
||||
;
|
||||
final kBit = (k >> i).isOdd;
|
||||
|
||||
if (k3Bit != kBit) {
|
||||
Q = Q.add(k3Bit ? this : neg);
|
||||
}
|
||||
}
|
||||
|
||||
return Q;
|
||||
}
|
||||
}
|
||||
|
||||
class ECCurveFp {
|
||||
ECCurveFp(this.q, BigInt a, BigInt b) {
|
||||
this.a = fromBigInteger(a);
|
||||
this.b = fromBigInteger(b);
|
||||
infinity = ECPointFp(this, null, null); // 无穷远点
|
||||
}
|
||||
|
||||
final BigInt q;
|
||||
late ECFieldElementFp a;
|
||||
late ECFieldElementFp b;
|
||||
late ECPointFp infinity;
|
||||
|
||||
bool equals(Object? other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! ECCurveFp) return false;
|
||||
return q == other.q && a == other.a && b == other.b;
|
||||
}
|
||||
|
||||
ECFieldElementFp fromBigInteger(BigInt x) {
|
||||
return ECFieldElementFp(q, x);
|
||||
}
|
||||
|
||||
ECPointFp? decodePointHex(String s) {
|
||||
switch (int.parse(s.substring(0, 2), radix: 16)) {
|
||||
case 0:
|
||||
return infinity;
|
||||
case 2:
|
||||
case 3:
|
||||
final x = fromBigInteger(BigInt.parse(s.substring(2), radix: 16));
|
||||
var y = fromBigInteger(x
|
||||
.multiply(x.square())
|
||||
.add(x.multiply(a))
|
||||
.add(b)
|
||||
.toBigInteger()
|
||||
.modPow(q ~/ BigInt.from(4) + BigInt.one, q));
|
||||
|
||||
/* var y = x
|
||||
.multiply(x.square())
|
||||
.add(x.multiply(a.add(b)))
|
||||
.toBigInteger()
|
||||
.modPow(q ~/ BigInt.from(4) + BigInt.one, q);*/
|
||||
if (y.toBigInteger() % BigInt.two !=
|
||||
BigInt.parse(s.substring(0, 2), radix: 16) - BigInt.two) {
|
||||
y = y.negate();
|
||||
}
|
||||
return ECPointFp(this, x, y);
|
||||
case 4:
|
||||
case 6:
|
||||
case 7:
|
||||
final len = (s.length - 2) ~/ 2;
|
||||
final xHex = s.substring(2, 2 + len);
|
||||
final yHex = s.substring(2 + len, 2 + 2 * len);
|
||||
/*print("xHex: ${BigInt.parse(xHex, radix: 16).toRadixString(16)}");
|
||||
print("yHex: ${BigInt.parse(yHex, radix: 16).toRadixString(16)}");*/
|
||||
return ECPointFp(this, fromBigInteger(BigInt.parse(xHex, radix: 16)),
|
||||
fromBigInteger(BigInt.parse(yHex, radix: 16)));
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String leftPad(String input, int num) {
|
||||
if (input.length >= num) return input;
|
||||
return List.filled(num - input.length, '0').join() + input;
|
||||
}
|
||||
|
||||
46
star_lock/lib/blue/sm4Encipher/utils/utils.dart
Normal file
46
star_lock/lib/blue/sm4Encipher/utils/utils.dart
Normal file
@ -0,0 +1,46 @@
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
class SMUtils{
|
||||
static int leftShift(int x, int n){
|
||||
int s = n & 31;
|
||||
x = (x & 0xFFFFFFFF).toSigned(32);
|
||||
return (((x << s) | ((x & 0xFFFFFFFF) >> (32 - s))) & 0xFFFFFFFF).toSigned(32);
|
||||
}
|
||||
|
||||
static int rightShift(int x, int n) {
|
||||
int s = n & 31;
|
||||
x = (x & 0xFFFFFFFF).toSigned(32);
|
||||
return ((x >> s) | ((x << (32 - s)) & 0xFFFFFFFF)).toSigned(32);
|
||||
}
|
||||
|
||||
static String bytesToHexString(List<int> bytes) {
|
||||
final buffer = StringBuffer();
|
||||
for (final byte in bytes) {
|
||||
buffer.write(byte.toRadixString(16).padLeft(2, '0'));
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
static List<int> hexStringToBytes(String hexString) {
|
||||
final length = hexString.length ~/ 2;
|
||||
final bytes = List<int>.filled(length, 0);
|
||||
for (int i = 0; i < length; i++) {
|
||||
final byteString = hexString.substring(i * 2, i * 2 + 2);
|
||||
bytes[i] = int.parse(byteString, radix: 16);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static String utf8ToHexString(String input) {
|
||||
List<int> utf8Encoded = utf8.encode(input);
|
||||
// 转换到16进制
|
||||
StringBuffer hexChars = StringBuffer();
|
||||
for (int i = 0; i < utf8Encoded.length; i++) {
|
||||
int bite = utf8Encoded[i];
|
||||
hexChars.write((bite >> 4).toRadixString(16));
|
||||
hexChars.write((bite & 0x0f).toRadixString(16));
|
||||
}
|
||||
return hexChars.toString();
|
||||
}
|
||||
}
|
||||
@ -87,7 +87,6 @@ dependencies:
|
||||
#加密解密
|
||||
encrypt: ^5.0.1
|
||||
crypto: ^3.0.3
|
||||
sm_crypto: ^1.0.3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user