RSA加密

Posted lcxsummer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RSA加密相关的知识,希望对你有一定的参考价值。

RSA加密的原理:

https://www.cnblogs.com/coolYuan/p/9168284.html

其实知不知道RSA加密的原理都不太影响开发,无非是前端页面输入用户名密码后,在发送请求到后台去的时候,把用户名密码的明文字符串加密成密文传递到后台,这样别人截获请求参数的时候,截获到的只能是看不懂的密文,后台收到密文后,进行解密,解密后用明文做明文原本该做的逻辑判断和处理。

简单说就是js加密,Java解密。

js加密需要一个js的RSA加密库 jsencrypt.min.js

java解密需要一个RSA加密解密的jar包 bcprov-jdk15-145.jar

js代码:

        <!-- 用户名密码加密 -->
        <script type="text/javascript" src="/login/js/jsencrypt.min.js"></script>
        <!-- remote -->
        <script type="text/javascript" src="/resource/remoting/resource/remote.js"></script>
        <script type="text/javascript" src="/login/js/signInAction.js"></script>
        <h:outputScript library="seam" name="seam.rescript.js" />
        <script>
        var publicKey = "";
        var encrypt = new JSEncrypt();
        function getPublicKey() {
            Seam.Component.getInstance("signInAction").getKey(function(data){
                console.log(data);
                publicKey = data;
                encrypt.setPublicKey(publicKey);
                
            }, excHandler);
        }
        function encryptionUserName() {
            var username = $(.loguserName).val();
            username = encrypt.encrypt(username);
            Seam.Component.getInstance("signInAction").setUserName(username, function(){}, excHandler);
        }
        function encryptionUserPwd() {
            var password = $(.logpassword).val();
            password = encrypt.encrypt(password);
            Seam.Component.getInstance("signInAction").setUserPwd(password, function(){}, excHandler);
        }
        j(function(){
            getPublicKey();
        });
        </script>

 

 getPublicKey 获取公钥,encrypt.setPublicKey 这个是设置公钥, encrypt.encrypt 这个是加密方法, Seam.Component.getInstance 这个是平台框架的类似Ajax的方法,用于js请求后台。

Java 加密解密工具类代码:

package com.seam.mango.utils;

import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;

/**
 * 用到的jar包:bcprov-jdk15-145.jar*/
public class RSAUtils {private static final KeyPair keyPair = initKey();
    
    /**
     * 计算公钥
     */
    private static KeyPair initKey() {
        try {
            Provider provider =new org.bouncycastle.jce.provider.BouncyCastleProvider();
            Security.addProvider(provider);
            SecureRandom random = new SecureRandom();
            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", provider);
            generator.initialize(1024, random);
            return generator.generateKeyPair();
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 加密
     */
    public static String encrypt( String str, String publicKey ) throws Exception{
        //base64编码的公钥
        byte[] decoded = Base64.decodeBase64(publicKey.getBytes());
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        //RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        byte[] outStr = Base64.encodeBase64(cipher.doFinal(str.getBytes("UTF-8")));
        return new String(outStr);
    }
    
    /**
     * 获取公钥
     */
    public static String generateBase64PublicKey() {
        PublicKey publicKey = (RSAPublicKey)keyPair.getPublic();
        return new String(Base64.encodeBase64(publicKey.getEncoded()));
    }
    
    /**
     * 解密
     */
    public static String decryptBase64(String string) {
        return new String(decrypt(Base64.decodeBase64(string.getBytes())));
    }
    private static byte[] decrypt(byte[] byteArray) {
        try {
            Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
            Security.addProvider(provider);
            Cipher cipher = Cipher.getInstance(
                    "RSA/ECB/PKCS1Padding" /*"RSA/None/PKCS1Padding"*/ /*"RSA/None/NoPadding"*/ /*"RSA/ECB/NoPadding"*/ , provider);
            PrivateKey privateKey = keyPair.getPrivate();
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] plainText = cipher.doFinal(byteArray);
            return plainText;
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

}

 

java原先的登录方法只需要接收加密的字符串调用解密的方法就可以了,原先的逻辑不用动:

    /**
     * 前端获取公钥
     */
    @WebRemote
    public String getKey(){
        return RSAUtils.generateBase64PublicKey();
    }
    /**
     * 接收前端用户名密文
     */
    @WebRemote
    public void setUserName(String username){
        credentials.setUsername(username);
        System.out.println("==================== username: " + username + " =====================");
    }
    /**
     * 接收前端密码密文
     */
    @WebRemote
    public void setUserPwd(String pwd){
        credentials.setPassword(pwd);
        System.out.println("==================== pwd: " + pwd + " =====================");
    }

 

登录方法里加入解密过程:

credentials.setUsername(RSAUtils.decryptBase64(credentials.getUsername()));
credentials.setPassword(RSAUtils.decryptBase64(credentials.getPassword()));

 

上面说的这些其实都不是难点,难的是环境的配置,因为没有人告诉你该怎么配环境,只能看代码跑起来的时候报什么错,根据报错内容去搜索解决方案,大致遇到的就是下面两个异常:

1、unknown block type

这个异常百度后,大致觉得是因为jdk在调用加密解密有关的jar包时,需要安全认证

我不明白,Security.addProvider(provider); 这句话不起作用的吗?

手动加认证的方式:

修改 jdk1.8.0_60_x64jrelibsecurityjava.security

技术图片

 

 添加一个provider

security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider

技术图片

 

 将jar包 bcprov-jdk15-145.jar 放入 jdk1.8.0_60_x64jrelibext 目录

 

2、Cannot verify jar

我对这个异常的大致理解是 jboss 运行时,对加密解密也需要安全认证

需要修改jboss的配置文件,步骤如下:

在 jboss-eap-6.2modulesorg 路径下添加 bouncycastle 文件夹,里面再添加 main 文件夹

把jar包 bcprov-jdk15-145.jar 放入 jboss-eap-6.2modulesorgouncycastlemain 目录

并再 jboss-eap-6.2modulesorgouncycastlemain 目录下添加 module.xml 文件,这个文件可以仿照 modules 文件夹里的其他 module.xml 文件,内容如下

<?xml version="1.0" encoding="UTF-8"?>

<module xmlns="urn:jboss:module:1.1" name="org.bouncycastle">
    <resources>
        <resource-root path="bcprov-jdk15-145.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api" slot="main" export="true"/>
    </dependencies>
</module>

 

技术图片

 

最后一步,找到 jboss-eap-6.2standaloneconfigurationstandalone.xml 配置文件, 并找到这一行:
<subsystem xmlns="urn:jboss:domain:ee:1.1">

添加下面的配置:

           <global-modules>
               <module name="org.bouncycastle" slot="main"/>
           </global-modules>

技术图片

 

到此,这个看似小菜却又并不小菜的功能搞定!

 

以上是关于RSA加密的主要内容,如果未能解决你的问题,请参考以下文章

PHP RSA和RSA2加密算法代码

非对称加密及RSA加密算法

rsa解密错误

php/js/linux: js加密(rsa公钥加密) php解密(rsa私钥解密)

php RSA加密传输代码示例(轉)

求RSA加密解密算法,c++源代码