Java加密和数字签名本文主要谈一下密码学中的加密和数字签名以及其在java中如何进行使用对密码学有兴趣的伙伴推荐看 Bruce Schneier的着作Applied Crypotography在jdk的发行版本中安全性方面有了很大的改进也提供了对RSA算法的直接支持现在我们从实例入手解决问题(本文仅是作为简单介绍)
一密码学上常用的概念
)消息摘要
这是一种与消息认证码结合使用以确保消息完整性的技术主要使用单向散列函数算法可用于检验消息的完整性和通过散列密码直接以文本形式保存等目前广泛使用的算法有MDMDSHAjdk对上面都提供了支持在java中进行消息摘要很简单 javasecurityMessageDigest提供了一个简易的操作方法
/**
*MessageDigestExamplejava
*Copyright
*/
import javasecurityMessageDigest;
/**
*单一的消息摘要算法不使用密码可以用来对明文消息(如密码)隐藏保存
*/
public class MessageDigestExample{
public static void main(String[] args) throws Exception{
if(argslength!=){
Systemerrprintln(Usage:java MessageDigestExample text);
Systemexit();
}
byte[] plainText=args[]getBytes(UTF);
//使用getInstance(算法)来获得消息摘要这里使用SHA的位算法
MessageDigest messageDigest=MessageDigestgetInstance(SHA);
Systemoutprintln(\n+messageDigestgetProvider()getInfo());
//开始使用算法
messageDigestupdate(plainText);
Systemoutprintln(\nDigest:);
//输出算法运算结果
Systemoutprintln(new String(messageDigestdigest()UTF));
}
}
还可以通过消息认证码来进行加密实现javaxcryptoMac提供了一个解决方案有兴趣者可以参考相关API文档本文只是简单介绍什么是摘要算法
这里补充另一个运用消息摘要的方式加密的例子:
public class TestEncrypt {
public TestEncrypt() {
}
/**
* @param strSrc :strSrc is a string will be encrypted
* @param encName : encName is the algorithm name will be used
* encName dafault to MD
* @return String
*/
public String Encrypt(String strSrc String encName) {
MessageDigest md = null;
String strDes = null;
byte[] bt = strSrcgetBytes();
try {
if (encName == null || encNameequals()) {
encName = MD;
}
md = MessageDigestgetInstance(encName);
mdupdate(bt);
strDes = bytesHex(mddigest()); //to HexString
}
catch (NoSuchAlgorithmException e) {
Systemoutprintln(Invalid algorithm);
return null;
}
return strDes;
}
public String bytesHex(byte[] bts) {
String des = ;
String tmp = null;
for (int i = ; i < btslength; i++) {
tmp = (IntegertoHexString(bts[i] & xFF));
if (tmplength() == ) {
des += ;
}
des += tmp;
}
return des;
}
public static void main(String[]args) {
TestEncrypt te = new TestEncrypt();
String strSrc = 可以加密汉字Ohand english;
Systemoutprintln(Source String: + strSrc);
Systemoutprintln(Encrypted String:);
Systemoutprintln(Use Def: + teEncrypt(strSrc null));
Systemoutprintln(Use MD: + teEncrypt(strSrc MD));
Systemoutprintln(Use SHA: + teEncrypt(strSrc SHA));
Systemoutprintln(Use SHA: + teEncrypt(strSrc SHA));
}
}
另外在javawebparts中的 RequestHelpers里的generateGUID方法也涉及到了MD的方法代码如下:
public static String generateGUID(HttpServletRequest request) {
String out = ;
try {
// Construct a string that is comprised of:
// Remote IP Address + Host IP Address + Date (yyyyMMdd) +
// Time (hhmmssSSa) + Requested Path + Session ID +
// HashCode Of ParameterMap
StringBuffer sb = new StringBuffer();
sbappend(requestgetRemoteAddr());
InetAddress ia = InetAddressgetLocalHost();
sbappend(iagetHostAddress());
sbappend(new SimpleDateFormat(yyyyMMddhhmmssSSa)format(new Date()));
String path = requestgetServletPath();
String pathInfo = requestgetPathInfo();
if (pathInfo != null) {
path += pathInfo;
}
sbappend(path);
sbappend(requestgetSession(false));
sbappend(requestgetParameterMap()hashCode());
String str = sbtoString();
// Now encode the string using an MD encryption algorithm
MessageDigest md = MessageDigestgetInstance(md);
mdupdate(strgetBytes());
byte[] digest = mddigest();
StringBuffer hexStr = new StringBuffer();
for (int i = ; i < digestlength; i++) {
str = IntegertoHexString(xFF & digest[i]);
if (strlength() < ) {
str = + str;
}
hexStrappend(str);
}
out = hexStrtoString();
} catch (NoSuchAlgorithmException nsae) {
logerror(nsae);
} catch (UnknownHostException uhe) {
logerror(uhe);
}
// Return the encrypted string It should be unique based on the
// components that comprise the plain text string and should always be
// characters thanks to the MD algorithm
return out;
} // End generateGUID()
)私钥加密
消息摘要只能检查消息的完整性但是单向的对明文消息并不能加密要加密明文的消息的话就要使用其他的算法要确保机密性我们需要使用私钥密码术来交换私有消息
这种最好理解使用对称算法比如A用一个密钥对一个文件加密而B读取这个文件的话则需要和A一样的密钥双方共享一个私钥(而在web环境下私钥在传递时容易被侦听)
使用私钥加密的话首先需要一个密钥可用javaxcryptoKeyGenerator产生一个密钥(javasecurityKey) 然后传递给一个加密工具(javaxcryptoCipher)该工具再使用相应的算法来进行加密主要对称算法有DES(实际密钥只用到 位)AES(支持三种密钥长度位)通常首先位其他的还有DESede等jdk种也提供了对对称算法的支持以下例子使用AES算法来加密
/**
*PrivateExmaplejava
*Copyright
*/
import javaxcryptoCipher;
import javaxcryptoKeyGenerator;
import javasecurityKey;
/**
*私鈅加密保证消息机密性
*/
public class PrivateExample{
public static void main(String[] args) throws Exception{
if(argslength!=){
Systemerrprintln(Usage:java PrivateExample <text>);
Systemexit();
}
byte[] plainText=args[]getBytes(UTF);
//通过KeyGenerator形成一个key
Systemoutprintln(\nStart generate AES key);
KeyGenerator keyGen=KeyGeneratorgetInstance(AES);
keyGeninit();
Key key=keyGengenerateKey();
Systemoutprintln(Finish generating DES key);
//获得一个私鈅加密类CipherECB是加密方式PKCSPadding是填充方法
Cipher cipher=CiphergetInstance(AES/ECB/PKCSPadding);
Systemoutprintln(\n+ciphergetProvider()getInfo());
//使用私鈅加密
Systemoutprintln(\nStart encryption:);
cipherinit(CipherENCRYPT_MODEkey);
byte[] cipherText=cipherdoFinal(plainText);
Systemoutprintln(Finish encryption:);
Systemoutprintln(new String(cipherTextUTF));
Systemoutprintln(\nStart decryption:);
cipherinit(CipherDECRYPT_MODEkey);
byte[] newPlainText=cipherdoFinal(cipherText);
Systemoutprintln(Finish decryption:);
Systemoutprintln(new String(newPlainTextUTF));
}
}
)公钥加密
上面提到私钥加密需要一个共享的密钥那么如何传递密钥呢?web环境下直接传递的话很容易被侦听到幸好有了公钥加密的出现公钥加密也叫不对称加密不对称算法使用一对密钥对一个公钥一个私钥使用公钥加密的数据只有私钥能解开(可用于加密)同时使用私钥加密的数据只有公钥能解开(签名)但是速度很慢(比私钥加密慢到倍)公钥的主要算法有RSA还包括BlowfishDiffieHelman等 jdk种提供了对RSA的支持是一个改进的地方
/**
*PublicExamplejava
*Copyright
*/
import javasecurityKey;
import javaxcryptoCipher;
import javasecurityKeyPairGenerator;
import javasecurityKeyPair;
/**
*一个简单的公鈅加密例子Cipher类使用KeyPairGenerator生成的公鈅和私鈅
*/
public class PublicExample{
public static void main(String[] args) throws Exception{
if(argslength!=){
Systemerrprintln(Usage:java PublicExample <text>);
Systemexit();
}
byte[] plainText=args[]getBytes(UTF);
//构成一个RSA密钥
Systemoutprintln(\nStart generating RSA key);
KeyPairGenerator keyGen=KeyPairGeneratorgetInstance(RSA);
keyGeninitialize();
KeyPair key=keyGengenerateKeyPair();
Systemoutprintln(Finish generating RSA key);
//获得一个RSA的Cipher类使用公鈅加密
Cipher cipher=CiphergetInstance(RSA/ECB/PKCSPadding);
Systemoutprintln(\n+ciphergetProvider()getInfo());
Systemoutprintln(\nStart encryption);
cipherinit(CipherENCRYPT_MODEkeygetPublic());
byte[] cipherText=cipherdoFinal(plainText);
Systemoutprintln(Finish encryption:);
Systemoutprintln(new String(cipherTextUTF));
//使用私鈅解密
Systemoutprintln(\nStart decryption);
cipherinit(CipherDECRYPT_MODEkeygetPrivate());
byte[] newPlainText=cipherdoFinal(cipherText);
Systemoutprintln(Finish decryption:);
Systemoutprintln(new String(newPlainTextUTF));
}
}