123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582 |
- import 'dart:convert';
- import 'dart:math';
- import 'dart:typed_data';
- class SM3 {
- static const List<int> _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<int> digest(Uint8List data) {
- int len = data.length * 8;
- List<int> 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<int> v = List.from(_iv);
- for (int i = 0; i < msg.length; i += 64) {
- List<int> b = msg.sublist(i, i + 64);
- List<int> w = List.filled(68, 0);
- List<int> 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<int> 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<BigInt> _extendedGcd(BigInt a, BigInt b) {
- if (a == BigInt.zero) {
- return [BigInt.zero, BigInt.one, b];
- }
- List<BigInt> 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<int> 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<int> result = [];
- int ct = 1;
- while (result.length < klen) {
- List<int> input = [
- ...z,
- ...[(ct >> 24) & 0xFF, (ct >> 16) & 0xFF, (ct >> 8) & 0xFF, ct & 0xFF]
- ];
- List<int> hash = _sm3Hash(Uint8List.fromList(input));
- result.addAll(hash);
- ct++;
- }
- return Uint8List.fromList(result.take(klen).toList());
- }
- // SM3哈希函数(简化版本)
- static List<int> _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<int> 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<int> 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<int> computedC3 = _sm3Hash(hashInput);
- String computedC3Hex = _bytesToHex(Uint8List.fromList(computedC3));
- if (computedC3Hex != c3) {
- throw Exception('Hash verification failed');
- }
- return utf8.decode(messageBytes);
- }
- // 生成密钥对
- static Map<String, String> 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<String, String> 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');
- // }
|