之前一直在用RN开发应用,最近Flutter很火,就研究了下,而大家在开发与服务端做接口交互时,为了保证安全性,基本上都会使用加密方式来隐藏通讯内容,非对称加密方式,相比其他固定算法加密方式要安全很多,

非对称加密使用了私钥、公钥来分别对数据进行解密、加密操作,公钥做加密后的数据,只有私钥才能解密,因此会非常的安全。

Flutter使用的是Dart语言,Dart语言和Java非常的像,基本上会使用Java的程序员可以直接上手,部分查下就Ok了。

在Dart中,非对称加密可以使用 encrypt 包,可以直接在 pubspec.yaml 中增加 encrypt: ^2.0.0 即可完成包的引用,当然,不要忘记执行 packages get

做非对称加密,就必须要有公钥和私钥,特别注意一点,当前的 encrypt 为2.0.0版本,当前仅支持 PKCS#1文件格式的密钥

首先我们要生成私钥

openssl genrsa -out private_key.pem 4096
这样就生成了一个私钥,而且就是PKCS#1格式的,如果有PKCS#8格式的,也可以用这个命令来转换为PKCS#1
openssl pkcs8 -in pkcs8_private_key.pem -nocrypt -out pkcs1_private_key.pem

第一个坑,在flutter中,密钥文件直接存放在目录中是无法使用File读取到的,只能放在asset中才可以,所以需要在 pubspec.yaml中增加相关密钥文件才行,例如将密钥文件存放在与 pubspec.yaml 同级的目录 keys 下,则需要在 pubspec.yaml 中增加如下代码

assets:
- keys/private_key.pem
- keys/public_key.pem

之后我们可以在代码中使用

String publicKeyString = await rootBundle.loadString('keys/public_key.pem');
来获取到公钥的文本,再通过
parser = RSAKeyParser();
RSAPublicKey publicKey = parser.parse(publicKeyString);
来生成公钥,通过
final encrypter = Encrypter(RSA(publicKey: publicKey));
创建加密器,再对原始数据加密
encrypter.encrypt(srcContent)

解密和加密差不多方式,只不过需要用私钥做解密。

下面放一个加密解密的辅助类

import 'package:encrypt/encrypt.dart';
import 'package:pointycastle/asymmetric/api.dart';
import 'dart:async';
import 'package:flutter/services.dart' show rootBundle;

final parser = RSAKeyParser();

class EncryptHelper {

static Future<String> encode(String src) async {
String publicKeyString = await rootBundle.loadString('keys/public_key.pem');
RSAPublicKey publicKey = parser.parse(publicKeyString);
final encrypter = Encrypter(RSA(publicKey: publicKey));
return encrypter.encrypt(src).base64;
}

static Future<String> decode(String decoded) async {
String privateKeyString = await rootBundle.loadString('keys/private_key.pem');

final privateKey = parser.parse(privateKeyString);

final encrypter = Encrypter(RSA(privateKey: privateKey));
return encrypter.decrypt(Encrypted.fromBase64(decoded));
}

}

基本上再Flutter中的非对称加密就是这样的了,但是记得开发接口的时候,应该是用两套密钥,服务器存储一个私钥,用于解密应用调用接口过来的密文,同时服务器端还需要存储另一套RSA的公钥,用来加密返回的数据,而应用内存储的一个是服务器端私钥的公钥,另一个则是服务端公钥对应的私钥,用来解密服务器端返回的数据,这样通讯就完全通过两套RSA密钥来做安全性保护了。

8 个评论

  1. 具体报错信息是 类型不匹配。
    对于 报错就在 RSAPublicKey,
    final modulus = (sequence.elements[0] as ASN1Integer).valueAsBigInteger;
    在rsa.dart文件里的这行。

    可不可以不用pem格式的文件呢,直接用hardcode公钥字符串来生成?
    如果不可以,那么 需要使用多大的密钥才可以?

    匿名

评论功能已关闭。