最近在开发这个库的时候需要用到rsa加密,在 pub.dev/ 上找了一圈,最后使用了encrypt
开发中遇到了一个问题——私钥解密后一直校验失败,encrypt rsa加密填充方式只支持:OAEP 和 PKCS1,并不支持noPadding。
因此需要自己扩展一下,以支持noPadding填充。
什么是rsa填充方式
RSA加密常用的填充模式有三种:RSA_PKCS1_PADDING, RSA_PKCS1_OAEP_PADDING, RSA_NO_PADDING。
与对称加密算法DES,AES一样,RSA算法也是一个块加密算法( block cipher algorithm),总是在一个固定长度的块上进行操作。但跟AES等不同的是,block length是跟key length有关的。
每次RSA加密的明文的长度是受RSA填充模式限制的,但是RSA每次加密的块长度就是key length。
RSA_NO_PADDING是在输入数据长度比钥模长(modulus)短时,不足的部分前面补0.
pubspec.yaml 添加依赖
dependencies:# encryptencrypt: ^4.0.0pointycastle: ^1.0.2
encrypt_ext.dart
import 'dart:typed_data';
import 'package:encrypt/encrypt.dart';
import 'package:pointycastle/export.dart' hide Algorithm;
class NoPaddingEncoding extends PKCS1Encoding {
NoPaddingEncoding(this._engine) : super(_engine);
final AsymmetricBlockCipher _engine;
late int _keyLength;
late bool _forEncryption;
@override
void init(bool forEncryption, CipherParameters params) {
super.init(forEncryption, params);
this._forEncryption = forEncryption;
if (params is AsymmetricKeyParameter<RSAAsymmetricKey>) {
this._keyLength = (params.key.modulus!.bitLength + 7) ~/ 8;
}
}
int get inputBlockSize {
return _keyLength;
}
int get outputBlockSize {
return _keyLength;
}
@override
int processBlock(
Uint8List inp, int inpOff, int len, Uint8List out, int outOff) {
if (_forEncryption) {
return _encodeBlock(inp, inpOff, len, out, outOff);
} else {
return _decodeBlock(inp, inpOff, len, out, outOff);
}
}
int _encodeBlock(
Uint8List inp, int inpOff, int inpLen, Uint8List out, int outOff) {
if (inpLen > inputBlockSize) {
throw new ArgumentError("Input data too large");
}
var block = new Uint8List(inputBlockSize);
var padLength = (block.length - inpLen);
// 补0
block.fillRange(0, padLength, 0x00);
block.setRange(padLength, block.length, inp.sublist(inpOff));
return _engine.processBlock(block, 0, block.length, out, outOff);
}
int _decodeBlock(
Uint8List inp, int inpOff, int inpLen, Uint8List out, int outOff) {
var block = new Uint8List(outputBlockSize);
var len = _engine.processBlock(inp, inpOff, inpLen, block, 0);
block = block.sublist(0, len);
if (block.length < outputBlockSize) {
throw new ArgumentError("Block truncated");
}
return block.length;
}
}
abstract class AbstractRSAExt {
final RSAPublicKey publicKey;
final RSAPrivateKey? privateKey;
final PublicKeyParameter<RSAPublicKey> _publicKeyParams;
final PrivateKeyParameter<RSAPrivateKey>? _privateKeyParams;
final AsymmetricBlockCipher _cipher;
AbstractRSAExt({
required this.publicKey,
this.privateKey,
}) : this._publicKeyParams = PublicKeyParameter(publicKey),
this._privateKeyParams = privateKey!=null? PrivateKeyParameter(privateKey!): null,
this._cipher = NoPaddingEncoding(RSAEngine());
}
class RSAExt extends AbstractRSAExt implements Algorithm {
RSAExt({required RSAPublicKey publicKey, RSAPrivateKey? privateKey})
: super(publicKey: publicKey, privateKey: privateKey);
@override
Encrypted encrypt(Uint8List bytes, {IV? iv, Uint8List? associatedData}) {
if (publicKey == null) {
throw StateError('Can\'t encrypt without a public key, null given.');
}
_cipher
..reset()
..init(true, _publicKeyParams);
return Encrypted(_cipher.process(bytes));
}
@override
Uint8List decrypt(Encrypted encrypted, {IV? iv, Uint8List? associatedData}) {
if (privateKey == null) {
throw StateError('Can\'t decrypt without a private key, null given.');
}
if (_privateKeyParams == null) {
throw StateError('Can\'t decrypt without a privateKeyParams, null given.');
}
_cipher
..reset()
..init(false, _privateKeyParams!);
return _cipher.process(encrypted.bytes);
}
}
引用:(RSA非对称加解密算法填充方式(Padding)) blog.csdn.net/makenothing…