java 信息熵 加密
在阅读开源代码过程中,发现出现了好多crypto和digest类的代码,发现是加密方面的使用,以前也看过加密原理,但是似是而非没有理解,这次先记录一下java下使用已有的类来完成我们的加密,为后面的深入打下基础(先学会使用再学习原理 :) )
1.MessageDigest
java.security.MessageDigest类用于为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法 简单点说就是用于生成散列码。信息摘要是安全的单向哈希函数,它接收任意大小的数据,输出固定长度的哈希值。
public class DigestLeo {
//MD5 and SHA256
public static final DigestLeo MD5 = new DigestLeo("MD5");
public static final DigestLeo SHA256 = new DigestLeo("SHA-256");
//在构造函数中指定算法
private final String algorithm;
private DigestLeo(String algorithm) {
this.algorithm = algorithm;
}
/**
* @param data 输入
* 产生相应的散列码,数组
* */
public byte[] getRaw(String data){
return getRaw(data.getBytes(StandardCharsets.UTF_8));
}
/**
* 根据相应的算法产生散列码,数组
* 这个方法和上面的区别仅仅是输入不同,一个数组一个字符串
* */
public byte[] getRaw(byte[] data){
try {
return MessageDigest.getInstance(algorithm).digest(data);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
/**
* string to hex
* */
public String getHex(String data){
return getHex(data.getBytes(StandardCharsets.UTF_8));
}
/**
* bytes to hex
* */
private String getHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : getRaw(bytes)){
sb.append(String.format("%02x",0xFF&b));
}
return sb.toString();
}
/**
* 测试代码
*/
public static void main(String[] args) {
final String input = "leo";
DigestLeo d1 = MD5; //使用MD5算法
System.out.println(Arrays.toString(d1.getRaw(input)));
System.out.println(Arrays.toString(d1.getRaw(input)));
System.out.println(d1.getHex(input));
System.out.println(d1.getHex(input));
//同一个算法会产生长度相同的输出
System.out.println(Arrays.toString(d1.getRaw("leocat")));
System.out.println(Arrays.toString(d1.getRaw("leocat")));
System.out.println(d1.getHex("leocat"));
System.out.println(d1.getHex("leocat"));
//不同的算法产生的长度不同
DigestLeo d2 = SHA256; //使用SHA256算法
System.out.println(Arrays.toString(d2.getRaw(input)));
System.out.println(Arrays.toString(d2.getRaw(input)));
System.out.println(d2.getHex(input));
System.out.println(d2.getHex(input));
}
}
使用场景 , 在android中使用SharedPreference会用一个文件名的参数,当我们直接使用字符串时会暴露我们的信息,这时我们就可以使用MD5产生一个字符串的信息熵来作位文件名,或者在保存一些数据到文件中文件名可以这样产生,特点是任意的输入产生特定大小的输出,当然不同的算法(比如MD5和SHA256)会产生不同的长度大小,缺点是单向的,根据信息熵不可以得到输入的数据,这也不算缺点,双向的就是加密,下面来介绍
2.Cipher,此类为加密和解密提供密码功能。
这个demo只是简单的加密,仅仅可以加密的byte数组是16位,再测试过程中遇到了各种异常,在这里暂时加密16位输入
public class CryptoLeo {
//加密的数组
private static byte[] raw = new byte[]{'l', 'e', 'o', '-', '-', '-', '-', '-', 'c', 'a', 't', '-', '-', 'o', ':', ')'};
//instance
public static final CryptoLeo AES = new CryptoLeo("AES" );
//AES算法
private static final SecretKey secret = new SecretKeySpec(raw,"AES" );
private final String algorithm ;
public CryptoLeo(String algorithm) {
this.algorithm = algorithm;
}
/**
* 加密
* 输入要加密的16位数组
*/
public byte[] decrypt(byte[] data) throws CryptoException {
byte[] ret;
try {
Cipher cipher = Cipher.getInstance(algorithm+"/CBC/NoPadding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(new byte[cipher.getBlockSize()]);
cipher.init(Cipher.DECRYPT_MODE , secret , ivParameterSpec );
ret = cipher.doFinal(data);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException
| InvalidKeyException | BadPaddingException | IllegalBlockSizeException e ) {
throw new CryptoException("decrypt error :" , e);
}
return ret;
}
/**
*解密
* 输入的是加密后的数组
*/
public byte[] encrypt(byte[] data) throws CryptoException {
try {
Cipher cipher = Cipher.getInstance(algorithm+"/CBC/NoPadding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(new byte[cipher.getBlockSize()]);
cipher.init(Cipher.ENCRYPT_MODE , secret , ivParameterSpec);
return cipher.doFinal(data);
} catch (NoSuchAlgorithmException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException e) {
throw new CryptoException("Encrypt error.", e);
}
}
public static class CryptoException extends Exception {
private CryptoException(String message, Throwable cause) {
super(message, cause);
}
}
public static void main(String[] args) {
CryptoLeo c = AES;
try {
byte[] datas = AES.decrypt(raw);
System.out.println(Arrays.toString(datas));
System.out.println(new String(datas));
System.out.println(new String(AES.encrypt(datas)));
} catch (CryptoException e) {
e.printStackTrace();
}
}
}
使用场景 ,结合上面的MessageDigest,在SharedPreference中,文件名有MessageDigest产生,里面重要的数据可以加密后保存,这样在我们需要使用时可以解密获取数据,但是别人即使copy了文件文件中保存的是加密后的数据也无法破解
3.学习体悟
通过阅读开源代码,一点一点慢慢进步