赞
踩
Web登录时存在明文传输用户名和密码的安全漏洞,要求是:web客户端通信的数据包中不能包含明文的账号和密码,建议采用RSA加密算法解决此漏洞。
1、在WEB系统中编写工具类如下:
- package com.gsww.jup.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;
-
- public class RSAUtil {
- private static String RSAKeyStore = "RSAKey.txt";
- /**
- * 生成秘钥对
- * @return
- * @throws Exception
- */
- 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();
-
- System.out.println(keyPair.getPrivate());
- System.out.println(keyPair.getPublic());
-
- saveKeyPair(keyPair);
- return keyPair;
- } catch (Exception e) {
- throw new Exception(e.getMessage());
- }
-
- }
- public static KeyPair getKeyPair() throws Exception {
- FileInputStream fis = new FileInputStream(RSAKeyStore);
- 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(RSAKeyStore);
- ObjectOutputStream oos = new ObjectOutputStream(fos);
- oos.writeObject(kp);
- oos.close();
- fos.close();
- }
- 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());
- }
- }
-
-
- 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());
- }
- }
-
- 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());
- }
- }
- 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());
- }
- }
- }
该类属于工具类,提供加密解密的基础方法。该类用到第三方jar包,需要在pom文件中增加如下配置:
- <dependency>
- <groupId>org.bouncycastle</groupId>
- <artifactId>bcprov-jdk16</artifactId>
- <version>1.46</version>
- </dependency>
2、为了较小的影响现有业务,建立单独的控制器(可以是Servlet,JSP,springmvc的Controller,struts2的action等),用于将生成公钥,私钥,并可以将公钥返回至浏览器,用于JS加密。实例代码如下:
- package com.gsww.jup.controller.sys;
-
- import java.security.KeyPair;
- import java.security.interfaces.RSAPrivateKey;
- import java.security.interfaces.RSAPublicKey;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
- import org.codehaus.jackson.map.ObjectMapper;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.ResponseBody;
-
- import com.gsww.jup.controller.BaseController;
- import com.gsww.jup.entity.sys.SysOperator;
- import com.gsww.jup.service.sys.SysOperatorService;
- import com.gsww.jup.util.RSAUtil;
-
- @Controller
- @RequestMapping(value = "/sys/mybatis")
- public class MybatisController extends BaseController{
- private static Logger logger = LoggerFactory.getLogger(MybatisController.class);
-
- @Autowired
- private SysOperatorService sysOperatorService;
-
- @RequestMapping(value = "/show", method = RequestMethod.POST)
- @ResponseBody
- public List<SysOperator> accountView(String userAcctId,Model model,HttpServletRequest request,HttpServletResponse response) throws Exception {
-
- List<SysOperator> list=sysOperatorService.findList(null);
- SysOperator sysOperator=sysOperatorService.findByOperatorId("1");
- return list;
- }
-
- @RequestMapping(value = "/getkey")
- @ResponseBody
- public Object getPublicKey(HttpServletRequest request)throws Exception{
- Map<String,String> result = new HashMap<String,String>();
- KeyPair kp = RSAUtil.generateKeyPair();
- RSAPublicKey pubk = (RSAPublicKey) kp.getPublic();// 生成公钥
- RSAPrivateKey prik = (RSAPrivateKey) kp.getPrivate();// 生成私钥
-
- String publicKeyExponent = pubk.getPublicExponent().toString(16);// 16进制
- String publicKeyModulus = pubk.getModulus().toString(16);// 16进制
- request.getSession().setAttribute("prik", prik);
- result.put("pubexponent", publicKeyExponent);
- result.put("pubmodules", publicKeyModulus);
- return result;
- }
-
- }
说明,该被需要在过滤器中忽略,因为在登录之前要调用该方法。
3、登录页面,在完成非空校验后,以Ajax的方式从后台获取公钥,并对密码进行加密,将加密的数据通过登录方法提交至后台。
以公司JUP平台为例,改造如下:
- <!DOCTYPE html>
- <%@ page contentType="text/html;charset=UTF-8"%>
- <html>
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=no">
- <title>甘肃万维JAVA统一开发平台</title>
- <link rel="stylesheet" href="res/skin/default/css/login-jup.css">
- </head>
- <body>
- <div class="login-warp">
- <div class="main">
- <div class="logo"></div>
- <div class="login-form">
- <form id="login-form">
- <div class="form-title">甘肃万维JAVA统一开发平台 </div>
- <ul>
- <li>
- <div class="input-content">
- <span class="icon uname"></span>
- <input type="text" class="input " id="userName" name="userName" placeholder="请输入您的帐号" value="admin">
- </div>
- </li>
- <li>
- <div class="input-content">
- <span class="icon upwd"></span>
- <input type="password" class="input " id="passWord" name="passWord" placeholder="请输入您的密码" value="111111">
- </div>
- </li>
- <li>
- <div class="input-content yzm-input">
- <span class="icon uyzm"></span>
- <input type="text" class="input input-yzm" name="kaptcha" id="kaptcha" placeholder="请输入验证码" >
- </div>
- <div class="input-verificationCode yzm-img">
- <img style="cursor:pointer;" id="kaptchaImage" src="kaptcha/image" title="看不清,点击换一张" />
- </div>
- </li>
- <li>
- <input class="input-submit" type="submit" name="" value="登录" />
- </li>
- </ul>
- </form>
- </div>
- </div>
- <div class="footer">
- <p>版权所有:甘肃万维信息技术有限责任公司</p>
- <p> (c)2015 You company name.All rights reserve</p>
- </div>
- </div>
-
- <script type="text/javascript" src="res/skin/default/js/jquery-1.8.3.min.js"></script>
- <script type="text/javascript" src="res/skin/default/plugin/validate/jquery.validate.js"></script>
- <script type="text/javascript" src="res/skin/default/plugin/validate/jquery.validate.extension.js"></script>
- <script type="text/javascript" src="res/skin/default/plugin/rsa/BigInt.js"></script>
- <script type="text/javascript" src="res/skin/default/plugin/rsa/Barrett.js"></script>
- <script type="text/javascript" src="res/skin/default/plugin/rsa/RSA.js"></script>
- <script type="text/javascript">
- $(document).ready(function() {
-
- $(function() {
- $("#kaptchaImage").click(function() {//生成验证码
- $(this).attr(
- 'src',
- 'kaptcha/image?' + Math.floor(Math.random() * 100)).fadeIn();
- event.cancelBubble = true;
- });
- });
-
- $("#login-form").jupLogin();
- });
-
-
-
- // 创建一个闭包
- (function($) {
- // 插件的定义
- $.fn.jupLogin = function(options) {
-
- // build main options before element iteration
- var opts = $.extend({}, $.fn.jupLogin.defaults, options);
- // iterate and reformat each matched element
- return this.each(function() {
- $this = $(this);
- init();
- $this.validate({
- debug : true ,
- onkeyup: false,
- onclick: false,
- // errorElement: "div",
- showErrors: function(errorMap, errorList) {
- showErrors(errorMap,errorList);
- },
- rules: {
- userName: "required" ,
- passWord : "required" ,
- kaptcha : "required"
- },
- submitHandler : function(form) {
- //此处获取加密公钥
- $.post("sys/mybatis/getkey",function(data){
- //data为获取到的公钥数据
- var pubexponent =data.pubexponent;
- var pubmodules =data.pubmodules;
- setMaxDigits(200);
- var key = new RSAKeyPair(pubexponent, "", pubmodules);
- var password=$("#passWord").val();
- var encrypedPwd = encryptedString(key, encodeURIComponent(password));
- $("#passWord").val(encrypedPwd);
- var formData = {
- "userName" : $(form).find("#userName").val() ,
- "passWord" : $(form).find("#passWord").val() ,
- "kaptcha" : $(form).find("#kaptcha").val()
- };
- //登录开始
- $.ajax({
- url: 'login/sysLogin',
- type: 'POST',
- dataType: 'json',
- data: formData,
- success : function(data){
- //window.location.href= "sysLogin";
- if(data.ret != 0) {
- if(data.ret == 1){
- showErrors(
- {userName : data.msg},
- [{
- element : "input#kaptcha.input",
- message:data.msg
- }]);
- }else{
- showErrors(
- {userName : data.msg},
- [{
- element : "input#userName.input",
- message:data.msg
- }]);
- }
-
- }else {
- window.location.href= "index";
- }
- }
- });
- //登录结束
- });
- }
- });
-
-
-
- });
- };
- function init(){
-
- };
-
- function showErrors(errorMap, errorList) {
- $('.error-content').remove();
- $('.error').removeClass('error');
- $(errorList).each(function(index, el) {
- $(el.element).parent().addClass("error");
- var $content = $("<div class='error-content error'> <span class='error-msg'>" + el.message +"</span></div>");
- $("body").append($content);
- $content.css('top',($(el.element).offset().top+2)).css('left',$(el.element).offset().left-$content.width()-70).show();
- shake($content,$content.offset().left);
- });
- };
- //抖动
- function shake(o,box_left){
- var $panel = $(o);
- //box_left = ($(window).width() - $panel.width()) / 2;
- //$panel.css({'left': box_left,'position':'absolute'});
- for(var i=1; 4>=i; i++){
- $panel.animate({left:box_left-0.3*(40-10*i)},50);
- $panel.animate({left:box_left+0.3*(40-10*i)},50);
- }
- };
-
- // 私有函数:debugging
- function debug($obj) {
- if (window.console && window.console.log)
- window.console.log('jupLogin selection count: ' + $obj.size());
- };
- // 定义暴露format函数
- $.fn.jupLogin.format = function(txt) {
- return '<strong>' + txt + '</strong>';
- };
- // 插件的defaults
- $.fn.jupLogin.defaults = {
-
- };
-
- // 闭包结束
- })(jQuery);
-
- </script>
- </body>
- </html>
- /**
- * ajax登录
- * @return
- * @throws Exception
- */
- public void login4() {
- response.setContentType("text/xml;charset=UTF-8");
- response.setHeader("Cache-Control", "no-cache");
- PrintWriter out = null;
- Map<String, Object> message = new HashMap();
-
- try {
- out=response.getWriter();
- // String session_authcode="1234";//测试环境
- //客户端验证码验证 正式环境
- String session_authcode =String.valueOf(session.getAttribute(Constants.SESSION_USER_PHONE_AUTHCODE));
-
- if("".equals(session_authcode)||session_authcode==null||validateCode==null||"".equals(validateCode)){
- //out.write("短信密码不能为空,请输入正确短信密码");
- //rentJavascript("$.alert2('短信验证码不能为空,请输入短信验证码',function(){location.href='login.jsp'; });");
- //return null;
- message.put("success", false);
- message.put("message", "短信验证码不能为空,请输入短信验证码");
- }else{
- if (session_authcode.length()>0 && !session_authcode.equals(validateCode)) {
- // rentJavascript("$.alert2('短信验证码输入错误,请重新输入',function(){location.href='login.jsp'; });");
- // return null;
- message.put("success", false);
- message.put("message", "短信验证码输入错误,请重新输入");
- }else if(validateCode.length()==0 || session_authcode.length() == 0){
- // out.write("短信密码不能为空,请输入正确短信密码!");
- //rentJavascript("$.alert2('短信验证码不能为空,请输入正确短信验证码!',function(){location.href='login.jsp'});");
- //return null;
- message.put("success", false);
- message.put("message", "短信验证码不能为空,请输入正确短信验证码!");
- }else {
-
- //正常登陆
- //RSA解密
- RSAPrivateKey prik = (RSAPrivateKey) request.getSession().getAttribute("prik");
- try{
-
- byte[] en_result = new BigInteger(loginName, 16).toByteArray();
-
- byte[] de_result = RSAUtil.decrypt(prik, en_result);
-
- StringBuffer sb = new StringBuffer();
-
- sb.append(new String(de_result));
-
- loginName= sb.reverse().toString();
- //loginName = java.net.URLEncoder.encode(loginName);
- loginName = java.net.URLDecoder.decode(loginName,"UTF-8");
-
- byte[] en_identityCode = new BigInteger(identityCode, 16).toByteArray();
-
- byte[] de_identityCode = RSAUtil.decrypt(prik, en_identityCode);
-
- StringBuffer sb1 = new StringBuffer();
-
- sb1.append(new String(de_identityCode));
-
- identityCode= sb1.reverse().toString();
-
- } catch(Exception ex){
-
- ex.printStackTrace();
- }
- Bj3typePerson user=sysUserService.findBj3typePerson(loginName,identityCode);
- if (user == null) {
- //rentJavascript("$.alert2('账号错误或不存在,请重新输入!',function(){location.href='login.jsp'});");
- //return null;
- message.put("success", false);
- message.put("message", "账号错误或用户不存在,请重新输入!");
- }else if ("00".equals(user.getPersonType())) { //管理员登录
- //rentJavascript("$.alert2('系统将自动跳转至符合权限的登录界面',function(){location.href='admin_login.jsp'});");
- //return null;
- message.put("success", false);
- message.put("ptype", "00");
- message.put("message", "系统将自动跳转至符合权限的登录界面");
- }else{
- session.setAttribute(Constants.SESSION_USER_TYPE, user.getPersonType());
- session.setAttribute(Constants.SESSION_USER_KEY, user.getAssessId());
- session.setAttribute(Constants.SESSION_USER_IP, request.getRemoteAddr());
- session.setAttribute(Constants.SESSION_USER_NAME, user.getName());
- session.setAttribute(Constants.SESSION_USER_MOBILE, user.getPhone());
- session.setAttribute(Constants.SESSION_USER_SETID,"297e672589a9e5210159a9f5999c0032");
- session.setAttribute(Constants.SESSION_IDENTITY_CODE, user.getIdentityCode());
- /*UserLoginLog loginLog=new UserLoginLog();
- loginLog.setLoginTime(TimeHelper.getCurrentTime());
- loginLog.setUserId(user.getAssessId());
- loginLog.setLoginType(Constants.PC_LOGIN);
- userLoginLogService.saveLoginLog(loginLog);*/
- OnLineUser onLineUser = (OnLineUser) ctx.getApplication().get("onlineuser");
- if (onLineUser==null){
- onLineUser=new OnLineUser();
- }
- onLineUser.addUser(user.getAssessId());
- ctx.getApplication().put("onlineuser", onLineUser);
- onlineService.onlinUserUpdate(user.getAssessId(), request.getRemoteAddr());
- //rentJavascript("function(){location.href='main/main.jsp'});");
- message.put("success", true);
- //return "login";
-
- }
- }
-
- }
-
-
- } catch (Exception e) {
- e.printStackTrace();
- //rentJavascript("alert('登录失败,请重新登录!');location.href='login.jsp';");
- //out.write("登录失败,请重新登录!");
- try {
- out=response.getWriter();
- message.put("success", false);
- message.put("message", "操作异常,请联系管理员");
- } catch (IOException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
- //return null;
- }finally{
-
- out.println(JSONUtil.writeMapJSON(message));
- out.flush();
- out.close();
- }
-
-
- }
附件:前面用到的3个js(Barrett.js、BigInt.js、RSA.js),CSDN博客不能上传附件,很无奈……只能把代码直接粘这里了
Barrett.js
- function BarrettMu(m)
- {
- this.modulus = biCopy(m);
- this.k = biHighIndex(this.modulus) + 1;
- var b2k = new BigInt();
- b2k.digits[2 * this.k] = 1; // b2k = b^(2k)
- this.mu = biDivide(b2k, this.modulus);
- this.bkplus1 = new BigInt();
- this.bkplus1.digits[this.k + 1] = 1; // bkplus1 = b^(k+1)
- this.modulo = BarrettMu_modulo;
- this.multiplyMod = BarrettMu_multiplyMod;
- this.powMod = BarrettMu_powMod;
- }
-
- function BarrettMu_modulo(x)
- {
- var q1 = biDivideByRadixPower(x, this.k - 1);
- var q2 = biMultiply(q1, this.mu);
- var q3 = biDivideByRadixPower(q2, this.k + 1);
- var r1 = biModuloByRadixPower(x, this.k + 1);
- var r2term = biMultiply(q3, this.modulus);
- var r2 = biModuloByRadixPower(r2term, this.k + 1);
- var r = biSubtract(r1, r2);
- if (r.isNeg) {
- r = biAdd(r, this.bkplus1);
- }
- var rgtem = biCompare(r, this.modulus) >= 0;
- while (rgtem) {
- r = biSubtract(r, this.modulus);
- rgtem = biCompare(r, this.modulus) >= 0;
- }
- return r;
- }
-
- function BarrettMu_multiplyMod(x, y)
- {
- /*
- x = this.modulo(x);
- y = this.modulo(y);
- */
- var xy = biMultiply(x, y);
- return this.modulo(xy);
- }
-
- function BarrettMu_powMod(x, y)
- {
- var result = new BigInt();
- result.digits[0] = 1;
- var a = x;
- var k = y;
- while (true) {
- if ((k.digits[0] & 1) != 0) result = this.multiplyMod(result, a);
- k = biShiftRight(k, 1);
- if (k.digits[0] == 0 && biHighIndex(k) == 0) break;
- a = this.multiplyMod(a, a);
- }
- return result;
- }
BigInt.js
- // BigInt, a suite of routines for performing multiple-precision arithmetic in
- // JavaScript.
- //
- // Copyright 1998-2005 David Shapiro.
- //
- // You may use, re-use, abuse,
- // copy, and modify this code to your liking, but please keep this header.
- // Thanks!
- //
- // Dave Shapiro
- // dave@ohdave.com
-
- // IMPORTANT THING: Be sure to set maxDigits according to your precision
- // needs. Use the setMaxDigits() function to do this. See comments below.
- //
- // Tweaked by Ian Bunning
- // Alterations:
- // Fix bug in function biFromHex(s) to allow
- // parsing of strings of length != 0 (mod 4)
-
- // Changes made by Dave Shapiro as of 12/30/2004:
- //
- // The BigInt() constructor doesn't take a string anymore. If you want to
- // create a BigInt from a string, use biFromDecimal() for base-10
- // representations, biFromHex() for base-16 representations, or
- // biFromString() for base-2-to-36 representations.
- //
- // biFromArray() has been removed. Use biCopy() instead, passing a BigInt
- // instead of an array.
- //
- // The BigInt() constructor now only constructs a zeroed-out array.
- // Alternatively, if you pass <true>, it won't construct any array. See the
- // biCopy() method for an example of this.
- //
- // Be sure to set maxDigits depending on your precision needs. The default
- // zeroed-out array ZERO_ARRAY is constructed inside the setMaxDigits()
- // function. So use this function to set the variable. DON'T JUST SET THE
- // VALUE. USE THE FUNCTION.
- //
- // ZERO_ARRAY exists to hopefully speed up construction of BigInts(). By
- // precalculating the zero array, we can just use slice(0) to make copies of
- // it. Presumably this calls faster native code, as opposed to setting the
- // elements one at a time. I have not done any timing tests to verify this
- // claim.
-
- // Max number = 10^16 - 2 = 9999999999999998;
- // 2^53 = 9007199254740992;
-
- var biRadixBase = 2;
- var biRadixBits = 16;
- var bitsPerDigit = biRadixBits;
- var biRadix = 1 << 16; // = 2^16 = 65536
- var biHalfRadix = biRadix >>> 1;
- var biRadixSquared = biRadix * biRadix;
- var maxDigitVal = biRadix - 1;
- var maxInteger = 9999999999999998;
-
- // maxDigits:
- // Change this to accommodate your largest number size. Use setMaxDigits()
- // to change it!
- //
- // In general, if you're working with numbers of size N bits, you'll need 2*N
- // bits of storage. Each digit holds 16 bits. So, a 1024-bit key will need
- //
- // 1024 * 2 / 16 = 128 digits of storage.
- //
-
- var maxDigits;
- var ZERO_ARRAY;
- var bigZero, bigOne;
-
- function setMaxDigits(value)
- {
- maxDigits = value;
- ZERO_ARRAY = new Array(maxDigits);
- for (var iza = 0; iza < ZERO_ARRAY.length; iza++) ZERO_ARRAY[iza] = 0;
- bigZero = new BigInt();
- bigOne = new BigInt();
- bigOne.digits[0] = 1;
- }
-
- setMaxDigits(20);
-
- // The maximum number of digits in base 10 you can convert to an
- // integer without JavaScript throwing up on you.
- var dpl10 = 15;
- // lr10 = 10 ^ dpl10
- var lr10 = biFromNumber(1000000000000000);
-
- function BigInt(flag)
- {
- if (typeof flag == "boolean" && flag == true) {
- this.digits = null;
- }
- else {
- this.digits = ZERO_ARRAY.slice(0);
- }
- this.isNeg = false;
- }
-
- function biFromDecimal(s)
- {
- var isNeg = s.charAt(0) == '-';
- var i = isNeg ? 1 : 0;
- var result;
- // Skip leading zeros.
- while (i < s.length && s.charAt(i) == '0') ++i;
- if (i == s.length) {
- result = new BigInt();
- }
- else {
- var digitCount = s.length - i;
- var fgl = digitCount % dpl10;
- if (fgl == 0) fgl = dpl10;
- result = biFromNumber(Number(s.substr(i, fgl)));
- i += fgl;
- while (i < s.length) {
- result = biAdd(biMultiply(result, lr10),
- biFromNumber(Number(s.substr(i, dpl10))));
- i += dpl10;
- }
- result.isNeg = isNeg;
- }
- return result;
- }
-
- function biCopy(bi)
- {
- var result = new BigInt(true);
- result.digits = bi.digits.slice(0);
- result.isNeg = bi.isNeg;
- return result;
- }
-
- function biFromNumber(i)
- {
- var result = new BigInt();
- result.isNeg = i < 0;
- i = Math.abs(i);
- var j = 0;
- while (i > 0) {
- result.digits[j++] = i & maxDigitVal;
- i = Math.floor(i / biRadix);
- }
- return result;
- }
-
- function reverseStr(s)
- {
- var result = "";
- for (var i = s.length - 1; i > -1; --i) {
- result += s.charAt(i);
- }
- return result;
- }
-
- var hexatrigesimalToChar = new Array(
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
- 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
- 'u', 'v', 'w', 'x', 'y', 'z'
- );
-
- function biToString(x, radix)
- // 2 <= radix <= 36
- {
- var b = new BigInt();
- b.digits[0] = radix;
- var qr = biDivideModulo(x, b);
- var result = hexatrigesimalToChar[qr[1].digits[0]];
- while (biCompare(qr[0], bigZero) == 1) {
- qr = biDivideModulo(qr[0], b);
- digit = qr[1].digits[0];
- result += hexatrigesimalToChar[qr[1].digits[0]];
- }
- return (x.isNeg ? "-" : "") + reverseStr(result);
- }
-
- function biToDecimal(x)
- {
- var b = new BigInt();
- b.digits[0] = 10;
- var qr = biDivideModulo(x, b);
- var result = String(qr[1].digits[0]);
- while (biCompare(qr[0], bigZero) == 1) {
- qr = biDivideModulo(qr[0], b);
- result += String(qr[1].digits[0]);
- }
- return (x.isNeg ? "-" : "") + reverseStr(result);
- }
-
- var hexToChar = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- 'a', 'b', 'c', 'd', 'e', 'f');
-
- function digitToHex(n)
- {
- var mask = 0xf;
- var result = "";
- for (i = 0; i < 4; ++i) {
- result += hexToChar[n & mask];
- n >>>= 4;
- }
- return reverseStr(result);
- }
-
- function biToHex(x)
- {
- var result = "";
- var n = biHighIndex(x);
- for (var i = biHighIndex(x); i > -1; --i) {
- result += digitToHex(x.digits[i]);
- }
- return result;
- }
-
- function charToHex(c)
- {
- var ZERO = 48;
- var NINE = ZERO + 9;
- var littleA = 97;
- var littleZ = littleA + 25;
- var bigA = 65;
- var bigZ = 65 + 25;
- var result;
-
- if (c >= ZERO && c <= NINE) {
- result = c - ZERO;
- } else if (c >= bigA && c <= bigZ) {
- result = 10 + c - bigA;
- } else if (c >= littleA && c <= littleZ) {
- result = 10 + c - littleA;
- } else {
- result = 0;
- }
- return result;
- }
-
- function hexToDigit(s)
- {
- var result = 0;
- var sl = Math.min(s.length, 4);
- for (var i = 0; i < sl; ++i) {
- result <<= 4;
- result |= charToHex(s.charCodeAt(i))
- }
- return result;
- }
-
- function biFromHex(s)
- {
- var result = new BigInt();
- var sl = s.length;
- for (var i = sl, j = 0; i > 0; i -= 4, ++j) {
- result.digits[j] = hexToDigit(s.substr(Math.max(i - 4, 0), Math.min(i, 4)));
- }
- return result;
- }
-
- function biFromString(s, radix)
- {
- var isNeg = s.charAt(0) == '-';
- var istop = isNeg ? 1 : 0;
- var result = new BigInt();
- var place = new BigInt();
- place.digits[0] = 1; // radix^0
- for (var i = s.length - 1; i >= istop; i--) {
- var c = s.charCodeAt(i);
- var digit = charToHex(c);
- var biDigit = biMultiplyDigit(place, digit);
- result = biAdd(result, biDigit);
- place = biMultiplyDigit(place, radix);
- }
- result.isNeg = isNeg;
- return result;
- }
-
- function biDump(b)
- {
- return (b.isNeg ? "-" : "") + b.digits.join(" ");
- }
-
- function biAdd(x, y)
- {
- var result;
-
- if (x.isNeg != y.isNeg) {
- y.isNeg = !y.isNeg;
- result = biSubtract(x, y);
- y.isNeg = !y.isNeg;
- }
- else {
- result = new BigInt();
- var c = 0;
- var n;
- for (var i = 0; i < x.digits.length; ++i) {
- n = x.digits[i] + y.digits[i] + c;
- result.digits[i] = n % biRadix;
- c = Number(n >= biRadix);
- }
- result.isNeg = x.isNeg;
- }
- return result;
- }
-
- function biSubtract(x, y)
- {
- var result;
- if (x.isNeg != y.isNeg) {
- y.isNeg = !y.isNeg;
- result = biAdd(x, y);
- y.isNeg = !y.isNeg;
- } else {
- result = new BigInt();
- var n, c;
- c = 0;
- for (var i = 0; i < x.digits.length; ++i) {
- n = x.digits[i] - y.digits[i] + c;
- result.digits[i] = n % biRadix;
- // Stupid non-conforming modulus operation.
- if (result.digits[i] < 0) result.digits[i] += biRadix;
- c = 0 - Number(n < 0);
- }
- // Fix up the negative sign, if any.
- if (c == -1) {
- c = 0;
- for (var i = 0; i < x.digits.length; ++i) {
- n = 0 - result.digits[i] + c;
- result.digits[i] = n % biRadix;
- // Stupid non-conforming modulus operation.
- if (result.digits[i] < 0) result.digits[i] += biRadix;
- c = 0 - Number(n < 0);
- }
- // Result is opposite sign of arguments.
- result.isNeg = !x.isNeg;
- } else {
- // Result is same sign.
- result.isNeg = x.isNeg;
- }
- }
- return result;
- }
-
-
- function biHighIndex(x)
- {
- var result = x.digits.length - 1;
- while (result > 0 && x.digits[result] == 0) --result;
- return result;
- }
-
- function biNumBits(x)
- {
- var n = biHighIndex(x);
- var d = x.digits[n];
- var m = (n + 1) * bitsPerDigit;
- var result;
- for (result = m; result > m - bitsPerDigit; --result) {
- if ((d & 0x8000) != 0) break;
- d <<= 1;
- }
- return result;
- }
-
- function biMultiply(x, y)
- {
- var result = new BigInt();
- var c;
- var n = biHighIndex(x);
- var t = biHighIndex(y);
- var u, uv, k;
-
- for (var i = 0; i <= t; ++i) {
- c = 0;
- k = i;
- for (j = 0; j <= n; ++j, ++k) {
- uv = result.digits[k] + x.digits[j] * y.digits[i] + c;
- result.digits[k] = uv & maxDigitVal;
- c = uv >>> biRadixBits;
- //c = Math.floor(uv / biRadix);
- }
- result.digits[i + n + 1] = c;
- }
- // Someone give me a logical xor, please.
- result.isNeg = x.isNeg != y.isNeg;
- return result;
- }
-
- function biMultiplyDigit(x, y)
- {
- var n, c, uv;
-
- result = new BigInt();
- n = biHighIndex(x);
- c = 0;
- for (var j = 0; j <= n; ++j) {
- uv = result.digits[j] + x.digits[j] * y + c;
- result.digits[j] = uv & maxDigitVal;
- c = uv >>> biRadixBits;
- //c = Math.floor(uv / biRadix);
- }
- result.digits[1 + n] = c;
- return result;
- }
-
- function arrayCopy(src, srcStart, dest, destStart, n)
- {
- var m = Math.min(srcStart + n, src.length);
- for (var i = srcStart, j = destStart; i < m; ++i, ++j) {
- dest[j] = src[i];
- }
- }
-
- var highBitMasks = new Array(0x0000, 0x8000, 0xC000, 0xE000, 0xF000, 0xF800,
- 0xFC00, 0xFE00, 0xFF00, 0xFF80, 0xFFC0, 0xFFE0,
- 0xFFF0, 0xFFF8, 0xFFFC, 0xFFFE, 0xFFFF);
-
- function biShiftLeft(x, n)
- {
- var digitCount = Math.floor(n / bitsPerDigit);
- var result = new BigInt();
- arrayCopy(x.digits, 0, result.digits, digitCount,
- result.digits.length - digitCount);
- var bits = n % bitsPerDigit;
- var rightBits = bitsPerDigit - bits;
- for (var i = result.digits.length - 1, i1 = i - 1; i > 0; --i, --i1) {
- result.digits[i] = ((result.digits[i] << bits) & maxDigitVal) |
- ((result.digits[i1] & highBitMasks[bits]) >>>
- (rightBits));
- }
- result.digits[0] = ((result.digits[i] << bits) & maxDigitVal);
- result.isNeg = x.isNeg;
- return result;
- }
-
- var lowBitMasks = new Array(0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F,
- 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF,
- 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF);
-
- function biShiftRight(x, n)
- {
- var digitCount = Math.floor(n / bitsPerDigit);
- var result = new BigInt();
- arrayCopy(x.digits, digitCount, result.digits, 0,
- x.digits.length - digitCount);
- var bits = n % bitsPerDigit;
- var leftBits = bitsPerDigit - bits;
- for (var i = 0, i1 = i + 1; i < result.digits.length - 1; ++i, ++i1) {
- result.digits[i] = (result.digits[i] >>> bits) |
- ((result.digits[i1] & lowBitMasks[bits]) << leftBits);
- }
- result.digits[result.digits.length - 1] >>>= bits;
- result.isNeg = x.isNeg;
- return result;
- }
-
- function biMultiplyByRadixPower(x, n)
- {
- var result = new BigInt();
- arrayCopy(x.digits, 0, result.digits, n, result.digits.length - n);
- return result;
- }
-
- function biDivideByRadixPower(x, n)
- {
- var result = new BigInt();
- arrayCopy(x.digits, n, result.digits, 0, result.digits.length - n);
- return result;
- }
-
- function biModuloByRadixPower(x, n)
- {
- var result = new BigInt();
- arrayCopy(x.digits, 0, result.digits, 0, n);
- return result;
- }
-
- function biCompare(x, y)
- {
- if (x.isNeg != y.isNeg) {
- return 1 - 2 * Number(x.isNeg);
- }
- for (var i = x.digits.length - 1; i >= 0; --i) {
- if (x.digits[i] != y.digits[i]) {
- if (x.isNeg) {
- return 1 - 2 * Number(x.digits[i] > y.digits[i]);
- } else {
- return 1 - 2 * Number(x.digits[i] < y.digits[i]);
- }
- }
- }
- return 0;
- }
-
- function biDivideModulo(x, y)
- {
- var nb = biNumBits(x);
- var tb = biNumBits(y);
- var origYIsNeg = y.isNeg;
- var q, r;
- if (nb < tb) {
- // |x| < |y|
- if (x.isNeg) {
- q = biCopy(bigOne);
- q.isNeg = !y.isNeg;
- x.isNeg = false;
- y.isNeg = false;
- r = biSubtract(y, x);
- // Restore signs, 'cause they're references.
- x.isNeg = true;
- y.isNeg = origYIsNeg;
- } else {
- q = new BigInt();
- r = biCopy(x);
- }
- return new Array(q, r);
- }
-
- q = new BigInt();
- r = x;
-
- // Normalize Y.
- var t = Math.ceil(tb / bitsPerDigit) - 1;
- var lambda = 0;
- while (y.digits[t] < biHalfRadix) {
- y = biShiftLeft(y, 1);
- ++lambda;
- ++tb;
- t = Math.ceil(tb / bitsPerDigit) - 1;
- }
- // Shift r over to keep the quotient constant. We'll shift the
- // remainder back at the end.
- r = biShiftLeft(r, lambda);
- nb += lambda; // Update the bit count for x.
- var n = Math.ceil(nb / bitsPerDigit) - 1;
-
- var b = biMultiplyByRadixPower(y, n - t);
- while (biCompare(r, b) != -1) {
- ++q.digits[n - t];
- r = biSubtract(r, b);
- }
- for (var i = n; i > t; --i) {
- var ri = (i >= r.digits.length) ? 0 : r.digits[i];
- var ri1 = (i - 1 >= r.digits.length) ? 0 : r.digits[i - 1];
- var ri2 = (i - 2 >= r.digits.length) ? 0 : r.digits[i - 2];
- var yt = (t >= y.digits.length) ? 0 : y.digits[t];
- var yt1 = (t - 1 >= y.digits.length) ? 0 : y.digits[t - 1];
- if (ri == yt) {
- q.digits[i - t - 1] = maxDigitVal;
- } else {
- q.digits[i - t - 1] = Math.floor((ri * biRadix + ri1) / yt);
- }
-
- var c1 = q.digits[i - t - 1] * ((yt * biRadix) + yt1);
- var c2 = (ri * biRadixSquared) + ((ri1 * biRadix) + ri2);
- while (c1 > c2) {
- --q.digits[i - t - 1];
- c1 = q.digits[i - t - 1] * ((yt * biRadix) | yt1);
- c2 = (ri * biRadix * biRadix) + ((ri1 * biRadix) + ri2);
- }
-
- b = biMultiplyByRadixPower(y, i - t - 1);
- r = biSubtract(r, biMultiplyDigit(b, q.digits[i - t - 1]));
- if (r.isNeg) {
- r = biAdd(r, b);
- --q.digits[i - t - 1];
- }
- }
- r = biShiftRight(r, lambda);
- // Fiddle with the signs and stuff to make sure that 0 <= r < y.
- q.isNeg = x.isNeg != origYIsNeg;
- if (x.isNeg) {
- if (origYIsNeg) {
- q = biAdd(q, bigOne);
- } else {
- q = biSubtract(q, bigOne);
- }
- y = biShiftRight(y, lambda);
- r = biSubtract(y, r);
- }
- // Check for the unbelievably stupid degenerate case of r == -0.
- if (r.digits[0] == 0 && biHighIndex(r) == 0) r.isNeg = false;
-
- return new Array(q, r);
- }
-
- function biDivide(x, y)
- {
- return biDivideModulo(x, y)[0];
- }
-
- function biModulo(x, y)
- {
- return biDivideModulo(x, y)[1];
- }
-
- function biMultiplyMod(x, y, m)
- {
- return biModulo(biMultiply(x, y), m);
- }
-
- function biPow(x, y)
- {
- var result = bigOne;
- var a = x;
- while (true) {
- if ((y & 1) != 0) result = biMultiply(result, a);
- y >>= 1;
- if (y == 0) break;
- a = biMultiply(a, a);
- }
- return result;
- }
-
- function biPowMod(x, y, m)
- {
- var result = bigOne;
- var a = x;
- var k = y;
- while (true) {
- if ((k.digits[0] & 1) != 0) result = biMultiplyMod(result, a, m);
- k = biShiftRight(k, 1);
- if (k.digits[0] == 0 && biHighIndex(k) == 0) break;
- a = biMultiplyMod(a, a, m);
- }
- return result;
- }
-
RSA.js
- // RSA, a suite of routines for performing RSA public-key computations in
- // JavaScript.
- //
- // Requires BigInt.js and Barrett.js.
- //
- // Copyright 1998-2005 David Shapiro.
- //
- // You may use, re-use, abuse, copy, and modify this code to your liking, but
- // please keep this header.
- //
- // Thanks!
- //
- // Dave Shapiro
- // dave@ohdave.com
-
- function RSAKeyPair(encryptionExponent, decryptionExponent, modulus)
- {
- this.e = biFromHex(encryptionExponent);
- this.d = biFromHex(decryptionExponent);
- this.m = biFromHex(modulus);
- // We can do two bytes per digit, so
- // chunkSize = 2 * (number of digits in modulus - 1).
- // Since biHighIndex returns the high index, not the number of digits, 1 has
- // already been subtracted.
- this.chunkSize = 2 * biHighIndex(this.m);
- this.radix = 16;
- this.barrett = new BarrettMu(this.m);
- }
-
- function twoDigit(n)
- {
- return (n < 10 ? "0" : "") + String(n);
- }
-
- function encryptedString(key, s)
- // Altered by Rob Saunders (rob@robsaunders.net). New routine pads the
- // string after it has been converted to an array. This fixes an
- // incompatibility with Flash MX's ActionScript.
- {
- var a = new Array();
- var sl = s.length;
- var i = 0;
- while (i < sl) {
- a[i] = s.charCodeAt(i);
- i++;
- }
-
- while (a.length % key.chunkSize != 0) {
- a[i++] = 0;
- }
-
- var al = a.length;
- var result = "";
- var j, k, block;
- for (i = 0; i < al; i += key.chunkSize) {
- block = new BigInt();
- j = 0;
- for (k = i; k < i + key.chunkSize; ++j) {
- block.digits[j] = a[k++];
- block.digits[j] += a[k++] << 8;
- }
- var crypt = key.barrett.powMod(block, key.e);
- var text = key.radix == 16 ? biToHex(crypt) : biToString(crypt, key.radix);
- result += text + " ";
- }
- return result.substring(0, result.length - 1); // Remove last space.
- }
-
- function decryptedString(key, s)
- {
- var blocks = s.split(" ");
- var result = "";
- var i, j, block;
- for (i = 0; i < blocks.length; ++i) {
- var bi;
- if (key.radix == 16) {
- bi = biFromHex(blocks[i]);
- }
- else {
- bi = biFromString(blocks[i], key.radix);
- }
- block = key.barrett.powMod(bi, key.d);
- for (j = 0; j <= biHighIndex(block); ++j) {
- result += String.fromCharCode(block.digits[j] & 255,
- block.digits[j] >> 8);
- }
- }
- // Remove trailing null, if any.
- if (result.charCodeAt(result.length - 1) == 0) {
- result = result.substring(0, result.length - 1);
- }
- return result;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。