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

  • Post author:
  • Post category:java


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

具体实现思路如下:

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

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

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

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

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

此文即为实现此步而作。

加密算法为RSA:

1。服务端的RSA  java实现。

Java代码

收藏代码


  1. /**

  2. *

  3. */

  4. package

    com.sunsoft.struts.util;

  5. import

    java.io.ByteArrayOutputStream;

  6. import

    java.io.FileInputStream;

  7. import

    java.io.FileOutputStream;

  8. import

    java.io.ObjectInputStream;

  9. import

    java.io.ObjectOutputStream;

  10. import

    java.math.BigInteger;

  11. import

    java.security.KeyFactory;

  12. import

    java.security.KeyPair;

  13. import

    java.security.KeyPairGenerator;

  14. import

    java.security.NoSuchAlgorithmException;

  15. import

    java.security.PrivateKey;

  16. import

    java.security.PublicKey;

  17. import

    java.security.SecureRandom;

  18. import

    java.security.interfaces.RSAPrivateKey;

  19. import

    java.security.interfaces.RSAPublicKey;

  20. import

    java.security.spec.InvalidKeySpecException;

  21. import

    java.security.spec.RSAPrivateKeySpec;

  22. import

    java.security.spec.RSAPublicKeySpec;

  23. import

    javax.crypto.Cipher;

  24. /**

  25. * RSA 工具类。提供加密,解密,生成密钥对等方法。

  26. * 需要到http://www.bouncycastle.org下载bcprov-jdk14-123.jar。

  27. *

  28. */

  29. public


    class

    RSAUtil {

  30. /**

  31. * * 生成密钥对 *

  32. *

  33. * @return KeyPair *

  34. * @throws EncryptException

  35. */

  36. public


    static

    KeyPair generateKeyPair()

    throws

    Exception {

  37. try

    {
  38. KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(

    “RSA”

    ,

  39. new

    org.bouncycastle.jce.provider.BouncyCastleProvider());

  40. final


    int

    KEY_SIZE =

    1024

    ;

    // 没什么好说的了,这个值关系到块加密的大小,可以更改,但是不要太大,否则效率会低
  41. keyPairGen.initialize(KEY_SIZE,

    new

    SecureRandom());
  42. KeyPair keyPair = keyPairGen.generateKeyPair();
  43. saveKeyPair(keyPair);

  44. return

    keyPair;
  45. }

    catch

    (Exception e) {

  46. throw


    new

    Exception(e.getMessage());
  47. }
  48. }

  49. public


    static

    KeyPair getKeyPair()

    throws

    Exception{
  50. FileInputStream fis =

    new

    FileInputStream(

    “C:/RSAKey.txt”

    );
  51. ObjectInputStream oos =

    new

    ObjectInputStream(fis);
  52. KeyPair kp= (KeyPair) oos.readObject();
  53. oos.close();
  54. fis.close();

  55. return

    kp;
  56. }

  57. public


    static


    void

    saveKeyPair(KeyPair kp)

    throws

    Exception{
  58. FileOutputStream fos =

    new

    FileOutputStream(

    “C:/RSAKey.txt”

    );
  59. ObjectOutputStream oos =

    new

    ObjectOutputStream(fos);

  60. //生成密钥
  61. oos.writeObject(kp);
  62. oos.close();
  63. fos.close();
  64. }

  65. /**

  66. * * 生成公钥 *

  67. *

  68. * @param modulus *

  69. * @param publicExponent *

  70. * @return RSAPublicKey *

  71. * @throws Exception

  72. */

  73. public


    static

    RSAPublicKey generateRSAPublicKey(

    byte

    [] modulus,

  74. byte

    [] publicExponent)

    throws

    Exception {
  75. KeyFactory keyFac =

    null

    ;

  76. try

    {
  77. keyFac = KeyFactory.getInstance(

    “RSA”

    ,

  78. new

    org.bouncycastle.jce.provider.BouncyCastleProvider());
  79. }

    catch

    (NoSuchAlgorithmException ex) {

  80. throw


    new

    Exception(ex.getMessage());
  81. }
  82. RSAPublicKeySpec pubKeySpec =

    new

    RSAPublicKeySpec(

    new

    BigInteger(
  83. modulus),

    new

    BigInteger(publicExponent));

  84. try

    {

  85. return

    (RSAPublicKey) keyFac.generatePublic(pubKeySpec);
  86. }

    catch

    (InvalidKeySpecException ex) {

  87. throw


    new

    Exception(ex.getMessage());
  88. }
  89. }

  90. /**

  91. * * 生成私钥 *

  92. *

  93. * @param modulus *

  94. * @param privateExponent *

  95. * @return RSAPrivateKey *

  96. * @throws Exception

  97. */

  98. public


    static

    RSAPrivateKey generateRSAPrivateKey(

    byte

    [] modulus,

  99. byte

    [] privateExponent)

    throws

    Exception {
  100. KeyFactory keyFac =

    null

    ;

  101. try

    {
  102. keyFac = KeyFactory.getInstance(

    “RSA”

    ,

  103. new

    org.bouncycastle.jce.provider.BouncyCastleProvider());
  104. }

    catch

    (NoSuchAlgorithmException ex) {

  105. throw


    new

    Exception(ex.getMessage());
  106. }
  107. RSAPrivateKeySpec priKeySpec =

    new

    RSAPrivateKeySpec(

    new

    BigInteger(
  108. modulus),

    new

    BigInteger(privateExponent));

  109. try

    {

  110. return

    (RSAPrivateKey) keyFac.generatePrivate(priKeySpec);
  111. }

    catch

    (InvalidKeySpecException ex) {

  112. throw


    new

    Exception(ex.getMessage());
  113. }
  114. }

  115. /**

  116. * * 加密 *

  117. *

  118. * @param key

  119. *            加密的密钥 *

  120. * @param data

  121. *            待加密的明文数据 *

  122. * @return 加密后的数据 *

  123. * @throws Exception

  124. */

  125. public


    static


    byte

    [] encrypt(PublicKey pk,

    byte

    [] data)

    throws

    Exception {

  126. try

    {
  127. Cipher cipher = Cipher.getInstance(

    “RSA”

    ,

  128. new

    org.bouncycastle.jce.provider.BouncyCastleProvider());
  129. cipher.init(Cipher.ENCRYPT_MODE, pk);

  130. int

    blockSize = cipher.getBlockSize();

    // 获得加密块大小,如:加密前数据为128个byte,而key_size=1024

  131. // 加密块大小为127

  132. // byte,加密后为128个byte;因此共有2个加密块,第一个127

  133. // byte第二个为1个byte

  134. int

    outputSize = cipher.getOutputSize(data.length);

    // 获得加密块加密后块大小

  135. int

    leavedSize = data.length % blockSize;

  136. int

    blocksSize = leavedSize !=

    0

    ? data.length / blockSize +

    1
  137. : data.length / blockSize;

  138. byte

    [] raw =

    new


    byte

    [outputSize * blocksSize];

  139. int

    i =

    0

    ;

  140. while

    (data.length – i * blockSize >

    0

    ) {

  141. if

    (data.length – i * blockSize > blockSize)
  142. cipher.doFinal(data, i * blockSize, blockSize, raw, i
  143. * outputSize);

  144. else
  145. cipher.doFinal(data, i * blockSize, data.length – i
  146. * blockSize, raw, i * outputSize);

  147. // 这里面doUpdate方法不可用,查看源代码后发现每次doUpdate后并没有什么实际动作除了把byte[]放到

  148. // ByteArrayOutputStream中,而最后doFinal的时候才将所有的byte[]进行加密,可是到了此时加密块大小很可能已经超出了

  149. // OutputSize所以只好用dofinal方法。
  150. i++;
  151. }

  152. return

    raw;
  153. }

    catch

    (Exception e) {

  154. throw


    new

    Exception(e.getMessage());
  155. }
  156. }

  157. /**

  158. * * 解密 *

  159. *

  160. * @param key

  161. *            解密的密钥 *

  162. * @param raw

  163. *            已经加密的数据 *

  164. * @return 解密后的明文 *

  165. * @throws Exception

  166. */

  167. public


    static


    byte

    [] decrypt(PrivateKey pk,

    byte

    [] raw)

    throws

    Exception {

  168. try

    {
  169. Cipher cipher = Cipher.getInstance(

    “RSA”

    ,

  170. new

    org.bouncycastle.jce.provider.BouncyCastleProvider());
  171. cipher.init(cipher.DECRYPT_MODE, pk);

  172. int

    blockSize = cipher.getBlockSize();
  173. ByteArrayOutputStream bout =

    new

    ByteArrayOutputStream(

    64

    );

  174. int

    j =

    0

    ;

  175. while

    (raw.length – j * blockSize >

    0

    ) {
  176. bout.write(cipher.doFinal(raw, j * blockSize, blockSize));
  177. j++;
  178. }

  179. return

    bout.toByteArray();
  180. }

    catch

    (Exception e) {

  181. throw


    new

    Exception(e.getMessage());
  182. }
  183. }

  184. /**

  185. * * *

  186. *

  187. * @param args *

  188. * @throws Exception

  189. */

  190. public


    static


    void

    main(String[] args)

    throws

    Exception {
  191. RSAPublicKey rsap = (RSAPublicKey) RSAUtil.generateKeyPair().getPublic();
  192. String test =

    “hello world”

    ;

  193. byte

    [] en_test = encrypt(getKeyPair().getPublic(),test.getBytes());

  194. byte

    [] de_test = decrypt(getKeyPair().getPrivate(),en_test);
  195. System.out.println(

    new

    String(de_test));
  196. }
  197. }

2.测试页面:

IndexAction.java

Java代码

收藏代码


  1. /*

  2. * Generated by MyEclipse Struts

  3. * Template path: templates/java/JavaClass.vtl

  4. */

  5. package

    com.sunsoft.struts.action;

  6. import

    java.security.interfaces.RSAPrivateKey;

  7. import

    java.security.interfaces.RSAPublicKey;

  8. import

    javax.servlet.http.HttpServletRequest;

  9. import

    javax.servlet.http.HttpServletResponse;

  10. import

    org.apache.struts.action.Action;

  11. import

    org.apache.struts.action.ActionForm;

  12. import

    org.apache.struts.action.ActionForward;

  13. import

    org.apache.struts.action.ActionMapping;

  14. import

    com.sunsoft.struts.util.RSAUtil;

  15. /**

  16. * MyEclipse Struts

  17. * Creation date: 06-28-2008

  18. *

  19. * XDoclet definition:

  20. * @struts.action validate=”true”

  21. */

  22. public


    class

    IndexAction

    extends

    Action {

  23. /*

  24. * Generated Methods

  25. */

  26. /**

  27. * Method execute

  28. * @param mapping

  29. * @param form

  30. * @param request

  31. * @param response

  32. * @return ActionForward

  33. */

  34. public

    ActionForward execute(ActionMapping mapping, ActionForm form,
  35. HttpServletRequest request, HttpServletResponse response)

    throws

    Exception {
  36. RSAPublicKey rsap = (RSAPublicKey) RSAUtil.getKeyPair().getPublic();
  37. String module = rsap.getModulus().toString(

    16

    );
  38. String empoent = rsap.getPublicExponent().toString(

    16

    );
  39. System.out.println(

    “module”

    );
  40. System.out.println(module);
  41. System.out.println(

    “empoent”

    );
  42. System.out.println(empoent);
  43. request.setAttribute(

    “m”

    , module);
  44. request.setAttribute(

    “e”

    , empoent);

  45. return

    mapping.findForward(

    “login”

    );
  46. }
  47. }

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

3。登录页面 login.jsp

Html代码

收藏代码


  1. <

    %@ page

    language

    =

    “java”


    pageEncoding

    =

    “GBK”

    %

    >

  2. <

    %@ taglib

    uri

    =

    “http://struts.apache.org/tags-bean”


    prefix

    =

    “bean”

    %

    >

  3. <

    %@ taglib

    uri

    =

    “http://struts.apache.org/tags-html”


    prefix

    =

    “html”

    %

    >

  4. <

    %@ taglib

    uri

    =

    “http://struts.apache.org/tags-logic”


    prefix

    =

    “logic”

    %

    >

  5. <

    %@ taglib

    uri

    =

    “http://struts.apache.org/tags-tiles”


    prefix

    =

    “tiles”

    %

    >
  6. <!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”

    >

  7. <


    html:html


    lang

    =

    “true”


    >

  8. <


    head


    >

  9. <


    html:base


    />

  10. <


    title


    >

    login

    </


    title


    >

  11. <


    meta


    http-equiv

    =

    “pragma”


    content

    =

    “no-cache”


    >

  12. <


    meta


    http-equiv

    =

    “cache-control”


    content

    =

    “no-cache”


    >

  13. <


    meta


    http-equiv

    =

    “expires”


    content

    =

    “0”


    >

  14. <


    meta


    http-equiv

    =

    “keywords”


    content

    =

    “keyword1,keyword2,keyword3”


    >

  15. <


    meta


    http-equiv

    =

    “description”


    content

    =

    “This is my page”


    >

  16. <!–

  17. <link rel=”stylesheet” type=”text/css” href=”styles.css”>

  18. –>

  19. <


    script


    type

    =

    “text/javascript”


    src

    =

    “js/RSA.js”


    >


    </


    script


    >

  20. <


    script


    type

    =

    “text/javascript”


    src

    =

    “js/BigInt.js”


    >


    </


    script


    >

  21. <


    script


    type

    =

    “text/javascript”


    src

    =

    “js/Barrett.js”


    >


    </


    script


    >

  22. <


    script


    type

    =

    “text/javascript”


    >
  23. function rsalogin()
  24. {
  25. bodyRSA();
  26. var

    result

    =

    encryptedString

    (key, document.getElementById(“pwd”).value);
  27. //alert(result);

  28. loginForm.action

    =

    “login.do?result=”

    +result;
  29. loginForm.submit();
  30. }
  31. var key ;
  32. function bodyRSA()
  33. {
  34. setMaxDigits(130);

  35. key

    =

    new

    RSAKeyPair(“10001″,””,”8c1cd09a04ed01aafe70dc84c5f32ae23a16fe8fc8898aba6797c5a9c708720de4f08dbf086af429fc51c0636208f56de20a8ab5686affd9bdfb643ae1e90d5617155c4867eef06b0884ba8ecd187907c7069ae3eed4f0155eeca6573411864035ae803ad8fd91a0cc479f27e41b19c13465ab30f3cfbfd14de56f49cbd09481″);
  36. }

  37. </


    script


    >

  38. </


    head


    >

  39. <


    body


    >

  40. <


    html:form


    action

    =

    “login”


    method

    =

    “post”


    focus

    =

    “username”


    >

  41. <


    table


    border

    =

    “0”


    >

  42. <


    tr


    >

  43. <


    td


    >

    Login:

    </


    td


    >

  44. <


    td


    >


    <


    html:text


    property

    =

    “username”


    />


    </


    td


    >

  45. </


    tr


    >

  46. <


    tr


    >

  47. <


    td


    >

    Password:

    </


    td


    >

  48. <


    td


    >


    <


    html:password


    property

    =

    “password”


    styleId

    =

    “pwd”


    />


    </


    td


    >

  49. </


    tr


    >

  50. <


    tr


    >

  51. <


    td


    colspan

    =

    “2”


    align

    =

    “center”


    >


    <


    input


    type

    =

    “button”


    value

    =

    “SUBMIT”


    onclick

    =

    “rsalogin();”


    />


    </


    td


    >

  52. </


    tr


    >

  53. </


    table


    >

  54. </


    html:form


    >

  55. </


    body


    >

  56. </


    html:html


    >

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

Java代码

收藏代码


  1. /*

  2. * Generated by MyEclipse Struts

  3. * Template path: templates/java/JavaClass.vtl

  4. */

  5. package

    com.sunsoft.struts.action;

  6. import

    java.math.BigInteger;

  7. import

    javax.servlet.http.HttpServletRequest;

  8. import

    javax.servlet.http.HttpServletResponse;

  9. import

    org.apache.struts.action.Action;

  10. import

    org.apache.struts.action.ActionForm;

  11. import

    org.apache.struts.action.ActionForward;

  12. import

    org.apache.struts.action.ActionMapping;

  13. import

    com.sunsoft.struts.util.RSAUtil;

  14. /**

  15. * MyEclipse Struts

  16. * Creation date: 06-28-2008

  17. *

  18. * XDoclet definition:

  19. * @struts.action path=”/login” name=”loginForm” input=”/login.jsp” scope=”request” validate=”true”

  20. * @struts.action-forward name=”error” path=”/error.jsp”

  21. * @struts.action-forward name=”success” path=”/success.jsp”

  22. */

  23. public


    class

    LoginAction

    extends

    Action {

  24. /*

  25. * Generated Methods

  26. */

  27. /**

  28. * Method execute

  29. * @param mapping

  30. * @param form

  31. * @param request

  32. * @param response

  33. * @return ActionForward

  34. */

  35. public

    ActionForward execute(ActionMapping mapping, ActionForm form,
  36. HttpServletRequest request, HttpServletResponse response)

    throws

    Exception{

  37. //LoginForm loginForm = (LoginForm) form;
  38. String result = request.getParameter(

    “result”

    );
  39. System.out.println(

    “原文加密后为:”

    );
  40. System.out.println(result);

  41. byte

    [] en_result =

    new

    BigInteger(result,

    16

    ).toByteArray();
  42. System.out.println(

    “转成byte[]”

    +

    new

    String(en_result));

  43. byte

    [] de_result = RSAUtil.decrypt(RSAUtil.getKeyPair().getPrivate(),en_result);
  44. System.out.println(

    “还原密文:”

    );
  45. System.out.println(

    new

    String(de_result));
  46. StringBuffer sb =

    new

    StringBuffer();
  47. sb.append(

    new

    String(de_result));
  48. System.out.println(sb.reverse().toString());

  49. return

    mapping.findForward(

    “success”

    );
  50. }
  51. }

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

4。login.jsp所调用的js


  • js.rar

    (6.4 KB)
  • 描述: login.jsp所调用的javascript,有:RSA.jsBigInt.jsBarrett.js

原文地址:http://sunxboy.iteye.com/blog/209156