Spring security uses RAS encryption to request plaintext encryption for login account password

1: Scene

When a user logs in, as long as anyone who has a little basic knowledge of browsing the web page knows that opening the browser console can get the header information of the post request in the request grabbing block, and our user's login account password is just saved here. If no encryption is added, others can crawl the user's information, which is not safe at all, so we have to solve the problem, In the request, we encrypt all the account passwords and send them to the background for decryption, so this problem is solved. The idea is such a logic, and how to realize it is the problem we will talk about next; as follows

2: Technical point

Spring security is used to realize user authentication and authorization, and RAS asymmetric encryption is used to encrypt data

3: Technical description

RAS is called asymmetric encryption for short. Its security factor is very high. It uses key pair to encrypt data. First, it generates a pair of keys (public key, private key) in the background. The public key can be given to users or multiple people. It is only responsible for data encryption, but the private key cannot be disclosed. It can decrypt the corresponding public key. This is the only way to decrypt public key, So as long as the private key of your corresponding public key is not disclosed, others will not get your corresponding encryption method
Spring security authentication mode needs to tangle the source code, so it will not be explained in this article at first, and a corresponding article will be published later to explain how to customize user authentication and dynamic authorization from the source point of view

4: Don't talk much

RSAUtils: encapsulates the way that RSA generation rules have been decrypted. Call

public class RSAUtils {

    /** */
    /**
     * Encryption algorithm RSA
     */
    public static final String KEY_ALGORITHM = "RSA";

    /** */
    /**
     * signature algorithm 
     */
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

    /** */
    /**
     * Get the key of public key
     */
    private static final String PUBLIC_KEY = "RSAPublicKey";

    /** */
    /**
     * Get the key of the private key
     */
    private static final String PRIVATE_KEY = "RSAPrivateKey";

    /** */
    /**
     * RSA Maximum encrypted clear text size
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

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

    /** */
    /**
     * RSA If the maximum encryption and maximum decryption above 2048 are used, 245 256 must be filled in
     */
    private static final int INITIALIZE_LENGTH = 1024;

    /** */
    /**
     * <p>
     * Generate key pair (public key and private key)
     * </p>
     *
     * @return
     * @throws Exception
     */
    public static Map<String, Object> genKeyPair() throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(INITIALIZE_LENGTH);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /** */
    /**
     * <p>
     * Using private key to generate digital signature for information
     * </p>
     *
     * @param data
     *            Encrypted data
     * @param privateKey
     *            Private key (BASE64 encoded)
     *
     * @return
     * @throws Exception
     */
    public static String sign(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = Base64.decodeBase64(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateK);
        signature.update(data);
        return Base64.encodeBase64String(signature.sign());
    }

    /** */
    /**
     * <p>
     * Verify digital signature
     * </p>
     *
     * @param data
     *            Encrypted data
     * @param publicKey
     *            Public key (BASE64 encoded)
     * @param sign
     *            digital signature 
     *
     * @return
     * @throws Exception
     *
     */
    public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
        byte[] keyBytes = Base64.decodeBase64(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicK = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(publicK);
        signature.update(data);
        return signature.verify(Base64.decodeBase64(sign));
    }

    /** */
    /**
     * <P>
     * Private key decryption
     * </p>
     *
     * @param encryptedData
     *            Encrypted data
     * @param privateKey
     *            Private key (BASE64 encoded)
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
        byte[] keyBytes = Base64.decodeBase64(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // Segment decryption of data
        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;
    }

    /** */
    /**
     * <p>
     * Public key decryption
     * </p>
     *
     * @param encryptedData
     *            Encrypted data
     * @param publicKey
     *            Public key (BASE64 encoded)
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {
        byte[] keyBytes = Base64.decodeBase64(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // Segment decryption of data
        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;
    }

    /** */
    /**
     * <p>
     * Public key encryption
     * </p>
     *
     * @param data
     *            Source data
     * @param publicKey
     *            Public key (BASE64 encoded)
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
        byte[] keyBytes = Base64.decodeBase64(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        // Encrypt data
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // Segment encryption of data
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }

    /** */
    /**
     * <p>
     * Private key encryption
     * </p>
     *
     * @param data
     *            Source data
     * @param privateKey
     *            Private key (BASE64 encoded)
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = Base64.decodeBase64(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // Segment encryption of data
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }

    /** */
    /**
     * <p>
     * Get private key
     * </p>
     *
     * @param keyMap
     *            Key pair
     * @return
     * @throws Exception
     */
    public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        return Base64.encodeBase64String(key.getEncoded());
    }

    /** */
    /**
     * <p>
     * Get public key
     * </p>
     *
     * @param keyMap
     *            Key pair
     * @return
     * @throws Exception
     */
    public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        return Base64.encodeBase64String(key.getEncoded());
    }

    /**
     * java End public key encryption
     */
    public static String encryptedDataOnJava(String data, String PUBLICKEY) {
        try {
            data = Base64.encodeBase64String(encryptByPublicKey(data.getBytes(), PUBLICKEY));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return data;
    }

    /**
     * java End private key decryption
     */
    public static String decryptDataOnJava(String data, String PRIVATEKEY) {
        String temp = "";
        try {
            byte[] rs = Base64.decodeBase64(data);
            temp = new String(RSAUtils.decryptByPrivateKey(rs, PRIVATEKEY),"UTF-8");

        } catch (Exception e) {
            e.printStackTrace();
        }
        return temp;
    }

    public static void main(String[] args) throws  Exception{
        //Generate key pair (public key and private key)
        Map<String, Object> msd =  genKeyPair();
        //Get private key
        String ss = getPrivateKey(msd);
        //Get public key
        String gs =getPublicKey(msd);

        //java side public key encryption
        String gsmm = encryptedDataOnJava("wangtao",gs);
        //java side private key decryption
        String ssmm = decryptDataOnJava("gsmm",ss);
        //

        //
    }


}

1: When we request to go to the login page, we generate the corresponding key pair and return it to the front end. In spring security, we jump to the user-defined login page. We need to set the corresponding login page in the WebSecurityConfigurerAdapter implementation class * * configure (httpsecurity HTTP * *). In the login page, according to the public key passed from the back end, we use JSEncrypt to encrypt it and send it to the back end.

2: When the front-end initiates the login verification request, it will go through the spring security interceptor. The login verification is mainly through the usernamepasswordfilter. When the interceptor is called in turn, the authentication account is called in order in the abstractprovide implementation class, and the password verification method is used for decryption. In comparison, the decryption method is even the tool class shown in the figure above, which is the idea.

Tags: Spring Java

Posted on Sun, 21 Jun 2020 02:55:49 -0400 by D3xt3r