在阅读开源代码过程中,发现出现了好多crypto和digest类的代码,发现是加密方面的使用,以前也看过加密原理,但是似是而非没有理解,这次先记录一下java下使用已有的类来完成我们的加密,为后面的深入打下基础(先学会使用再学习原理 :) )
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("x",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)会产生不同的长度大小,缺点是单向的,根据信息熵不可以得到输入的数据,这也不算缺点,双向的就是加密,下面来介绍
这个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了文件文件中保存的是加密后的数据也无法破解
通过阅读开源代码,一点一点慢慢进步
