From b6bafc9a478b85c6a80bdfc9fff9ea834aca1e3d Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Fri, 11 Aug 2023 09:48:00 +0800 Subject: [PATCH] =?UTF-8?q?1=EF=BC=8C=E4=BF=AE=E6=94=B9SM4=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E6=BA=90=E6=96=87=E4=BB=B6=20=E8=A7=A3=E5=86=B3SM4?= =?UTF-8?q?=E5=8A=A0=E5=AF=86=E4=B8=8D=E4=B8=80=E8=87=B4=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blue/io_protocol/io_getPrivateKey.dart | 30 +- star_lock/lib/blue/io_tool/io_tool.dart | 61 +- star_lock/lib/blue/sm4Encipher/sm4.dart | 535 ++++++++++++++++++ .../lib/blue/sm4Encipher/utils/asn1.dart | 150 +++++ star_lock/lib/blue/sm4Encipher/utils/ec.dart | 248 ++++++++ .../lib/blue/sm4Encipher/utils/utils.dart | 46 ++ star_lock/pubspec.yaml | 1 - 7 files changed, 1034 insertions(+), 37 deletions(-) create mode 100644 star_lock/lib/blue/sm4Encipher/sm4.dart create mode 100644 star_lock/lib/blue/sm4Encipher/utils/asn1.dart create mode 100644 star_lock/lib/blue/sm4Encipher/utils/ec.dart create mode 100644 star_lock/lib/blue/sm4Encipher/utils/utils.dart diff --git a/star_lock/lib/blue/io_protocol/io_getPrivateKey.dart b/star_lock/lib/blue/io_protocol/io_getPrivateKey.dart index 15691ef5..0215ef78 100644 --- a/star_lock/lib/blue/io_protocol/io_getPrivateKey.dart +++ b/star_lock/lib/blue/io_protocol/io_getPrivateKey.dart @@ -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 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 dataDetail) + GetPrivateKeyReply.parseData(CommandType commandType, List dataDetail) : super.parseData(commandType, dataDetail) { print('获取私钥'); int index = 0; @@ -134,4 +136,4 @@ class GetPrivateKeyReply extends Reply { // } // } } -} \ No newline at end of file +} diff --git a/star_lock/lib/blue/io_tool/io_tool.dart b/star_lock/lib/blue/io_tool/io_tool.dart index 63ab1364..3d633952 100644 --- a/star_lock/lib/blue/io_tool/io_tool.dart +++ b/star_lock/lib/blue/io_tool/io_tool.dart @@ -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(Listdata, String key) { - String dataStr = radixString(data); - String iv = SM4.createHexKey(key: key); +// String getSM4Str(Listdata, 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 data){ +String md5Crypto(List data) { final dig = md5.convert(data); var keyStr = dig.toString(); return keyStr.substring(0, 16).toLowerCase(); } // 获取固定长度的数组 -List getFixedLengthList(Listdata, int length) { - for(int i = 0; i getFixedLengthList(List 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位,取剩下四位 diff --git a/star_lock/lib/blue/sm4Encipher/sm4.dart b/star_lock/lib/blue/sm4Encipher/sm4.dart new file mode 100644 index 00000000..c226412d --- /dev/null +++ b/star_lock/lib/blue/sm4Encipher/sm4.dart @@ -0,0 +1,535 @@ +import 'dart:convert'; +import 'utils/utils.dart'; + +enum SM4CryptoMode { ECB, CBC } + +class SM4 { + static const List 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 FK = [0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC]; + + static const List 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.filled(32, 0); + static final _decryptKey = List.filled(32, 0); + + static int _readUint32BE(List 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 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 a = List.filled(4, 0); + List b = List.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 keyBytes = List.filled(4, 0); + List sboxBytes = List.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 keyBytes = SMUtils.hexStringToBytes(key); + List intermediateKeys = List.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 sk, List input, List output) { + int i = 0; + List ulbuf = List.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 _padding(List input, int mode) { + final int padLen = blockSize - (input.length % blockSize); + + if (mode == SM4_ENCRYPT) { + final paddedList = List.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 _crypto( + List data, int flag, SM4CryptoMode mode, String? iv) { + late List 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 output = []; + + for (int offset = 0; offset < length; offset += blockSize) { + final outData = List.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 _utf8ToArray(String str) { + return utf8.encode(str); + } + + // /// auto add 0x00 + static List _autoAddZero(List list) { + /// supplementary list + List supplementList = List.filled(16, 0x00); + + /// complete list + List completeList = [...list, ...supplementList].sublist(0, 16); + return completeList; + } + + /// hex byte list to hex string + static String _listToHex(List 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 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 encrypt(List data, + {String? key, SM4CryptoMode mode = SM4CryptoMode.ECB, String? iv}) { + if (key != null) setKey(key); + List input = data; + List 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 input = SMUtils.hexStringToBytes(cipherText); + List output = _crypto(input, SM4_DECRYPT, mode, iv); + return utf8.decode(output); + } +} diff --git a/star_lock/lib/blue/sm4Encipher/utils/asn1.dart b/star_lock/lib/blue/sm4Encipher/utils/asn1.dart new file mode 100644 index 00000000..144578a7 --- /dev/null +++ b/star_lock/lib/blue/sm4Encipher/utils/asn1.dart @@ -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 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}; + } +} \ No newline at end of file diff --git a/star_lock/lib/blue/sm4Encipher/utils/ec.dart b/star_lock/lib/blue/sm4Encipher/utils/ec.dart new file mode 100644 index 00000000..66d137c7 --- /dev/null +++ b/star_lock/lib/blue/sm4Encipher/utils/ec.dart @@ -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; +} + diff --git a/star_lock/lib/blue/sm4Encipher/utils/utils.dart b/star_lock/lib/blue/sm4Encipher/utils/utils.dart new file mode 100644 index 00000000..5ed948db --- /dev/null +++ b/star_lock/lib/blue/sm4Encipher/utils/utils.dart @@ -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 bytes) { + final buffer = StringBuffer(); + for (final byte in bytes) { + buffer.write(byte.toRadixString(16).padLeft(2, '0')); + } + return buffer.toString(); + } + + static List hexStringToBytes(String hexString) { + final length = hexString.length ~/ 2; + final bytes = List.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 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(); + } +} diff --git a/star_lock/pubspec.yaml b/star_lock/pubspec.yaml index 6380d7ae..8da6a97d 100644 --- a/star_lock/pubspec.yaml +++ b/star_lock/pubspec.yaml @@ -87,7 +87,6 @@ dependencies: #加密解密 encrypt: ^5.0.1 crypto: ^3.0.3 - sm_crypto: ^1.0.3 dev_dependencies: flutter_test: