RSA前端JS加密,后端JAVA解密实现

时间:2022-07-26 21:08:38

    用RSA非对称加密方式实现。后台生成rsa密钥对,然后在页面设置rsa公钥,提交时用公钥加密密码,生成的密文传到后台,后台再用私钥解密,获取密码明文。
     这样客户端只需要知道rsa加密方式和公钥,前台不知道私钥是无法解密的,此解决方案还是相对比较安全的。
     需要到http://www.bouncycastle.org下载bcprov-jdk16-140.jar文件。
    缺陷: 由于进行的都是大数计算,使得RSA最快的情况也比DES慢上100倍,无论 是软件还是硬件实现。所以 一般来说只用于少               量数据 加密。
    下面我们就来一个实际的例子:

    1、前端加密需要引入Barrett.js、BigInt.js和RSA.js。
  1. <script src="/rsa/RSA.js" type="text/javascript"></script>
  2.         <script src="/rsa/BigInt.js" type="text/javascript"></script>
  3.         <script src="/rsa/Barrett.js" type="text/javascript"></script>
复制代码
2、前端加密代码:
  1. encryptedString : (function(paramStr, rsaKey){
  2.     setMaxDigits(130);
  3.     //第一个参数为加密指数、第二个参数为解密参数、第三个参数为加密系数
  4.     key = new RSAKeyPair("10001", "", rsaKey); 
  5.     //返回加密后的字符串
  6.     return encryptedString(key, encodeURIComponent(paramStr));
  7.         })
复制代码
其中的加密系数可以自定义,这里为:8246a46f44fc4d961e139fd70f4787d272d374532f4d2d9b7cbaad6a15a8c1301319aa6b3f30413b859351c71938aec516fa7147b69168b195e81df46b6bed7950cf3a1c719d42175f73d7c97a85d7d20a9e83688b92f05b3059bb2ff75cd7190a042cd2db97ebc2ab4da366f2a7085556ed613b5a39c9fdd2bb2595d1dc23b5
    3、后台RSA加密解密方法如下:
  1. import java.io.ByteArrayOutputStream;
  2. import java.io.FileInputStream;
  3. import java.io.FileOutputStream;
  4. import java.io.ObjectInputStream;
  5. import java.io.ObjectOutputStream;
  6. import java.math.BigInteger;
  7. import java.security.KeyFactory;
  8. import java.security.KeyPair;
  9. import java.security.KeyPairGenerator;
  10. import java.security.NoSuchAlgorithmException;
  11. import java.security.PrivateKey;
  12. import java.security.PublicKey;
  13. import java.security.SecureRandom;
  14. import java.security.interfaces.RSAPrivateKey;
  15. import java.security.interfaces.RSAPublicKey;
  16. import java.security.spec.InvalidKeySpecException;
  17. import java.security.spec.RSAPrivateKeySpec;
  18. import java.security.spec.RSAPublicKeySpec;

  19. import javax.crypto.Cipher;

  20. import org.apache.commons.lang.StringUtils;

  21. import com.jd.uwp.common.Constants;

  22. /**
  23. * RSA 工具类。提供加密,解密,生成密钥对等方法。
  24. * 需要bcprov-jdk16-140.jar包。

  25. */
  26. public class RSAUtil {
  27.         
  28.         private static String RSAKeyStore = "RSAKey.txt";

  29.         /**
  30.          * * 生成密钥对 *
  31.          * @return KeyPair *
  32.          * @throws EncryptException
  33.          */
  34.         public static KeyPair generateKeyPair(String basePath) throws Exception {
  35.     try {
  36.         KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA",
  37.         new org.bouncycastle.jce.provider.BouncyCastleProvider());
  38.         //大小
  39.         final int KEY_SIZE = 1024;
  40.         keyPairGen.initialize(KEY_SIZE, new SecureRandom());
  41.         KeyPair keyPair = keyPairGen.generateKeyPair();
  42.         saveKeyPair(keyPair, basePath);
  43.         return keyPair;
  44.     } catch (Exception e) {
  45.         throw new Exception(e.getMessage());
  46.     }
  47.         }

  48.         /**
  49.          * 获取密钥对
  50.          * @return
  51.          * @throws Exception
  52.          */
  53.         public static KeyPair getKeyPair(String basePath) throws Exception {
  54.     FileInputStream fis = new FileInputStream(StringUtils.isNotBlank(basePath) ? (basePath + RSAKeyStore) :     RSAKeyStore);
  55.     ObjectInputStream oos = new ObjectInputStream(fis);
  56.     KeyPair kp = (KeyPair) oos.readObject();
  57.     oos.close();
  58.     fis.close();
  59.     return kp;
  60.         }

  61.         /**
  62.          * 保存密钥
  63.          * @param kp
  64.          * @throws Exception
  65.          */
  66.         public static void saveKeyPair(KeyPair kp, String basePath) throws Exception {
  67.     FileOutputStream fos = new FileOutputStream(StringUtils.isNotBlank(basePath) ? (basePath + RSAKeyStore) :     RSAKeyStore);
  68.     ObjectOutputStream oos = new ObjectOutputStream(fos);
  69.     // 生成密钥
  70.     oos.writeObject(kp);
  71.     oos.close();
  72.     fos.close();
  73.         }

  74.         /**
  75.          * * 生成公钥 *
  76.          * @param modulus *
  77.          * @param publicExponent *
  78.          * @return RSAPublicKey *
  79.          * @throws Exception
  80.          */
  81.         public static RSAPublicKey generateRSAPublicKey(byte[] modulus,
  82.     byte[] publicExponent) throws Exception {
  83.     KeyFactory keyFac = null;
  84.     try {
  85.         keyFac = KeyFactory.getInstance("RSA",
  86.         new org.bouncycastle.jce.provider.BouncyCastleProvider());
  87.     } catch (NoSuchAlgorithmException ex) {
  88.         throw new Exception(ex.getMessage());
  89.     }
  90.     RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(
  91.         modulus), new BigInteger(publicExponent));
  92.     try {
  93.         return (RSAPublicKey) keyFac.generatePublic(pubKeySpec);
  94.     } catch (InvalidKeySpecException ex) {
  95.         throw new Exception(ex.getMessage());
  96.     }
  97.         }

  98.         /**
  99.          * * 生成私钥 *
  100.          * @param modulus *
  101.          * @param privateExponent *
  102.          * @return RSAPrivateKey *
  103.          * @throws Exception
  104.          */
  105.         public static RSAPrivateKey generateRSAPrivateKey(byte[] modulus,
  106.     byte[] privateExponent) throws Exception {
  107.     KeyFactory keyFac = null;
  108.     try {
  109.         keyFac = KeyFactory.getInstance("RSA",
  110.         new org.bouncycastle.jce.provider.BouncyCastleProvider());
  111.     } catch (NoSuchAlgorithmException ex) {
  112.         throw new Exception(ex.getMessage());
  113.     }
  114.     RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(
  115.         modulus), new BigInteger(privateExponent));
  116.     try {
  117.         return (RSAPrivateKey) keyFac.generatePrivate(priKeySpec);
  118.     } catch (InvalidKeySpecException ex) {
  119.         throw new Exception(ex.getMessage());
  120.                 }
  121.         }

  122.         /**
  123.          * * 加密 *
  124.          * @param key
  125.          *            加密的密钥 *
  126.          * @param data
  127.          *            待加密的明文数据 *
  128.          * @return 加密后的数据 *
  129.          * @throws Exception
  130.          */
  131.         public static byte[] encrypt(PublicKey pk, byte[] data) throws Exception {
  132.     try {
  133.         Cipher cipher = Cipher.getInstance("RSA",
  134.         new org.bouncycastle.jce.provider.BouncyCastleProvider());
  135.         cipher.init(Cipher.ENCRYPT_MODE, pk);
  136.         // 获得加密块大小,如:加密前数据为128个byte,而key_size=1024
  137.         int blockSize = cipher.getBlockSize();
  138.         // 加密块大小为127
  139.         // byte,加密后为128个byte;因此共有2个加密块,第一个127
  140.         // byte第二个为1个byte
  141.         int outputSize = cipher.getOutputSize(data.length);// 获得加密块加密后块大小
  142.         int leavedSize = data.length % blockSize;
  143.         int blocksSize = leavedSize != 0 ? data.length / blockSize + 1 : data.length / blockSize;
  144.         byte[] raw = new byte[outputSize * blocksSize];
  145.         int i = 0;
  146.         while (data.length - i * blockSize > 0) {
  147.                 if (data.length - i * blockSize > blockSize) {
  148.                     cipher.doFinal(data, i * blockSize, blockSize, raw, i * outputSize);
  149.                 } else {
  150.                     cipher.doFinal(data, i * blockSize, data.length - i * blockSize, raw, i * outputSize);
  151.                 }
  152.                 i++;
  153.         }
  154.         return raw;
  155.     } catch (Exception e) {
  156.         throw new Exception(e.getMessage());
  157.     }
  158.         }

  159.         /**
  160.          * * 解密 *
  161.          * 
  162.          * @param key
  163.          *            解密的密钥 *
  164.          * @param raw
  165.          *            已经加密的数据 *
  166.          * @return 解密后的明文 *
  167.          * @throws Exception
  168.          */
  169.         @SuppressWarnings("static-access")
  170.         public static byte[] decrypt(PrivateKey pk, byte[] raw) throws Exception {
  171.     try {
  172.         Cipher cipher = Cipher.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
  173.         cipher.init(cipher.DECRYPT_MODE, pk);
  174.         int blockSize = cipher.getBlockSize();
  175.         ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
  176.         int j = 0;
  177.         while (raw.length - j * blockSize > 0) {
  178.             bout.write(cipher.doFinal(raw, j * blockSize, blockSize));
  179.             j++;
  180.         }
  181.         return bout.toByteArray();
  182.     } catch (Exception e) {
  183.         throw new Exception(e.getMessage());
  184.     }
  185.         }
  186.         
  187. /**
  188. * 解密方法
  189. * paramStr    ->密文
  190. * basePath    ->RSAKey.txt所在的文件夹路径
  191. **/
  192.         public static String decryptStr(String paramStr, String basePath) throws Exception{
  193.     byte[] en_result = new BigInteger(paramStr, 16).toByteArray();
  194.     byte[] de_result = decrypt(getKeyPair(basePath).getPrivate(), en_result);
  195.     StringBuffer sb = new StringBuffer();
  196.     sb.append(new String(de_result));
  197.     //返回解密的字符串
  198.     return sb.reverse().toString();
  199. }
  200. }
复制代码
4、前端提交到后端解密调用:
  1. //前端 表单提交
  2. $.ajax({
  3.     url : contextPath + "test.action",
  4.     //加密传输
  5.     data : {pwd:encryptedString ($("#pwd").val(), "adasdasdasdasdadsasdasdasdasd")},
  6.     type  : "post",
  7.     datatype : "json",
  8.     success : function(retData){
  9.     }
  10. });

  11. //后端解密代码
  12. RSAUtil.decryptStr(paramMap.getString("pwd"),  request.getSession().getServletContext().getRealPath("/"));
复制代码