Moment For Technology

Springboot + security based on the separation of front and rear end RSA | login password encryption process in August more challenges

Posted on Dec. 3, 2022, 9:19 a.m. by Kismat Kant
Category: The back-end Tag: The back-end java

This is the first day of my participation in the August Challenge. For details, see:August is more challenging

? the

The inertia of refusing to learn is terrible

Now is not the same as before, more information, access to a wide, in the middle of the interspersed advertising is also very much. This makes it difficult for many beginners to find their own knowledge, finally see someone recommend the relevant learning materials immediately block, delete, but at the same time the technology of excellent data can not let the people who need to see. Over time, more time and energy are put on games, entertainment, audio and video, appropriate relaxation is ok, but it is often difficult to come out after addiction, so we need to do some plans that can make their own growth, a little restraint.

Today, let's share --springboot + securityBased on front and rear end separationRSAPassword encryption login process, welcome to pay attention!

Note that this mode of request may occur with a + parameter replaced by a space, please refer to this article:RSA encryption request error: javax.mail. Crypto. BadPaddingException: Decryption error


? Introduction to RSA encryption

RSA encryptionIt's a kind of asymmetric encryption. Decryption can be accomplished without directly passing the key. This can ensure the security of the information, to avoid the direct transmission of the key caused by the risk of cracking. Is the process of encryption and decryption by a pair of keys, respectively called public key and private key. There is a mathematical correlation between them. The principle of this encryption algorithm is the difficulty of factorization of a maximum integer to ensure the security. The public key is public (it may be held by more than one person at a time).


✨ RSA encryption

Encryption is for security, simply put, encryption is to prevent information from being leaked

Scenario: Agent B is sending A message to Agent A about A command.

The RSA encryption process is as follows: (1) Agent A generates A pair of keys (public key and private key). The private key is not disclosed and agent A keeps the private key. The public key is public and can be obtained by anyone. (2) Agent A passes his public key to agent B, and agent B uses Agent A's public key to encrypt the message. (3) Agent A receives the message encrypted by Agent B and uses Agent A's private key to decrypt the message.

In this process, there are only two transmission processes, the first time is agent A passes the public key to agent B, and the second time is agent B passes the encrypted message to agent A. Even if both are intercepted by the enemy, there is no danger, because only agent A's private key can decrypt the message, preventing the disclosure of the message content. Based on this feature, we can encrypt the passwords on the front and back ends. Ensure password security.


?RSA password encryption (Java) implementation

  • For the login function, the password cannot be transmitted in plain text. Therefore, the password sent from the front end must be the RSA encrypted password.
  • becauseRSAPublic key encryption, private key decryption. Then you can randomly generate a public key private key key pair, and then save the key pair, do not leak, give the public key to the front end to encrypt the password, the back end using the private key to decrypt. Finally, the password is saved to the database by adding salt encryption

The following isRSA encryptionThe code of

  • In practice, you can generate the public and private keys in advance and put them in the configuration file
  • Say a train of thought, specific usage can run directlymainThe main function is studied slowly.

Base64: Encapsulates Base64 encoding. Used for RSA cipher encoding and decoding

import com.fckj.fckjrestaurant.constant.Constant;
import com.fckj.fckjrestaurant.util.codec.Base64Utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

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


/ * * *@Description: RSA encryption and decryption *@BelongsProject: fckj-restaurant
 * @BelongsPackage: com.fckj.fckjrestaurant.util.RSA
 * @Author: ChenYongJia
 * @CreateTime: the 2021-06-04 11:46 *@Email: [email protected]
 * @Version: 1.0 * /
@Slf4j
public class RSAUtils {

    /** * Maximum RSA encryption plaintext size */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /** * RSA maximum ciphertext size */
    private static final int MAX_DECRYPT_BLOCK = 128;

    /** * Obtain key pair **@return java.security.KeyPair
     * @date2021/6/7 * descend@author ChenYongJia
     * @version1.0 * /
    public static KeyPair getKeyPair(a) throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance(Constant.ALGORITHM_NAME);
        generator.initialize(1024);
        return generator.generateKeyPair();
    }

    /** * Obtain private key **@paramPrivateKey privateKey character string *@return java.security.PrivateKey
     * @date2021/6/7 * descend@author ChenYongJia
     * @version1.0 * /
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(Constant.ALGORITHM_NAME);
        byte[] decodedKey = Base64Utils.decoder(privateKey.getBytes());
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
        return keyFactory.generatePrivate(keySpec);
    }

    /** * Get public key **@paramPublicKey publicKey the value is a character string (*)@param publicKey
     * @return java.security.PublicKey
     * @date2021/6/7 * descend@author ChenYongJia
     * @version1.0 * /
    public static PublicKey getPublicKey(String publicKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(Constant.ALGORITHM_NAME);
        byte[] decodedKey = Base64Utils.decoder(publicKey.getBytes());
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
        return keyFactory.generatePublic(keySpec);
    }

    /** * RSA encryption **@paramData Data to be encrypted *@paramPublicKey public key *@return java.lang.String
     * @date2021/6/7 * descend@author ChenYongJia
     * @version1.0 * /
    public static String encrypt(String data, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance(Constant.ALGORITHM_NAME);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        int inputLen = data.getBytes().length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        // Encrypt the 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();
        // The encrypted content is encoded using Base64 and converted to a string using UTF-8
        // The encrypted string
        return new String(Base64Utils.encoder(encryptedData));
    }

    /** * RSA decryption **@paramData Data to be decrypted *@paramPrivateKey private key *@return java.lang.String
     * @date2021/6/7 15:33 the *@author ChenYongJia
     * @version1.0 * /
    public static String decrypt(String data, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance(Constant.ALGORITHM_NAME);
        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 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 *@return java.lang.String
     * @date2021/6/7 15:33 the *@author ChenYongJia
     * @version1.0 * /
    public static String sign(String data, PrivateKey privateKey) throws Exception {
        byte[] keyBytes = privateKey.getEncoded();
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(Constant.ALGORITHM_NAME);
        PrivateKey key = keyFactory.generatePrivate(keySpec);
        Signature signature = Signature.getInstance(Constant.MD5_RSA);
        signature.initSign(key);
        signature.update(data.getBytes());
        return new String(Base64Utils.encoder(signature.sign()));
    }

    /** * Check the signature **@paramSrcData Raw string *@paramPublicKey public key *@paramSign the signature *@return boolean
     * @date2021/6/7 15:33 the *@author ChenYongJia
     * @version1.0 * /
    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(Constant.ALGORITHM_NAME);
        PublicKey key = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(Constant.MD5_RSA);
        signature.initVerify(key);
        signature.update(srcData.getBytes());
        return signature.verify(Base64Utils.decoder(sign.getBytes()));
    }

    public static void main(String[] args) {
        try {
            // Generate the key pair
            KeyPair keyPair = getKeyPair();
            String privateKey = new String(Base64Utils.encoder(keyPair.getPrivate().getEncoded()));
            String publicKey = new String(Base64Utils.encoder(keyPair.getPublic().getEncoded()));
            log.info("The private key." + privateKey);
            log.info("Public." + publicKey);
            / / RSA encryption
            String data = "123456";
            String encryptData = encrypt(data, getPublicKey(publicKey));
            log.info("Encrypted content :" + encryptData);
            / / RSA decryption
            String decryptData = decrypt(encryptData, getPrivateKey(privateKey));
            log.info("Contents after decryption :" + decryptData);
            / / RSA signature
            String sign = sign(data, getPrivateKey(privateKey));
            / / RSA attestation
            boolean result = verify(data, getPublicKey(publicKey), sign);
            log.info("Verification result :" + result);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("RSA encryption and Decryption exception"); }}}Copy the code

SpringbootBusiness code implementation

Logic: the front-end obtains publickey -- the publickey, uses the publickey to encode and encrypt the password, the back-end obtains the password, uses the corresponding private key to decrypt and encrypt the data, and compares the password with the database

Generate a key pair, store it in Redis, and return the front-end public key

 @Override
    public String getPublicKey(a) {
        try {
            Object privateKey = redisUtil.get(Constant.RSA_PRIVATE_KEY);
            Object publicKey = redisUtil.get(Constant.RSA_PUBLIC_KEY);
            if (WyCheckUtil.isEmpty(publicKey) || WyCheckUtil.isEmpty(privateKey)) {
                KeyPair keyPair = RSAUtils.getKeyPair();
                privateKey = new String(Base64Utils.encoder(keyPair.getPrivate().getEncoded()));
                publicKey = new String(Base64Utils.encoder(keyPair.getPublic().getEncoded()));
                // Store the private key
                redisUtil.set(Constant.RSA_PRIVATE_KEY, privateKey);
                // Store the public key
                redisUtil.set(Constant.RSA_PUBLIC_KEY, publicKey);
            }
            log.info("PrivateKey = {}, publicKey = {}", privateKey, publicKey);
            return publicKey.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null; }}Copy the code

Front end: based on iView and VUE framework

The front end is encrypted with crypto-JS, NPM I jsencrypt, and then the page header is introducedimport JSEncrypt from 'jsencrypt';
const encrypt = new JSEncrypt();
encrypt.setPublicKey('Your public key'); Password = encrypt.encrypt(' your password ');// The encrypted string
Copy the code
getPublicKey().then(res=  {
            let password = this.form.password
            let publicKey = res.data.data.data
            console.log(publicKey)
            const encrypt = new JSEncrypt()
            encrypt.setPublicKey(publicKey)
            password = encrypt.encrypt(password)
            console.log(password)
            this.$emit('on-success-valid', {
              userName: this.form.userName,
              password: password
            })
          })
Copy the code

Comparison of decryption during login authentication

String inputDecryptData = "";
        try {
            Object privateKey = redisUtil.get(Constant.RSA_PRIVATE_KEY);
            inputDecryptData =  RSAUtils.decrypt(password, RSAUtils.getPrivateKey(privateKey.toString()));
        } catch (Exception e) {
            log.error("Exception occurs in RSA encryption and decryption ======", e);
            throw new BizException("Abnormal RSA encryption and decryption");
        }
Copy the code

First get the private key, I put it in Redis, and then use the private key to decrypt and encrypt the data. My colleagues get the database user object and use the private key to decrypt the password and compare it with the password entered by the user

At this point, Springbootsecurity's RSA password-encrypted login process based on front and back end separation is complete


? finally

  • For more references, see here:Chen Yongjia's Blog

  • Like the little friend of the blogger can add a concern, point a like oh, continue to update hey hey!

Search
About
mo4tech.com (Moment For Technology) is a global community with thousands techies from across the global hang out!Passionate technologists, be it gadget freaks, tech enthusiasts, coders, technopreneurs, or CIOs, you would find them all here.