著名的密码学者Ron Rivest曾经说过:“密码学是关于如何在敌人存在的环境中通讯”。
的确,从严谨的角度来讲,不管是公网环境还是在企业内网,我们设计系统的时候都需要充分考虑通讯安全。以下总结了一些常用的java密码技术,供参考。
1,单向散列函数
又称单向Hash函数、杂凑函数,就是把任意长的输入消息串变化成固定长的输出串且由输出串难以得到输入串的一种函数。这个输出串称为该消息的散列值。一般用于产生消息摘要,密钥加密等.
1)MD5
是RSA数据安全公司开发的一种单向散列算法,MD5被广泛使用。MD5的强抗碰撞性目前已被破解。
代码示例:
package com.huangzi.demo;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5 {
public static byte[] eccrypt(String info) throws NoSuchAlgorithmException{
//获取MD5的MessageDigest对象
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] srcBytes = info.getBytes();
md5.update(srcBytes);
byte[] resultBytes = md5.digest();
return resultBytes;
}
public static void main(String args[]) throws NoSuchAlgorithmException{
String msg = "皇子——常用java密码技术";
byte[] resultBytes = MD5.eccrypt(msg);
System.out.println("密文:" + new String(resultBytes));
System.out.println("明文:" + msg);
}
}
2)SHA
分为SHA-1,SHA-224,SHA-256,SHA-384。目前SHA-1的强抗碰撞性已被破解。
package com.huangzi.demo;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class SHA {
public static byte[] eccrypt(String shaType,String info) throws NoSuchAlgorithmException{
MessageDigest md5 = MessageDigest.getInstance(shaType);
byte[] srcBytes = info.getBytes();
md5.update(srcBytes);
byte[] resultBytes = md5.digest();
return resultBytes;
}
/**
* @param args
* @throws NoSuchAlgorithmException
*/
public static void main(String[] args) throws NoSuchAlgorithmException {
String msg = "皇子讲java密码技术";
String[] shaTypes = new String[] { "SHA1", "SHA-256", "SHA-384", "SHA-512" };
for(String shaType : shaTypes) {
System.out.println(shaType);
byte[] resultBytes = SHA.eccrypt(shaType,msg);
System.out.println("明文:" + msg);
System.out.println("密文:" + new String(resultBytes));
System.out.println("========================");
}
}
}
2,对称加密
一种加密与解密用的是相同的密钥的加密方式。
1)DES
DES,全称为“Data Encryption Standard”,中文名为“数据加密标准”,是一种使用密钥加密的块算法。1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
public class DES {
private KeyGenerator keygen;
private SecretKey deskey;
private Cipher cipher;
private byte[] cipherByte;
public DES() throws NoSuchAlgorithmException, NoSuchPaddingException{
keygen = KeyGenerator.getInstance("DES");
deskey = keygen.generateKey();
cipher = Cipher.getInstance("DES");
}
public byte[] Encrytor(String str) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException {
cipher.init(Cipher.ENCRYPT_MODE, deskey);
byte[] src = str.getBytes();
cipherByte = cipher.doFinal(src);
return cipherByte;
}
public byte[] Decryptor(byte[] buff) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException {
cipher.init(Cipher.DECRYPT_MODE, deskey);
cipherByte = cipher.doFinal(buff);
return cipherByte;
}
public static void main(String[] args) throws Exception {
DES de1 = new DES();
String msg ="皇子讲java密码技术";
byte[] encontent = de1.Encrytor(msg);
byte[] decontent = de1.Decryptor(encontent);
System.out.println("明文:" + msg);
System.out.println("密文:" + new String(encontent));
System.out.println("解密:" + new String(decontent));
}
}
2)3DES
又称Triple DES,是DES加密算法的一种模式,它使用3条56位的密钥对3DES数据进行三次加密。
package com.huangzi.demo;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
public class DESDESDES {
private KeyGenerator keygen;
private SecretKey deskey;
private Cipher c;
private byte[] cipherByte;
public DESDESDES() throws NoSuchAlgorithmException, NoSuchPaddingException {
keygen = KeyGenerator.getInstance("DESede");
deskey = keygen.generateKey();
c = Cipher.getInstance("DESede");
}
/**
* 加密
*
* @param str
* @return
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public byte[] Encrytor(String str) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException {
c.init(Cipher.ENCRYPT_MODE, deskey);
byte[] src = str.getBytes();
cipherByte = c.doFinal(src);
return cipherByte;
}
/**
* 解密
*
* @param buff
* @return
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public byte[] Decryptor(byte[] buff) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException {
c.init(Cipher.DECRYPT_MODE, deskey);
cipherByte = c.doFinal(buff);
return cipherByte;
}
/**
* @param args
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
* @throws InvalidKeyException
*/
public static void main(String[] args) throws Exception {
DESDESDES des = new DESDESDES();
String msg ="皇子讲java密码技术";
byte[] encontent = des.Encrytor(msg);
byte[] decontent = des.Decryptor(encontent);
System.out.println("明文:" + msg);
System.out.println("密文:" + new String(encontent));
System.out.println("解密:" + new String(decontent));
}
}
3)AES
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。由美国国家标准与技术研究院(NIST)发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。是对称密钥加密中最流行的算法之一。
package com.huangzi.demo;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
public class AES {
private KeyGenerator keygen;
private SecretKey deskey;
private Cipher cipher;
private byte[] cipherByte;
public AES() throws NoSuchAlgorithmException, NoSuchPaddingException{
keygen = KeyGenerator.getInstance("AES");
deskey = keygen.generateKey();
cipher = Cipher.getInstance("AES");
}
/**
* 加密
* @param str
* @return
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public byte[] Encrytor(String str) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException {
cipher.init(Cipher.ENCRYPT_MODE, deskey);
byte[] src = str.getBytes();
cipherByte = cipher.doFinal(src);
return cipherByte;
}
/**
* 解密
* @param buff
* @return
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public byte[] Decryptor(byte[] buff) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException {
cipher.init(Cipher.DECRYPT_MODE, deskey);
cipherByte = cipher.doFinal(buff);
return cipherByte;
}
/**
* @param args
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
* @throws InvalidKeyException
*/
public static void main(String[] args) throws Exception {
AES aes = new AES();
String msg ="皇子讲java密码技术";
byte[] encontent = aes.Encrytor(msg);
byte[] decontent = aes.Decryptor(encontent);
System.out.println("明文:" + msg);
System.out.println("密文:" + new String(encontent));
System.out.println("解密:" + new String(decontent));
}
}
4)PBE
PBE算法(Password Based Encryption,基于口令加密)是一种基于口令的加密算法,其特点是使用口令代替了密钥,而口令由用户自己掌管,采用随机数杂凑多重加密等方法保证数据的安全性。
PBE算法在加密过程中并不是直接使用口令来加密,而是加密的密钥由口令生成,这个功能由PBE算法中的KDF函数完成。KDF函数的实现过程为:将用户输入的口令首先通过“盐”(salt)的扰乱产生准密钥,再将准密钥经过散列函数多次迭代后生成最终加密密钥,密钥生成后,PBE算法再选用对称加密算法对数据进行加密,可以选择DES、3DES、RC5等对称加密算法。
package com.huangzi.demo;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
public class PEB {
private static Cipher cipher;
private static SecretKey generateKey;
private static PBEParameterSpec pbeParameterSpec;
public static byte[] encode(String src) throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, InvalidAlgorithmParameterException{
SecureRandom secureRandom = new SecureRandom();
byte[] salt = secureRandom.generateSeed(8);
String password = "abc123";
PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBEWITHMD5andDES");
generateKey = secretKeyFactory.generateSecret(pbeKeySpec);
pbeParameterSpec = new PBEParameterSpec(salt, 100);
cipher = Cipher.getInstance("PBEWITHMD5andDES");
cipher.init(Cipher.ENCRYPT_MODE, generateKey, pbeParameterSpec);
return cipher.doFinal(src.getBytes());
}
public static byte[] decode(byte[] src) throws InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{
cipher.init(Cipher.DECRYPT_MODE, generateKey, pbeParameterSpec);
return cipher.doFinal(src);
}
public static void main(String[] args) throws Exception{
String msg ="皇子讲java密码技术";
byte[] encontent = PEB.encode(msg);
byte[] decontent = PEB.decode(encontent);
System.out.println("明文:" + msg);
System.out.println("密文:" + new String(encontent));
System.out.println("解密:" + new String(decontent));
}
}
3,公钥密码
公钥密码又称为非对称密码,拥有公钥密码的用户分别拥有加密密钥和解密密钥。通过加密密钥不能得到解密密钥。并且加密密钥是公开的。
解密密钥一开始就由接收者自己保管,可以解决密钥配送的问题
1)RSA
1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。1987年7月首次在美国公布,当时他们三人都在麻省理工学院工作实习。RSA就是他们三人姓氏开头字母拼在一起组成的。
RSA是目前最有影响力和最常用的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。
今天只有短的RSA钥匙才可能被强力方式解破。到2008年为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。
但在分布式计算和量子计算机理论日趋成熟的今天,RSA加密安全性受到了挑战和质疑。
package com.huangzi.demo;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import javax.crypto.Cipher;
public class RSA {
public static byte[] encrypt(RSAPublicKey publicKey,byte[] srcBytes) throws Exception{
if(publicKey!=null){
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] resultBytes = cipher.doFinal(srcBytes);
return resultBytes;
}
return null;
}
public static byte[] decrypt(RSAPrivateKey privateKey,byte[] srcBytes) throws Exception{
if(privateKey!=null){
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] resultBytes = cipher.doFinal(srcBytes);
return resultBytes;
}
return null;
}
public static void main(String[] args) throws Exception {
String msg = "皇子讲java密码技术";
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();
RSAPublicKey publicKey = (RSAPublicKey)keyPair.getPublic();
byte[] srcBytes = msg.getBytes();
byte[] resultBytes = RSA.encrypt(publicKey, srcBytes);
byte[] decBytes = RSA.decrypt(privateKey, resultBytes);
System.out.println("明文:" + msg);
System.out.println("密文:" + new String(resultBytes));
System.out.println("解密:" + new String(decBytes));
}
}
4,数字签名
数字签名(又称公钥数字签名、电子签章)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。
数字签名会使用公钥和私钥组成的密钥对
私钥加密相当于生成签名;用公钥解密相当于验证签名
package com.huangzi.demo;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
public class RSASign {
public static byte[] sign(PrivateKey rsaPrivateKey,String msg) throws Exception{
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initSign(privateKey);
signature.update(msg.getBytes());
return signature.sign();
}
public static boolean verify(PublicKey rsaPublicKey,String msg,byte[] signatureByte) throws Exception {
Signature signature = Signature.getInstance("MD5withRSA");
signature = Signature.getInstance("MD5withRSA");
signature.initVerify(rsaPublicKey);
signature.update(msg.getBytes());
return signature.verify(signatureByte);
}
public static void main(String[] args) throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
PrivateKey rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate();
String msg = "皇子讲java密码技术";
byte[] signature = RSASign.sign(rsaPrivateKey, msg);
System.out.println("消息明文:" + msg);
System.out.println("签名:" + new String(signature));
boolean flag = RSASign.verify(rsaPublicKey, msg, signature);
System.out.println("验签结果:" + flag);
}
}
作者:VIP.FCS 皇子
日期:2018.1.14
来赞赏一瓶可乐?