新浪微博登录,QQ登录网页javascript脚本实现RSA加密的原理

今天在原来的系统上增加网页操作的功能,原来系统是JAVA写的,数据传输用的是RSA加密,为了实现网页登录,研究了javascript的RSA加密方法。

这个系统是一个移动电话会议系统,是手机上就能发起电话会议的为数不多的几个系统之一。

以前开发系统的时候是参考这篇文章写的 http://alunblog.duapp.com/?p=50

前段时间在开发欣所罗门公司自动化营销系统的时候,研究过QQ网页登录方法,里面有RSA加密的脚本。

欣所罗门公司自动化营销系统是一套全自动建立营销数据库的系统。

打开QQ注册页面,把里面的http://4.url.cn/zc/chs/js/10062/rsa.js下载了下来,然后写了个HTA测试页面。

HTA相当于用网页技术实现的一个桌面程序,非常好用,能够实现绝大多数桌面程序的功能。

QQ注册RSA加密的相关代码是这样的:
 
function  rsaEncrypt ( txt ) {
     var  b = new  RSAKey ;
     b . setPublic ( "C4D23C2DB0ECC904FE0CD0CBBCDC988C039D79E1BDA8ED4BFD4D43754EC9693460D15271AB43A59AD6D0F0EEE95424F70920F2C4A08DFDF03661300047CA3A6212E48204C1BE71A846E08DD2D9F1CBDDFF40CA00C10C62B1DD42486C70A09C454293BCA9ED4E7D6657E3F62076A14304943252A88EFA416770E0FBA270A141E7" ,
     "10001" ) ; return  b . encrypt ( a )
}
rsaEncrypt ( $ ( "password" ) . value )
 
我们原来的密钥是通过OPENSSL命令行工具生成的,是一个PEM文件,打开后内容是这样的:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSipVLWBnTtIaLpSkvtmQTJNFl
INLKNmLufvgp9JIpGgFOYU6f1231QFDhbK2dEykNLwaDmCOVHLpR5fm0b/qhZeJ0
zWGgQ7hOyTISiwUM5PGqwAXlfJRS/ZQXe72l7/+ijBEdTZ3U/5okDQA5QTAVWo9Q
JGqKj1IVL0Hs9JwK8wIDAQAB
-----END PUBLIC KEY-----
 
开始的时候我是把这段内容去掉换行符连在一起做为公钥,代码像这样
 
< script  language = "JavaScript"  type = "text/javascript"  src = "rsa.js" >< /script>
< script  type = "text/javascript" >
function  rsaEncrypt ( txt ) {
     var  b = new  RSAKey ;
     b . setPublic ( "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSipVLWBnTtIaLpSkvtmQTJNFlINLKNmLufvgp9JIpGgFOYU6f1231QFDhbK2dEykNLwaDmCOVHLpR5fm0b/qhZeJ0zWGgQ7hOyTISiwUM5PGqwAXlfJRS/ZQXe72l7/+ijBEdTZ3U/5okDQA5QTAVWo9QJGqKj1IVL0Hs9JwK8wIDAQAB" ,
     "10001" ) ; return  b . encrypt ( a )
}
}
< /script>
 
加密完以后,一解密就出错,百思不得其解,于是把rsa.js的内容格式化了一下,发现javascript里的公钥是16进制的字符串,而我的公钥是BASE64的字符串,找到原因后就好做了。

把原来的JAVA里实现 的RSA加密函数改了一下,把BASE64的公钥转成16进制的字符串,心想这下应该没问题了吧,代码如下:
 
     private  static  final  String  RSA_PUBLICE  =
              "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSipVLWBnTtIaLpSkvtmQTJNFl\n"  +
                        "INLKNmLufvgp9JIpGgFOYU6f1231QFDhbK2dEykNLwaDmCOVHLpR5fm0b/qhZeJ0\n"  +
                        "zWGgQ7hOyTISiwUM5PGqwAXlfJRS/ZQXe72l7/+ijBEdTZ3U/5okDQA5QTAVWo9Q\n"  +
                        "JGqKj1IVL0Hs9JwK8wIDAQAB";
     private  static  final  String  ALGORITHM  =  "RSA";
     /**
      * 
      *  @param  algorithm
      *  @param  bysKey
      *  @return
      */
     private  static  PublicKey  getPublicKeyFromX509( String  algorithm,
                                                              String  bysKeythrows  NoSuchAlgorithmExceptionException {
         byte[]  decodedKey  =  Base64. decode( bysKeyBase64. DEFAULT);
         X509EncodedKeySpec  x509  =  new  X509EncodedKeySpec( decodedKey);
         KeyFactory  keyFactory  =  KeyFactory. getInstance( algorithm);
         return  keyFactory. generatePublic( x509);
    }
    
    
     public  static  String  getPublicKey()
    {
         try {
             PublicKey  pubkey  =  getPublicKeyFromX509( ALGORITHMRSA_PUBLICE);
             java. security. interfaces. RSAPublicKey  pk  = ( java. security. interfaces. RSAPublicKey) pubkey;
             return  pk. getModulus(). toString( 16);
        }  catch ( Exception  e) {
              return  null;
        }
    }
 
生成公钥后的javascript代码变成了这样:
 
< script  language = "JavaScript"  type = "text/javascript"  src = "rsa.js" >< /script>
< script  type = "text/javascript" >
function  rsaEncrypt ( txt ) {
     var  b = new  RSAKey ;
     b . setPublic ( "d28a954b5819d3b4868ba5292fb6641324d16520d2ca3662ee7ef829f492291a014e614e9fd76df54050e16cad9d13290d2f06839823951cba51e5f9b46ffaa165e274cd61a043b84ec932128b050ce4f1aac005e57c9452fd94177bbda5efffa28c111d4d9dd4ff9a240d00394130155a8f50246a8a8f52152f41ecf49c0af3" ,
     "10001" ) ; return  b . encrypt ( a )
}
}
< /script>
 
接下来,用这段代码加密了一段文本,然后尝试解密了一下,还是错误!

当然,对于一个优秀的程序员来说,不达目的绝不罢休,于是又去翻JAVA的加密和解密代码。

终于,在看到加密函数最后一段的时候突然明白了,代码如下:
 
                   PublicKey  pubkey  =  getPublicKeyFromX509( ALGORITHMRSA_PUBLICE);
                   Cipher  cipher  =  Cipher. getInstance( "RSA/ECB/PKCS1Padding");
                   cipher. init( Cipher. ENCRYPT_MODEpubkey);
                   byte[]  output  =  cipher. doFinal( plaintext);
                   String  s  =  new  String( Base64. encode( outputBase64. NO_WRAP));
 
原来的加密结果是用BASE64编码的,但是javascript加密出来的字符串感觉明显不是BASE64的,哈哈,胜利在望!

翻看了rsa.js的代码,果然,加密结果转换成了16进制的字符串。

于是百度了一下把BigInteger进行base64编码的方法,找到一个网站 http://www-cs-students.stanford.edu/~tjw/jsbn/  

上面除了RSA加密代码外,还同时支持输出16进制和BASE64的结果,而且提供了测试页面 http://www-cs-students.stanford.edu/~tjw/jsbn/rsa.html

在测试页面输入16进制的公钥后,生成base64的密文,然后用服务器的解密函数尝试解了一下,结果是预料之中的!解密成功!

问题解决,也懒得去折腾qq的rsa.js了,直接把测试页面的所有js下载下来,照着写了一个页面:
文件rsa.hta内容  
< html >
< head >
     < meta  http-equiv = "Content-Type"  content = "text/html; charset=utf-8"  />
< title >RSA title >
< HTA:Application  ID = "oHTA" 
Applicationname = "rsaApp" 
border = "thin" 
borderstyle = "normal" 
caption = "yes" 
icon = "filename.ico" 
maximizebutton = "no"
minimizebutton = "yes" 
showintaskbar = "yes" 
singleinstance = "yes" 
sysmenu = "yes" 
version = "1.0" 
windowstate = "normal"
scroll = "no" >
head >
< body >
< script  language = "JavaScript"  type = "text/javascript"  src = "jsbn.js" > script >
< script  language = "JavaScript"  type = "text/javascript"  src = "prng4.js" > script >
< script  language = "JavaScript"  type = "text/javascript"  src = "rng.js" > script >
< script  language = "JavaScript"  type = "text/javascript"  src = "rsa.js" > script >
< script  language = "JavaScript"  type = "text/javascript"  src = "base64.js" > script >
< script  type = "text/javascript" >
function  rsaEncrypt ( txt ) {
   var  rsa  =  new  RSAKey ( ) ;
   rsa . setPublic ( "d28a954b5819d3b4868ba5292fb6641324d16520d2ca3662ee7ef829f492291a014e614e9fd76df54050e16cad9d13290d2f06839823951cba51e5f9b46ffaa165e274cd61a043b84ec932128b050ce4f1aac005e57c9452fd94177bbda5efffa28c111d4d9dd4ff9a240d00394130155a8f50246a8a8f52152f41ecf49c0af3" ,  "10001" ) ;
   var  res  =  rsa . encrypt ( txt ) ;
   if ( res )  {
     //linebrk(res, 64);  16
     return  linebrk ( hex2b64 ( res ) ,  64 ) ;
   }
   return  "" ;
}
script >
< center >
     < br  />
     < br  />
     < input  type = "text"  id = "txtMing"  size = "52"  />
     < br  />
     < br  />
     < textarea  rows = "10"  cols = "40"  id = "txtMi" > textarea >
     < br  />
     < br  />
     < button  onclick = "document.getElementById('txtMi').value=rsaEncrypt(document.getElementById('txtMing').value)" > button >
center >
< SCRIPT  Language = "VBScript" >
Sub Window_Onload
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * From Win32_DesktopMonitor")
For Each objItem in colItems
intHorizontal = objItem.ScreenWidth
intVertical = objItem.ScreenHeight
Next
intLeft = (intHorizontal - 450) / 2
intTop = (intVertical - 400) / 2
window.resizeTo 450,400
window.moveTo intLeft, intTop
End Sub
SCRIPT >
body >
html >
 
我是位流先锋,我的QQ是 2720574276,微信是 bit0001,欢迎加我为好友交流!

如果你热衷编程技术,欢迎加入我们的交流群: 341313960

你可能感兴趣的:(微信)