使用库
encrypt: ^5.0.3
pointycastle: ^3.9.1
asn1lib: ^1.5.5
工具类代码
import 'package:encrypt/encrypt.dart' as ep;
import 'dart:convert';
import 'dart:typed_data';
import 'dart:math';
import 'package:pointycastle/export.dart';
import "package:asn1lib/asn1lib.dart";
class IFRsaUtil {
static void onLaunch() async {
ASN1ObjectIdentifier.registerFrequentNames();
}
static String encrypt(String message, RSAPublicKey pubKey) {
ep.Encrypter handler = ep.Encrypter(ep.RSA(publicKey: pubKey));
ep.Encrypted encrypted = handler.encrypt(message);
return encrypted.base64;
}
static String decrypt(String base64Data, RSAPrivateKey priKey) {
ep.Encrypter handler = ep.Encrypter(ep.RSA(privateKey: priKey));
ep.Encrypted encrypted = ep.Encrypted.fromBase64(base64Data);
return handler.decrypt(encrypted);
}
static void createRSAKeyPair() {
final rsaKeyPair = generateRSAKeyPair();
String pubKey = encodePublicKeyToPem(rsaKeyPair.publicKey);
String priKey = encodePrivateKeyToPem(rsaKeyPair.privateKey);
print("pub $pubKey\n pri $priKey");
}
// 从 PEM 字符串解析出 RSAPublicKey
static RSAPublicKey parsePublicKeyFromPem(String pemString) {
var publicKeyBytes = _extractBytesFromPem(pemString);
var asn1Parser = ASN1Parser(publicKeyBytes);
var sequence = asn1Parser.nextObject() as ASN1Sequence;
var publicKeyBitString = sequence.elements[1] as ASN1BitString;
var publicKeySequence = ASN1Parser(publicKeyBitString.stringValue as Uint8List).nextObject() as ASN1Sequence;
var modulus = publicKeySequence.elements[0] as ASN1Integer;
var exponent = publicKeySequence.elements[1] as ASN1Integer;
return RSAPublicKey(modulus.valueAsBigInteger, exponent.valueAsBigInteger);
}
// 从 PEM 字符串解析出 RSAPrivateKey
static RSAPrivateKey parsePrivateKeyFromPem(String pemString) {
var privateKeyBytes = _extractBytesFromPem(pemString);
var asn1Parser = ASN1Parser(privateKeyBytes);
var sequence = asn1Parser.nextObject() as ASN1Sequence;
var modulus = sequence.elements[1] as ASN1Integer;
var privateExponent = sequence.elements[3] as ASN1Integer;
var p = sequence.elements[4] as ASN1Integer;
var q = sequence.elements[5] as ASN1Integer;
return RSAPrivateKey(modulus.valueAsBigInteger, privateExponent.valueAsBigInteger, p.valueAsBigInteger, q.valueAsBigInteger);
}
// Helper function to extract bytes from PEM string
static Uint8List _extractBytesFromPem(String pem) {
// 去除前面部分
String regex = r'-----BEGIN.*---\n';
RegExp regExp = RegExp(regex, multiLine: false);
RegExpMatch? m = regExp.firstMatch(pem);
String pemKey = pem;
if(m != null) {
pemKey = pem.substring(m.end);
}
// 去除后面部分
var endsWith = pemKey.indexOf('-----END');
pemKey = pemKey.substring(0, endsWith).replaceAll('\n', '');
// 解码
return base64.decode(pemKey);
}
// // 生成 RSA 密钥对 (公钥和私钥)
static AsymmetricKeyPair<RSAPublicKey, RSAPrivateKey> generateRSAKeyPair() {
final keyGen = KeyGenerator('RSA');
final secureRandom = _secureRandom();
keyGen.init(ParametersWithRandom(
RSAKeyGeneratorParameters(BigInt.parse('65537'), 2048, 64), secureRandom));
final pair = keyGen.generateKeyPair();
final myPublic = pair.publicKey as RSAPublicKey;
final myPrivate = pair.privateKey as RSAPrivateKey;
return AsymmetricKeyPair<RSAPublicKey, RSAPrivateKey>(myPublic, myPrivate);
}
// 初始化 SecureRandom (使用 FortunaRandom 实现)
static SecureRandom _secureRandom() {
final secureRandom = FortunaRandom();
final seedSource = Random.secure(); // 使用 Dart 内置的 secure 随机数生成器
final seeds = <int>[];
for (int i = 0; i < 32; i++) {
seeds.add(seedSource.nextInt(256)); // 生成 32 字节的种子
}
secureRandom.seed(KeyParameter(Uint8List.fromList(seeds)));
return secureRandom;
}
// 将 RSAPublicKey 转换为 PEM 字符串
static String encodePublicKeyToPem(RSAPublicKey publicKey) {
var algorithmSeq = ASN1Sequence();
var algorithmAsn1Seq = ASN1Sequence();
algorithmAsn1Seq.add(ASN1ObjectIdentifier.fromName("rsaEncryption"));
algorithmAsn1Seq.add(ASN1Null());
algorithmSeq.add(algorithmAsn1Seq);
var publicKeySeq = ASN1Sequence();
publicKeySeq.add(ASN1Integer(publicKey.modulus!));
publicKeySeq.add(ASN1Integer(publicKey.exponent!));
var publicKeyBitString = ASN1BitString(Uint8List.fromList(publicKeySeq.encodedBytes));
algorithmSeq.add(publicKeyBitString);
var bytes = Uint8List.fromList(algorithmSeq.encodedBytes);
return '''-----BEGIN PUBLIC KEY-----\n${base64.encode(bytes)}\n-----END PUBLIC KEY-----''';
}
// 将 RSAPrivateKey 转换为 PEM 字符串
static String encodePrivateKeyToPem(RSAPrivateKey privateKey) {
var privateKeySeq = ASN1Sequence();
privateKeySeq.add(ASN1Integer(BigInt.from(0))); // version
privateKeySeq.add(ASN1Integer(privateKey.n!)); // modulus
privateKeySeq.add(ASN1Integer(privateKey.exponent!)); // publicExponent
privateKeySeq.add(ASN1Integer(privateKey.d!)); // privateExponent
privateKeySeq.add(ASN1Integer(privateKey.p!)); // prime1
privateKeySeq.add(ASN1Integer(privateKey.q!)); // prime2
privateKeySeq
.add(ASN1Integer(privateKey.privateExponent! % (privateKey.p! - BigInt.one))); // exponent1
privateKeySeq
.add(ASN1Integer(privateKey.privateExponent! % (privateKey.q! - BigInt.one))); // exponent2
privateKeySeq.add(ASN1Integer(privateKey.q!.modInverse(privateKey.p!))); // coefficient
var bytes = Uint8List.fromList(privateKeySeq.encodedBytes);
return '''-----BEGIN PRIVATE KEY-----\n${base64.encode(bytes)}\n-----END PRIVATE KEY-----''';
}
}
测试代码
import 'package:family_box_server_core/utils/if_rsa_util.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pointycastle/asymmetric/api.dart';
void main() {
test('security', () {
IFRsaUtil.onLaunch();
final keyPair = IFRsaUtil.generateRSAKeyPair();
String pubKeyString = IFRsaUtil.encodePublicKeyToPem(keyPair.publicKey);
debugPrint("public key $pubKeyString");
String priKeyString = IFRsaUtil.encodePrivateKeyToPem(keyPair.privateKey);
debugPrint("private key $priKeyString");
RSAPublicKey decodedPubKey = IFRsaUtil.parsePublicKeyFromPem(pubKeyString);
RSAPrivateKey decodedPriKey = IFRsaUtil.parsePrivateKeyFromPem(priKeyString);
String message = "abc123啊哦呃";
String base64Data = IFRsaUtil.encrypt(message, decodedPubKey);
String decrypted = IFRsaUtil.decrypt(base64Data, decodedPriKey);
String decrypted2 = IFRsaUtil.decrypt(base64Data, keyPair.privateKey);
assert(decrypted == message);
assert(decrypted2 == message);
});
}
那么多库,就没一个省心的。