今天在原来的系统上增加网页操作的功能,原来系统是JAVA写的,数据传输用的是RSA加密,为了实现网页登录,研究了javascript的RSA加密方法。
我们原来的密钥是通过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
bysKey)
throws
NoSuchAlgorithmException,
Exception {
byte[]
decodedKey
=
Base64.
decode(
bysKey,
Base64.
DEFAULT);
X509EncodedKeySpec
x509
=
new
X509EncodedKeySpec(
decodedKey);
KeyFactory
keyFactory
=
KeyFactory.
getInstance(
algorithm);
return
keyFactory.
generatePublic(
x509);
}
public
static
String
getPublicKey()
{
try {
PublicKey
pubkey
=
getPublicKeyFromX509(
ALGORITHM,
RSA_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(
ALGORITHM,
RSA_PUBLICE);
Cipher
cipher
=
Cipher.
getInstance(
"RSA/ECB/PKCS1Padding");
cipher.
init(
Cipher.
ENCRYPT_MODE,
pubkey);
byte[]
output
=
cipher.
doFinal(
plaintext);
String
s
=
new
String(
Base64.
encode(
output,
Base64.
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