一、Java常用API之Base64加密与解密
在进行任何语言类库的设计过程之中,除了比较大型的类库结构之外,例如:国际化、正则表达式、字符串等,还会提供很多小类库,简单的理解为它可以完成部分的操作功能,而本文讨论的Base64就属于这样的一中小的类库功能。Base64是在软件设计过程中比较常见的一中数据的加密和解密的处理形式,这个类实在JDK1.8之后的版本菜开始提供的工具类。
为了数据的安全一般在网络上都会进行加密的方式进行数据的传输,一但加密之后就需要有特定的方式来进行解密的处理操作,Base64是一种数据的处理格式,不完全只是为了加密而存在,但是却可以实现加密的功能。
二、常用API
1、加密、解密
/**
* 加密、解密
*/
@Test
public void demo01() {
String message = "www.baidu.com";//原始数据
Base64.Encoder encoder = Base64.getEncoder();//加密工具类
byte[] encode = encoder.encode(message.getBytes());//需要传字节数组对数据进行加密处理
System.out.println("【加密后的数据】" + new String(encode));
Base64.Decoder decoder = Base64.getDecoder();//解密工具类
byte[] decode = decoder.decode(encode);//同样需要传入字节数组进行解密
System.out.println("【解密后的数据】" + new String(decode));
}
2、自定义数据加密的工具类
Base64并不属于私人的加密处理,而是属于一中在整个互联网上最为常见的一中数据的编码形式,所以如果现在纯粹使用以上的模式基本上是没有加密的意义的,如果要让这些数据存在加密的意义,最佳的做法一定是执行多次的加密处理,同时为了保证数据更加安全,一般还建议在数据前追加一个盐值(salt)。
范例: 自定义数据加密的工具类
/**
* 密码加密工具类
*/
public class PasswordUtil {
private static final int REPEAT = 5; // 表示重复加密5次
private static final String SALT = "www.baidu.com";// 追加操作盐值(真正应用的时候盐值要使用随机生成的字符串)
private PasswordUtil(){}//该类的方法为static方法
/**
* 加密的方法
* @param password 需要加密的字符串
* @return 加密后的字符串
*/
public static String encrypt(String password){
String encodeData = "{"+ SALT +"}" + password;
Base64.Encoder encoder = Base64.getEncoder();//获得加密类对象
for (int i = 0; i < REPEAT; i++) {
encodeData = encoder.encodeToString(encodeData.getBytes());//执行加密操作
}
return encodeData;
}
/**
* 解密的方法
* @param password 加密后的字符串
* @return 原始字符串数据
*/
public static String decrypt(String password){
Base64.Decoder decoder = Base64.getDecoder();//获得解密类对象
byte[] bytes = password.getBytes();//根据字节数组进行解密操作
for (int i = 0; i < REPEAT; i++) {
bytes = decoder.decode(bytes);//多次解密
}
String decodeData = new String(bytes);
return decodeData.substring(("{"+ SALT +"}").length());
}
}
三、RSA非对称加密
1、秘钥生成工具类
/**
* 非对称加密:
* 用公钥加密,用私钥解密,并且公钥加密后的数据无法再用公钥解密
* 生成两把密钥:公钥和私钥
* 公钥用于加密,私钥用于解密
*/
public class RSAKeyCreater {
/**
* 注意:
* 1、生成公钥和私钥
* 2、公钥和私钥应该一起生成,否则加密后无法正确解密
* 3、每次调用此方法生成的公钥和私钥都不相同
* @return 公钥和私钥的集合
*/
public static Map<String, Object> createKeyPairs() {
Map<String,Object> map = new HashMap<>(2);
try {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");
generator.initialize(512, new SecureRandom());
KeyPair pair = generator.generateKeyPair();
PublicKey pubKey = pair.getPublic();
PrivateKey privKey = pair.getPrivate();
map.put("publicKey",pubKey);
map.put("privateKey",privKey);
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
}
2、加密解密工具类
/**
* RSA加密解密类
*/
public class RsaUtil {
/**
* RSA加密
* @param data 待加密数据
* @param publicKey 公钥
* @return 加密后的数据
*/
public static String encryptData(String data, PublicKey publicKey) {
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] dataToEncrypt = data.getBytes("utf-8");
byte[] encryptedData = cipher.doFinal(dataToEncrypt);
String encryptString = Base64.encodeBase64String(encryptedData);
return encryptString;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* RSA解密
* @param data 待解密数据
* @param privateKey 私钥
* @return 解密后的数据
*/
public static String decryptData(String data, PrivateKey privateKey) {
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] descryptData = Base64.decodeBase64(data);
byte[] descryptedData = cipher.doFinal(descryptData);
String srcData = new String(descryptedData, "utf-8");
return srcData;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
四、MD5
/**
* MD5加密---不可逆
*/
public class MD5Utils {
/**
* 生成含有随机盐的密码
* @param password 要加密的密码
* @return String 加密后的含有随机盐的密码
*/
public static String getSaltMD5(String password) {
// 生成一个16位的随机数
Random random = new Random();
StringBuilder sBuilder = new StringBuilder(16);
sBuilder.append(random.nextInt(99999999)).append(random.nextInt(99999999));
int len = sBuilder.length();
if (len < 16) {
for (int i = 0; i < 16 - len; i++) {
sBuilder.append("0");
}
}
// 生成最终的加密盐值
String salt = sBuilder.toString();
password = md5Hex(password + salt);
char[] cs = new char[48];
for (int i = 0; i < 48; i += 3) {
cs[i] = password.charAt(i / 3 * 2);
char c = salt.charAt(i / 3);
cs[i + 1] = c;
cs[i + 2] = password.charAt(i / 3 * 2 + 1);
}
return String.valueOf(cs);
}
/**
* 验证加盐后是否和原密码一致
* @param password 原密码
* @param password 加密之后的密码
* @return boolean true表示和原密码一致 false表示和原密码不一致
*/
public static boolean getSaltverifyMD5(String password, String md5str) {
char[] cs1 = new char[32];
char[] cs2 = new char[16];
for (int i = 0; i < 48; i += 3) {
cs1[i / 3 * 2] = md5str.charAt(i);
cs1[i / 3 * 2 + 1] = md5str.charAt(i + 2);
cs2[i / 3] = md5str.charAt(i + 1);
}
String Salt = new String(cs2);
return md5Hex(password + Salt).equals(String.valueOf(cs1));
}
/**
* byte[]字节数组 转换成 十六进制字符串
* @param arr 要转换的byte[]字节数组
* @return String 返回十六进制字符串
*/
private static String hex(byte[] arr) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < arr.length; ++i) {
sb.append(Integer.toHexString((arr[i] & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString();
}
/**
* MD5加密,并把结果由字节数组转换成十六进制字符串
* @param str 要加密的内容
* @return String 返回加密后的十六进制字符串
*/
private static String md5Hex(String str) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(str.getBytes());
return hex(digest);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
// 原密码
String plaintext = "admin";
// 获取加盐后的MD5值
String ciphertext = MD5Utils.getSaltMD5(plaintext);
System.out.println("加盐后MD5:" + ciphertext);
System.out.println("是否是同一字符串:" + MD5Utils.getSaltverifyMD5(plaintext, ciphertext));
}
}