If you find this article helpful to you, welcome to πŸ‘, my Github.


Recently, when developing this library, WE needed RSA encryption. We searched pub.dev/ and used ENCRYPT

Encrypt RSA only supports OAEP and PKCS1. NoPadding is not supported.

So you need to extend it yourself to support noPadding.

What is RSA padding

There are three commonly used padding modes for RSA encryption: RSA_PKCS1_PADDING, RSA_PKCS1_OAEP_PADDING, and RSA_NO_PADDING.

Like the symmetric encryption algorithms DES and AES, RSA is a block cipher algorithm. It always operates on a block of a fixed length. But unlike AES, block length is related to key Length.

The plaintext length of each RSA encryption is limited by the RSA filling mode, but the block length of each RSA encryption is the key length.

Fill the way The input The output
RSA_PKCS1_PADDING Modulus must be at least 11 bytes shorter than RSA_size(RSA) -11 As long as modulus
RSA_PKCS1_OAEP_PADDING RSA_size (rsa) – 41 As long as modulus
RSA_NO_PADDING It can be as long as the RSA key module. If the input plaintext is too long, it must be cut and filled As long as modulus

Modulus RSA_NO_PADDING is a complement of 0 when the input data is shorter than the modulus of the key.


The implementation is as follows:

Pubspec.yaml adds dependencies

dependencies:
  # encrypt
  encrypt: ^ 4.0.0
  pointycastle: ^ 1.0.2
Copy the code

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;

  int _keyLength;
  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");
    }

    returnblock.length; }}abstract class AbstractRSAExt {
  final RSAPublicKey publicKey;
  final RSAPrivateKey privateKey;
  final PublicKeyParameter<RSAPublicKey> _publicKeyParams;
  final PrivateKeyParameter<RSAPrivateKey> _privateKeyParams;
  final AsymmetricBlockCipher _cipher;

  AbstractRSAExt({
    this.publicKey,
    this.privateKey,
  })  : this._publicKeyParams = PublicKeyParameter(publicKey),
        this._privateKeyParams = PrivateKeyParameter(privateKey),
        this._cipher = NoPaddingEncoding(RSAEngine());
}

class RSAExt extends AbstractRSAExt implements Algorithm {
  RSAExt({RSAPublicKey publicKey, RSAPrivateKey privateKey})
      : super(publicKey: publicKey, privateKey: privateKey);

  @override
  Encrypted encrypt(Uint8List bytes, {IV iv}) {
    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}) {
    if (privateKey == null) {
      throw StateError('Can\'t decrypt without a private key, null given.'); } _cipher .. reset() .. init(false, _privateKeyParams);

    return_cipher.process(encrypted.bytes); }}Copy the code

use

final parser = RSAKeyParser();
final encrypter =
  Encrypter(RSAExt(publicKey: parser.parse(_publicKey)));
encrypter.doSome...
Copy the code

RSA asymmetric encryption and decryption algorithm Padding