150 lines
5.1 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'dart:typed_data';
import 'package:convert/convert.dart';
// import 'package:fast_rsa/fast_rsa.dart' as fastRsa;
import 'package:flutter/services.dart';
import 'package:pointycastle/export.dart' as pc;
import 'dart:convert';
import 'package:asn1lib/asn1lib.dart' as asn1lib;
import 'package:star_lock/talk/starChart/exception/start_chart_message_exception.dart'; // Prefix for asn1lib
class DoSign {
// 生成签名sing
// Future<String> generateSign({
// required int currentTimestamp,
// required String privateKeyHex,
// }) async {
// String resultSign = '';
// try {
// // 1. 将 32 位时间戳以小端字节序编码为二进制数据
// Uint8List signData = encodeTimestampToLittleEndianBytes(currentTimestamp);
//
// // 2.将十六进制字符串转换为字节数组
// List<int> privateKeyBytes = hexToBytes(privateKeyHex);
//
// // 3.将私钥转换为 PEM 格式
// final pemPrivateKey =
// convertToPemPrivateKey(privateKeyBytes, isPKCS8: true);
// // 4.签名
// var result = await fastRsa.RSA
// .signPKCS1v15Bytes(signData, fastRsa.Hash.SHA256, pemPrivateKey);
// resultSign = hex.encode(result);
// } catch (e) {
// throw StartChartMessageException('❌--->上报信息生成签名时出现错误: $e');
// }
// return resultSign ?? '';
// }
Future<String> generateSign({
required int currentTimestamp,
required String privateKeyHex,
}) async {
String resultSign = '';
try {
// 1. 将 32 位时间戳以小端字节序编码为二进制数据
Uint8List signData = encodeTimestampToLittleEndianBytes(currentTimestamp);
// 2. 加载私钥
final privateKey = loadPrivateKey(privateKeyHex);
// 3. 创建 RSA 签名器
final signer = pc.RSASigner(pc.SHA256Digest(), '0609608648016503040201');
signer.init(true, pc.PrivateKeyParameter<pc.RSAPrivateKey>(privateKey));
// 4. 生成签名
final signature = signer.generateSignature(signData);
resultSign = hex.encode(signature.bytes);
} catch (e) {
throw StartChartMessageException('❌--->上报信息生成签名时出现错误: $e');
}
return resultSign;
}
// 将 32 位时间戳以小端字节序编码为二进制数据
Uint8List encodeTimestampToLittleEndianBytes(int timestamp) {
// 创建一个 4 字节的 ByteData 对象
ByteData byteData = ByteData(4);
// 将 32 位时间戳写入 ByteData使用小端字节序
byteData.setUint32(0, timestamp, Endian.little);
// 将 ByteData 转换为 Uint8List
Uint8List bytes = byteData.buffer.asUint8List();
return bytes;
}
/// 转换私钥格式
String convertToPemPrivateKey(List<int> privateKeyBytes,
{bool isPKCS8 = true}) {
// 将字节数组转换为Base64编码的字符串
String base64PrivateKey = base64Encode(privateKeyBytes);
// 添加PEM格式的头尾标签
String pemHeader;
String pemFooter;
if (isPKCS8) {
pemHeader = "-----BEGIN PRIVATE KEY-----";
pemFooter = "-----END PRIVATE KEY-----";
} else {
pemHeader = "-----BEGIN RSA PRIVATE KEY-----";
pemFooter = "-----END RSA PRIVATE KEY-----";
}
// 将Base64字符串分行为每行64个字符
const lineLength = 64;
List<String> lines = []; // 用于存储每一行
for (int i = 0; i < base64PrivateKey.length; i += lineLength) {
int end = (i + lineLength < base64PrivateKey.length)
? i + lineLength
: base64PrivateKey.length;
lines.add(base64PrivateKey.substring(i, end));
}
// 组合成完整的PEM格式字符串
return "$pemHeader\n${lines.join('\n')}\n$pemFooter";
}
/// 自定义 PEM 格式的 RSA 私钥解析器
pc.RSAPrivateKey loadPrivateKey(String privateKeyHex) {
// 将十六进制字符串转换为字节数组
final uint8list = Uint8List.fromList(hexToBytes(privateKeyHex));
try {
// 使用 asn1lib 的 ASN1Parser 解析
final asn1Parser = asn1lib.ASN1Parser(uint8list);
final topLevelSeq = asn1Parser.nextObject() as asn1lib.ASN1Sequence;
final modulus = bytesToBigInt(
(topLevelSeq.elements[1] as asn1lib.ASN1Integer).valueBytes());
final privateExponent = bytesToBigInt(
(topLevelSeq.elements[3] as asn1lib.ASN1Integer).valueBytes());
final p = bytesToBigInt(
(topLevelSeq.elements[4] as asn1lib.ASN1Integer).valueBytes());
final q = bytesToBigInt(
(topLevelSeq.elements[5] as asn1lib.ASN1Integer).valueBytes());
return pc.RSAPrivateKey(modulus, privateExponent, p, q);
} catch (e) {
// 如果发生解码错误,打印错误信息
print("Error decoding private key: $e");
rethrow;
}
}
// 将十六进制字符串转换为字节数组
List<int> hexToBytes(String hex) {
return List<int>.generate(hex.length ~/ 2,
(i) => int.parse(hex.substring(i * 2, i * 2 + 2), radix: 16));
}
BigInt bytesToBigInt(Uint8List bytes) {
return BigInt.parse(
bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join(),
radix: 16,
);
}
}