import 'dart:convert'; import 'dart:math'; import 'dart:typed_data'; class SM3 { static const List _iv = [ 0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600, 0xA96F30BC, 0x163138AA, 0xE38DEE4D, 0xB0FB0E4E ]; static int _rotl(int x, int n) { assert(n >= 0 && n < 32); n = n & 31; // 保证 n 在 0~31 之间 return ((x << n) | (x >> (32 - n))) & 0xFFFFFFFF; } static int _p0(int x) => x ^ _rotl(x, 9) ^ _rotl(x, 17); static int _p1(int x) => x ^ _rotl(x, 15) ^ _rotl(x, 23); static int _ff(int x, int y, int z, int j) => (j < 16) ? (x ^ y ^ z) : ((x & y) | (x & z) | (y & z)); static int _gg(int x, int y, int z, int j) => (j < 16) ? (x ^ y ^ z) : ((x & y) | (~x & z)); static List digest(Uint8List data) { int len = data.length * 8; List msg = List.from(data); msg.add(0x80); while ((msg.length * 8) % 512 != 448) { msg.add(0x00); } for (int i = 7; i >= 0; i--) { msg.add((len >> (i * 8)) & 0xFF); } List v = List.from(_iv); for (int i = 0; i < msg.length; i += 64) { List b = msg.sublist(i, i + 64); List w = List.filled(68, 0); List w1 = List.filled(64, 0); for (int j = 0; j < 16; j++) { w[j] = (b[j * 4] << 24) | (b[j * 4 + 1] << 16) | (b[j * 4 + 2] << 8) | (b[j * 4 + 3]); } for (int j = 16; j < 68; j++) { int rotl3 = _rotl(w[j - 3], 15); int rotl13 = _rotl(w[j - 13], 7); w[j] = _p1(w[j - 16] ^ w[j - 9] ^ rotl3) ^ rotl13 ^ w[j - 6]; w[j] &= 0xFFFFFFFF; } for (int j = 0; j < 64; j++) { w1[j] = w[j] ^ w[j + 4]; } int a = v[0], b_ = v[1], c = v[2], d = v[3]; int e = v[4], f = v[5], g = v[6], h = v[7]; for (int j = 0; j < 64; j++) { int tj = (j < 16) ? 0x79CC4519 : 0x7A879D8A; int rotlA12 = _rotl(a, 12); int rotlTj = _rotl(tj, j & 0x1F); // 保证位移参数在0~31 int ss1 = _rotl((rotlA12 + e + rotlTj) & 0xFFFFFFFF, 7); int ss2 = ss1 ^ rotlA12; int tt1 = (_ff(a, b_, c, j) + d + ss2 + w1[j]) & 0xFFFFFFFF; int tt2 = (_gg(e, f, g, j) + h + ss1 + w[j]) & 0xFFFFFFFF; d = c; c = _rotl(b_, 9); b_ = a; a = tt1; h = g; g = _rotl(f, 19); f = e; e = _p0(tt2); } v[0] ^= a; v[1] ^= b_; v[2] ^= c; v[3] ^= d; v[4] ^= e; v[5] ^= f; v[6] ^= g; v[7] ^= h; } List out = []; for (int i = 0; i < v.length; i++) { out.addAll([ (v[i] >> 24) & 0xFF, (v[i] >> 16) & 0xFF, (v[i] >> 8) & 0xFF, v[i] & 0xFF ]); } return out; } } // SM2椭圆曲线参数 class SM2Curve { static final BigInt p = BigInt.parse( 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', radix: 16); static final BigInt a = BigInt.parse( 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC', radix: 16); static final BigInt b = BigInt.parse( '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93', radix: 16); static final BigInt n = BigInt.parse( 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B61C6B3A2F4F6B7E4B8E5F5FF', radix: 16); static final BigInt gx = BigInt.parse( '32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7', radix: 16); static final BigInt gy = BigInt.parse( 'BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0', radix: 16); } // 椭圆曲线点 class ECPoint { BigInt? x; BigInt? y; bool isInfinity; ECPoint(this.x, this.y) : isInfinity = false; ECPoint.infinity() : isInfinity = true, x = null, y = null; @override String toString() { if (isInfinity) return 'O'; return '(${x!.toRadixString(16)}, ${y!.toRadixString(16)})'; } } // SM2加解密类 class SM2Crypto { static final Random _random = Random.secure(); // 模运算 static BigInt _mod(BigInt a, BigInt m) { BigInt result = a % m; return result < BigInt.zero ? result + m : result; } // 模逆运算 static BigInt _modInverse(BigInt a, BigInt m) { if (a < BigInt.zero) a = _mod(a, m); BigInt g = _gcd(a, m); if (g != BigInt.one) { throw Exception('Modular inverse does not exist'); } return _mod(_extendedGcd(a, m)[0], m); } // 扩展欧几里德算法 static List _extendedGcd(BigInt a, BigInt b) { if (a == BigInt.zero) { return [BigInt.zero, BigInt.one, b]; } List result = _extendedGcd(b % a, a); BigInt x1 = result[0]; BigInt y1 = result[1]; BigInt gcd = result[2]; BigInt x = y1 - (b ~/ a) * x1; BigInt y = x1; return [x, y, gcd]; } // 最大公约数 static BigInt _gcd(BigInt a, BigInt b) { while (b != BigInt.zero) { BigInt temp = b; b = a % b; a = temp; } return a; } // 椭圆曲线点加法 static ECPoint _pointAdd(ECPoint p1, ECPoint p2) { if (p1.isInfinity) return p2; if (p2.isInfinity) return p1; if (p1.x == p2.x) { if (p1.y == p2.y) { return _pointDouble(p1); } else { return ECPoint.infinity(); } } BigInt dx = _mod(p2.x! - p1.x!, SM2Curve.p); BigInt dy = _mod(p2.y! - p1.y!, SM2Curve.p); BigInt s = _mod(dy * _modInverse(dx, SM2Curve.p), SM2Curve.p); BigInt x3 = _mod(s * s - p1.x! - p2.x!, SM2Curve.p); BigInt y3 = _mod(s * (p1.x! - x3) - p1.y!, SM2Curve.p); return ECPoint(x3, y3); } // 椭圆曲线点倍乘 static ECPoint _pointDouble(ECPoint p) { if (p.isInfinity) return p; BigInt s = _mod( (BigInt.from(3) * p.x! * p.x! + SM2Curve.a) * _modInverse(BigInt.from(2) * p.y!, SM2Curve.p), SM2Curve.p); BigInt x3 = _mod(s * s - BigInt.from(2) * p.x!, SM2Curve.p); BigInt y3 = _mod(s * (p.x! - x3) - p.y!, SM2Curve.p); return ECPoint(x3, y3); } // 椭圆曲线标量乘法 static ECPoint _pointMultiply(BigInt k, ECPoint point) { if (k == BigInt.zero || point.isInfinity) { return ECPoint.infinity(); } ECPoint result = ECPoint.infinity(); ECPoint addend = point; while (k > BigInt.zero) { if (k.isOdd) { result = _pointAdd(result, addend); } addend = _pointDouble(addend); k = k >> 1; } return result; } // 生成随机数 static BigInt _generateRandomBigInt(BigInt max) { int byteLength = (max.bitLength + 7) ~/ 8; BigInt randomNumber; do { List bytes = List.generate(byteLength, (_) => _random.nextInt(256)); randomNumber = BigInt.parse( bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join(), radix: 16); } while (randomNumber >= max || randomNumber == BigInt.zero); return randomNumber; } // KDF密钥派生函数 static Uint8List _kdf(Uint8List z, int klen) { List result = []; int ct = 1; while (result.length < klen) { List input = [ ...z, ...[(ct >> 24) & 0xFF, (ct >> 16) & 0xFF, (ct >> 8) & 0xFF, ct & 0xFF] ]; List hash = _sm3Hash(Uint8List.fromList(input)); result.addAll(hash); ct++; } return Uint8List.fromList(result.take(klen).toList()); } // SM3哈希函数(简化版本) static List _sm3Hash(Uint8List data) { return SM3.digest(data); } // 字节数组转换为十六进制字符串 static String _bytesToHex(Uint8List bytes) { return bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join(); } // 十六进制字符串转换为字节数组 static Uint8List _hexToBytes(String hex) { if (hex.length % 2 != 0) hex = '0' + hex; List bytes = []; for (int i = 0; i < hex.length; i += 2) { bytes.add(int.parse(hex.substring(i, i + 2), radix: 16)); } return Uint8List.fromList(bytes); } // BigInt转换为定长字节数组 static Uint8List _bigIntToBytes(BigInt value, int length) { String hex = value.toRadixString(16).padLeft(length * 2, '0'); return _hexToBytes(hex); } // 公钥压缩(与gm-crypto保持一致) static String compressPublicKey(String publicKey) { if (publicKey.length == 66) return publicKey; // 已经是压缩格式 if (publicKey.startsWith('04')) { publicKey = publicKey.substring(2); } String x = publicKey.substring(0, 64); String y = publicKey.substring(64, 128); BigInt yBig = BigInt.parse(y, radix: 16); String prefix = yBig.isEven ? '02' : '03'; return prefix + x; } // 公钥解压缩 static String decompressPublicKey(String compressedKey) { if (compressedKey.length == 130) return compressedKey; if (compressedKey.length != 66) throw Exception('压缩公钥长度非法'); // 已经是非压缩格式 String prefix = compressedKey.substring(0, 2); String x = compressedKey.substring(2); BigInt xBig = BigInt.parse(x, radix: 16); // 计算y² BigInt ySquared = _mod(xBig * xBig * xBig + SM2Curve.a * xBig + SM2Curve.b, SM2Curve.p); // 计算y BigInt y = _modSqrt(ySquared, SM2Curve.p); // 根据前缀选择正确的y值 if ((prefix == '02' && y.isOdd) || (prefix == '03' && y.isEven)) { y = SM2Curve.p - y; } return '04' + x + y.toRadixString(16).padLeft(64, '0'); } // 模平方根 static BigInt _modSqrt(BigInt a, BigInt p) { // 使用Tonelli-Shanks算法或简化版本 return a.modPow((p + BigInt.one) ~/ BigInt.from(4), p); } // SM2加密(支持C1C2C3和C1C3C2两种模式) static String encrypt(String message, String publicKey, {bool c1c3c2Mode = true}) { // 确保公钥是完整格式 String fullPublicKey = decompressPublicKey(publicKey); if (fullPublicKey.startsWith('04')) { fullPublicKey = fullPublicKey.substring(2); } String xHex = fullPublicKey.substring(0, 64); String yHex = fullPublicKey.substring(64, 128); BigInt px = BigInt.parse(xHex, radix: 16); BigInt py = BigInt.parse(yHex, radix: 16); ECPoint publicKeyPoint = ECPoint(px, py); Uint8List messageBytes = utf8.encode(message); while (true) { // 生成随机数k BigInt k = _generateRandomBigInt(SM2Curve.n); // 计算C1 = k*G ECPoint c1Point = _pointMultiply(k, ECPoint(SM2Curve.gx, SM2Curve.gy)); // 计算k*P ECPoint kPPoint = _pointMultiply(k, publicKeyPoint); // 计算x2||y2 Uint8List x2Bytes = _bigIntToBytes(kPPoint.x!, 32); Uint8List y2Bytes = _bigIntToBytes(kPPoint.y!, 32); Uint8List x2y2 = Uint8List.fromList([...x2Bytes, ...y2Bytes]); // KDF生成密钥流 Uint8List keyStream = _kdf(x2y2, messageBytes.length); // 检查密钥流是否全零 bool allZero = keyStream.every((b) => b == 0); if (allZero) continue; // 计算C2 = M ⊕ t Uint8List c2 = Uint8List.fromList(List.generate( messageBytes.length, (i) => messageBytes[i] ^ keyStream[i])); // 计算C3 = Hash(x2||M||y2) Uint8List hashInput = Uint8List.fromList([...x2Bytes, ...messageBytes, ...y2Bytes]); List c3 = _sm3Hash(hashInput); // 组装密文 Uint8List c1x = _bigIntToBytes(c1Point.x!, 32); Uint8List c1y = _bigIntToBytes(c1Point.y!, 32); String result; if (c1c3c2Mode) { // C1||C3||C2模式(新标准,默认) result = '04' + _bytesToHex(c1x) + _bytesToHex(c1y) + _bytesToHex(Uint8List.fromList(c3)) + _bytesToHex(c2); } else { // C1||C2||C3模式(旧标准) result = '04' + _bytesToHex(c1x) + _bytesToHex(c1y) + _bytesToHex(c2) + _bytesToHex(Uint8List.fromList(c3)); } return result; } } // SM2解密(自动检测C1C2C3和C1C3C2模式) static String decrypt(String ciphertext, String privateKey, {bool? c1c3c2Mode}) { // 解析密文 if (ciphertext.startsWith('04')) { ciphertext = ciphertext.substring(2); } // C1点坐标(64字节) String c1x = ciphertext.substring(0, 64); String c1y = ciphertext.substring(64, 128); // 构造C1点 BigInt c1xBig = BigInt.parse(c1x, radix: 16); BigInt c1yBig = BigInt.parse(c1y, radix: 16); ECPoint c1Point = ECPoint(c1xBig, c1yBig); // 私钥 BigInt d = BigInt.parse(privateKey, radix: 16); // 计算d*C1 ECPoint dC1Point = _pointMultiply(d, c1Point); // 计算x2||y2 Uint8List x2Bytes = _bigIntToBytes(dC1Point.x!, 32); Uint8List y2Bytes = _bigIntToBytes(dC1Point.y!, 32); Uint8List x2y2 = Uint8List.fromList([...x2Bytes, ...y2Bytes]); String remainingCiphertext = ciphertext.substring(128); // 如果没有指定模式,先尝试C1C3C2模式,失败后尝试C1C2C3模式 if (c1c3c2Mode == null) { try { return _decryptWithMode( remainingCiphertext, x2Bytes, y2Bytes, x2y2, true); } catch (e) { try { return _decryptWithMode( remainingCiphertext, x2Bytes, y2Bytes, x2y2, false); } catch (e2) { throw Exception( 'Decryption failed with both C1C3C2 and C1C2C3 modes'); } } } else { return _decryptWithMode( remainingCiphertext, x2Bytes, y2Bytes, x2y2, c1c3c2Mode); } } // 辅助解密函数 static String _decryptWithMode(String remainingCiphertext, Uint8List x2Bytes, Uint8List y2Bytes, Uint8List x2y2, bool c1c3c2Mode) { String c2, c3; if (c1c3c2Mode) { // C1C3C2模式:C3哈希值(64字节),然后是C2密文 c3 = remainingCiphertext.substring(0, 64); c2 = remainingCiphertext.substring(64); } else { // C1C2C3模式:先是C2密文,最后64字节是C3哈希值 c2 = remainingCiphertext.substring(0, remainingCiphertext.length - 64); c3 = remainingCiphertext.substring(remainingCiphertext.length - 64); } // 解析C2 Uint8List c2Bytes = _hexToBytes(c2); // KDF生成密钥流 Uint8List keyStream = _kdf(x2y2, c2Bytes.length); // 解密得到明文 Uint8List messageBytes = Uint8List.fromList( List.generate(c2Bytes.length, (i) => c2Bytes[i] ^ keyStream[i])); // 验证C3 Uint8List hashInput = Uint8List.fromList([...x2Bytes, ...messageBytes, ...y2Bytes]); List computedC3 = _sm3Hash(hashInput); String computedC3Hex = _bytesToHex(Uint8List.fromList(computedC3)); if (computedC3Hex != c3) { throw Exception('Hash verification failed'); } return utf8.decode(messageBytes); } // 生成密钥对 static Map generateKeyPair() { BigInt privateKey = _generateRandomBigInt(SM2Curve.n); ECPoint publicKeyPoint = _pointMultiply(privateKey, ECPoint(SM2Curve.gx, SM2Curve.gy)); String privateKeyHex = privateKey.toRadixString(16).padLeft(64, '0'); String publicKeyHex = '04' + publicKeyPoint.x!.toRadixString(16).padLeft(64, '0') + publicKeyPoint.y!.toRadixString(16).padLeft(64, '0'); return { 'privateKey': privateKeyHex, 'publicKey': publicKeyHex, 'compressedPublicKey': compressPublicKey(publicKeyHex), }; } } // 使用示例 // void main() { // // 生成密钥对 // Map keyPair = SM2Crypto.generateKeyPair(); // print('Private Key: ${keyPair['privateKey']}'); // print('Public Key: ${keyPair['publicKey']}'); // print('Compressed Public Key: ${keyPair['compressedPublicKey']}'); // String message = 'Hello SM2!'; // // 测试C1C3C2模式(新标准,默认) // print('\n=== C1C3C2模式测试 ==='); // String ciphertext1 = SM2Crypto.encrypt(message, keyPair['publicKey']!, c1c3c2Mode: true); // print('C1C3C2 Ciphertext: $ciphertext1'); // String decrypted1 = SM2Crypto.decrypt(ciphertext1, keyPair['privateKey']!); // print('C1C3C2 Decrypted: $decrypted1'); // // 测试C1C2C3模式(旧标准) // print('\n=== C1C2C3模式测试 ==='); // String ciphertext2 = SM2Crypto.encrypt(message, keyPair['publicKey']!, c1c3c2Mode: false); // print('C1C2C3 Ciphertext: $ciphertext2'); // String decrypted2 = SM2Crypto.decrypt(ciphertext2, keyPair['privateKey']!); // print('C1C2C3 Decrypted: $decrypted2'); // // 测试自动模式检测 // print('\n=== 自动模式检测测试 ==='); // String autoDecrypted1 = SM2Crypto.decrypt(ciphertext1, keyPair['privateKey']!); // String autoDecrypted2 = SM2Crypto.decrypt(ciphertext2, keyPair['privateKey']!); // print('Auto detect C1C3C2: $autoDecrypted1'); // print('Auto detect C1C2C3: $autoDecrypted2'); // // 测试与压缩公钥的兼容性 // print('\n=== 压缩公钥兼容性测试 ==='); // String ciphertext3 = SM2Crypto.encrypt(message, keyPair['compressedPublicKey']!); // String decrypted3 = SM2Crypto.decrypt(ciphertext3, keyPair['privateKey']!); // print('Compressed key test: $decrypted3'); // }