Skip to main content

Overview

RSAUtils is a utility class that implements RSA public key encryption and decryption, using asymmetric encryption algorithms to ensure data transmission security. In API communication, it is used to encrypt sensitive business data for transmission and decrypt encrypted data returned from the server.

Code Examples

import java.io.ByteArrayOutputStream;
import java.util.Base64;
import javax.crypto.Cipher;
import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.X509EncodedKeySpec;

/**
* RSA public key encryption/decryption utility class
* <p>
* Provides asymmetric encryption and decryption based on public key,
* suitable for encrypted data transmission in API communication.
*/
public class RSAUtils {
  // RSA encryption maximum block size (unit: bytes)
  private static final int MAX_ENCRYPT_BLOCK = 117;

  /**
   * Encrypt data using public key
   *
   * @param data Original binary data
   * @param publicKey Base64 encoded public key string
   * @return Encrypted binary data
   *
   * Usage scenario: Encrypt business data before sending API requests.
   * Automatically handles chunked encryption of large data (117 bytes/chunk).
   *
   * Example:
   * byte[] encrypted = RSAUtils.encryptByPublicKey(
   *     jsonData.getBytes(),
   *     "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQ..."
   * );
   */
  public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
      // 1. Base64 decode public key
      byte[] keyBytes = Base64Util.decodeString(publicKey);

      // 2. Generate public key object
      KeyFactory keyFactory = KeyFactory.getInstance("RSA");
      Key publicK = keyFactory.generatePublic(
          new X509EncodedKeySpec(keyBytes)
      );

      // 3. Create and initialize cipher
      Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
      cipher.init(Cipher.ENCRYPT_MODE, publicK);

      // 4. Chunked encryption for large data
      int inputLen = data.length;
      int offset = 0;
      java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream();

      while (inputLen - offset > 0) {
          int blockSize = Math.min(inputLen - offset, MAX_ENCRYPT_BLOCK);
          byte[] encryptedBlock = cipher.doFinal(data, offset, blockSize);
          out.write(encryptedBlock, 0, encryptedBlock.length);
          offset += blockSize;
      }

      return out.toByteArray();
  }

  /**
   * Decrypt data using public key
   *
   * @param encryptedData Encrypted binary data
   * @param publicKey Base64 encoded public key string
   * @return Decrypted original binary data
   *
   * Usage scenario: Decrypt encrypted data returned from APIs.
   * Suitable for one-time decryption of small data chunks.
   *
   * Example:
   * byte[] decrypted = RSAUtils.decryptByPublicKey(
   *     encryptedBytes,
   *     "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQ..."
   * );
   */
  public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {

      final int MAX_DECRYPT_BLOCK = 128;

      // 1. Base64 decode public key
      byte[] keyBytes = Base64Util.decodeString(publicKey);

      // 2. Generate public key object
      KeyFactory keyFactory = KeyFactory.getInstance("RSA");
      Key publicK = keyFactory.generatePublic(
          new X509EncodedKeySpec(keyBytes)
      );

      // 3. Create and initialize decrypter
      Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
      cipher.init(Cipher.DECRYPT_MODE, publicK);

      // 4. One-time decryption (suitable for small data)
      // return cipher.doFinal(encryptedData);
      int inputLen = encryptedData.length;
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      int offSet = 0;
      byte[] cache;
      int i = 0;
      // Decrypt data in segments
      while (inputLen - offSet > 0) {
          if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
              cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
          } else {
              cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
          }
          out.write(cache, 0, cache.length);
          i++;
          offSet = i * MAX_DECRYPT_BLOCK;
      }
      byte[] decryptedData = out.toByteArray();
      out.close();
      return decryptedData;
  }
}
const crypto = require('crypto');
const Base64Util = require('./Base64Util');

/**
* RSA Public Key Encryption/Decryption Utility Class
*
* Provides asymmetric encryption and decryption capabilities based on public keys,
* suitable for secure data transmission in API communications.
*/
class RSAUtils {
  // Maximum block size for RSA encryption (in bytes)
  static MAX_ENCRYPT_BLOCK = 117;

  /**
   * Encrypts data using a public key
   * @param {Buffer} data - Raw binary data to be encrypted
   * @param {string} publicKey - Base64 encoded public key string
   * @returns {Buffer} Encrypted binary data
   *
   * Usage scenario: Encrypts business data before sending API requests.
   * Automatically handles large data segmentation (117 bytes per block).
   */
  static encryptByPublicKey(data, publicKey) {
      try {
          // 1. Convert Base64 public key to PEM format
          const pemKey = `-----BEGIN PUBLIC KEY-----\n${publicKey}\n-----END PUBLIC KEY-----`;

          // 2. Generate public key object
          const key = crypto.createPublicKey(pemKey);

          // 3. Create and initialize encryptor
          const encryptedParts = [];
          const buffer = Buffer.from(data);
          let offset = 0;
          const inputLen = buffer.length;

          // 4. Segment and encrypt large data
          while (offset < inputLen) {
              const blockSize = Math.min(inputLen - offset, RSAUtils.MAX_ENCRYPT_BLOCK);
              const chunk = buffer.slice(offset, offset + blockSize);
              const encryptedChunk = crypto.publicEncrypt({
                  key: key,
                  padding: crypto.constants.RSA_PKCS1_PADDING
              }, chunk);
              encryptedParts.push(encryptedChunk);
              offset += blockSize;
          }

          return Buffer.concat(encryptedParts);
      } catch (error) {
          throw new Error(`RSA encryption failed: ${error.message}`);
      }
  }

  /**
   * Decrypts data using a public key
   * @param {Buffer} encryptedData - Encrypted binary data
   * @param {string} publicKey - Base64 encoded public key string
   * @returns {Buffer} Decrypted raw binary data
   *
   * Usage scenario: Decrypts encrypted data returned from API responses.
   * Automatically handles large data segmentation (128 bytes per block).
   */
  static decryptByPublicKey(encryptedData, publicKey) {
      try {
          // 1. Convert Base64 public key to PEM format
          const pemKey = `-----BEGIN PUBLIC KEY-----\n${publicKey}\n-----END PUBLIC KEY-----`;

          // 2. Generate public key object
          const key = crypto.createPublicKey(pemKey);

          // 3. Create and initialize decryptor
          const decryptedParts = [];
          const buffer = Buffer.from(encryptedData);
          let offset = 0;
          const inputLen = buffer.length;
          const MAX_DECRYPT_BLOCK = 128;

          // 4. Segment and decrypt data
          while (offset < inputLen) {
              const blockSize = Math.min(inputLen - offset, MAX_DECRYPT_BLOCK);
              const chunk = buffer.slice(offset, offset + blockSize);
              const decryptedChunk = crypto.publicDecrypt({
                  key: key,
                  padding: crypto.constants.RSA_PKCS1_PADDING
              }, chunk);
              decryptedParts.push(decryptedChunk);
              offset += blockSize;
          }

          return Buffer.concat(decryptedParts);
      } catch (error) {
          throw new Error(`RSA decryption failed: ${error.message}`);
      }
  }
}

module.exports = RSAUtils;
import base64
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.backends import default_backend

class RSAUtils:
# RSA encryption maximum block size (unit: bytes)
MAX_ENCRYPT_BLOCK = 117

@staticmethod
def encrypt_by_public_key(data: bytes, public_key_str: str) -> bytes:
    """
    Encrypt data using public key
    @param data: Original binary data
    @param public_key_str: Base64 encoded public key string
    @return: Encrypted binary data

    Usage scenario: Encrypt business data before sending API requests
    Automatically handles chunked encryption of large data (117 bytes/chunk)
    """
    # 1. Base64 decode public key
    public_key_der = base64.b64decode(public_key_str)

    # 2. Load public key object
    public_key = serialization.load_der_public_key(
        public_key_der,
        backend=default_backend()
    )

    # 3. Chunked encryption
    offset = 0
    encrypted_chunks = []
    while offset < len(data):
        block = data[offset:offset + RSAUtils.MAX_ENCRYPT_BLOCK]
        encrypted_chunk = public_key.encrypt(
            block,
            padding.OAEP(
                mgf=padding.MGF1(algorithm=hashes.SHA256()),
                algorithm=hashes.SHA256(),
                label=None
            )
        )
        encrypted_chunks.append(encrypted_chunk);
        offset += len(block)

    return b''.join(encrypted_chunks)

@staticmethod
def decrypt_by_public_key(encrypted_data: bytes, public_key_str: str) -> bytes:
    """
    Decrypt data using public key
    @param encrypted_data: Encrypted binary data
    @param public_key_str: Base64 encoded public key string
    @return: Decrypted original binary data

    Usage scenario: Decrypt encrypted data returned from APIs
    Suitable for one-time decryption of small data chunks
    """
    # 1. Base64 decode public key
    public_key_der = base64.b64decode(public_key_str)

    # 2. Load public key object
    public_key = serialization.load_der_public_key(
        public_key_der,
        backend=default_backend()
    )

    # 3. One-time decryption
    return public_key.decrypt(
        encrypted_data,
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),
            algorithm=hashes.SHA256(),
            label=None
        )
    )

# Usage example
if __name__ == "__main__":
# Simulate public key string
public_key = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQ..."

# Data to encrypt
data = b"Sensitive data 12345"

try:
    # Encryption
    encrypted = RSAUtils.encrypt_by_public_key(data, public_key)
    print("Encryption result:", base64.b64encode(encrypted).decode())

    # Decryption
    decrypted = RSAUtils.decrypt_by_public_key(encrypted, public_key)
    print("Decryption result:", decrypted.decode())
except Exception as e:
    print("RSA operation failed:", e)