`
sunxboy
  • 浏览: 2871735 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

用javascript与java进行RSA加密与解密

阅读更多

这几天一直做安全登录,网上查了好多资料,不尽如意。

具体实现思路如下:

1。服务端生成公钥与私钥,保存。

2。客户端在请求到登录页面后,随机生成一字符串。

3。后此随机字符串作为密钥加密密码,再用从服务端获取到的公钥加密生成的随机字符串。

4。将此两段密文传入服务端,服务端用私钥解出随机字符串,再用此私钥解出加密的密文。

这其中有一个关键是解决服务端的公钥,传入客户端,客户端用此公钥加密字符串后,后又能在服务端用私钥解出。

此文即为实现此步而作。

加密算法为RSA:

1。服务端的RSA  java实现。

/**
 * 
 */
package com.sunsoft.struts.util;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;

import javax.crypto.Cipher;



/**
 * RSA 工具类。提供加密,解密,生成密钥对等方法。
 * 需要到http://www.bouncycastle.org下载bcprov-jdk14-123.jar。
 * 
 */
public class RSAUtil {
	/**
	 * * 生成密钥对 *
	 * 
	 * @return KeyPair *
	 * @throws EncryptException
	 */
	public static KeyPair generateKeyPair() throws Exception {
		try {
			KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA",
					new org.bouncycastle.jce.provider.BouncyCastleProvider());
			final int KEY_SIZE = 1024;// 没什么好说的了,这个值关系到块加密的大小,可以更改,但是不要太大,否则效率会低
			keyPairGen.initialize(KEY_SIZE, new SecureRandom());
			KeyPair keyPair = keyPairGen.generateKeyPair();
			saveKeyPair(keyPair);
			return keyPair;
		} catch (Exception e) {
			throw new Exception(e.getMessage());
		}
	}
	
	public static KeyPair getKeyPair()throws Exception{
		FileInputStream fis = new FileInputStream("C:/RSAKey.txt");
		 ObjectInputStream oos = new ObjectInputStream(fis);
		 KeyPair kp= (KeyPair) oos.readObject();
		 oos.close();
		 fis.close();
		 return kp;
	}
	
	public static void saveKeyPair(KeyPair kp)throws Exception{
		
		 FileOutputStream fos = new FileOutputStream("C:/RSAKey.txt");
         ObjectOutputStream oos = new ObjectOutputStream(fos);
         //生成密钥
         oos.writeObject(kp);
         oos.close();
         fos.close();
	}

	/**
	 * * 生成公钥 *
	 * 
	 * @param modulus *
	 * @param publicExponent *
	 * @return RSAPublicKey *
	 * @throws Exception
	 */
	public static RSAPublicKey generateRSAPublicKey(byte[] modulus,
			byte[] publicExponent) throws Exception {
		KeyFactory keyFac = null;
		try {
			keyFac = KeyFactory.getInstance("RSA",
					new org.bouncycastle.jce.provider.BouncyCastleProvider());
		} catch (NoSuchAlgorithmException ex) {
			throw new Exception(ex.getMessage());
		}

		RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(
				modulus), new BigInteger(publicExponent));
		try {
			return (RSAPublicKey) keyFac.generatePublic(pubKeySpec);
		} catch (InvalidKeySpecException ex) {
			throw new Exception(ex.getMessage());
		}
	}

	/**
	 * * 生成私钥 *
	 * 
	 * @param modulus *
	 * @param privateExponent *
	 * @return RSAPrivateKey *
	 * @throws Exception
	 */
	public static RSAPrivateKey generateRSAPrivateKey(byte[] modulus,
			byte[] privateExponent) throws Exception {
		KeyFactory keyFac = null;
		try {
			keyFac = KeyFactory.getInstance("RSA",
					new org.bouncycastle.jce.provider.BouncyCastleProvider());
		} catch (NoSuchAlgorithmException ex) {
			throw new Exception(ex.getMessage());
		}

		RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(
				modulus), new BigInteger(privateExponent));
		try {
			return (RSAPrivateKey) keyFac.generatePrivate(priKeySpec);
		} catch (InvalidKeySpecException ex) {
			throw new Exception(ex.getMessage());
		}
	}

	/**
	 * * 加密 *
	 * 
	 * @param key
	 *            加密的密钥 *
	 * @param data
	 *            待加密的明文数据 *
	 * @return 加密后的数据 *
	 * @throws Exception
	 */
	public static byte[] encrypt(PublicKey pk, byte[] data) throws Exception {
		try {
			Cipher cipher = Cipher.getInstance("RSA",
					new org.bouncycastle.jce.provider.BouncyCastleProvider());
			cipher.init(Cipher.ENCRYPT_MODE, pk);
			int blockSize = cipher.getBlockSize();// 获得加密块大小,如:加密前数据为128个byte,而key_size=1024
			// 加密块大小为127
			// byte,加密后为128个byte;因此共有2个加密块,第一个127
			// byte第二个为1个byte
			int outputSize = cipher.getOutputSize(data.length);// 获得加密块加密后块大小
			int leavedSize = data.length % blockSize;
			int blocksSize = leavedSize != 0 ? data.length / blockSize + 1
					: data.length / blockSize;
			byte[] raw = new byte[outputSize * blocksSize];
			int i = 0;
			while (data.length - i * blockSize > 0) {
				if (data.length - i * blockSize > blockSize)
					cipher.doFinal(data, i * blockSize, blockSize, raw, i
							* outputSize);
				else
					cipher.doFinal(data, i * blockSize, data.length - i
							* blockSize, raw, i * outputSize);
				// 这里面doUpdate方法不可用,查看源代码后发现每次doUpdate后并没有什么实际动作除了把byte[]放到
				// ByteArrayOutputStream中,而最后doFinal的时候才将所有的byte[]进行加密,可是到了此时加密块大小很可能已经超出了
				// OutputSize所以只好用dofinal方法。

				i++;
			}
			return raw;
		} catch (Exception e) {
			throw new Exception(e.getMessage());
		}
	}

	/**
	 * * 解密 *
	 * 
	 * @param key
	 *            解密的密钥 *
	 * @param raw
	 *            已经加密的数据 *
	 * @return 解密后的明文 *
	 * @throws Exception
	 */
	public static byte[] decrypt(PrivateKey pk, byte[] raw) throws Exception {
		try {
			Cipher cipher = Cipher.getInstance("RSA",
					new org.bouncycastle.jce.provider.BouncyCastleProvider());
			cipher.init(cipher.DECRYPT_MODE, pk);
			int blockSize = cipher.getBlockSize();
			ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
			int j = 0;

			while (raw.length - j * blockSize > 0) {
				bout.write(cipher.doFinal(raw, j * blockSize, blockSize));
				j++;
			}
			return bout.toByteArray();
		} catch (Exception e) {
			throw new Exception(e.getMessage());
		}
	}

	/**
	 * * *
	 * 
	 * @param args *
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		RSAPublicKey rsap = (RSAPublicKey) RSAUtil.generateKeyPair().getPublic();
		String test = "hello world";
		byte[] en_test = encrypt(getKeyPair().getPublic(),test.getBytes());
		byte[] de_test = decrypt(getKeyPair().getPrivate(),en_test);
		System.out.println(new String(de_test));
	}
}

 2.测试页面:

IndexAction.java

/*
 * Generated by MyEclipse Struts
 * Template path: templates/java/JavaClass.vtl
 */
package com.sunsoft.struts.action;

import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import com.sunsoft.struts.util.RSAUtil;

/** 
 * MyEclipse Struts
 * Creation date: 06-28-2008
 * 
 * XDoclet definition:
 * @struts.action validate="true"
 */
public class IndexAction extends Action {
	/*
	 * Generated Methods
	 */

	/** 
	 * Method execute
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return ActionForward
	 */
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)throws Exception {
		
		RSAPublicKey rsap = (RSAPublicKey) RSAUtil.getKeyPair().getPublic();
		String module = rsap.getModulus().toString(16);
		String empoent = rsap.getPublicExponent().toString(16);
		System.out.println("module");
		System.out.println(module);
		System.out.println("empoent");
		System.out.println(empoent);
		request.setAttribute("m", module);
		request.setAttribute("e", empoent);
		return mapping.findForward("login");
	}
}

 通过此action进入登录页面,并传入公钥的 Modulus 与PublicExponent的hex编码形式。

3。登录页面 login.jsp

<%@ page language="java" pageEncoding="GBK"%>

<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
<%@ taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html:html lang="true">
  <head>
    <html:base />
    
    <title>login</title>

	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->
<script type="text/javascript" src="js/RSA.js"></script>
<script type="text/javascript" src="js/BigInt.js"></script>
<script type="text/javascript" src="js/Barrett.js"></script>
<script type="text/javascript">
function rsalogin()
{
   bodyRSA();
   var result = encryptedString(key, document.getElementById("pwd").value);
   //alert(result);
   loginForm.action="login.do?result="+result;
   loginForm.submit();
}
var key ;
function bodyRSA()
{
	setMaxDigits(130);
  	key = new RSAKeyPair("10001","","8c1cd09a04ed01aafe70dc84c5f32ae23a16fe8fc8898aba6797c5a9c708720de4f08dbf086af429fc51c0636208f56de20a8ab5686affd9bdfb643ae1e90d5617155c4867eef06b0884ba8ecd187907c7069ae3eed4f0155eeca6573411864035ae803ad8fd91a0cc479f27e41b19c13465ab30f3cfbfd14de56f49cbd09481"); 
  
}

</script>
  </head>
  
  <body >
    <html:form action="login" method="post" focus="username">
      <table border="0">
        <tr>
          <td>Login:</td>
          <td><html:text property="username" /></td>
        </tr>
        <tr>
          <td>Password:</td>
          <td><html:password property="password" styleId="pwd"/></td>
        </tr>
        <tr>
          <td colspan="2" align="center"><input type="button" value="SUBMIT" onclick="rsalogin();"/></td>
        </tr>
      </table>
    </html:form>
  </body>
</html:html>

 3.点击登录后,调用LoginAction.java

/*
 * Generated by MyEclipse Struts
 * Template path: templates/java/JavaClass.vtl
 */
package com.sunsoft.struts.action;

import java.math.BigInteger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import com.sunsoft.struts.util.RSAUtil;

/** 
 * MyEclipse Struts
 * Creation date: 06-28-2008
 * 
 * XDoclet definition:
 * @struts.action path="/login" name="loginForm" input="/login.jsp" scope="request" validate="true"
 * @struts.action-forward name="error" path="/error.jsp"
 * @struts.action-forward name="success" path="/success.jsp"
 */
public class LoginAction extends Action {
	/*
	 * Generated Methods
	 */

	/** 
	 * Method execute
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return ActionForward
	 */
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) throws Exception{
		//LoginForm loginForm = (LoginForm) form;
		String result = request.getParameter("result");
		System.out.println("原文加密后为:");
		System.out.println(result);
		byte[] en_result = new BigInteger(result, 16).toByteArray();
		System.out.println("转成byte[]"+new String(en_result));
		byte[] de_result = RSAUtil.decrypt(RSAUtil.getKeyPair().getPrivate(),en_result);
		System.out.println("还原密文:");
		
		System.out.println(new String(de_result));
		StringBuffer sb = new StringBuffer();
		sb.append(new String(de_result));
		System.out.println(sb.reverse().toString());
		return mapping.findForward("success");
	}
}

 因为发现解出的明文是倒序的,后面就用StringBuffer的reverse()来转换了一下。

4。login.jsp所调用的js

 

  • js.rar (6.4 KB)
  • 描述: login.jsp所调用的javascript,有: RSA.js BigInt.js Barrett.js
  • 下载次数: 2848
分享到:
评论
8 楼 jjiangxixihahaitcyc 2011-06-03  
JS加密过,不能正常解密,是怎么回事啊?
7 楼 lein07 2011-02-26  
我觉得,每个Session新建一对密钥,这样Javascript就不需要随机码了,并且更安全。
6 楼 hxskwk 2011-01-14  
4楼所说情况确实存在,问题出现在那呢?
这里:byte[] en_result = new BigInteger(result, 16).toByteArray(); 
有的时候你会发现数组长度129,第一个元素为0,这肯定是不正确的!
解决办法:自己写一个16进制转字节数组的方法,很简单,在网上一搜一大堆!
至于加密中文我到没试过......
5 楼 chris_strive 2010-05-05  
C:/RSAKey.txt 是什么文件啊?
4 楼 basakasky 2010-04-05  
楼主,我只在Action中调用generateKeyPair方法产生一个KeyPair对象存入session中,
登陆时从session中取出该KeyPair对象,这样做的话不知是否可行?

我的试验结果是有时候输入:
"//","%","?"时会报异常Bad arguments,有时候输入这几个字符却不会报异常
不知你是否碰到过?

持续关 注中!
3 楼 hdown 2009-07-21  
已经在用了,谢谢啦

不过加密个别中英文字符串的时候会抛异常的
2 楼 yanghong21240 2008-11-05  
1 楼 wv1124 2008-09-04  
好强啊,谢谢了

相关推荐

    javascript与java进行RSA加密与解密

    JavaScript 和 Java 之间的 RSA 加密与解密是跨平台数据安全传输的重要技术。...通过以上步骤和库的使用,JavaScript 和 Java 之间可以实现安全的 RSA 加密解密交互,确保在数据传输过程中的隐私和安全。

    RSA 使用java 和javascript进行加解密

    在Web开发中,由于浏览器端不支持Java,而JavaScript则可以在客户端运行,因此,使用RSA在Java后端生成密钥对,并将公钥传递给JavaScript前端进行加密,再将加密后的数据发送回服务器,由Java后端使用私钥解密,是...

    java_RSA2048加密解密.zip

    后端,Java作为一种常用的企业级开发语言,拥有丰富的安全库,例如Bouncy Castle,用于处理RSA加密解密。Java代码可能使用了`java.security`包下的`KeyPairGenerator`、`PublicKey`、`PrivateKey`等类来生成和管理...

    RSA加密解密之javascript与java配套源码.zip

    在提供的压缩包中,有两个Java文件(RSACrypt.java和RSACryptTest.java)和一个JavaScript文件(jsencrypt.min.js),这表明代码实现了RSA加密解密的Java版本和JavaScript版本,可以在客户端和服务端之间进行安全的...

    Js Java Rsa 加密解密

    JavaScript、Java和RSA加密解密是信息安全领域中的关键技术,它们被广泛应用于数据传输、用户认证、Web应用安全等场景。RSA是一种非对称加密算法,以其发明者Ron Rivest、Adi Shamir和Leonard Adleman的名字命名,它...

    java js RSA加密支持超长加密

    在Java和JavaScript中实现RSA加密,对于处理较长的数据至关重要,因为这两种语言的标准库默认的RSA加密只能处理相对较小的块。这里我们将深入探讨如何在Java和JavaScript中实现超长数据的RSA加密,并解决跨平台兼容...

    Java RSA加密前后端实现

    总之,这个项目展示了如何在Java后端和JavaScript前端之间使用RSA加密技术进行安全的数据交换,保护敏感信息,尤其适用于处理用户登录等涉及用户隐私的操作。通过深入理解RSA算法和相关的编程库,开发者可以构建更...

    RSA通过javascript加密java解密

    - 数据解密:Java端使用私钥对加密数据进行解密,这是通过执行模逆运算来实现的,与加密过程相对应。 - 解密结果:解密完成后,原始数据会恢复出来,服务器可以安全地处理这些信息。 在这个过程中,需要注意的是...

    可以互操作的Java和Javascript RSA加密解密程序

    在“可以互操作的Java和Javascript RSA加密解密程序”中,我们看到这种技术被巧妙地应用于Java和JavaScript两个不同的编程环境中,实现跨平台的加密解密互操作。 首先,我们需要理解RSA算法的基本原理。RSA基于大数...

    前端使用jsencrypt加密后端使用java RSA解密功能实现源码

    本文将详细介绍一个实际案例:如何在前端使用JavaScript库`jsencrypt`进行RSA加密,并在后端使用Java进行解密。这个功能实现的核心知识点包括RSA算法、`jsencrypt`库的使用以及前后端的交互。 首先,RSA是一种非...

    易语言调用JSEncrypt实现RSA加密解密

    在易语言中调用JSEncrypt库来实现RSA加密解密,可以为易语言的应用增加一层安全防护。 JSEncrypt是一个JavaScript库,由Benjamin van Ryseghem开发,主要用于RSA加密操作,特别适用于前端与后端之间的安全通信。它...

    java RSA加解密 zip加解密, js MD5 SHA1 RSA加密

    本文将深入探讨Java中的RSA加解密、ZIP加密压缩以及JavaScript中的MD5、SHA1和RSA加密算法。这些技术在网络安全、数据传输、用户认证等多个领域中广泛应用。 首先,我们来看RSA加密算法。RSA是一种非对称加密算法,...

    RSA加密解密的使用,含jsencrypt.js文件(uni-app也可用)

    RSA加密解密是一种广泛应用于网络安全中的非对称加密算法,由Ron Rivest、Adi Shamir和Leonard Adleman三位科学家在1977年提出,因此得名RSA。这种算法基于大数因子分解的困难性,为数据提供了一种安全的传输方式。 ...

    rsa加密(js加密java解密)

    以下是使用RSA加密解密的基本步骤: 1. **密钥生成**:在服务器端,使用`KeyPairGenerator`生成一对RSA密钥,包括公钥和私钥。公钥通常会被发送给前端,而私钥则保留在服务器上。 2. **前端加密**:前端接收到公钥...

    兼容JS和C#的RSA加密解密实例

    在给定的"兼容JS和C#的RSA加密解密实例"中,我们关注的是如何在JavaScript(前端)和C#(后端)之间使用RSA进行安全的数据交换。这涉及到两个主要的方面:前端的加密和后端的解密。 前端部分,JavaScript通常用于...

    C#RSA加密解密工具

    总的来说,C# RSA加密解密工具是一个实用的开发辅助工具,帮助开发者在C#环境中方便地实现RSA加密和解密操作,同时考虑到了与其他语言(如JavaScript和Java)的兼容性,提高了数据安全传输的灵活性和便利性。

    关于使用JS前台加密、JAVA后台解密的RSA实现,RSA加密和签名

    总的来说,这篇博文提供了JS和JAVA结合使用RSA加密解密和签名的实践方法,对于理解和实现前后端数据安全传输具有指导意义。在实际项目中,应根据具体需求选择合适的加密强度和实现方式,同时结合其他安全措施,如...

Global site tag (gtag.js) - Google Analytics