RSA非对称加密(java版)

201 阅读4分钟

RSA非对称加密(java版)

对于什么是RSA百度上写的很清楚,我就不重复了,直接看代码说问题。

webRSAweb端采用公钥加密需要依赖[jsencrypt.js](http://passport.cnblogs.com/scripts/jsencrypt.min.js)
    引用的时候很简单:
	    var encrypt = new JSEncrypt();
		encrypt.setPublicKey("后台传过来的公钥");
		encrypt.encrypt("需要加密的数据")

java后台RSA加密的工具类:
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;
 
import org.apache.commons.codec.binary.Base64;
 
 
public class RSAUtils {
     
	  public static final String KEY_ALGORITHM = "RSA";
	    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

	    private static final String PUBLIC_KEY = "RSAPublicKey";
	    private static final String PRIVATE_KEY = "RSAPrivateKey";

	    public static byte[] decryptBASE64(String key) {
	        return Base64.decodeBase64(key);
	    }

	    public static String encryptBASE64(byte[] bytes) {
	        return Base64.encodeBase64String(bytes);
	    }

	    /**
	     * 用私钥对信息生成数字签名
	     *
	     * @param data       加密数据
	     * @param privateKey 私钥
	     * @return
	     * @throws Exception
	     */
	    public static String sign(byte[] data, String privateKey) throws Exception {
	        // 解密由base64编码的私钥
	        byte[] keyBytes = decryptBASE64(privateKey);
	        // 构造PKCS8EncodedKeySpec对象
	        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
	        // KEY_ALGORITHM 指定的加密算法
	        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
	        // 取私钥匙对象
	        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
	        // 用私钥对信息生成数字签名
	        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
	        signature.initSign(priKey);
	        signature.update(data);
	        return encryptBASE64(signature.sign());
	    }

	    /**
	     * 校验数字签名
	     *
	     * @param data      加密数据
	     * @param publicKey 公钥
	     * @param sign      数字签名
	     * @return 校验成功返回true 失败返回false
	     * @throws Exception
	     */
	    public static boolean verify(byte[] data, String publicKey, String sign)
	            throws Exception {
	        // 解密由base64编码的公钥
	        byte[] keyBytes = decryptBASE64(publicKey);
	        // 构造X509EncodedKeySpec对象
	        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
	        // KEY_ALGORITHM 指定的加密算法
	        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
	        // 取公钥匙对象
	        PublicKey pubKey = keyFactory.generatePublic(keySpec);
	        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
	        signature.initVerify(pubKey);
	        signature.update(data);
	        // 验证签名是否正常
	        return signature.verify(decryptBASE64(sign));
	    }

	    public static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception{
	        // 对密钥解密
	        byte[] keyBytes = decryptBASE64(key);
	        // 取得私钥
	        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
	        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
	        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
	        // 对数据解密
	        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
	        cipher.init(Cipher.DECRYPT_MODE, privateKey);
	        return cipher.doFinal(data);
	    }

	    /**
	     * 解密<br>
	     * 用私钥解密
	     *
	     * @param data
	     * @param key
	     * @return
	     * @throws Exception
	     */
	    public static byte[] decryptByPrivateKey(String data, String key)
	            throws Exception {
	        return decryptByPrivateKey(decryptBASE64(data),key);
	    }

	    /**
	     * 解密<br>
	     * 用公钥解密
	     *
	     * @param data
	     * @param key
	     * @return
	     * @throws Exception
	     */
	    public static byte[] decryptByPublicKey(byte[] data, String key)
	            throws Exception {
	        // 对密钥解密
	        byte[] keyBytes = decryptBASE64(key);
	        // 取得公钥
	        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
	        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
	        Key publicKey = keyFactory.generatePublic(x509KeySpec);
	        // 对数据解密
	        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
	        cipher.init(Cipher.DECRYPT_MODE, publicKey);
	        return cipher.doFinal(data);
	    }

	    /**
	     * 加密<br>
	     * 用公钥加密
	     *
	     * @param data
	     * @param key
	     * @return
	     * @throws Exception
	     */
	    public static byte[] encryptByPublicKey(String data, String key)
	            throws Exception {
	        // 对公钥解密
	        byte[] keyBytes = decryptBASE64(key);
	        // 取得公钥
	        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
	        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
	        Key publicKey = keyFactory.generatePublic(x509KeySpec);
	        // 对数据加密
	        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
	        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
	        return cipher.doFinal(data.getBytes());
	    }

	    /**
	     * 加密<br>
	     * 用私钥加密
	     *
	     * @param data
	     * @param key
	     * @return
	     * @throws Exception
	     */
	    public static byte[] encryptByPrivateKey(byte[] data, String key)
	            throws Exception {
	        // 对密钥解密
	        byte[] keyBytes = decryptBASE64(key);
	        // 取得私钥
	        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
	        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
	        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
	        // 对数据加密
	        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
	        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
	        return cipher.doFinal(data);
	    }

	    /**
	     * 取得私钥
	     *
	     * @param keyMap
	     * @return
	     * @throws Exception
	     */
	    public static String getPrivateKey(Map<String, Key> keyMap)
	            throws Exception {
	        Key key = (Key) keyMap.get(PRIVATE_KEY);
	        return encryptBASE64(key.getEncoded());
	    }

	    /**
	     * 取得公钥
	     *
	     * @param keyMap
	     * @return
	     * @throws Exception
	     */
	    public static String getPublicKey(Map<String, Key> keyMap)
	            throws Exception {
	        Key key = keyMap.get(PUBLIC_KEY);
	        return encryptBASE64(key.getEncoded());
	    }

	    /**
	     * 初始化密钥
	     *客户端通过公钥进行加密,服务端通过私钥进行解密
	     * JS端应用需要依赖jsencrypt.js 下载地址http://www.oschina.net/action/code/download?code=48994&id=71045
	     * @return
	     * @throws Exception
	     */
	    public static Map<String, Key> initKey() throws Exception {
	        KeyPairGenerator keyPairGen = KeyPairGenerator
	                .getInstance(KEY_ALGORITHM);
	        keyPairGen.initialize(1024);
	        KeyPair keyPair = keyPairGen.generateKeyPair();
	        Map<String, Key> keyMap = new HashMap(2);
	        keyMap.put(PUBLIC_KEY, keyPair.getPublic());// 公钥
	        keyMap.put(PRIVATE_KEY, keyPair.getPrivate());// 私钥
	        return keyMap;
	    }
}

生成公,私钥

	    Map<String, Key> keyMap = RSAUtils.initKey();
	    publicKey = RSAUtils.getPublicKey(keyMap);
	    privateKey = RSAUtils.getPrivateKey(keyMap);

私钥解密

String temp= new String(RSAUtils.decryptByPrivateKey("加密过的数据","后台生成的私钥"),"utf-8")

大体就这么多,再说问题:

  1. byte[] 转String的时候注意编码格式
  2. 在web端传到java后台的时候注意字符替换(RSA加密的数据中加号会被替换成空格,然后就解密不出来了)
  3. 这次是为以前的客户升级,已经没有源码了,以后可以tomcat远程调试(参考链接
  4. 如果服务器操作系统是win,可以把控制台打印的东西写入文件查看( System.setErr(new PrintStream(new FileOutputStream("output.txt"))) 默认在tomcat的bin目录中)
  5. 以后想在jar中加class,但是没办法打包时,可以按照文件目录建文件,把class文件直接放入文件目录中就可以,jvm读的时候会先读它