对数据加密的算法有很多种。总体来说分为两大类:对称加密算法和非对称加密算法。
对称加密算法
对称加密算法要求加密与解密使用同一个共享密钥。解密算法是加密算法的逆运算,加密密钥和解密密钥相同。
对称加密的工作原理如下:
其中,对称加密算法有两种主要的方式:
- 流密码:对明文的单个位进行运算,转换为密文的单个位。
- 分组密码:将明文划分成不同的组,分别对每个组进行加密解密。
平常使用时,分组密码是最常用的。分组密码根据数据加密时每个加密区块间的关联方式来区分,可以分为4种工作模式:
- 电子密码本模式-ECB
- 密文链接模式-CBC
- 密文反馈模式-CFB
- 输出反馈模式-OFB
在Java的编码实现时,需要指定相应的工作模式。关于选择何种模式,可以参考这篇博客
另外,分组密码有三种填充方式:
- NoPadding:不填充。
- ZerosPadding:全部填充为0。
- PKCS5Padding:每个填充的字节都记录了填充的总字节数。
一般而言,会选择PKCS5Padding的方式。
对称加密有三种常用的算法:DES 3DES AES。以下是各个算法的比较:
下面是DES算法的Java实现:
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
public class DesEncrypt {
public static final String KEY_ALGORITHM = "DES";
public static final String CIPHER_ALGORIGHM = "DES/ECB/PKCS5Padding";
public static final int KEY_LENGTH = 56;
private static final Charset CHARSET = Charset.forName("UTF-8");
/**
* 获取Key
* @param key 指定的密钥
* @return 生成的Key
*/
public Key getKey(byte[] key) {
try {
if (key == null || key.length == 0) {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
keyGenerator.init(KEY_LENGTH);
SecretKey secretKey = keyGenerator.generateKey();
key = secretKey.getEncoded();
}
DESKeySpec desKeySpec = new DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
return keyFactory.generateSecret(desKeySpec);
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
return null;
}
/**
* 加密
* @param data 要加密的数据
* @param key 密钥
* @return 加密后的数据
*/
public byte[] encrypt(byte[] data, Key key) {
try {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORIGHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
return null;
}
/**
* 解密
* @param data 要解密的密文
* @param key 密钥
* @return 解密后的数据
*/
public byte[] decrypt(byte[] data, Key key) {
try {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORIGHM);
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(data);
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
return null;
}
}
非对称加密算法
非对称加密算法分为两个密钥,一个公开,一个保密。公开的密钥称为公钥,保密的密钥称为私钥。私钥加密的数据必须公钥解密,公钥加密的数据必须私钥解密。
工作原理如下:
注意的是:公钥加密的数据,必须用私钥解密;私钥加密的数据,必须用公钥解密。
常用的非对称加密算法是RSA。
下面是RSA的实现:
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
/**
* RSA加密解密
*/
public class RSAAlgorithm {
public static final String KEY_ALGORITHM = "RSA";
private static final int KEY_SIZE = 512;
private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private KeyPair keyPair;
private byte[] data;
public RSAAlgorithm(String data) {
this(data.getBytes(DEFAULT_CHARSET));
}
public RSAAlgorithm(byte[] data) {
this.data = data;
generateKey();
}
public void generateKey() {
KeyPairGenerator keyPairGenerator = null;
try {
keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGenerator.initialize(KEY_SIZE);
keyPair = keyPairGenerator.generateKeyPair();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
//获取公钥
public Key getPublicKey() {
return keyPair.getPublic();
}
//获取私钥
public Key getPrivateKey() {
return keyPair.getPrivate();
}
//私钥加密
public byte[] encryptByPrivateKey() {
try{
byte[] key = getPrivateKey().getEncoded();
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return cipher.doFinal(data);
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
return null;
}
//私钥解密
public byte[] decryptByPrivateKey() {
try {
byte[] key = getPrivateKey().getEncoded();
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
return null;
}
//公钥加密
public byte[] encryptByPublicKey() {
try {
byte[] key = getPublicKey().getEncoded();
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
return null;
}
//公钥解密
public byte[] decryptByPublicKey() {
try {
byte[] key = getPublicKey().getEncoded();
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return cipher.doFinal(data);
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
return null;
}
}
总结
如果要使用对称加密算法,建议采用AES算法,不管从性能还是安全性来说,都有很大的优势。非对称加密算法当然不止RSA一种,但是RSA是我们接触最多的,安全性也很好。非对称加密比对称加密的安全性要高,但是运算速度相比较低。