class _ASN1Object { _ASN1Object() { tlv = null; } String? tlv; String t = '00'; String l = '00'; String v = ''; /// 获取 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 { _DERSequence(this.asn1Array) : super() { t = '30'; // 序列标签说明 } List<_ASN1Object> asn1Array; @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}; } }