Brief introduction:

RSA encryption algorithm: an asymmetric encryption algorithm that requires two keys, one public key and the other private key. The public key is used for encryption and the private key for decryption. Only the corresponding private key can be used to decrypt and obtain the original plaintext. The public key used for encryption cannot be used for decryption. Encryption and decryption require two different keys, so it is called asymmetric encryption. Currently, you can use keys of 1024, 2048, and 4096 bytes. The security increases with the byte length, but the performance decreases with it. The time complexity is O(nlogn).

Usage Scenarios:

User login, including personal information and mobile phone number, input bank account password, etc.

So do you know how your personal information was leaked?

Three important roles

  • KEY_SIZE: indicates the number of RSA keys
  • MAX_ENCRYPT_BLOCK: specifies the maximum length of RSA encryption plaintext
  • MAX_DECRYPT_BLOCK: indicates the maximum length of ENCRYPTED RSA ciphertext

The relationship between the three

    private static final int KEY_SIZE = 4096;
	// Number of bytes = key bits / 8
    private static final int MAX_ENCRYPT_BLOCK = KEY_SIZE / 8 - 11;
    private static final int MAX_DECRYPT_BLOCK = KEY_SIZE / 8;
Copy the code

RSA has requirements on the plaintext length (bytes) : The plaintext length m must be 0< M < key length N.

The plaintext length can be calculated as follows:


Plaintext maximum length = The key length 11 ( byte ) Maximum plaintext length = Key length -11 (bytes)

The maximum length of decrypted ciphertext can be calculated as follows:


The length of the public key = The key figures / 8 ( byte ) Public key Length = Key bits / 8 (bytes)

In RSA encryption, Padding is involved in calculation of Padding, so the difference between plaintext and ciphertext 11 is the Padding length (when the plaintext length is insufficient, it is used as data Padding). When the plaintext data is too long (when the maximum number of digits exceeds 4096), segmenting encryption and decryption can be used. If the plaintext or key length cannot exceed 117/245/501, check whether the plaintext length matches the plaintext length. Of course, whether to use segmental encryption and decryption needs to develop the encryption and decryption of both sides jointly agreed.

For example:

If the 1024 bit key is used for encryption by default, the maximum plaintext length is 117 bytes, and the maximum ciphertext length is 1024/8 = 128 bytes.

Digital attestation

Verify digital signature: The sender encrypts the data with MD5 and then signs the data. If the data is modified and then signs the data again, the digital signature is inconsistent with the original digital signature. Therefore, you can use digital signature to prevent the data from being modified.

Here is my RSA encryption utility class, right out of the box. SpringBoot project integration RSA encryption algorithm interface encryption Demo at the end of this article.

talk is cheap,show me your code.


package com.example.ltx.eshare.common.utils;

import cn.hutool.http.HttpUtil;
import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/ * * *@author Liutx
 * @date 2021/1/28 21:23
 * @Description* /
public class TestRSaUtil {
    /** * The maximum encrypted plaintext size of RSA */

    /** * Maximum size of RSA ciphertext */



    private static final int KEY_SIZE = 4096;
    private static final int MAX_ENCRYPT_BLOCK = KEY_SIZE / 8 - 11;
    private static final int MAX_DECRYPT_BLOCK = KEY_SIZE / 8;

    /** * get the key pair **@returnThe key to * /
    public static KeyPair getKeyPair(a) throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        generator.initialize(KEY_SIZE);
        return generator.generateKeyPair();
    }

    /** * get the private key **@paramPrivateKey privateKey character string *@return* /
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes());
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
        return keyFactory.generatePrivate(keySpec);
    }

    /** * Get public key **@paramPublicKey publicKey character string *@return* /
    public static PublicKey getPublicKey(String publicKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes());
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
        return keyFactory.generatePublic(keySpec);
    }

    /** * RSA encryption **@paramData Indicates the data to be encrypted@paramPublicKey public key *@return* /
    public static String encrypt(String data, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        int inputLen = data.getBytes().length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        // Encrypt data in segments
        while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        // Get the encrypted content encoded using Base64 and converted to a string using UTF-8 standards
        // An encrypted string
        return new String(Base64.encodeBase64String(encryptedData));
    }

    /** * RSA decryption **@paramData Data to be decrypted *@paramPrivateKey private key *@return* /
    public static String decrypt(String data, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] dataBytes = Base64.decodeBase64(data);
        int inputLen = dataBytes.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(dataBytes, offset, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        // The decrypted content
        return new String(decryptedData, "UTF-8");
    }

    /** ** signature **@paramData Data to be signed *@paramPrivateKey private key *@returnSignature * /
    public static String sign(String data, PrivateKey privateKey) throws Exception {
        byte[] keyBytes = privateKey.getEncoded();
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey key = keyFactory.generatePrivate(keySpec);
        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initSign(key);
        signature.update(data.getBytes());
        return new String(Base64.encodeBase64(signature.sign()));
    }

    /** * check the signature **@paramSrcData The original string *@paramPublicKey public key *@paramSign the signature *@returnCheck whether the visa is approved */
    public static boolean verify(String srcData, PublicKey publicKey, String sign) throws Exception {
        byte[] keyBytes = publicKey.getEncoded();
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey key = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initVerify(key);
        signature.update(srcData.getBytes());
        return signature.verify(Base64.decodeBase64(sign.getBytes()));
    }

    public static void main(String[] args) {
        try {
            // Generate a key pair
            KeyPair keyPair = getKeyPair();
            String privateKey = new String(Base64.encodeBase64(keyPair.getPrivate().getEncoded()));
            String publicKey = new String(Base64.encodeBase64(keyPair.getPublic().getEncoded()));
            System.out.println("The private key." + privateKey);
            System.out.println("Public." + publicKey);
            / / RSA encryption
// String data = "Text content to be encrypted ";
            String data = HttpUtil.get("https://v1.jinrishici.com/all.json");
            String encryptData = encrypt(data, getPublicKey(publicKey));
            System.out.println("Encrypted content :" + encryptData);
            / / RSA decryption
            String decryptData = decrypt(encryptData, getPrivateKey(privateKey));
            System.out.println("Decrypted content :" + decryptData);

            / / RSA signature
            String sign = sign(data, getPrivateKey(privateKey));
            / / RSA attestation
            boolean result = verify(data, getPublicKey(publicKey), sign);
            System.out.print("Inspection Result :" + result);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.print("Encryption and decryption exception"); }}}Copy the code

RSA can also be used with SpringBoot annotations. When returning to the interface, the returned data is encrypted. For details, please refer to my Gitee.

eshare