java安全相关加解密工具类
package test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.cert.Certificate;
import java.util.Date;
import java.util.Enumeration;
import java.util.Properties;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.sun.crypto.provider.SunJCE;
/**
*
* 安全方面的工具类
* 如:DES、MD5、SHA-1、RSA、DSA、P12等等
*
*/
public final class SecurityUtil
{
private static Log log=LogFactory.getLog(SecurityUtil.class);
public static final String ALGORITHM_TYPE_MD5="MD5";
public static final String ALGORITHM_TYPE_SHA="SHA-1";
public static final String ALGORITHM_TYPE_DSA="DSA";
public static final String ALGORITHM_TYPE_MD5withRSA="MD5withRSA";
public static final String ALGORITHM_TYPE_RSA="RSA";
public static final String ALGORITHM_TYPE_DES="DES";
public static final String ALGORITHM_TYPE_DESede="DESede";
public static final String ALGORITHM_TYPE_Blowfish="Blowfish";
/**
* 生成消息摘要
* @param text 源字符
* @param algorithm 生成摘要的算法如:MD5、SHA-1
* @return 小写16进制字符串,失败返回""
*/
public static String getMessageDigest(String text,String algorithm)
{
try
{
byte[] bs=text.getBytes();
MessageDigest md=MessageDigest.getInstance(algorithm);
md.update(bs);
byte[] digestBytes=md.digest();
return byte2hex(digestBytes);
}
catch (NoSuchAlgorithmException e)
{
log.error(e);
}
return "";
}
/**
* 把字节转成小写的16进制字符串
* @param b 字节数组
* @return 小写的16进制字符串
*/
public static String byte2hex(byte[] b)
{
String hs="";
String stmp="";
for (int n=0;n<b.length;n++)
{
stmp=(java.lang.Integer.toHexString(b[n] & 0XFF));
if (stmp.length()==1)
{
hs=hs+"0"+stmp;
}
else
{
hs+=stmp;
}
}
return hs.toLowerCase();
}
/**
* 16进制转byte
* @param hex 16进制字符串
* @return
*/
public static byte[] hex2byte(String hex)
{
byte b[]=hex.toLowerCase().getBytes();
if ((b.length % 2) != 0)
{
throw new IllegalArgumentException("长度不是偶数");
}
byte[] b2 = new byte[b.length / 2];
for (int n = 0; n < b.length; n += 2)
{
String item = new String(b, n, 2);
b2[n/2] = (byte)Integer.parseInt(item, 16);
}
return b2;
}
/**
* 针对非对称处理
* 根据algorithm参数生成公、私钥文件(密钥生成器的长度为512,随机产生器字串为时间戳字符)
* 以下涉及到的文件都是对象流格式保存的
* @param privateKeyPath 私钥文件生成路径(含文件名)
* @param publicKeyPath 公钥文件生成路径(含文件名)
* @param algorithm 算法目前只有:RSA和DSA,失败不生成文件
*/
public static void keyPairGenerator2File(String privateKeyPath,String publicKeyPath,String algorithm)
{
String randomText=(new Date()).toString();
KeyPairGenerator keygen=null;
try
{
keygen = KeyPairGenerator.getInstance(algorithm);
}
catch (NoSuchAlgorithmException e1)
{
log.error(e1);
return;
}
/*
* 如果设定随机产生器就用如相代码初始化
*/
SecureRandom secrand=new SecureRandom();
/*
* 初始化随机产生器
*/
secrand.setSeed(randomText.getBytes());
/*
* 初始化密钥生成器
*/
keygen.initialize(512,secrand);
/*
* 生成密钥公钥pubkey和私钥prikey
* 生成密钥组
*/
KeyPair keys=keygen.generateKeyPair();
PublicKey pubkey=keys.getPublic();
PrivateKey prikey=keys.getPrivate();
/*
* 分别保存在myprikey.dat和mypubkey.dat中,以便下次不在生成
* 生成密钥对的时间比较长
*/
ObjectOutputStream out=null;
try
{
out = new ObjectOutputStream(new FileOutputStream(privateKeyPath));
out.writeObject(prikey);
out.close();
out=new ObjectOutputStream(new FileOutputStream(publicKeyPath));
out.writeObject(pubkey);
out.close();
out=null;
}
catch (Exception e)
{
log.error(e);
}
finally
{
if(out!=null)
{
try
{
out.close();
}
catch (IOException e)
{
log.error(e);
}
}
}
}
/**
* 用私钥privateKeyPath对sourceText内容加密
* @param privateKeyPath 私钥文件地址
* @param sourceText 明文信息
* @param algorithm 算法. 算法类型目前只有DSA、MD5withRSA(注意:privateKeyPath文件格式必须是与该参数类型对应否则不对报错)
* @return 成功返回加密(即签名)后的十六进制内容否则为null
*/
public static String signature(String privateKeyPath,String sourceText,String algorithm)
{
PrivateKey myprikey=getPrivateKey(privateKeyPath);
return signature(myprikey,sourceText,algorithm);
}
public static String signature(PrivateKey myprikey,String sourceText,String algorithm)
{
/*
* 初始一个Signature对象,并用私钥对信息签名
*/
Signature signet=null;
try
{
signet = Signature.getInstance(algorithm);
signet.initSign(myprikey);
signet.update(sourceText.getBytes());
byte[] signed=signet.sign();
BigInteger bi=new BigInteger(signed);
return bi.toString(16);
}
catch (Exception e)
{
log.error(e);
return null;
}
}
/**
* 验证sourceText内容是否是由主方(即privateKey)签署过来的数据
* @param publicKeyPath 公钥地址
* @param sourceText 主方发送过来的数据
* @param signatureHexStr 主方签名信息(十六进制字符)
* @param algorithm 算法.算法类型目前只有DSA、MD5withRSA(注意:privateKeyPath文件格式必须是与该参数类型对应否则不对报错)
* @return
*/
public static boolean verifySignature(String publicKeyPath,String sourceText,String signatureHexStr,String algorithm)
{
PublicKey pubkey=getPublicKey(publicKeyPath);
return verifySignature(pubkey,sourceText,signatureHexStr,algorithm);
}
public static boolean verifySignature(PublicKey pubkey,String sourceText,String signatureHexStr,String algorithm)
{
BigInteger bi=new BigInteger(signatureHexStr, 16);
byte[] signed=bi.toByteArray();
/*
* 初始一个Signature对象,并用公钥和签名进行验证
*/
Signature signetcheck=null;
try {
signetcheck = Signature.getInstance(algorithm);
signetcheck.initVerify(pubkey);
signetcheck.update(sourceText.getBytes());
return signetcheck.verify(signed);
}
catch (Exception e)
{
log.error(e);
return false;
}
}
/**
* 针对非对称处理
* 根据algorithm参数与privateKeyPath私钥文件对sourceText进行签名并生成签名文件:signatrueFilePath
* 说明:生成的签名文件含两部分第一部分为sourceText内容;第二部分为签名内容
* 以下涉及到的文件都是对象流格式保存的
* @param privateKeyPath 私钥文件路径
* @param sourceText 签名源文本信息
* @param signatrueFilePath 生成的签名文件路径(含文件名)
* @param algorithm 算法类型目前只有DSA、MD5withRSA(注意:privateKeyPath文件格式必须是与该参数类型对应否则不对报错)
*/
public static void signature2File(String privateKeyPath,String sourceText,
String signatrueFilePath,String algorithm)
{
PrivateKey myprikey=getPrivateKey(privateKeyPath);
signature2File(myprikey,sourceText,signatrueFilePath,algorithm);
}
public static void signature2File(PrivateKey myprikey,String sourceText,
String signatrueFilePath,String algorithm)
{
ObjectOutputStream out=null;
try
{
/*
* 初始一个Signature对象,并用私钥对信息签名
*/
Signature signet=Signature.getInstance(algorithm);
signet.initSign(myprikey);
signet.update(sourceText.getBytes());
byte[] signed=signet.sign();
/*
* 把信息和签名保存在一个文件中(signatrueFilePath)
*/
out=new ObjectOutputStream(new FileOutputStream(signatrueFilePath));
/*
* 第一部分
*/
out.writeObject(sourceText);
/*
* 第二部分
*/
out.writeObject(signed);
out.close();
out=null;
}
catch (Exception e)
{
log.error(e);
}
finally
{
if(out!=null)
{
try
{
out.close();
}
catch (IOException e)
{
log.error(e);
}
}
}
}
/**
* 针对非对称处理
* 用publicKeyPath文件验证signatureFile文件是否正确
* 以下涉及到的文件都是对象流格式保存的
* @param publicKeyPath 公钥文件路径
* @param signatureFile 签名文件(含源内容)
* 第一部分为源内容,第二部分为签名内容
* @param algorithm 算法类型:DSA、MD5withRSA
* @return 正确返回true,失败或不正确返回false
*/
public static boolean verifySignature(String publicKeyPath,String signatureFile,String algorithm)
{
ObjectInputStream in=null;
try
{
PublicKey pubkey=getPublicKey(publicKeyPath);
/*
* 读入签名和信息
*/
in=new ObjectInputStream(new FileInputStream(signatureFile));
/*
* 第一部分为源内容
*/
String info=(String)in.readObject();
/*
* 第二部分为签名内容
*/
byte[] signed=(byte[])in.readObject();
in.close();
in=null;
/*
* 初始一个Signature对象,并用公钥和签名进行验证
*/
Signature signetcheck=Signature.getInstance(algorithm);
signetcheck.initVerify(pubkey);
signetcheck.update(info.getBytes());
return signetcheck.verify(signed);
}
catch (Exception e)
{
log.error(e);
return false;
}
finally
{
if(in!=null)
{
try
{
in.close();
}
catch (IOException e)
{
log.error(e);
}
}
}
}
public static boolean verifySignature(PublicKey pubkey,String signatureFile,String algorithm)
{
ObjectInputStream in=null;
try
{
/*
* 读入签名和信息
*/
in=new ObjectInputStream(new FileInputStream(signatureFile));
/*
* 第一部分为源内容
*/
String info=(String)in.readObject();
/*
* 第二部分为签名内容
*/
byte[] signed=(byte[])in.readObject();
in.close();
in=null;
/*
* 初始一个Signature对象,并用公钥和签名进行验证
*/
Signature signetcheck=Signature.getInstance(algorithm);
signetcheck.initVerify(pubkey);
signetcheck.update(info.getBytes());
return signetcheck.verify(signed);
}
catch (Exception e)
{
log.error(e);
return false;
}
finally
{
if(in!=null)
{
try
{
in.close();
}
catch (IOException e)
{
log.error(e);
}
}
}
}
/**
* 针对非对称处理
* 取得公钥对象(针对于本util生成的公钥文件)
* @param publicKeyPath 公钥文件路径
* @return 成功返回对象,失败返回null
*/
public static PublicKey getPublicKey(String publicKeyPath)
{
FileInputStream fis=null;
try
{
fis=new FileInputStream(publicKeyPath);
return getPublicKey(fis);
}
catch (Exception e)
{
log.error(e);
return null;
}
finally
{
try
{
if(fis!=null)
{
fis.close();
}
}
catch (Exception e)
{
log.error(e);
}
}
}
/**
* 针对非对称处理
* 取得公钥对象(针对于本util生成的公钥文件)
* @param publicKeyIs 公钥文件路径
* @return 成功返回对象,失败返回null
*/
public static PublicKey getPublicKey(InputStream publicKeyIs)
{
ObjectInputStream in=null;
try
{
in=new ObjectInputStream(publicKeyIs);
PublicKey pubkey=(PublicKey)in.readObject();
in.close();
in=null;
return pubkey;
}
catch(Exception e)
{
log.error(e);
return null;
}
finally
{
if(in!=null)
{
try
{
in.close();
}
catch (IOException e)
{
log.error(e);
}
}
}
}
/**
* 针对非对称处理
* 取得私钥对象(针对于本util生成的私钥文件)
* @param privateKeyPath 私钥文件路径
* @return 成功返回对象,失败返回null
*/
public static PrivateKey getPrivateKey(String privateKeyPath)
{
FileInputStream fis=null;
try
{
fis = new FileInputStream(privateKeyPath);
return getPrivateKey(fis);
}
catch (FileNotFoundException e)
{
log.error(e);
return null;
}
finally
{
if(fis!=null)
{
try
{
fis.close();
}
catch (Exception e)
{
log.error(e);
}
}
}
}
/**
* 针对非对称处理
* 取得私钥对象(针对于本util生成的私钥文件)
* @param privateKeyIs 私钥文件流
* @return 成功返回对象,失败返回null
*/
public static PrivateKey getPrivateKey(InputStream privateKeyIs)
{
ObjectInputStream in=null;
try
{
in=new ObjectInputStream(privateKeyIs);
PrivateKey prvkey=(PrivateKey)in.readObject();
in.close();
in=null;
return prvkey;
}
catch(Exception e)
{
log.error(e);
return null;
}
finally
{
if(in!=null)
{
try
{
in.close();
}
catch (IOException e)
{
log.error(e);
}
}
}
}
/**
* RSA加密
* @param text 要加密的文本内容
* @param pk 公钥
* @return 成功返回16进制小写字串,失败返回""
*/
public static String rsaEncrypt(String text,PublicKey pk)
{
try
{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pk);
byte[] encryptB=cipher.doFinal(text.getBytes());
return byte2hex(encryptB);
}
catch (Exception e)
{
log.error(e);
return "";
}
}
/**
* RSA解密
* @param cipherText 16进制的密文字串
* @param pk 私钥对象
* @return 成功还原cipherText对应的正常字串,失败返回""
*/
public static String rsaDecrypt(String cipherText,PrivateKey pk)
{
Cipher cipher=null;
try
{
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, pk);
byte[] textB= cipher.doFinal(hex2byte(cipherText));
return new String(textB,"UTF-8");
}
catch (Exception e)
{
log.error(e);
return "";
}
}
/**
* 本方法针对对称加密类型
* 生成对称加密算法的密钥文件
* @param outKeyPath 生成密钥的路径
* @param algorithm 算法类型:DES、DESede、Blowfish等
*/
public static void generatorKey2File(String outKeyPath,String algorithm)
{
getSecretKey(outKeyPath,algorithm);
}
/**
* 本方法针对对称加密类型
* 生成对称加密算法的密钥文件并返回其密钥对象
* @param outKeyPath 生成密钥的路径
* @param algorithm 算法类型:DES、DESede、Blowfish等
*/
public static SecretKey getSecretKey(String outKeyPath,String algorithm)
{
Security.addProvider(new SunJCE());
ObjectOutputStream out=null;
try
{
KeyGenerator kg=KeyGenerator.getInstance(algorithm);
kg.init(new SecureRandom());
SecretKey sk= kg.generateKey();
out = new ObjectOutputStream(new FileOutputStream(outKeyPath));
out.writeObject(sk);
out.close();
out=null;
return sk;
}
catch (Exception e)
{
log.error("generatorKey2File()-->",e);
return null;
}
finally
{
if(out!=null)
{
try
{
out.close();
}
catch (IOException e)
{
log.error(e);
}
}
}
}
/**
* 本方法针对对称加密类型
* 从keyFilePath文件取得对称密钥对象
* @param keyFilePath 对称密钥文件路径
* @return 成功返回SecretKey对象,失败返回null
*/
public static SecretKey getSecretKey(String keyFilePath)
{
FileInputStream fis=null;
try
{
fis = new FileInputStream(keyFilePath);
return getSecretKey(fis);
}
catch (FileNotFoundException e)
{
log.error(e);
return null;
}
finally
{
if(fis!=null)
{
try
{
fis.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
/**
* 本方法针对对称加密类型
* 从keyIs流取得对称密钥对象
* @param keyIs 对称密钥文件流
* @return 成功返回SecretKey对象,失败返回null
*/
public static SecretKey getSecretKey(InputStream keyIs)
{
ObjectInputStream in=null;
try
{
in=new ObjectInputStream(keyIs);
SecretKey prvkey=(SecretKey)in.readObject();
in.close();
in=null;
return prvkey;
}
catch(Exception e)
{
log.error(e);
return null;
}
finally
{
if(in!=null)
{
try
{
in.close();
}
catch (IOException e)
{
log.error(e);
}
}
}
}
/**
* 本方法针对对称加密类型
* 根据sk和algorithm把text生成加密字串
* 注意:sk对象必须对应于algorithm算法类型生成的对象
* @param text 要加密的源文本
* @param sk 由本util生成的密钥文件取出来的对象
* @param algorithm 算法类型DES、DESede、Blowfish等
* @return 成功返回加密后的字串,失败返回""
*/
public static String encrypt(String text,SecretKey sk,String algorithm)
{
Security.addProvider(new com.sun.crypto.provider.SunJCE());
Cipher cipher=null;
try
{
cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, sk);
byte[] cipherB= cipher.doFinal(text.getBytes());
return byte2hex(cipherB);
}
catch (Exception e)
{
log.error(e);
return "";
}
}
/**
* 本方法针对对称加密类型
* 根据sk和algorithm对cipherText字串解密
* 注意:sk对象必须对应于algorithm算法类型生成的对象
* @param cipherText 16进制加密的文本
* @param sk 由本util生成的密钥文件取出来的对象
* @param algorithm 算法类型DES、DESede、Blowfish等
* @return 成功返回解密后的字串,失败返回""
*/
public static String decrypt(String cipherText,SecretKey sk,String algorithm)
{
Security.addProvider(new com.sun.crypto.provider.SunJCE());
Cipher cipher=null;
try
{
cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, sk);
byte[] cipherB= cipher.doFinal(hex2byte(cipherText));
return new String(cipherB,"UTF-8");
}
catch (Exception e)
{
log.error(e);
return "";
}
}
private static void genLic()
{
String cr="\r\n";
StringBuilder lic=new StringBuilder("provider=seedo-platform");
lic.append(cr);
lic.append("org/com=seedo platform .ltc");
lic.append(cr);
lic.append("signeDate="+DateUtil.formatDate(new Date()));
lic.append(cr);
lic.append("expireDate="+DateUtil.formatDate(DateUtil.parse("2015-06-30")));
lic.append(cr);
String licInfo=lic.toString();
licInfo=signature("D:/project/k1-workspace/commons-srv-utils/src/private-rsa.dat", licInfo,ALGORITHM_TYPE_MD5withRSA);
lic.append("lisence="+licInfo);
FileUtil.write2File("d:/temp/mmo2o.lic", lic.toString());
}
private static void validLic() throws FileNotFoundException
{
FileInputStream is=new FileInputStream("d:/temp/mmo2o.lic");
System.out.println("is OK=="+ck(is));
}
private static boolean ck(InputStream is)
{
String pb="-5312fffa8c8dffeb959e899ed18c9a9c8a8d968b86d1b49a86ad9a8f4206b04c77655abcfdfffbb3fff69e9398908d968b97928bffedb3959e899ed0939e9198d0ac8b8d969198c4a4fff89a919c909b9a9b8bfffda4bdb3fff999908d929e8b8eff81fffeb3fffb8b868f9a8bffe4b3959e899ed08c9a9c8a8d968b86d0b49a86ad9a8fdbab868f9ac4878f8bfffcadacbe8a8dfffda4bd530ce807f9f7ab1ffdffff878fffffffa1cfa3cff2f9f6d579b77908f2fefefefafffcb4ffcfb7fdbeff7e658b969a2598ed9c8cdc4776b72c648075f35f6d5616615fa25da0e2ac09d1a8704fc02f0f43c8f0bed2ca9629a66fc5c232677cee8dcb500bbaf617a543c0fdfcfefffe8bfffaa7d1cacfc6818dffe6959e899ed18c9a9c8a8d968b86d1b49a86ad9a8fdbab868f9affffffffffffffffedffff878dfff1959e899ed1939e9198d1ba918a92ffffffffffffffffedffff878f8bfff9afaabdb3b6bd";
if(is==null)
{
return false;
}
InputStreamReader isr=null;
boolean result=false;
try
{
Properties pro=new Properties();
isr=new InputStreamReader(is);
pro.load(isr);
String pvd=new String(new byte[]{112,114,111,118,105,100,101,114});
String company=new String(new byte[]{111,114,103,47,99,111,109});
String sd=new String(new byte[]{115,105,103,110,101,68,97,116,101});
String ed=new String(new byte[]{101,120,112,105,114,101,68,97,116,101});
String lc=new String(new byte[]{108,105,115,101,110,99,101});
String cr="\r\n";
StringBuilder lic=new StringBuilder();
lic.append(pvd+"="+pro.getProperty(pvd));
lic.append(cr);
lic.append(company+"="+pro.getProperty(company));
lic.append(cr);
lic.append(sd+"="+pro.getProperty(sd));
lic.append(cr);
lic.append(ed+"="+pro.getProperty(ed));
lic.append(cr);
String licInfo=pro.getProperty(lc);
PublicKey pk=(PublicKey)SerializableUtil.byteToObject(SerializableUtil.hex2Byte(pb));
if(!SecurityUtil.verifySignature(pk, lic.toString(), licInfo, SecurityUtil.ALGORITHM_TYPE_MD5withRSA))
{
is.close();
isr.close();
}
Date ep=DateUtil.parse(pro.getProperty(ed).toString());
if(!(new Date().getTime()>ep.getTime()))
{
result=true;
}
}
catch(Exception e)
{
return false;
}
finally
{
FileUtil.closeReader(isr);
FileUtil.closeInputStream(is);
}
return result;
}
/**
* 读取P12证书相关资源
*
* @author:Mars
* @创建日期:2017-8-14
* @功能说明:
*/
private static void ReadP12CertUtil() {
final String KEYSTORE_FILE = "aaaaaaaaaaaaaaa.p12";
final String KEYSTORE_PASSWORD = "test";
// final String KEYSTORE_ALIAS = "alias";
try {
KeyStore ks = KeyStore.getInstance("PKCS12");
FileInputStream fis = new FileInputStream(KEYSTORE_FILE);
// If the keystore password is empty(""), then we have to set
// to null, otherwise it won't work!!!
char[] nPassword = null;
if ((KEYSTORE_PASSWORD == null) || KEYSTORE_PASSWORD.trim().equals("")) {
nPassword = null;
} else {
nPassword = KEYSTORE_PASSWORD.toCharArray();
}
ks.load(fis, nPassword);
fis.close();
System.out.println("keystore type=" + ks.getType());
// Now we loop all the aliases, we need the alias to get keys.
// It seems that this value is the "Friendly name" field in the
// detals tab <-- Certificate window <-- view <-- Certificate
// Button <-- Content tab <-- Internet Options <-- Tools menu
// In MS IE 6.
Enumeration enum1 = ks.aliases();
String keyAlias = null;
if (enum1.hasMoreElements()) // we are readin just one certificate.
{
keyAlias = (String) enum1.nextElement();
System.out.println("alias=[" + keyAlias + "]");
}
// Now once we know the alias, we could get the keys.
System.out.println("is key entry=" + ks.isKeyEntry(keyAlias));
PrivateKey prikey = (PrivateKey) ks.getKey(keyAlias, nPassword);
Certificate cert = ks.getCertificate(keyAlias);
PublicKey pubkey = cert.getPublicKey();
System.out.println("cert class = " + cert.getClass().getName());
System.out.println("cert = " + cert);
System.out.println("public key = " + pubkey);
System.out.println("private key = " + prikey);
} catch (Exception e) {
e.printStackTrace();
}
}
}