如何实现用javascript实现rsa加解密

JavaScript048

如何实现用javascript实现rsa加解密,第1张

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

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

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

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

步骤:

服务端的RSA  Java实现:

/** 

 *  

 */  

package com.sunsoft.struts.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  

  

  

  

/** 

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

 * 需要到

下载bcprov-jdk14-123.jar。 

 *  

 */  

public class RSAUtil {  

    /** 

     * * 生成密钥对 * 

     *  

     * @return KeyPair * 

     * @throws EncryptException 

     */  

    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()  

            saveKeyPair(keyPair)  

            return keyPair  

        } catch (Exception e) {  

            throw new Exception(e.getMessage())  

        }  

    }  

      

    public static KeyPair getKeyPair()throws Exception{  

        FileInputStream fis = new FileInputStream("C:/RSAKey.txt")  

         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("C:/RSAKey.txt")  

         ObjectOutputStream oos = new ObjectOutputStream(fos)  

         //生成密钥  

         oos.writeObject(kp)  

         oos.close()  

         fos.close()  

    }  

  

    /** 

     * * 生成公钥 * 

     *  

     * @param modulus * 

     * @param publicExponent * 

     * @return RSAPublicKey * 

     * @throws Exception 

     */  

    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())  

        }  

    }  

  

    /** 

     * * 生成私钥 * 

     *  

     * @param modulus * 

     * @param privateExponent * 

     * @return RSAPrivateKey * 

     * @throws Exception 

     */  

    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())  

        }  

    }  

  

    /** 

     * * 加密 * 

     *  

     * @param key 

     *            加密的密钥 * 

     * @param data 

     *            待加密的明文数据 * 

     * @return 加密后的数据 * 

     * @throws Exception 

     */  

    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())  

        }  

    }  

  

    /** 

     * * 解密 * 

     *  

     * @param key 

     *            解密的密钥 * 

     * @param raw 

     *            已经加密的数据 * 

     * @return 解密后的明文 * 

     * @throws Exception 

     */  

    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())  

        }  

    }  

  

    /** 

     * * * 

     *  

     * @param args * 

     * @throws Exception 

     */  

    public static void main(String[] args) throws Exception {  

        RSAPublicKey rsap = (RSAPublicKey) RSAUtil.generateKeyPair().getPublic()  

        String test = "hello world"  

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

        byte[] de_test = decrypt(getKeyPair().getPrivate(),en_test)  

        System.out.println(new String(de_test))  

    }  

}

测试页面IndexAction.java:

/* 

 * Generated by MyEclipse Struts 

 * Template path: templates/java/JavaClass.vtl 

 */  

package com.sunsoft.struts.action  

  

import java.security.interfaces.RSAPrivateKey  

import java.security.interfaces.RSAPublicKey  

  

import javax.servlet.http.HttpServletRequest  

import javax.servlet.http.HttpServletResponse  

  

import org.apache.struts.action.Action  

import org.apache.struts.action.ActionForm  

import org.apache.struts.action.ActionForward  

import org.apache.struts.action.ActionMapping  

  

import com.sunsoft.struts.util.RSAUtil  

  

/**  

 * MyEclipse Struts 

 * Creation date: 06-28-2008 

 *  

 * XDoclet definition: 

 * @struts.action validate="true" 

 */  

public class IndexAction extends Action {  

    /* 

     * Generated Methods 

     */  

  

    /**  

     * Method execute 

     * @param mapping 

     * @param form 

     * @param request 

     * @param response 

     * @return ActionForward 

     */  

    public ActionForward execute(ActionMapping mapping, ActionForm form,  

            HttpServletRequest request, HttpServletResponse response)throws Exception {  

          

        RSAPublicKey rsap = (RSAPublicKey) RSAUtil.getKeyPair().getPublic()  

        String module = rsap.getModulus().toString(16)  

        String empoent = rsap.getPublicExponent().toString(16)  

        System.out.println("module")  

        System.out.println(module)  

        System.out.println("empoent")  

        System.out.println(empoent)  

        request.setAttribute("m", module)  

        request.setAttribute("e", empoent)  

        return mapping.findForward("login")  

    }  

}

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

npm 安装 jsrsasign

封装方法

前端H5的使用

定义方法

使用方法

使用自己的私钥签名

使用后台交换的平台公钥验证签名

签名的工作最好在后端完成,前台不暴露公钥私钥。