基於RSA的前后端登陸密碼加密JAVA實現(轉)


RSA加密算法簡介

  SA加密算法是一種非對稱加密算法。在公開密鑰加密和電子商業中RSA被廣泛使用。對極大整數做因數分解的難度決定了RSA算法的可靠性。換言之,對一極大整數做因數分解愈困難,RSA算法愈可靠。假如有人找到一種快速因數分解的算法的話,那么用RSA加密的信息的可靠性就肯定會極度下降。但找到這樣的算法的可能性是非常小的。今天只有短的RSA鑰匙才可能被強力方式解破。到目前為止,世界上還沒有任何可靠的攻擊RSA算法的方式。只要其鑰匙的長度足夠長,用RSA加密的信息實際上是不能被解破的。

RSA加密的java實現

  實現的思路,由RSA隨機生成一對公鑰和私鑰,公鑰方到客戶端,私鑰放到服務端,發送數據的時候由公鑰對傳輸數據進行加密,然后發送給服務端,服務端用私鑰才能對數據進行解密.下面是代碼實現的例子

import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.apache.commons.codec.binary.Base64;

public class MyRSAencryptionMethod {
    
    private static Map<Integer, String> keyMap = new HashMap<>(); // 用於封裝隨機產生的公鑰與私鑰
    
    public static void main(String[] args) {
        //生成公鑰和私鑰
        genKeyPair();
        //加密字符串
        String message = "df723820";
        System.out.println("隨機生成的公鑰為:" + keyMap.get(0));
        System.out.println("隨機生成的私鑰為:" + keyMap.get(1));
        String messageEn = encrypt(message, keyMap.get(0));
        System.out.println("加密后的字符串為:" + messageEn);
        String messageDe = decrypt(messageEn, keyMap.get(1));
        System.out.println("還原后的字符串為:" + messageDe);
    }
    
    //隨機生成密鑰對
    public static void genKeyPair() {
        // KeyPairGenerator類用於生成公鑰和私鑰對,基於RSA算法生成對象
        KeyPairGenerator keyPairGen = null;
        
        try {
            keyPairGen = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        
        // 初始化密鑰對生成器,密鑰大小為96-1024位
        assert keyPairGen != null;
        keyPairGen.initialize(1024, new SecureRandom());
        // 生成一個密鑰對,保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私鑰
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公鑰
        String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
        // 得到私鑰字符串
        String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
        // 將公鑰和私鑰保存到Map
        keyMap.put(0, publicKeyString);  //0表示公鑰
        keyMap.put(1, privateKeyString);  //1表示私鑰
    }
    
    /** RSA公鑰加密
     * @param str  加密字符串
     * @param publicKey  公鑰
     * @return  密文
     */
    public static String encrypt(String str, String publicKey) {
        //base64編碼的公鑰
        byte[] decoded = Base64.decodeBase64(publicKey);
        RSAPublicKey pubKey = null;
        String outStr = null;
        
        try {
            pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8)));
        } catch (InvalidKeySpecException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException | NoSuchPaddingException | NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        //RSA加密
        return outStr;
    }
    
    /**  RSA私鑰解密
     * @param str   加密字符串
     * @param privateKey  私鑰
     * @return  銘文
     */
    public static String decrypt(String str, String privateKey) {
        //64位解碼加密后的字符串
        byte[] inputByte = Base64.decodeBase64(str.getBytes(StandardCharsets.UTF_8));
        //base64編碼的私鑰
        byte[] decoded = Base64.decodeBase64(privateKey);
        RSAPrivateKey priKey = null;
        //RSA解密
        Cipher cipher = null;
        String outStr = null;
        
        try {
            priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            outStr = new String(cipher.doFinal(inputByte));
        } catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException e) {
            e.printStackTrace();
        }
        return outStr;
    }
}

運行結果:

隨機生成的公鑰為:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCi+2HgEYFX+8XgpNGK49hwufR3fWkD6vs8gll0qYsnF2RmjiL94w+UOP8IGjapzliZ1w8CFvJ5aO/U5ALG7AzlboZC8xl3n8nmCsVfGNtXQlo2PJVCNziP+6hFar5Jyo7t98Eg9MLQ/VY+qIKmUfd/AXnA12Teik+zGmQeeeGagwIDAQAB
隨機生成的私鑰為:MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKL7YeARgVf7xeCk0Yrj2HC59Hd9aQPq+zyCWXSpiycXZGaOIv3jD5Q4/wgaNqnOWJnXDwIW8nlo79TkAsbsDOVuhkLzGXefyeYKxV8Y21dCWjY8lUI3OI/7qEVqvknKju33wSD0wtD9Vj6ogqZR938BecDXZN6KT7MaZB554ZqDAgMBAAECgYBdY7A8xasY8FL9m1Pawx410cgsY/c14ILftE1wFOqAlt3YCiAw3NgDdflk+ihSesO4O0wFRYLhYOj0U0boF0B3lOLwefLndglMG1f0dM8lehHiaaDnl8kk5rdRjk3Xc2MCpglM7/Z5Tir9zuuaqS0Ps+cxop8Ebe92D1L4JPybOQJBAPbnGQleStYyrmAPcj6J1hhYCWm3V4H8csepAiMNAfsYwLN21Z8j7muiYTtHyTRTuXVn7KaJ1OKCT3qu5YkpcVUCQQCo/LReIR7xRjdsgvnf/G0Q5h6lyJ5w7FKmS/rWiKxRtGcG826MqJc1lP9iBtiHh9RY39s6LwXwxcZJySw01jx3AkEAs4fa9qrvs8zqasMQiVTkrpLlVU+Re907AN9txFrjA9g91sEkGDGiXfWWyeoq7berdSl6NKaoe4PRkx21ngTaeQJBAJdD3ZCExVXkLKiNdW7yXg7KbpSnyGv8nt8NFDQFk3pvqemm7kYqg3ALN69fwWNQStxjRbIHdaHY524VDeUeAHECQAzE19Ktuiq9xdBngwuojWnoYgKo59mJbqhJiykIdcrYsClcyyF0DMK36thg+KvCRzMLDYBjiyXsbVUXXZj0BRc=
加密后的字符串為:TtFXKWl6Kb3O8TcA0UmosQQcBdIFRdctViqh7OVtY/vX7j4ry2O0Ess+AxEYism4qHEnjPNsqqWTjWGpywDuR2VW+xpni7qLrDR4wmJea9Mp4952R1aLdzeHJy940jCBlXs9zzQHX2ymcmziN2//B2tr3VmHdaBjsX827IezMy8=
還原后的字符串為:df723820

再次運行一次結果:

隨機生成的公鑰為:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpah3f/oGknklFOCExGJXOXkmj5AwW9Hs6ABDR7DoGXPH08MmYYPZL7eD+baTavOb5/t3JJFswWqq/Uf2j9lCrZYaxDkwOmW/PuSkPxaKaxAnRlbdg6EFlh3j+gn1kxB+74cRQBplb1nqSVgCYSuqaSx8KlMAxv6X4XBKNcmlZHQIDAQAB
隨機生成的私鑰為:MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKlqHd/+gaSeSUU4ITEYlc5eSaPkDBb0ezoAENHsOgZc8fTwyZhg9kvt4P5tpNq85vn+3ckkWzBaqr9R/aP2UKtlhrEOTA6Zb8+5KQ/FoprECdGVt2DoQWWHeP6CfWTEH7vhxFAGmVvWepJWAJhK6ppLHwqUwDG/pfhcEo1yaVkdAgMBAAECgYBHczHWXohe3UMZpmqZQj0sJCf6rxtKMyIlfBGb930hYeHJ5COh2IMH0vOpWqTEfBcOKKdxRZwP8K1Cs1m95QxwDTpKGQ13pwvmLT0iv8Zo+OliRUpriPt+UE+zdO/wIJ3cpJr47nxSsYn4L5RqoJsWqpdJpj/MeB90QdyNM3muAQJBANjoIZ9bUlFJERzYVp0f0ZwBt16u30Ro4Fi6QniWp8Do6/xN0Fab0nuQI/GqRI8ZHdYlTpCgMMNtixz8kRTITbECQQDH8r0xhOuDUh29G+SuUQ+NqzszIwZjPlWBAmxE2ZOWiNx4P+nHWxu2rUlUcCp9c3c3t60SVoNR6Z9lm6msxgEtAkAitkNrNTofOAo9C4IQ8x6gUMX/qQyh7ga5LFWm5rVB8gSSBAHrWlR84bxe2FjQbbyQoLfJ/VjQbZ9trB2rrcKBAkBSgMS0RCZxv1ZqC7JmgygpyrfYt+EQ3k2lt/w4xJZzjPF75NNv4RYkYIhbgRTnQte0c+PEJ1J0YDPXV03B7snZAkEAsoeJzIlIfDLcbG9uVOdxgeyuyww3g72YA8/aOWBiTGZ625Ue5dzvbCI91bpXeBI1q2/aG1XeKasBVhU9+3J+fA==
加密后的字符串為:Am11mhbFpvhHzmq+jcyud7qP2suyDE6iAWpSBnWnE6kdQwvWFy6/ujbMqq6UdOpSf+9I4T8DGGTsFbCjc2Cbv1TDfe+S+IoWRBS4qz9EOc0+116+0yzrPpoIi5bxHcxLgSGfY21kXQHMwSK2TG4jQwPaT5/7CXBB++s2TRt1LSE=
還原后的字符串為:df723820

可以看出公鑰每次都是一樣。

 

RSA加密的前端用法

前端用crypto-js進行加密,
npm i jsencrypt,
然后頁面頭引入import JSEncrypt from 'jsencrypt';
const encrypt = new JSEncrypt();
encrypt.setPublicKey('你的公鑰');
password = encrypt.encrypt(‘你的密碼’);// 加密后的字符串

后續

  在實際應用中RSA加密也還是遠遠不夠,一般還會加入MD5加密的方式,以及加密驗證,token等等方式作為請求連接的校驗,比如后端加密一個MD5字符串,給前端之后,前端用特定組合加上傳輸數據返回一個RSA加密的字符串,后端接收后解密,然后和自身的字符串進行對比,以確認數據來源的准確性.



出處鏈接:https://www.jianshu.com/p/d1e303b976aa
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM