一、对称性加密算法
1.概述
DES(Data Encryption Standard):数字签名算法,速度较快,适用于大量数据加密
3DES(Triple DES):是基于DES,对一块数据用三个不同的密钥进行三次加密,强度更高。
AES(Advanced Encryption Standard):高级加密标准,是下一代的加密算法标准,速度快,安全级别高
密钥长度 | 运算速度 | 安全性 | 资源消耗 | |
DES | 56位 | 较快 | 低 | 中 |
3DES | 112位或168位 | 慢 | 中 | 高 |
AES | 128、192、256位 | 快 | 高 | 低 |
2.java代码的实现
DES:下面这种实现密钥长度要大于8位
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import org.apache.commons.codec.binary.Base64;
public class DESTool {
//算法名称/加密模式/填充方式
//DES共有四种工作模式-->>ECB:电子密码本模式、CBC:加密分组链接模式、CFB:加密反馈模式、OFB:输出反馈模式
public static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";
/**
*
* 生成密钥key对象
* @param KeyStr 密钥字符串
* @return 密钥对象
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws Exception
*/
private static SecretKey keyGenerator(String keyStr) throws Exception {
DESKeySpec desKey = new DESKeySpec(keyStr.getBytes());
//创建一个密匙工厂,然后用它把DESKeySpec转换成
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey);
return securekey;
}
/**
* 加密数据
* @param data 待加密数据
* @param key 密钥
* @return 加密后的数据
*/
public static String encrypt(String data, String key) throws Exception {
Key deskey = keyGenerator(key);
// 实例化Cipher对象,它用于完成实际的加密操作
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
SecureRandom random = new SecureRandom();
// 初始化Cipher对象,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, deskey, random);
byte[] results = cipher.doFinal(data.getBytes());
// 执行加密操作。加密后的结果通常都会用Base64编码进行传输
return Base64.encodeBase64String(results);
}
/**
* 解密数据
* @param data 待解密数据
* @param key 密钥
* @return 解密后的数据
*/
public static String decrypt(String data, String key) throws Exception {
Key deskey = keyGenerator(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
//初始化Cipher对象,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, deskey);
// 执行解密操作
return new String(cipher.doFinal(Base64.decodeBase64(data)));
}
}
AES:
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class AESTool {
/**
* 加密
*
* @param content
* 需要加密的内容
* @param password
* 加密密码
* @return
*/
public static String encrypt(String content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
byte[] result = cipher.doFinal(byteContent);
return Base64.encodeBase64String(result);// 加密
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 解密
*
* @param content
* 待解密内容
* @param password
* 解密密钥
* @return
*/
public static String decrypt(String content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
byte[] result = cipher.doFinal(Base64.decodeBase64(content));
return new String(result); // 加密
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
二、非对称加密算法
1.概述
加密密钥和解密密钥不同
RSA:由 RSA 公司发明,是一个支持变长密钥的公共密钥算法,需要加密的文件块的长度也是可变的;
DSA(Digital Signature Algorithm):数字签名算法,是一种标准的 DSS(数字签名标准);
成熟度 | 安全性(取决于密钥长度) | 运算速度 | 资源消耗 | |
RSA | 高 | 高 | 慢 | 高 |
DSA | 高 | 高 | 慢 | 只能用于数字签名 |
2.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.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 RSATool {
public static final String PUBLIC_KEY = "RSAPublicKey";//公钥
public static final String PRIVATE_KEY = "RSAPrivateKey";//私钥
/**
* 初始化密钥
* @return
* @throws Exception
*/
public static Map<String,Key> initKey()throws Exception{
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
//公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
//私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map<String,Key> keyMap = new HashMap<String,Key>(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
/**
* 用公钥加密
* @param data 加密数据
* @param key 密钥
* @return
* @throws Exception
*/
public static String encryptByPublicKey(String data,Key key)throws Exception{
//取公钥
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");//指定加密算法
Key publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
//对数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] results =cipher.doFinal(data.getBytes());
return Base64.encodeBase64String(results);
}
/**
* 用私钥解密
* @param data 加密数据
* @param key 密钥
* @return
* @throws Exception
*/
public static String decryptByPrivateKey(String data,Key key)throws Exception{
//取私钥
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");//指定加密算法
Key privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
//对数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] results =cipher.doFinal(Base64.decodeBase64(data));
return new String(results);
}
/**
*用私钥对信息生成数字签名
* @param data 原数据
* @param privateKey 私钥
* @return
* @throws Exception
*/
public static String sign(String data,Key privateKey)throws Exception{
//取私钥
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");//指定加密算法
PrivateKey privateKey2 = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
//用私钥对信息生成数字签名
Signature signature = Signature.getInstance("MD5withRSA");
signature.initSign(privateKey2);
signature.update(data.getBytes());
return Base64.encodeBase64String(signature.sign());
}
/**
* 公钥校验数字签名
* @param data 加密数据
* @param publicKey 公钥
* @param sign 数字签名
* @return
* @throws Exception
*/
public static boolean verify(String data,Key publicKey,String sign)throws Exception{
//取公钥
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey2 = keyFactory.generatePublic(x509EncodedKeySpec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initVerify(publicKey2);
signature.update(data.getBytes());
//验证签名是否正常
return signature.verify(Base64.decodeBase64(sign));
}
}
DSA:代码跟RSA算法一样,只需把获得算法参数改成DSA.另DSA只能用于签名
三、散列算法
1.概述
这种算法只生成一串不可逆的密文
MD5(Message Digest Algorithm 5):是RSA数据安全公司开发的一种单向散列算法,非可逆,相同的明文产生相同的密文。
SHA-1(Secure Hash Algorithm):安全度相对高;
2.java代码的实现
private static String sha1X16(String data) throws Exception{
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.reset();
md.update(data.getBytes("utf-8"));
byte[] bytes =md.digest();
//转16进制
StringBuilder sha1StrBuff = new StringBuilder();
for (int i = 0; i < bytes.length; ++i){
if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
sha1StrBuff.append("0").append(
Integer.toHexString(0xFF & bytes[i]));
} else
sha1StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
}
return sha1StrBuff.toString().toLowerCase();
} catch (Exception e) {
throw e;
}
}
四、密钥证书
1、常见证书格式
.pfx/.p12 PKCS#12标准定义,包含了公钥和私钥的二进制格式的证书形式。
.cer/.crt是用于存放证书,它是DER 编码(ASCII)的2进制形式存放的,不含私钥。
.pem是用于存放证书,它是BASE64 编码的2进制形式存放的,不含私钥。
2、java代码实现
.pfx格式:获得公钥和私钥
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.util.Enumeration;
public class CerTool {
public static final String KEYSTORE_FILE = "D:/test.pfx";
public static final String KEYSTORE_PASSWORD = "111111";
public static void main(String[] args) {
FileInputStream fis = null;
try {
// 获得KeyStore
KeyStore ks = KeyStore.getInstance("PKCS12");
fis = new FileInputStream(KEYSTORE_FILE);
char[] nPassword = KEYSTORE_PASSWORD.toCharArray();
ks.load(fis, nPassword);
// 根据条目获得私钥
Enumeration aliasenum = ks.aliases();
String keyAlias = null;
if (aliasenum.hasMoreElements()) {
keyAlias = (String) aliasenum.nextElement();
}
PrivateKey priKey = (PrivateKey) ks.getKey(keyAlias,
KEYSTORE_PASSWORD.toCharArray());
// 根据条目获得公钥
Certificate cert = ks.getCertificate(keyAlias);
PublicKey pubkey = cert.getPublicKey();
//使用RSA测试
String content="hello";
String en=RSATool.encryptByPublicKey(content,pubkey);
System.out.println(en);
System.out.println(RSATool.decryptByPrivateKey(en,priKey));
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
.cer格式:获得公钥
public PublicKey getPublic() {
InputStream in = null;
try {
//引用于java.security.cert
CertificateFactory cf = CertificateFactory.getInstance("X.509");
in = new FileInputStream("D:/test.cer");
X509Certificate verifyCert = (X509Certificate) cf
.generateCertificate(in);
PublicKey publicKey = verifyCert.getPublicKey();
return publicKey;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
五、算法的选择
由于非对称加密算法的运行速度比对称加密算法的速度慢很多,当我们需要加密大量的数据时,建议采用对称加密算法,提高加解密速度。
对称加密算法不能实现签名,因此签名只能非对称算法。
由于对称加密算法的密钥管理是一个复杂的过程,密钥的管理直接决定着他的安全性,因此当数据量很小时,我们可以考虑采用非对称加密算法。
在实际的操作过程中,我们通常采用的方式是:采用非对称加密算法管理对称算法的密钥,然后用对称加密算法加密数据,这样我们就集成了两类加密算法的优点,既实现了加密速度快的优点,又实现了安全方便管理密钥的优点。
那采用多少位的密钥呢? RSA建议采用1024位的数字,ECC建议采用160位,AES采用128为即可。
ps:数字签名和加密的区别
数字签名的作用一是保证数据的完整性,二是对发送者进行身份认证。所以它是采用非对称算法,消息发送者使用私钥加密,接收者使用公钥解密验签;
加密重点在于“数据的安全性”,可以防止数据被监听攻击。所以消息发送者采用公钥加密,只有拥有私钥的接收者才能解密;