`
hb_keepmoving
  • 浏览: 226564 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

web 前端 javascript RSA加密提交数据,server端用java解密

阅读更多

前几天user有个要求,就是系统中所有的密码输入框的内容(password) 必须加密提交。即使用工具能抓取到request,但是抓取到的password 都是密文。

 

为此:找了很多解决方案,最终采用的如下

web 前端 javascript RSA加密提交数据,server端用java解密

采用的第三方组件及jar

1.jquery-1.6.js

2.jquery.jcryption-1.1.js

jar files:

3.bcprov-ext-jdk15on-148.jar

4.bcprov-jdk15on-148.jar

 

步骤:

第一:当系统在加载页面完成后,如果发现页面中包含密码框,则向server发起请求来获取key--用于js加密。此key要存于session中,以便server解密。

第二:当密码框在输入密码失焦时,调用js加密。在提交的时候,check password是否加密。阻止明文提交。

第三:server在收到请求后,对密文进行解密。

 

js code:

var keys;

$(function(){
	var hasPass = $('input:password');
	var token = $('#csrfToken').val();
	
	getKeys();
	
	$(hasPass).each(function(index){
		var currentItem = $(this);
		$(currentItem).focus(function(){
			$(currentItem).val("");
		});
		$(currentItem).blur(function(){
			var cVal = $(currentItem).val();
			if($.trim(cVal) != "" && "undefined" != keys && null != keys){
				$.jCryption.encrypt($(currentItem).val(), keys, function(encryptedPasswd) {
					$(currentItem).val(encryptedPasswd);
				});
			}
		});
	});
});

function getKeys() {
	$.jCryption.getKeys(URL,function(receivedKeys) {
		keys = receivedKeys;
	});
	
}
function submitForm(form){
	var flag = true;
	//check password is encrypt or not
	var Cpass;
	$(form).find("input:password").each(function(index){
		var currPass = $(this);
		var value = $.trim($(currPass).val());
		var reg = /^[A-Za-z0-9]{128}$/;
		if(value == ""){
			flag = false;
			Cpass = $(currPass);
		}else if(!reg.test(value)){
			//the reason maybe previous request gain public key failed
			//so please check - public key via ajax request.-(getKey(val))
			//alert("key-->"+keys);
			alert("encrypt failed.");
			flag = false;
		}
	});
	if(flag == true){
		form.submit();
	}else{
		if(undefined != Cpass && null != Cpass && $(Cpass).val() == ""){
			alert("Please key in your password.");
			$(Cpass).focus();
		}else{//redirect to login page
			var url = window.location.href;
			//there can do clear form ...
			window.location.href = url+"?request=Login";
		}
	}
}

 

加密解密工具类

package util.jsRSAjava;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;


/**
 * @author hbkeepmoving@hotmail.com
 * 
 */
public class JCryptionUtil {
	
	public static final java.security.Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
	/**
	 * Constructor
	 */
	public JCryptionUtil() throws Exception {
		java.security.Security.addProvider(provider);
	}

	/**
	 * Generates the Keypair with the given keyLength.
	 * 
	 * @param keyLength
	 *            length of key
	 * @return KeyPair object
	 * @throws RuntimeException
	 *             if the RSA algorithm not supported
	 */
	public KeyPair generateKeypair(int keyLength) throws Exception {
		try {
			KeyPairGenerator kpg; 
			try {
				kpg = KeyPairGenerator.getInstance("RSA");
			} catch (Exception e) {
				kpg = KeyPairGenerator.getInstance("RSA",provider);
			}
			kpg.initialize(keyLength);
			KeyPair keyPair = kpg.generateKeyPair();
			return keyPair;
		} catch (NoSuchAlgorithmException e1) {
			throw new RuntimeException("RSA algorithm not supported", e1);
		} catch (Exception e) {
			throw new Exception("other exceptions", e);
		}
	}

	/**
	 * Decrypts a given string with the RSA keys
	 * 
	 * @param encrypted
	 *            full encrypted text
	 * @param keys
	 *            RSA keys
	 * @return decrypted text
	 * @throws RuntimeException
	 *             if the RSA algorithm not supported or decrypt operation failed
	 */
	public static String decrypt(String encrypted, KeyPair keys) throws Exception {
		Cipher dec;
		try {
			try {
				dec = Cipher.getInstance("RSA/NONE/NoPadding");
			} catch (Exception e) {
				dec = Cipher.getInstance("RSA/NONE/NoPadding",provider);
			}
			dec.init(Cipher.DECRYPT_MODE, keys.getPrivate());
		} catch (GeneralSecurityException e) {
			throw new RuntimeException("RSA algorithm not supported", e);
		}
		String[] blocks = encrypted.split("\\s");
		StringBuffer result = new StringBuffer();
		try {
			for (int i = blocks.length - 1; i >= 0; i--) {
				byte[] data = hexStringToByteArray(blocks[i]);
				byte[] decryptedBlock = dec.doFinal(data);
				result.append(new String(decryptedBlock));
			}
		} catch (GeneralSecurityException e) {
			throw new RuntimeException("Decrypt error", e);
		}
		/**
		 * Some code is getting added in first 2 digits with Jcryption need to investigate
		 */
		return result.reverse().toString().substring(2);
	}

	/**
	 * Parse url string (Todo - better parsing algorithm)
	 * 
	 * @param url
	 *            value to parse
	 * @param encoding
	 *            encoding value
	 * @return Map with param name, value pairs
	 */
	public static Map parse(String url, String encoding) {
		try {
			String urlToParse = URLDecoder.decode(url, encoding);
			String[] params = urlToParse.split("&");
			Map parsed = new HashMap();
			for (int i = 0; i < params.length; i++) {
				String[] p = params[i].split("=");
				String name = p[0];
				String value = (p.length == 2) ? p[1] : null;
				parsed.put(name, value);
			}
			return parsed;
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException("Unknown encoding.", e);
		}
	}

	/**
	 * Return public RSA key modulus
	 * 
	 * @param keyPair
	 *            RSA keys
	 * @return modulus value as hex string
	 */
	public static String getPublicKeyModulus(KeyPair keyPair) {
		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
		return publicKey.getModulus().toString(16);
	}

	/**
	 * Return public RSA key exponent
	 * 
	 * @param keyPair
	 *            RSA keys
	 * @return public exponent value as hex string
	 */
	public static String getPublicKeyExponent(KeyPair keyPair) {
		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
		return publicKey.getPublicExponent().toString(16);
	}

	/**
	 * Max block size with given key length
	 * 
	 * @param keyLength
	 *            length of key
	 * @return numeber of digits
	 */
	public static int getMaxDigits(int keyLength) {
		return ((keyLength * 2) / 16) + 3;
	}

	/**
	 * Convert byte array to hex string
	 * 
	 * @param bytes
	 *            input byte array
	 * @return Hex string representation
	 */
	public static String byteArrayToHexString(byte[] bytes) {
		StringBuffer result = new StringBuffer();
		for (int i = 0; i < bytes.length; i++) {
			result.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16)
					.substring(1));
		}
		return result.toString();
	}

	/**
	 * Convert hex string to byte array
	 * 
	 * @param data
	 *            input string data
	 * @return bytes
	 */
	public static byte[] hexStringToByteArray(String data) {
		int k = 0;
		byte[] results = new byte[data.length() / 2];
		for (int i = 0; i < data.length();) {
			results[k] = (byte) (Character.digit(data.charAt(i++), 16) << 4);
			results[k] += (byte) (Character.digit(data.charAt(i++), 16));
			k++;
		}
		return results;
	}

	/**
	 * @param args
	 */
//	public static void main(String[] args) {
//		JCryptionUtil jCryption = new JCryptionUtil();
//		System.out.println(jCryption.toPublicKeyString());
//	}

	/**
	 * @return
	 */
	public String toPublicKeyString() throws Exception {
		KeyPair keys = generateKeypair(512);
		StringBuffer out = new StringBuffer();

		String e = getPublicKeyExponent(keys);
		String n = getPublicKeyModulus(keys);
		String md = String.valueOf(getMaxDigits(512));

		out.append("{\"e\":\"");
		out.append(e);
		out.append("\",\"n\":\"");
		out.append(n);
		out.append("\",\"maxdigits\":\"");
		out.append(md);
		out.append("\"}");

		return out.toString();
	}

}

 

生成key的serverlet 代码。很简单。

JCryptionUtil jCryptionUtil = new JCryptionUtil();
KeyPair keys = null;
keys = jCryptionUtil.generateKeypair(512);
request.getSession().setAttribute("keys", keys);
StringBuffer output = new StringBuffer();
String e = JCryptionUtil.getPublicKeyExponent(keys);
String n = JCryptionUtil.getPublicKeyModulus(keys);
String md = String.valueOf(JCryptionUtil.getMaxDigits(512));
output.append("{\"e\":\"");
output.append(e);
output.append("\",\"n\":\"");
output.append(n);
output.append("\",\"maxdigits\":\"");
output.append(md);
output.append("\"}");
output.toString();
response.getOutputStream().print(output.toString().replaceAll("\r", "").replaceAll("\n", "").trim());

 

解密的servlet中代码,当然也可在写在filter中

String pass = request.getParameter("pass");//login pass
KeyPair keys = (KeyPair) SessionUtility.getSession(request).getAttribute("keys");
String decryptedPass = JCryptionUtil.decrypt(pass, keys);
request.setAttribute("pass", decryptedPass);

 

到此,就处理了。

现在我不知道,还有没有更好的解决方法。。。。各位大神多指点哈。。

 

 

 

 

另外:如果自己project 会部署到其他系统(eg:unix.....etc),如果在获取key失败,检查一下server log。如果有securityPermission的exception的话。

请参考

http://hb-keepmoving.iteye.com/blog/1851179

 

 

 

 

 

 

 

 

分享到:
评论
5 楼 hb_keepmoving 2014-12-29  
shenselongge 写道
KeyPair keys = (KeyPair) SessionUtility.getSession(request).getAttribute("keys"); 
SessionUtility在哪里?"keys"在哪里?



SessionUtility -- 是项目中的工具类,keys 也是自己定义的一个属性名称。
这些都是自定义的哈。。
4 楼 dacoolbaby 2014-12-10  
这个做法,大概是,用AJAX获得一个秘钥。
然后对密码进行加密。
然后用服务器的秘钥,进行解密。

这个想法相当不错,服务器秘钥和客户端秘钥随时可以改变。
而且提交的信息是加密的。

赞一个。
3 楼 shenselongge 2014-12-08  
KeyPair keys = (KeyPair) SessionUtility.getSession(request).getAttribute("keys"); 
SessionUtility在哪里?"keys"在哪里?
2 楼 cwqcwqmax9 2014-08-12  
还有 在   获取key后的Ajax异步的方法 执行,应该写在回调函数里
1 楼 cwqcwqmax9 2014-08-12  
当系统在加载页面完成后,如果发现页面中包含密码框,则向server发起请求来获取key--用于js加密。此key要存于session中,以便server解密。



你这句话写的有歧义 RSA 是非对称加密,你说的好像加密解密是同一个key(密匙),别人还以为是对称加密呢

相关推荐

Global site tag (gtag.js) - Google Analytics