Android常见的加密和算法
1.不可逆的算法
主要为MD5和SHA-1算法。(二者都不属于加密只能算作一种算法)
相同点:都是使用目前比较广泛的散列(Hash)函数,就是把任意长度的输入,变换成固定长度的输出,该输出就是散列值。计算的时候所有的数据都参与了运算,其中任何一个数据变化了都会导致计算出来的Hash值完全不同。(理论上来讲产生的密文都有可能产生碰撞)
不同点:MD5输出是128位的,SHA-1输出是160位的,MD5比SHA1运行速度快,SHA1比MD5强度高。MD5一般用于文件的校验,SHA-1主要使用于数字签名标准。
MD5使用:
1 public static String digest(String content){ 2 StringBuilder builder = new StringBuilder(); 3 try { 4 MessageDigest msgDitest = MessageDigest.getInstance("MD5"); 5 msgDitest.update(content.getBytes()); 6 byte[] digests = msgDitest.digest(); 7 //将每个字节转为16进制 8 for (int i=0;i<digests.length;i++){ 9 // TODO: 2019/11/10 需要再了解一下 10 builder.append(Integer.toHexString(digests[i] & 0xff +8));//+8为加盐操作 11 } 12 } catch (NoSuchAlgorithmException e) { 13 e.printStackTrace(); 14 } 15 return builder.toString(); 16 }
SHA-1使用:
1 public static String sha1Digest(String content){ 2 StringBuilder builder = new StringBuilder(); 3 try { 4 MessageDigest msgDitest = MessageDigest.getInstance("SHA-1"); 5 msgDitest.update(content.getBytes()); 6 byte[] digests = msgDitest.digest(); 7 //将每个字节转为16进制 8 for (int i=0;i<digests.length;i++){ 9 // TODO: 2019/11/10 再了解一下 10 builder.append(Integer.toHexString(digests[i] & 0xff +8));//+8为加盐操作 11 } 12 } catch (NoSuchAlgorithmException e) { 13 e.printStackTrace(); 14 } 15 return builder.toString(); 16 }
2.可逆算法
其中可逆算法按照密钥的数量和加密规则又分为对称加密和非对称加密。
(1)对称加密
密钥可以自己指定,只有一把密钥。常用的对称加密算法有DES和AES两种。对称加密的速度快,但是缺点是安全性低,因为只要密钥暴漏,数据就可以被解密。
AES加密解密使用:
1 package com.cn; 2 3 import sun.misc.BASE64Decoder; 4 import sun.misc.BASE64Encoder; 5 6 import javax.crypto.*; 7 import javax.crypto.spec.SecretKeySpec; 8 import java.io.IOException; 9 import java.io.UnsupportedEncodingException; 10 import java.security.InvalidKeyException; 11 import java.security.NoSuchAlgorithmException; 12 import java.security.SecureRandom; 13 import java.util.Scanner; 14 15 public class SymmetricEncoder { 16 /* 17 * 加密 18 * 1.构造密钥生成器 19 * 2.根据ecnodeRules规则初始化密钥生成器 20 * 3.产生密钥 21 * 4.创建和初始化密码器 22 * 5.内容加密 23 * 6.返回字符串 24 */ 25 public static String AESEncode(String encodeRules,String content){ 26 try { 27 //1.构造密钥生成器,指定为AES算法,不区分大小写 28 KeyGenerator keygen=KeyGenerator.getInstance("AES"); 29 //2.根据ecnodeRules规则初始化密钥生成器 30 //生成一个128位的随机源,根据传入的字节数组 31 keygen.init(128, new SecureRandom(encodeRules.getBytes())); 32 //3.产生原始对称密钥 33 SecretKey original_key=keygen.generateKey(); 34 //4.获得原始对称密钥的字节数组 35 byte [] raw=original_key.getEncoded(); 36 //5.根据字节数组生成AES密钥 37 SecretKey key=new SecretKeySpec(raw, "AES"); 38 //6.根据指定算法AES自成密码器 39 Cipher cipher=Cipher.getInstance("AES"); 40 //7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEY 41 cipher.init(Cipher.ENCRYPT_MODE, key); 42 //8.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码 43 byte [] byte_encode=content.getBytes("utf-8"); 44 //9.根据密码器的初始化方式--加密:将数据加密 45 byte [] byte_AES=cipher.doFinal(byte_encode); 46 //10.将加密后的数据转换为字符串 47 //这里用Base64Encoder中会找不到包 48 //解决办法: 49 //在项目的Build path中先移除JRE System Library,再添加库JRE System Library,重新编译后就一切正常了。 50 String AES_encode=new String(new BASE64Encoder().encode(byte_AES)); 51 //11.将字符串返回 52 return AES_encode; 53 } catch (NoSuchAlgorithmException e) { 54 e.printStackTrace(); 55 } catch (NoSuchPaddingException e) { 56 e.printStackTrace(); 57 } catch (InvalidKeyException e) { 58 e.printStackTrace(); 59 } catch (IllegalBlockSizeException e) { 60 e.printStackTrace(); 61 } catch (BadPaddingException e) { 62 e.printStackTrace(); 63 } catch (UnsupportedEncodingException e) { 64 e.printStackTrace(); 65 } 66 67 //如果有错就返加null 68 return null; 69 } 70 /* 71 * 解密 72 * 解密过程: 73 * 1.同加密1-4步 74 * 2.将加密后的字符串反纺成byte[]数组 75 * 3.将加密内容解密 76 */ 77 public static String AESDncode(String encodeRules,String content){ 78 try { 79 //1.构造密钥生成器,指定为AES算法,不区分大小写 80 KeyGenerator keygen=KeyGenerator.getInstance("AES"); 81 //2.根据ecnodeRules规则初始化密钥生成器 82 //生成一个128位的随机源,根据传入的字节数组 83 keygen.init(128, new SecureRandom(encodeRules.getBytes())); 84 //3.产生原始对称密钥 85 SecretKey original_key=keygen.generateKey(); 86 //4.获得原始对称密钥的字节数组 87 byte [] raw=original_key.getEncoded(); 88 //5.根据字节数组生成AES密钥 89 SecretKey key=new SecretKeySpec(raw, "AES"); 90 //6.根据指定算法AES自成密码器 91 Cipher cipher=Cipher.getInstance("AES"); 92 //7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二个参数为使用的KEY 93 cipher.init(Cipher.DECRYPT_MODE, key); 94 //8.将加密并编码后的内容解码成字节数组 95 byte [] byte_content= new BASE64Decoder().decodeBuffer(content); 96 /* 97 * 解密 98 */ 99 byte [] byte_decode=cipher.doFinal(byte_content); 100 String AES_decode=new String(byte_decode,"utf-8"); 101 return AES_decode; 102 } catch (NoSuchAlgorithmException e) { 103 e.printStackTrace(); 104 } catch (NoSuchPaddingException e) { 105 e.printStackTrace(); 106 } catch (InvalidKeyException e) { 107 e.printStackTrace(); 108 } catch (IOException e) { 109 e.printStackTrace(); 110 } catch (IllegalBlockSizeException e) { 111 e.printStackTrace(); 112 } catch (BadPaddingException e) { 113 e.printStackTrace(); 114 } 115 116 //如果有错就返加null 117 return null; 118 } 119 120 public static void main(String[] args) { 121 SymmetricEncoder se=new SymmetricEncoder(); 122 Scanner scanner=new Scanner(System.in); 123 /* 124 * 加密 125 */ 126 System.out.println("使用AES对称加密,请输入加密的规则"); 127 String encodeRules=scanner.next(); 128 System.out.println("请输入要加密的内容:"); 129 String content = scanner.next(); 130 System.out.println("根据输入的规则"+encodeRules+"加密后的密文是:"+se.AESEncode(encodeRules, content)); 131 132 /* 133 * 解密 134 */ 135 System.out.println("使用AES对称解密,请输入加密的规则:(须与加密相同)"); 136 encodeRules=scanner.next(); 137 System.out.println("请输入要解密的内容(密文):"); 138 content = scanner.next(); 139 System.out.println("根据输入的规则"+encodeRules+"解密后的明文是:"+se.AESDncode(encodeRules, content)); 140 } 141 }
DES加密解密使用:
1 package com.cn; 2 3 import javax.crypto.*; 4 import javax.crypto.spec.DESKeySpec; 5 import java.security.InvalidAlgorithmParameterException; 6 import java.security.InvalidKeyException; 7 import java.security.NoSuchAlgorithmException; 8 import java.security.SecureRandom; 9 import java.security.spec.InvalidKeySpecException; 10 11 public class DESUtil { 12 public static byte[] encode(String mes) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidKeySpecException, InvalidAlgorithmParameterException { 13 SecureRandom random = new SecureRandom(); 14 // TODO: 2019/11/10 密钥长度应该是要大于8 15 DESKeySpec desKey = new DESKeySpec("123abc123".getBytes()); 16 //创建一个密匙工厂,然后用它把DESKeySpec转换成 17 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); 18 SecretKey securekey = keyFactory.generateSecret(desKey); 19 //Cipher对象实际完成加密操作 20 Cipher cipher = Cipher.getInstance("DES"); 21 //用密匙初始化Cipher对象 22 cipher.init(Cipher.ENCRYPT_MODE, securekey, random); 23 return cipher.doFinal(mes.getBytes()); 24 } 25 26 public static byte[] decode(byte[] encodeBytes) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException { 27 // DES算法要求有一个可信任的随机数源 28 SecureRandom random = new SecureRandom(); 29 // 创建一个DESKeySpec对象 30 DESKeySpec desKey = new DESKeySpec("123abc123".getBytes()); 31 // 创建一个密匙工厂 32 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); 33 // 将DESKeySpec对象转换成SecretKey对象 34 SecretKey securekey = keyFactory.generateSecret(desKey); 35 // Cipher对象实际完成解密操作 36 Cipher cipher = Cipher.getInstance("DES"); 37 // 用密匙初始化Cipher对象 38 cipher.init(Cipher.DECRYPT_MODE, securekey, random); 39 // 真正开始解密操作 40 return cipher.doFinal(encodeBytes); 41 } 42 }
(2)非对称加密
常见的非对称加密算法是RSA;他有两把密钥,且是由程序生成的,不能自己指定;特点是加密速度比较慢,但是安全性比较高;加密和解密的规则是:公钥加密只能私钥解密,私钥加密只能公钥解密。
1 package com.cn; 2 3 import android.util.Base64; 4 5 import javax.crypto.Cipher; 6 import java.security.*; 7 import java.security.interfaces.RSAPrivateKey; 8 import java.security.interfaces.RSAPublicKey; 9 import java.security.spec.PKCS8EncodedKeySpec; 10 import java.security.spec.X509EncodedKeySpec; 11 import java.util.HashMap; 12 import java.util.Map; 13 14 public class RSAUtil { 15 private static Map<Integer, String> keyMap = new HashMap<Integer, String>(); //用于封装随机产生的公钥与私钥 16 public static void main(String[] args) throws Exception { 17 //生成公钥和私钥 18 genKeyPair(); 19 //加密字符串 20 String message = "abc12301230"; 21 System.out.println("随机生成的公钥为:" + keyMap.get(0)); 22 System.out.println("随机生成的私钥为:" + keyMap.get(1)); 23 String messageEn = encrypt(message,keyMap.get(0)); 24 System.out.println(message + "\t加密后的字符串为:" + messageEn); 25 String messageDe = decrypt(messageEn,keyMap.get(1)); 26 System.out.println("还原后的字符串为:" + messageDe); 27 } 28 29 /** 30 * 随机生成密钥对 31 * @throws NoSuchAlgorithmException 32 */ 33 public static void genKeyPair() throws NoSuchAlgorithmException { 34 // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象 35 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); 36 // 初始化密钥对生成器,密钥大小为96-1024位 37 keyPairGen.initialize(1024,new SecureRandom()); 38 // 生成一个密钥对,保存在keyPair中 39 KeyPair keyPair = keyPairGen.generateKeyPair(); 40 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到私钥 41 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 得到公钥 42 String publicKeyString = new String(Base64.encode(publicKey.getEncoded(), 0)); 43 // 得到私钥字符串 44 String privateKeyString = new String(Base64.encode(privateKey.getEncoded(), 0)); 45 // 将公钥和私钥保存到Map 46 keyMap.put(0,publicKeyString); //0表示公钥 47 keyMap.put(1,privateKeyString); //1表示私钥 48 } 49 /** 50 * RSA公钥加密 51 * 52 * @param str 53 * 加密字符串 54 * @param publicKey 55 * 公钥 56 * @return 密文 57 * @throws Exception 58 * 加密过程中的异常信息 59 */ 60 public static String encrypt(String str, String publicKey) throws Exception{ 61 //base64编码的公钥 62 byte[] decoded = Base64.decode(publicKey, 0); 63 RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded)); 64 //RSA加密 65 Cipher cipher = Cipher.getInstance("RSA"); 66 cipher.init(Cipher.ENCRYPT_MODE, pubKey); 67 String outStr = new String(Base64.encode(cipher.doFinal(str.getBytes("UTF-8")), 0)); 68 return outStr; 69 } 70 71 /** 72 * RSA私钥解密 73 * 74 * @param str 75 * 加密字符串 76 * @param privateKey 77 * 私钥 78 * @return 铭文 79 * @throws Exception 80 * 解密过程中的异常信息 81 */ 82 public static String decrypt(String str, String privateKey) throws Exception{ 83 //64位解码加密后的字符串 84 byte[] inputByte = Base64.decode(str.getBytes(), 0); 85 //base64编码的私钥 86 byte[] decoded = Base64.decode(privateKey, 0); 87 RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded)); 88 //RSA解密 89 Cipher cipher = Cipher.getInstance("RSA"); 90 cipher.init(Cipher.DECRYPT_MODE, priKey); 91 String outStr = new String(cipher.doFinal(inputByte)); 92 return outStr; 93 } 94 }
// TODO AES加密模式, padding填充模式??
参考资料:https://www.cnblogs.com/yegong0214/p/6498409.html
https://blog.csdn.net/u011897782/article/details/81163387
https://blog.csdn.net/joshho/article/details/88716314
https://www.cnblogs.com/jying/p/9511247.html
https://blog.csdn.net/qy20115549/article/details/83105736
// TODO
https://www.cnblogs.com/think-in-java/p/5527389.html