fix:调整新的中继协议中的上报签名逻辑
This commit is contained in:
parent
200a6ce44c
commit
c240f089c7
@ -235,13 +235,13 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
|
|||||||
: null)),
|
: null)),
|
||||||
SubmitBtn(
|
SubmitBtn(
|
||||||
btnName: '发送上线请求',
|
btnName: '发送上线请求',
|
||||||
onClick: () {
|
onClick: () async {
|
||||||
// 注册星图节点信息
|
// 注册星图节点信息
|
||||||
StartChartManage().clientRegister();
|
await StartChartManage().clientRegister();
|
||||||
// 查询中继信息
|
// 查询中继信息
|
||||||
StartChartManage().relayQuery();
|
await StartChartManage().relayQuery();
|
||||||
// 发送上线请求
|
// 发送上线请求
|
||||||
StartChartManage().onlineRelayService();
|
await StartChartManage().onlineRelayService();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SubmitBtn(
|
SubmitBtn(
|
||||||
|
|||||||
@ -289,4 +289,6 @@ abstract class Api {
|
|||||||
'/SL-A-1.0/relay/query'; // 星图--中继查询
|
'/SL-A-1.0/relay/query'; // 星图--中继查询
|
||||||
final String reportInformationDataURL =
|
final String reportInformationDataURL =
|
||||||
'/SL-A-1.0/peer/login'; // 星图--信息上报
|
'/SL-A-1.0/peer/login'; // 星图--信息上报
|
||||||
|
final String analyzeInformationOtherEndURL =
|
||||||
|
'/SL-A-1.0/peer/nslookup'; // 星图--解析对端信息
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,4 +55,15 @@ class StartChartApi extends BaseProvider {
|
|||||||
isUserBaseUrl: false,
|
isUserBaseUrl: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 星图--解析对端信息
|
||||||
|
Future<void> analyzeInformationOtherEnd({
|
||||||
|
required String peerId,
|
||||||
|
}) async {
|
||||||
|
final response = await get(
|
||||||
|
_startChartHost + analyzeInformationOtherEndURL.toUrl + '?id=$peerId',
|
||||||
|
isUnShowLoading: true,
|
||||||
|
isUserBaseUrl: false,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:convert/convert.dart';
|
import 'package:pointycastle/asn1/asn1_parser.dart';
|
||||||
import 'package:crypto/crypto.dart';
|
import 'package:pointycastle/asn1/primitives/asn1_integer.dart';
|
||||||
import 'package:encrypt/encrypt.dart';
|
import 'package:pointycastle/asn1/primitives/asn1_sequence.dart';
|
||||||
import 'package:pointycastle/asymmetric/api.dart';
|
|
||||||
import 'package:star_lock/app_settings/app_settings.dart';
|
import 'package:star_lock/app_settings/app_settings.dart';
|
||||||
import 'package:star_lock/flavors.dart';
|
import 'package:star_lock/flavors.dart';
|
||||||
import 'package:star_lock/network/start_chart_api.dart';
|
import 'package:star_lock/network/start_chart_api.dart';
|
||||||
@ -20,6 +18,12 @@ import 'package:star_lock/tools/deviceInfo_utils.dart';
|
|||||||
import 'package:star_lock/tools/storage.dart';
|
import 'package:star_lock/tools/storage.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:crypto/crypto.dart';
|
||||||
|
import 'package:pointycastle/export.dart' as pc; // 为 Pointy Castle 添加命名空间
|
||||||
|
import 'package:asn1lib/asn1lib.dart' as asn1lib; // Prefix for asn1lib
|
||||||
|
|
||||||
class StartChartManage {
|
class StartChartManage {
|
||||||
// 私有构造函数,防止外部直接new对象
|
// 私有构造函数,防止外部直接new对象
|
||||||
StartChartManage._internal();
|
StartChartManage._internal();
|
||||||
@ -225,7 +229,7 @@ class StartChartManage {
|
|||||||
// 生成签名
|
// 生成签名
|
||||||
final sign = await _generateSign(
|
final sign = await _generateSign(
|
||||||
currentTimestamp: currentTimestamp,
|
currentTimestamp: currentTimestamp,
|
||||||
privateKey: privateKey,
|
privateKeyHex: privateKey,
|
||||||
);
|
);
|
||||||
|
|
||||||
// 获取本机所有ip地址和中继返回的外网地址
|
// 获取本机所有ip地址和中继返回的外网地址
|
||||||
@ -341,28 +345,127 @@ class StartChartManage {
|
|||||||
// 生成签名sing
|
// 生成签名sing
|
||||||
Future<String> _generateSign({
|
Future<String> _generateSign({
|
||||||
required int currentTimestamp,
|
required int currentTimestamp,
|
||||||
required String privateKey,
|
required String privateKeyHex,
|
||||||
}) async {
|
}) async {
|
||||||
String resultSign = '';
|
String resultSign = '';
|
||||||
try {
|
try {
|
||||||
// 2. 将时间戳编码为小端字节序(Little Endian)
|
// 1. 获取当前时间戳并编码为小端字节序
|
||||||
Uint8List signData = Uint8List(4);
|
Uint8List signData = Uint8List(4);
|
||||||
signData.buffer
|
ByteData.view(signData.buffer)
|
||||||
.asByteData()
|
|
||||||
.setUint32(0, currentTimestamp, Endian.little);
|
.setUint32(0, currentTimestamp, Endian.little);
|
||||||
|
|
||||||
// 3. 使用 SHA-256 对 signData 进行哈希运算
|
// 2. 对时间戳数据计算 SHA-256 哈希值
|
||||||
final sha256Hash = sha256.convert(signData);
|
Digest hash = sha256.convert(signData);
|
||||||
var parser = RSAKeyParser();
|
|
||||||
final RSAPrivateKey parsePrivateKey =
|
// 3. 使用 RSA 私钥进行签名 (需要提供 RsaPrivateKey)
|
||||||
parser.parse('-----BEGIN RSA PRIVATE KEY-----\n' + privateKey)
|
pc.RSAPrivateKey privateKey =
|
||||||
as RSAPrivateKey;
|
loadPrivateKey(privateKeyHex); // 需要加载你的 RSA 私钥
|
||||||
|
Uint8List signature = rsaSign(privateKey, hash.bytes);
|
||||||
|
|
||||||
|
// 4. 将签名结果转换为十六进制字符串
|
||||||
|
String hexSignature = signature
|
||||||
|
.map((byte) => byte.toRadixString(16).padLeft(2, '0'))
|
||||||
|
.join();
|
||||||
|
resultSign = hexSignature;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_log(text: '❌--->生成签名时出现错误: $e');
|
_log(text: '❌--->上报信息生成签名时出现错误: $e');
|
||||||
}
|
}
|
||||||
return resultSign ?? '';
|
return resultSign ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 自定义 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析对端数据
|
||||||
|
Future<void> analyzeInformationOtherEnd() async {
|
||||||
|
await StartChartApi.to.analyzeInformationOtherEnd(peerId: ToPeerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将十六进制字符串转换为字节数组
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 使用 RSA 私钥进行 PKCS#1 v1.5 签名
|
||||||
|
Uint8List rsaSign(pc.RSAPrivateKey privateKey, List<int> data) {
|
||||||
|
final signer = pc.RSASigner(pc.SHA256Digest(), '06052b24030203')
|
||||||
|
..init(true, pc.PrivateKeyParameter<pc.RSAPrivateKey>(privateKey));
|
||||||
|
return signer.generateSignature(Uint8List.fromList(data)).bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析 RSA 私钥
|
||||||
|
// RSAPrivateKey parseRSAPrivateKey1(Uint8List bytes) {
|
||||||
|
// // 这里假设私钥是以 PKCS#1 DER 编码的
|
||||||
|
// ASN1Parser parser = ASN1Parser(bytes);
|
||||||
|
// ASN1Sequence seq = parser.nextObject() as ASN1Sequence;
|
||||||
|
// if (seq.elements == null || seq.elements!.length < 9) {
|
||||||
|
// throw ArgumentError("Invalid RSA private key");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 解析各个元素
|
||||||
|
// ASN1Integer version = seq.elements![0] as ASN1Integer;
|
||||||
|
// ASN1Integer modulus = seq.elements![1] as ASN1Integer;
|
||||||
|
// // ASN1Integer publicExponent = seq.elements![2] as ASN1Integer;
|
||||||
|
// ASN1Integer privateExponent = seq.elements![3] as ASN1Integer;
|
||||||
|
// ASN1Integer p = seq.elements![2] as ASN1Integer;
|
||||||
|
// ASN1Integer q = seq.elements![4] as ASN1Integer;
|
||||||
|
// ASN1Integer dP = seq.elements![5] as ASN1Integer;
|
||||||
|
// ASN1Integer dQ = seq.elements![6] as ASN1Integer;
|
||||||
|
// ASN1Integer qInv = seq.elements![7] as ASN1Integer;
|
||||||
|
//
|
||||||
|
// // 将 ASN1Integer 转换为 BigInt
|
||||||
|
// BigInt modulusValue = _convertToBigInt(modulus);
|
||||||
|
// // BigInt publicExponentValue = _convertToBigInt(publicExponent);
|
||||||
|
// BigInt privateExponentValue = _convertToBigInt(privateExponent);
|
||||||
|
// BigInt pValue = _convertToBigInt(p);
|
||||||
|
// BigInt qValue = _convertToBigInt(q);
|
||||||
|
// BigInt dPValue = _convertToBigInt(dP);
|
||||||
|
// BigInt dQPValue = _convertToBigInt(dQ);
|
||||||
|
// BigInt qInvQPValue = _convertToBigInt(qInv);
|
||||||
|
//
|
||||||
|
// // 创建 RSAPrivateKey 对象
|
||||||
|
// return RSAPrivateKey(modulusValue, privateExponentValue, pValue, qValue);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 将 ASN1Integer 转换为 BigInt
|
||||||
|
// BigInt _convertToBigInt(ASN1Integer integer) {
|
||||||
|
// // 获取 ASN1Integer 的字节数据
|
||||||
|
// Uint8List bytes = integer.valueBytes!;
|
||||||
|
// // 将字节数据转换为 BigInt
|
||||||
|
// return BigInt.parse(hex.encode(bytes), radix: 16);
|
||||||
|
// }
|
||||||
|
|
||||||
Future<String> getPublicKey() async {
|
Future<String> getPublicKey() async {
|
||||||
// 从缓存中获取星图注册节点信息
|
// 从缓存中获取星图注册节点信息
|
||||||
final StarChartRegisterNodeEntity? starChartRegisterNodeInfo =
|
final StarChartRegisterNodeEntity? starChartRegisterNodeInfo =
|
||||||
|
|||||||
@ -20,7 +20,7 @@ class CommandUDPReciverManager {
|
|||||||
if (dataSize < 4) {
|
if (dataSize < 4) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// AppLog.log('appReceiveUDPData:$data');
|
AppLog.log('appReceiveUDPData:$data');
|
||||||
|
|
||||||
final Uint8List data1 = Uint8List.fromList(data);
|
final Uint8List data1 = Uint8List.fromList(data);
|
||||||
if (data1.length == 1) {
|
if (data1.length == 1) {
|
||||||
|
|||||||
@ -184,7 +184,7 @@ dependencies:
|
|||||||
#加密解密
|
#加密解密
|
||||||
encrypt: ^5.0.1
|
encrypt: ^5.0.1
|
||||||
crypto: ^3.0.3
|
crypto: ^3.0.3
|
||||||
pointycastle: ^3.3.0
|
pointycastle: ^3.4.0
|
||||||
date_format: ^2.0.7
|
date_format: ^2.0.7
|
||||||
|
|
||||||
# 下拉刷新
|
# 下拉刷新
|
||||||
@ -248,7 +248,8 @@ dependencies:
|
|||||||
open_filex: ^4.4.0
|
open_filex: ^4.4.0
|
||||||
|
|
||||||
crc32_checksum: ^0.0.2
|
crc32_checksum: ^0.0.2
|
||||||
fast_rsa: ^3.6.6
|
cryptography: ^2.7.0
|
||||||
|
asn1lib: ^1.0.0
|
||||||
|
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
@ -256,6 +257,7 @@ dependency_overrides:
|
|||||||
google_maps_flutter_ios: 2.5.2
|
google_maps_flutter_ios: 2.5.2
|
||||||
flutter_plugin_android_lifecycle: 2.0.18
|
flutter_plugin_android_lifecycle: 2.0.18
|
||||||
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user