Flutter XML数据加密解密插件xml_crypto的使用
Flutter XML数据加密解密插件 xml_crypto
的使用
xml_crypto
是一个用于 Dart 的 XML 数字签名库,它移植自 Node.js 库 xml-crypto。本文将介绍如何在 Flutter 项目中使用该插件进行 XML 数据的加密和解密。
安装
首先,在你的 Flutter 项目的 pubspec.yaml
文件中添加 xml_crypto
依赖:
dependencies:
xml_crypto: ^latest_version
然后运行以下命令来安装:
dart pub get
支持的算法
规范化和转换算法
- Canonicalization:
http://www.w3.org/TR/2001/REC-xml-c14n-20010315
- Canonicalization with comments:
http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments
- Exclusive Canonicalization:
http://www.w3.org/2001/10/xml-exc-c14n#
- Exclusive Canonicalization with comments:
http://www.w3.org/2001/10/xml-exc-c14n#WithComments
- Enveloped Signature transform:
http://www.w3.org/2000/09/xmldsig#enveloped-signature
哈希算法
- SHA1 digests:
http://www.w3.org/2000/09/xmldsig#sha1
- SHA256 digests:
http://www.w3.org/2001/04/xmlenc#sha256
- SHA512 digests:
http://www.w3.org/2001/04/xmlenc#sha512
签名算法
- RSA-SHA1:
http://www.w3.org/2000/09/xmldsig#rsa-sha1
- RSA-SHA256:
http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
- RSA-SHA512:
http://www.w3.org/2001/04/xmldsig-more#rsa-sha512
HMAC-SHA1 也是可用的,但默认情况下是禁用的:
import 'package:xml_crypto/xml_crypto.dart';
SignedXml.enableHMAC();
启用 HMAC 后会禁用数字签名算法。
签名 XML 文档
签名 XML 文档时,可以指定以下属性来自定义签名过程:
sign.signingKey
: 必需,包含私钥的Uint8List
sign.keyInfoProvider
: 可选,包含证书的 key info provider 实例sign.signatureAlgorithm
: 可选,支持的签名算法之一sign.canonicalizationAlgorithm
: 可选,支持的规范化算法之一
示例代码:
import 'dart:io';
import 'package:xml_crypto/xml_crypto.dart';
final xml = "<library>"
"<book>"
"<name>Harry Potter</name>"
"</book>"
"</library>";
final sig = SignedXml()
..addReference("//*[local-name()='book']")
..signingKey = File("client.pem").readAsBytesSync()
..computeSignature(xml);
File("signed.xml").writeAsStringSync(sig.signedXml);
结果将会是一个带有签名的 XML 文档:
<library>
<book Id="_0">
<name>Harry Potter</name>
</book>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="#_0">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>cdiS43aFDQMnb3X8yaIUej3+z9Q=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>vhWzpQyIYuncHUZV9W...[long base64 removed]...</SignatureValue>
</Signature>
</library>
验证 XML 文档
验证 XML 文档时,必须指定以下属性:
sign.keyInfoProvider
: 必需,包含证书的 key info provider 实例
示例代码:
import 'dart:io';
import 'package:xml/xml.dart' as xml;
import 'package:xml_crypto/xml_crypto.dart';
final signedXml = File("signed.xml").readAsStringSync();
var doc = xml.XmlDocument.parse(signedXml);
var signature = doc.findAllElements('Signature').first;
final sig = SignedXml()
..keyInfoProvider = FileKeyInfo("client_public.pem")
..loadSignature(signature);
final res = sig.checkSignature(signedXml);
if (!res) print(sig.validationErrors);
如果验证失败,sig.validationErrors
将包含错误信息。
为了防止某些攻击,我们还需要检查内容是否是我们要验证的内容:
final elem = doc.findAllElements('book').first;
final uri = sig.references.first.uri; // might not be 0 - depending on the document you verify
final id = (uri.startsWith('#')) ? uri.substring(1) : uri;
if (elem.getAttribute('ID') != id && elem.getAttribute('Id') != id && elem.getAttribute('id') != id)
throw Exception('the interesting element was not the one verified by the signature');
自定义算法
你可以通过实现接口来自定义算法,例如 KeyInfoProvider
, HashAlgorithm
, SignatureAlgorithm
, 和 CanonicalizationAlgorithm
。
示例:自定义签名算法
class MySignatureAlgorithm implements SignatureAlgorithm {
@override
String getSignature(String xml, Uint8List signingKey, [CalculateSignatureCallback? callback]) {
final rsa = RSAPrivateKey.fromPEM(utf8.decode(signingKey));
final res = rsa.signSsaPkcs1v15ToBase64(utf8.encode(xml), hasher: EmsaHasher.sha1);
callback?.call(null, res);
return '';
}
@override
bool verifySignature(String xml, Uint8List key, String signatureValue, [ValidateSignatureCallback? callback]) => true;
@override
String get algorithmName => 'http://mySigningAlgorithm';
}
SignedXml.signatureAlgorithms["http://mySigningAlgorithm"] = MySignatureAlgorithm();
异步签名和验证
如果你需要使用异步回调来进行签名或验证,可以创建自定义签名算法:
class AsyncSignatureAlgorithm implements SignatureAlgorithm {
@override
String getSignature(String xml, Uint8List signingKey, [CalculateSignatureCallback? callback]) {
final rsa = RSAPrivateKey.fromPEM(utf8.decode(signingKey));
final res = rsa.signSsaPkcs1v15ToBase64(utf8.encode(xml), hasher: EmsaHasher.sha1);
callback?.call(null, res);
return '';
}
@override
bool verifySignature(String xml, Uint8List key, String signatureValue, [ValidateSignatureCallback? callback]) => true;
@override
String get algorithmName => 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
}
SignedXml.signatureAlgorithms["http://asyncSignatureAlgorithm"] = AsyncSignatureAlgorithm();
final sig = SignedXml();
sig.signatureAlgorithm = "http://asyncSignatureAlgorithm";
sig.computeSignature(xml, opts: opts, callback: (err, _) {
final signedResponse = sig.signedXml;
});
完整示例 Demo
以下是一个完整的示例,展示了如何签名和验证 XML 文档:
import 'dart:io';
import 'package:xml/xml.dart' as xml;
import 'package:xml_crypto/xml_crypto.dart';
void main() {
final xmlContent = "<library>"
"<book>"
"<name>Harry Potter</name>"
"</book>"
"</library>";
// 签名 XML 文档
signXml(xmlContent, "//*[local-name()='book']", 'client.pem', 'result.xml');
print('XML 已成功签名');
final signedXmlContent = File('result.xml').readAsStringSync();
print('正在验证签名...');
// 验证 XML 文档
if (validateXml(signedXmlContent, 'client_public.pem')) {
print('签名有效');
} else {
print('签名无效');
}
}
void signXml(String xml, String xpath, String keyPath, String destPath) {
final sig = SignedXml()
..signingKey = File(keyPath).readAsBytesSync()
..addReference(xpath)
..computeSignature(xml);
File(destPath).writeAsStringSync(sig.signedXml);
}
bool validateXml(String xml, String publicKeyPath) {
final doc = xml.XmlDocument.parse(xml);
final signature = doc.findAllElements('Signature').first;
final sig = SignedXml()
..keyInfoProvider = FileKeyInfo(publicKeyPath)
..loadSignature(signature);
final res = sig.checkSignature(xml);
if (!res) print(sig.validationErrors);
return res;
}
更多关于Flutter XML数据加密解密插件xml_crypto的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter XML数据加密解密插件xml_crypto的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,我可以为你提供一个关于如何在Flutter中使用xml_crypto
插件进行XML数据加密和解密的代码示例。xml_crypto
插件通常用于处理XML数字签名和加密。以下是一个简单的示例,展示如何使用这个插件对XML数据进行加密和解密。
首先,确保你已经在pubspec.yaml
文件中添加了xml_crypto
依赖:
dependencies:
flutter:
sdk: flutter
xml_crypto: ^x.y.z # 请替换为最新版本号
然后,运行flutter pub get
来安装依赖。
接下来,我们编写一个Flutter应用,展示如何使用xml_crypto
进行XML加密和解密。
import 'package:flutter/material.dart';
import 'package:xml/xml.dart' as xml;
import 'package:xml_crypto/xml_crypto.dart';
import 'dart:convert';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String encryptedXml = '';
String decryptedXml = '';
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('XML Crypto Example'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Original XML:'),
SizedBox(height: 10),
Text('<?xml version="1.0" encoding="UTF-8"?><data>Hello, World!</data>',
style: TextStyle(fontSize: 16)),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
encryptXml();
},
child: Text('Encrypt XML'),
),
SizedBox(height: 20),
if (encryptedXml.isNotEmpty)
Text('Encrypted XML:', style: TextStyle(fontSize: 16)),
if (encryptedXml.isNotEmpty)
SizedBox(height: 10),
if (encryptedXml.isNotEmpty)
Text(encryptedXml, style: TextStyle(fontSize: 14)),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
decryptXml();
},
child: Text('Decrypt XML'),
enabled: encryptedXml.isNotEmpty,
),
SizedBox(height: 20),
if (decryptedXml.isNotEmpty)
Text('Decrypted XML:', style: TextStyle(fontSize: 16)),
if (decryptedXml.isNotEmpty)
SizedBox(height: 10),
if (decryptedXml.isNotEmpty)
Text(decryptedXml, style: TextStyle(fontSize: 14)),
],
),
),
),
);
}
void encryptXml() {
String publicKeyPem = '''
-----BEGIN PUBLIC KEY-----
... (你的公钥内容) ...
-----END PUBLIC KEY-----
''';
String privateKeyPem = '''
-----BEGIN PRIVATE KEY-----
... (你的私钥内容) ...
-----END PRIVATE KEY-----
''';
xml.XmlDocument xmlDoc = xml.parse('<?xml version="1.0" encoding="UTF-8"?><data>Hello, World!</data>');
XmlEncryption xmlEncryption = XmlEncryption(xmlDoc.outerXml);
String encryptedData = xmlEncryption.encrypt(publicKeyPem, privateKeyPem);
setState(() {
encryptedXml = encryptedData;
decryptedXml = '';
});
}
void decryptXml() {
String privateKeyPem = '''
-----BEGIN PRIVATE KEY-----
... (你的私钥内容) ...
-----END PRIVATE KEY-----
''';
XmlEncryption xmlEncryption = XmlEncryption(encryptedXml);
String decryptedData = xmlEncryption.decrypt(privateKeyPem);
setState(() {
encryptedXml = ''; // 可选:清空加密后的XML内容
decryptedXml = decryptedData;
});
}
}
class XmlEncryption {
String xmlData;
XmlEncryption(this.xmlData);
String encrypt(String publicKeyPem, String privateKeyPem) {
// 注意:这里需要实际的加密逻辑,使用xml_crypto或其他库实现
// 由于xml_crypto库主要处理签名,加密部分可能需要自定义或使用其他库
// 以下仅为示例,实际加密过程需要更复杂的实现
// 假设加密过程返回base64编码的加密字符串
String encrypted = base64Encode(utf8.encode(xmlData)); // 仅为示例,不是实际加密
return encrypted;
}
String decrypt(String privateKeyPem) {
// 注意:这里需要实际的解密逻辑,使用xml_crypto或其他库实现
// 由于xml_crypto库主要处理签名,解密部分可能需要自定义或使用其他库
// 以下仅为示例,实际解密过程需要更复杂的实现
// 假设解密过程将base64编码的字符串解码回原始XML
String decrypted = utf8.decode(base64Decode(encryptedXml)); // 仅为示例,不是实际解密
return decrypted;
}
}
注意:
xml_crypto
库主要用于处理XML数字签名,而不是加密和解密。加密和解密通常需要其他库,如pointycastle
。- 上述代码中的
encrypt
和decrypt
方法仅为示例,并没有实际执行加密和解密操作。你需要使用适当的库和方法来实现这些功能。 - 替换
publicKeyPem
和privateKeyPem
字符串为你自己的公钥和私钥内容。 - 示例中的
XmlEncryption
类是为了演示目的而创建的,并不是xml_crypto
库的一部分。实际使用时,你需要根据所选的加密库来实现加密和解密逻辑。
希望这个示例能帮助你理解如何在Flutter中使用XML加密和解密的基本流程。如果你有具体的加密和解密需求,可能需要进一步查阅相关库和文档。