一、Base64编码
Base64,它是一种编码方式,算不上一种加密算法。它就是使用64个可打印字符来表示二进制数据的方法。Base64一般用于在HTTP协议下传输二进制数据,由于HTTP协议是文本协议,所以在HTTP协议下传输二进制数据需要将二进制数据转换为字符数据。然而直接转换是不行的,此时可以将子节序列用Base64编码。
Java提供了Base64的编解码器,直接使用即可。
public class Base64Test {
public static final Base64.Encoder encoder = Base64.getEncoder();
public static final Base64.Decoder decoder = Base64.getDecoder();
public static void main(String[] args) {
String data = "你好吗?我很好";
//编码
String base64EncodeString = encoder.encodeToString(data.getBytes());
//解码
byte[] bytes = decoder.decode(base64EncodeString);
System.out.println(new String(bytes));
}
}
二、单向加密
我们都知道哈希算法(Hash,又称摘要算法Digest),它可以对任意一组输入数据进行计算,并得到一个固定长度的输出摘要,它是不可逆的。单向加密即只能加密,无法通过加密后的密文加密还原数据,所以被称为单向加密,也是不可逆的,单向加密可用于做数据加签验签,效验数据是否被篡改。常见的单向加密算法有:
- MD5:message-digest algorithm 5 (信息-摘要算法)一种哈希算法。
- SHA:Secure Hash Algorithm,安全散列算法,一种哈希算法。SHA算法实际上是一个系列,包括SHA-0(已废弃)、SHA-1、SHA-256、SHA-512等。
- HMAC:Hash Message Authentication Code, Hmac算法就是一种基于密钥的消息认证码算法,是一种更安全的消息摘要算法。Hmac算法总是和某种哈希算法配合起来用的,常见的有HmacMD5,HmacSHA1,HmacSHA256,HmacSHA384,HmacSHA512。(HMAC相当于hash(密钥+input))
public class OneWayEncryptUtils {
private static final char[] HEX_CHARS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
private static final String MD5 = "MD5";
private static final String SHA256 = "SHA-256";
private static final String MAC_MD5 = "HmacMD5";
private static void checkSrcString(String src){
if(src == null || "".equals(src)){
throw new IllegalArgumentException("源数据不能为空");
}
}
private static String encrypt(byte[] src,String algorithm) throws NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
byte[] bytes = messageDigest.digest(src);
return encodeHex(bytes);
}
/**
* MD5进行单向加密
*/
public static String MD5Encrypt(String src){
try {
checkSrcString(src);
return encrypt(src.getBytes(),MD5);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
/**
* SHA256进行单向加密
*/
public static String SHA256Encrypt(String src){
try {
checkSrcString(src);
return encrypt(src.getBytes(),SHA256);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
/**
* HamcMD5使用随机生成的密钥进行单向加密,返回密钥和密文
*/
public static Map<String,byte[]> HmacEncrypt(String src) throws Exception {
checkSrcString(src);
Map<String,byte[]> hmacInfoMap = new HashMap<>(2);
//1.获取HmacMD5的密钥生成器
KeyGenerator keyGenerator = KeyGenerator.getInstance(MAC_MD5);
//2.随机生成一个密钥
SecretKey key = keyGenerator.generateKey();
Mac mac = Mac.getInstance(MAC_MD5);
//3.初始化密钥
mac.init(key);
//4.加密
hmacInfoMap.put("encryptCode",mac.doFinal(src.getBytes()));
hmacInfoMap.put("encryptKey",key.getEncoded());
return hmacInfoMap;
}
/**
* HamcMD5使用外部提供的密钥进行单向加密,返回密文
*/
public static byte[] HmacEncrypt(String src, byte[] sKey) throws Exception {
checkSrcString(src);
SecretKey secretKey = new SecretKeySpec(sKey, MAC_MD5);
Mac mac = Mac.getInstance(MAC_MD5);
mac.init(secretKey);
return mac.doFinal(src.getBytes());
}
private static String encodeHex(byte[] bytes) {
char[] chars = new char[32];
for(int i = 0; i < chars.length; i += 2) {
byte b = bytes[i / 2];
chars[i] = HEX_CHARS[b >>> 4 & 15];
chars[i + 1] = HEX_CHARS[b & 15];
}
return new String(chars);
}
}
三、双向加密
可逆加密,根据密文可解析出原文,一般用于网络数据传输前后对数据加解密。双向加密又分对称加密和非对称加密。
- 对称加密又叫单密钥加密,是通过单个密钥进行加解密的算法。
- 非对称加密是用公钥和私钥来加解密的算法,私钥可以用来解密公钥加密的密文,公钥无法揭秘私钥加密的密文。
1.对称加密
常见的对称加密算法有如下几种:
算法 | 密钥长度 | 工作模式 | 填充模式 |
---|---|---|---|
AES | 128/192/256 | ECB/CBC/PCBC/CTR/… | NoPadding/PKCS5Padding/PKCS7Padding/… |
DES | 56/64 | ECB/CBC/PCBC/CTR/… | NoPadding/PKCS5Padding/… |
IDEA | 128 | ECB | PKCS5Padding/PKCS7Padding/… |
密钥长度直接决定加密强度,而 工作模式和填充模式可以看成是对称加密算法的参数和格式选择 。Java标准库提供的算法实现并不包括所有的工作模式和所有填充模式,但是通常我们只需要挑选常用的使用就可以了。
Java提供了一些用于对称加密的类,常用的如下:
- KeyGenerator:对称加密的密钥生成器。支持的加密算法有:AES、ARCFOUR、Blowfish、DES、DESede、Hmac、RC2。(其中init(int keySize)可用于设置密钥生成器生成的密钥长度)
- SecretKey:代表密钥。
- Cipher:Java提供的用于做对称加密算法中加解密的工具。
- Cipher.ENCRYPT_MODE表示加密模式
- Cipher.DECRYPT_MODE表示解密模式
- SecureRandom:安全的随机种子。可用于生成指定长度且随机的子节数组。
- IvParameterSpec:代表算法参数规范,里面封装了向量Iv,使用CBC 有向量模式时,必须传入,如果是ECB(无向量模式)则可以不传。
Java对称加密编程流程如下:
- 根据算法名称和密钥实例化SecretKey对象实例;
- 根据算法名称/工作模式/填充模式获取Cipher实例;
- 初始化Cipher实例,需要指定SecretKey、加解密模式、CBC模式需要传入向量;
- 加/解密。
AES加解密实现
public class AesUtils {
private static final String CIPHER_VALUE = "AES/CBC/PKCS5Padding";
private static final String algorithm = "AES";
public static byte[] encrypy(byte[] sKey, byte[] srcBytes) throws Exception {
SecretKey secretKey = new SecretKeySpec(sKey, algorithm);
Cipher cipher = Cipher.getInstance(CIPHER_VALUE);
//CBC模式需要生成一个16子节的向量,此处使用SecureRandom生成
SecureRandom sr = SecureRandom.getInstanceStrong();
byte[] Iv = sr.generateSeed(16);
IvParameterSpec IvPS = new IvParameterSpec(Iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, IvPS);
return mergeByteArray(Iv,cipher.doFinal(srcBytes));
}
public static byte[] decrypy(byte[] sKey, byte[] targetBytes) throws Exception {
//获取Iv
byte[] Iv = new byte[16];
System.arraycopy(targetBytes,0,Iv,0,16);
//获取密文
byte[] encryptBytes = new byte[targetBytes.length - 16];
System.arraycopy(targetBytes,16,encryptBytes,0,targetBytes.length - 16);
SecretKey secretKey = new SecretKeySpec(sKey, algorithm);
Cipher cipher = Cipher.getInstance(CIPHER_VALUE);
cipher.init(Cipher.DECRYPT_MODE,secretKey,new IvParameterSpec(Iv));
return cipher.doFinal(encryptBytes);
}
private static byte[] mergeByteArray(byte[] bytes1, byte[] bytes2){
byte[] result = new byte[bytes1.length + bytes2.length];
System.arraycopy(bytes1,0,result,0,bytes1.length);
System.arraycopy(bytes2,0,result,bytes1.length,bytes2.length);
return result;
}
}
生成密钥进行测试
public static void main(String[] args) throws Exception {
String src = "你好吗,我很好";
KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
keyGenerator.init(128);
byte[] sKey = keyGenerator.generateKey().getEncoded();
byte[] encryptBytes = AesUtils.encrypy(sKey,src.getBytes());
System.out.println(new String(AesUtils.decrypy(sKey, encryptBytes)));
//你好吗,我很好
}
参考:https://blog.csdn.net/wangmx1993328/article/details/106170060