RSA是一种非对称加密技术,可以用公钥加密再用私钥解密,反之亦然。RSAUtils只实现了公钥加密和私钥解密。实现的过程中踩了几个坑,不过还是不太理解为什么用RSA加解密之后还要用Base64进行加解码。
package com.yy.utils;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import com.sun.org.apache.xml.internal.security.utils.Base64;
/**
* @Description: A encode and decode Utils class, based RSA algorithm.
* @author: leijing
* @date: 2016年11月10日 上午11:35:25
*/
public class RSAUtils {
private static Logger logger = Logger.getLogger(RSAUtils.class);
/* 指定加密算法为DESede */
private static final String ALGORITHM = "RSA";
/* 指定key的大小 */
private static final int KEYSIZE = 1024;
private KeyPair keyPair = null;
private String id = "";
private static final String BASE_FILE_PATH = Thread.currentThread().getContextClassLoader().getResource("").getPath();
private static final String FILE_SUFFIX = ".txt";
/* RSA最大加密明文大小 */
private static final int MAX_ENCRYPT_BLOCK = 117;
/* RSA最大解密密文大小 */
private static final int MAX_DECRYPT_BLOCK = 128;
/**
* @Description: create a RSAUtils object
* @param id
* @return: RSAUtils
* @author: leijing
* @date: 2016年11月10日 上午11:37:13
*/
public static RSAUtils newInstance(String id){
RSAUtils rsaUtils = new RSAUtils();
rsaUtils.id = id;
rsaUtils.init();
return rsaUtils;
}
/**
* @Description: init KeyPair object
* @return: void
* @author: leijing
* @date: 2016年11月10日 上午11:36:26
*/
private void init(){
try{
File file = genFile();
if(!file.exists()){//if file isn't exist, execute genKeyPair function
genKeyPair();
if(null != this.keyPair){
writeObjectToFile(file, this.keyPair);
}
}else{//if file is exist,read object from file
Object obj = readObjectFromFile(file);
if(null != obj){
this.keyPair = (KeyPair)obj;
}
}
}catch(Exception e){
logger.error("genKeyPair error:",e);
}
}
/**
* @Description: read KeyPair object from file
* @param file
* @throws Exception
* @return: Object
* @author: leijing
* @date: 2016年11月10日 上午11:39:32
*/
public Object readObjectFromFile(File file) throws Exception{
ObjectInputStream ois = null;
Object obj = null;
try {
if(!file.exists()){
logger.error("file not found!");
}
ois = new ObjectInputStream(new FileInputStream(file));
obj = ois.readObject();
} catch (Exception e) {
logger.error("readFromFile erroe:",e);
}finally{
if (null != ois) {
ois.close();
}
}
return obj;
}
/**
* @Description: generate a KeyPair object
* @return: void
* @author: leijing
* @date: 2016年11月10日 上午11:40:30
*/
private void genKeyPair(){
try{
/*创建一个KeyPairGenerator对象 */
KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM);
kpg.initialize(KEYSIZE);
/*生成密匙对 */
this.keyPair = kpg.generateKeyPair();
}catch(Exception e){
logger.error("genKeyPair error:",e);
}
}
/**
* @Description: get a File object
* @return: File
* @author: leijing
* @date: 2016年11月10日 上午11:41:20
*/
private File genFile(){
String filePath = genFilePath();
File file = new File(filePath);
return file;
}
/**
* @Description: get file path
* @return: String
* @author: leijing
* @date: 2016年11月10日 上午11:41:10
*/
private String genFilePath(){
if(StringUtils.isNotBlank(id)){
return BASE_FILE_PATH.concat(id).concat(FILE_SUFFIX);
}else{
return "";
}
}
/**
* @Description: get publickey
* @return: String
* @author: leijing
* @date: 2016年11月10日 上午11:41:50
*/
private String getPublicKey(){
return Base64Utils.encode(this.keyPair.getPublic().getEncoded());
}
/**
* @Description: get privateKey
* @return: String
* @author: leijing
* @date: 2016年11月10日 上午11:42:30
*/
private String getPrivateKey(){
return Base64Utils.encode(this.keyPair.getPrivate().getEncoded());
}
/**
* @Description: decode by privatekey
* @param cryptograph
* @return: String
* @author: leijing
* @date: 2016年11月10日 上午11:43:29
*/
public String decode(byte[] cryptograph){
ByteArrayOutputStream out = new ByteArrayOutputStream();
try{
if(null == keyPair || null == keyPair.getPrivate()){
logger.info("decode skipped!Because keyPair is null!");
return "";
}
// String key = getPrivateKey();
// byte[] keyBytes = Base64Utils.decode(key);
// PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
// KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
// Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
// Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
Key privateKey = keyPair.getPrivate();
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
if(cryptograph.length <= MAX_DECRYPT_BLOCK){//不大于128字节的一次性解密
byte[] bytes = cipher.doFinal(cryptograph);
out.write(bytes ,0,bytes.length);
}else{//大于128字节就要分段解密
for(int i = 0 ; i < cryptograph.length; i+= MAX_DECRYPT_BLOCK){
int inputLength = (cryptograph.length - i >= MAX_DECRYPT_BLOCK )?MAX_DECRYPT_BLOCK: (cryptograph.length - i);
byte[] bytes = cipher.doFinal(cryptograph, i, inputLength);
out.write(bytes ,0,bytes.length);
}
}
}
catch(Exception e){
logger.error("decode error:",e);
}finally{
try {
out.close();
} catch (IOException e) {
logger.error("close ByteArrayOutputStream error:",e);
}
}
return new String(out.toByteArray());
}
/**
* @Description: encode by publickey
* @param source
* @return: String
* @author: leijing
* @date: 2016年11月10日 上午11:45:29
*/
public String encode(byte[] source){
ByteArrayOutputStream out = new ByteArrayOutputStream();
try{
if(null == keyPair || null == keyPair.getPublic()){
logger.info("encode skipped!Because keyPair is null!");
return "";
}
// String key = getPublicKey();
// byte[] keyBytes = Base64Utils.decode(key);
// X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
// KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
// Key publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
// Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
Key publicKey = keyPair.getPublic();
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
if(source.length <= MAX_ENCRYPT_BLOCK){//不大于117字节的一次性加密
byte[] bytes = cipher.doFinal(source);
out.write(bytes ,0,bytes.length);
}else{//大于117字节分段加密
for(int i = 0 ; i < source.length; i+= MAX_ENCRYPT_BLOCK){
int inputLength = (source.length - i >= MAX_ENCRYPT_BLOCK )?MAX_ENCRYPT_BLOCK: (source.length - i);
byte[] bytes = cipher.doFinal(source, i, inputLength);
out.write(bytes ,0,bytes.length);
}
}
}catch(Exception e){
logger.error("encode error:",e);
}finally{
try {
out.close();
} catch (IOException e) {
logger.error("close ByteArrayOutputStream error:",e);
}
}
return Base64.encode(out.toByteArray());
}
/**
* @Description: write Object to File
* @param file
* @param obj
* @return: void
* @author: leijing
* @date: 2016年11月10日 上午11:54:40
*/
private void writeObjectToFile(File file , Object obj) {
long start = System.currentTimeMillis();
ObjectOutputStream oos = null;
try{
if(!file.exists()){
file.createNewFile();
}
oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(obj);
oos.flush();
}catch(Exception e){
logger.error("writeTofile error:",e);
}finally{
if(null != oos){
try {
oos.close();
} catch (IOException e) {
logger.error("file close error:",e);
}
}
}
logger.info("write object to file successful! Spent "+(System.currentTimeMillis() - start) +"ms.");
}
public static void main(String[] args) {
try{
RSAUtils rsaUtils = RSAUtils.newInstance("leijing");
String source = "Welcome to YY Inc!";
logger.info("source:"+source);
String cryptograph = rsaUtils.encode(source.getBytes());
logger.info("cryptograph:"+cryptograph);
byte[] decodedData = Base64Utils.decode(cryptograph);
String sourceStr = rsaUtils.decode(decodedData);
logger.info("sourceStr:"+sourceStr);
}catch(Exception e){
logger.error("main error:",e);
}
}
}
运行结果: