1,修改SM4加密源文件 解决SM4加密不一致问题

This commit is contained in:
Daisy 2023-08-11 09:48:00 +08:00
parent 83daf04a11
commit b6bafc9a47
7 changed files with 1034 additions and 37 deletions

View File

@ -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 {
// KeyIDauthUserIDmd5加密之后就是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 {
// }
// }
}
}
}

View File

@ -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,

View 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);
}
}

View 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};
}
}

View 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;
}

View 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();
}
}

View File

@ -87,7 +87,6 @@ dependencies:
#加密解密
encrypt: ^5.0.1
crypto: ^3.0.3
sm_crypto: ^1.0.3
dev_dependencies:
flutter_test: