Android算法知识-常用加密算法

https://blog.csdn.net/u013718120/article/details/56486408
https://github.com/songxiaoliang/EncryptionLib

一、对称加密算法

对称密码算法的 加密密钥和解密密钥相同
对于大多数对称密码算法,加解密过程互逆
AES 对 DES提高了安全性

1.DES,3DES

DES使用【56位密钥】以及附加的【8位奇偶校验位】对【64位的数据块】进行加密
并对64位的数据块进行16轮编码。
与每轮编码时,一个48位的“每轮”密钥值由56位的完整密钥得出来。

DES 密钥有效位是 56位,还有8位是用于奇偶校验位。

DES 加密对明文是有限制的,只会对64位明文即8个字节的数据加密

3DES 使用【两个密钥】对明文进行三次加密。

假设两个密钥是K1和K2

3DES 加密过程: C=Ek3(Dk2(Ek1(M)))
1) 用密钥K1进行DES加密。
2) 用K2对步骤1的结果进行DES解密。
3) 用步骤2的结果使用密钥K1进行DES加密。

3DES 解密过程: M=Dk1(EK2(Dk3©))
1) 用密钥K1堆数据进行进行DES解密。
2) 用K2对步骤1的结果进行DES加密。
3) 用步骤2的结果使用密钥K1进行DES解密。

3DES 的缺点,是要花费原来三倍时间,优点是使用两个密钥,有效密钥长度112位。

  • 优点:算法公开、计算量小、加密速度快、加密效率高

  • 缺点:双方都使用同样密钥,安全性得不到保证

    public class DESUtils {
      //生成密钥
      public static byte[] generateKey() {
      	KeyGenerator keyGen = null;
      	try {
      		keyGen = KeyGenerator.getInstance("DES"); // 秘钥生成器
      	} catch (NoSuchAlgorithmException e) {
      		e.printStackTrace();
      	}
      	keyGen.init(64); //初始密钥生成器,DES使用56位密钥
      	SecretKey secretKey = keyGen.generateKey(); // 生成秘钥
      	return secretKey.getEncoded(); // 获取秘钥字节数组
      }
    
      //加密
      public static byte[] encrypt(byte[] data, byte[] key) {
      	SecretKey secretKey = new SecretKeySpec(key, "DES"); // 恢复秘钥
      	Cipher cipher = null;
      	byte[] cipherBytes = null;
      	try {
      		cipher = Cipher.getInstance("DES"); // 对Cipher完成加密或解密工作
      		cipher.init(Cipher.ENCRYPT_MODE, secretKey); // 对Cipher初始化,加密模式
      		cipherBytes = cipher.doFinal(data); // 加密数据
      	} catch (Exception e) {
      		e.printStackTrace();
      	}
      	return cipherBytes;
      }
    
      //解密
      public static byte[] decrypt(byte[] data, byte[] key) {
      	SecretKey secretKey = new SecretKeySpec(key, "DES"); // 恢复秘钥
      	Cipher cipher = null;
      	byte[] plainBytes = null;
      	try {
      		cipher = Cipher.getInstance("DES"); // 对Cipher初始化,加密模式
      		cipher.init(Cipher.DECRYPT_MODE, secretKey); // 对Cipher初始化,加密模式
      		plainBytes = cipher.doFinal(data); // 解密数据
      	} catch (Exception e) {
      		e.printStackTrace();
      	}
      	return plainBytes;
      }
    }
    
2.AES

AES 为分组密码,分组密码也就是把明文分成一组一组的,每组长度相等
每次加密一组数据,直到加密完整个明文

在AES标准规范中,分组长度只能是128位,也就是说,每个分组为16个字节(每个字节8位)
密钥的长度可以使用128位、192位或256位。密钥的长度不同,推荐加密轮数也不同。

AES密钥长度分组长度加密轮数
AES-12816 byte16 byte10
AES-19224 byte16 byte12
AES-25632 byte16 byte14
  • 优点:算法公开、计算量小、加密速度快、加密效率高

  • 缺点:双方都使用同样密钥,安全性得不到保证

    public class AESUtils {
      //生成秘钥
      public static byte[] generateKey() {
      	KeyGenerator keyGen = null;
      	try {
      		keyGen = KeyGenerator.getInstance("AES"); // 秘钥生成器
      	} catch (NoSuchAlgorithmException e) {
      		e.printStackTrace();
      	}
      	keyGen.init(256); // 初始秘钥生成器 AES-256
      	SecretKey secretKey = keyGen.generateKey(); // 生成秘钥
      	return secretKey.getEncoded(); // 获取秘钥字节数组
      }
    
      //加密
      public static byte[] encrypt(byte[] data, byte[] key) {
      	SecretKey secretKey = new SecretKeySpec(key, "AES"); // 恢复秘钥
      	Cipher cipher = null;
      	byte[] cipherBytes = null;
      	try {
      		cipher = Cipher.getInstance("AES"); // 对Cipher完成加密或解密工作
      		cipher.init(Cipher.ENCRYPT_MODE, secretKey); // 对Cipher初始化,加密模式
      		cipherBytes = cipher.doFinal(data); // 加密数据
      	} catch (Exception e) {
      		e.printStackTrace();
      	}
      	return cipherBytes;
      }
    
      //解密
      public static byte[] decrypt(byte[] data, byte[] key) {
      	SecretKey secretKey = new SecretKeySpec(key, "AES"); // 恢复秘钥
      	Cipher cipher = null;
      	byte[] plainBytes = null;
      	try {
      		cipher = Cipher.getInstance("AES"); //对Cipher初始化,加密模式
      		cipher.init(Cipher.DECRYPT_MODE, secretKey); //对Cipher初始化,加密模式
      		plainBytes = cipher.doFinal(data); // 解密数据
      	} catch (Exception e) {
      		e.printStackTrace();
      	}
      	return plainBytes;
      }
      //文件加密  kotlin代码
    fun encryptFile(key: ByteArray?, sourceFilePath: String?, destFilePath: String?) {
      val sourceFile = File(sourceFilePath)
      val destFile = File(destFilePath)
      if (sourceFile.exists() && sourceFile.isFile) {
          var ins: InputStream? = null
          var ous: OutputStream? = null
          var cin: CipherInputStream? = null
          try {
              if (!destFile.parentFile.exists()) {
                  destFile.parentFile.mkdirs()
              }
              destFile.createNewFile()
              ins = FileInputStream(sourceFile)
              ous = FileOutputStream(destFile)
              val secretKey: SecretKey = SecretKeySpec(key, ALGORITHM)
              val cipher = Cipher.getInstance(CIPHER_ALGORITHM)
              cipher.init(Cipher.ENCRYPT_MODE, secretKey)
              cin = CipherInputStream(ins, cipher)
              val cache = ByteArray(CACHE_SIZE)
              var nRead = 0
              while (cin.read(cache).also { nRead = it } != -1) {
                  ous.write(cache, 0, nRead)
                  ous.flush()
              }
          } catch (e: Exception) {
              e.printStackTrace()
          } finally {
              ous?.close()
              cin?.close()
              ins?.close()
          }
      }
    }
    
    /**
     * 文件解密
     */
    fun decryptFile(key: ByteArray?, sourceFilePath: String?, destFilePath: String?) {
      val sourceFile = File(sourceFilePath)
      val destFile = File(destFilePath)
      if (sourceFile.exists() && sourceFile.isFile) {
          var ins: FileInputStream? = null
          var ous: FileOutputStream? = null
          var cout: CipherOutputStream? = null
          try {
              if (!destFile.parentFile.exists()) {
                  destFile.parentFile.mkdirs()
              }
              destFile.createNewFile()
              ins = FileInputStream(sourceFile)
              ous = FileOutputStream(destFile)
              val secretKeySpec = SecretKeySpec(key, ALGORITHM)
              val cipher = Cipher.getInstance(CIPHER_ALGORITHM)
              cipher.init(Cipher.DECRYPT_MODE, secretKeySpec)
              cout = CipherOutputStream(ous, cipher)
              val cache = ByteArray(CACHE_SIZE)
              var nRead = 0
              while (ins.read(cache).also { nRead = it } != -1) {
                  cout.write(cache, 0, nRead)
                  cout.flush()
              }
          } catch (e: Exception) {
              e.printStackTrace()
          } finally {
              cout?.close()
              ous?.close()
              ins?.close()
          }
      }
    }
    }
    

注意点:
1、加密后的 字节数组,不能直接转为字符串。否则会抛异常。需要转为16进制字符串来保存。
2、同时,解密时,把16进制的加密字符串,转为字节数组,然后再解密
3、关于 AES/CBC/PKCS5Padding

/*使用CBC模式,需要一个向量iv,可增加加密算法的强度
* IvParameterSpec 的参数是一个16位的字节数组,不一定是密钥
*/
val iv = IvParameterSpec(key);
cipher = Cipher.getInstance(CIPHER_ALGORITHM) // 对Cipher完成加密或解密工作
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv) // 对Cipher初始化,加密模式

二、非对称加密算法

1.RSA

最流行的公钥密码算法,使用长度可变的密钥
既能用于数据加密也能用于数字签名的算法。

公钥加密,只能私钥解密;私钥加密,只能公钥解密。

RSA算法原理(涉及数学知识,看不懂,了解)
1)随机选择两个大质数p和q,p不等于q,计算N=pq
2)选择一个大于1小于N的自然数e,e必须与(p-1)(q-1)互素
3)用公式计算出d:d×e = 1 (mod (p-1)(q-1))
4)销毁p和q
5)最终得到的N和e就是“公钥”,d就是“私钥”,
  发送方使用N去加密数据,接收方只有使用d才能解开数据内容

基于大数计算,比DES要慢上几倍,通常只能用于加密少量数据或者加密密钥

私钥加解密都很耗时,服务器要求解密效率高,客户端私钥加密,服务器公钥解密比较好一点。
但实际操作中,比如:https、以及一些权威机构的证书,都是公钥开放出来,自己保留私钥。

实现分段加密:
RSA非对称加密内容长度有限制,1024位key的最多只能加密127位数据
否则就会报错(javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes)

RSA 算法规定:
待加密的字节数不能超过密钥的长度值除以 8 再减去 11(即:KeySize / 8 - 11)
加密后得到密文的字节数,正好是密钥的长度值除以 8(即:KeySize / 8)

  • 优点:不可逆,既能用于数据加密,也可以应用于数字签名

  • 缺点:RSA非对称加密内容长度有限制,1024位key的最多只能加密127位数据

    public class RSAUtils {
      	public static final String RSA = "RSA"; // 非对称加密密钥算法
      	/**
      	 * android系统的RSA实现是"RSA/None/NoPadding",而标准JDK实现是"RSA/None/PKCS1Padding" ,
      	 * 这造成了在android机上加密后无法在服务器上解密的原因,所以android要和服务器相同即可。
      	 */
      	public static final String ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding";//加密填充方式
      	public static final int DEFAULT_KEY_SIZE = 2048;//秘钥默认长度
      	public static final byte[] DEFAULT_SPLIT = "#PART#".getBytes();// 当要加密的内容超过bufferSize,则采用partSplit进行分块加密
      	public static final int DEFAULT_BUFFERSIZE = (DEFAULT_KEY_SIZE / 8) - 11;//当前秘钥支持加密的最大字节数
      /**
       * 随机生成RSA密钥对
       *
       * @param keyLength 密钥长度,范围:512~2048
       *                  一般1024
       *                  使用:
       *                  KeyPair keyPair=RSAUtils.generateRSAKeyPair(RSAUtils.DEFAULT_KEY_SIZE);
       *                  公钥:RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
       *                  私钥:RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
       */
      public static KeyPair generateRSAKeyPair(int keyLength) {
      	try {
      		KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA);
      		kpg.initialize(keyLength);
      		return kpg.genKeyPair();
      	} catch (NoSuchAlgorithmException e) {
      		e.printStackTrace();
      		return null;
      	}
      }
    
      //公钥对字符串进行加密
      public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
      	// 得到公钥
      	X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
      	KeyFactory kf = KeyFactory.getInstance(RSA);
      	PublicKey keyPublic = kf.generatePublic(keySpec);
      	// 加密数据
      	Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
      	cp.init(Cipher.ENCRYPT_MODE, keyPublic);
      	return cp.doFinal(data);
      }
    
      //私钥加密
      public static byte[] encryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
      	// 得到私钥
      	PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
      	KeyFactory kf = KeyFactory.getInstance(RSA);
      	PrivateKey keyPrivate = kf.generatePrivate(keySpec);
      	// 数据加密
      	Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
      	cipher.init(Cipher.ENCRYPT_MODE, keyPrivate);
      	return cipher.doFinal(data);
      }
    
      //公钥解密
      public static byte[] decryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
      	// 得到公钥
      	X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
      	KeyFactory kf = KeyFactory.getInstance(RSA);
      	PublicKey keyPublic = kf.generatePublic(keySpec);
      	// 数据解密
      	Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
      	cipher.init(Cipher.DECRYPT_MODE, keyPublic);
      	return cipher.doFinal(data);
      }
    
      //使用私钥进行解密
      public static byte[] decryptByPrivateKey(byte[] encrypted, byte[] privateKey) throws Exception {
      	// 得到私钥
      	PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
      	KeyFactory kf = KeyFactory.getInstance(RSA);
      	PrivateKey keyPrivate = kf.generatePrivate(keySpec);
      	// 解密数据
      	Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
      	cp.init(Cipher.DECRYPT_MODE, keyPrivate);
      	byte[] arr = cp.doFinal(encrypted);
      	return arr;
      }
    
      //用公钥对字符串进行分段加密
      public static byte[] encryptByPublicKeyForSpilt(byte[] data, byte[] publicKey) throws Exception {
      	int dataLen = data.length;
      	if (dataLen <= DEFAULT_BUFFERSIZE) {
      		return encryptByPublicKey(data, publicKey);
      	}
      	List<Byte> allBytes = new ArrayList<Byte>(2048);
      	int bufIndex = 0;
      	int subDataLoop = 0;
      	byte[] buf = new byte[DEFAULT_BUFFERSIZE];
      	for (int i = 0; i < dataLen; i++) {
      		buf[bufIndex] = data[i];
      		if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) {
      			subDataLoop++;
      			if (subDataLoop != 1) {
      				for (byte b : DEFAULT_SPLIT) {
      					allBytes.add(b);
      				}
      			}
      			byte[] encryptBytes = encryptByPublicKey(buf, publicKey);
      			for (byte b : encryptBytes) {
      				allBytes.add(b);
      			}
      			bufIndex = 0;
      			if (i == dataLen - 1) {
      				buf = null;
      			} else {
      				buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)];
      			}
      		}
      	}
      	byte[] bytes = new byte[allBytes.size()];
      	int i = 0;
      	for (Byte b : allBytes) {
      		bytes[i++] = b.byteValue();
      	}
      	return bytes;
      }
    
      //私钥分段加密
      public static byte[] encryptByPrivateKeyForSpilt(byte[] data, byte[] privateKey) throws Exception {
      	int dataLen = data.length;
      	if (dataLen <= DEFAULT_BUFFERSIZE) {
      		return encryptByPrivateKey(data, privateKey);
      	}
      	List<Byte> allBytes = new ArrayList<Byte>(2048);
      	int bufIndex = 0;
      	int subDataLoop = 0;
      	byte[] buf = new byte[DEFAULT_BUFFERSIZE];
      	for (int i = 0; i < dataLen; i++) {
      		buf[bufIndex] = data[i];
      		if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) {
      			subDataLoop++;
      			if (subDataLoop != 1) {
      				for (byte b : DEFAULT_SPLIT) {
      					allBytes.add(b);
      				}
      			}
      			byte[] encryptBytes = encryptByPrivateKey(buf, privateKey);
      			for (byte b : encryptBytes) {
      				allBytes.add(b);
      			}
      			bufIndex = 0;
      			if (i == dataLen - 1) {
      				buf = null;
      			} else {
      				buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)];
      			}
      		}
      	}
      	byte[] bytes = new byte[allBytes.size()];
      	int i = 0;
      	for (Byte b : allBytes) {
      		bytes[i++] = b.byteValue();
      	}
      	return bytes;
      }
    
      //公钥分段解密
      public static byte[] decryptByPublicKeyForSpilt(byte[] encrypted, byte[] publicKey) throws Exception {
      	int splitLen = DEFAULT_SPLIT.length;
      	if (splitLen <= 0) {
      		return decryptByPublicKey(encrypted, publicKey);
      	}
      	int dataLen = encrypted.length;
      	List<Byte> allBytes = new ArrayList<Byte>(1024);
      	int latestStartIndex = 0;
      	for (int i = 0; i < dataLen; i++) {
      		byte bt = encrypted[i];
      		boolean isMatchSplit = false;
      		if (i == dataLen - 1) {
      			// 到data的最后了
      			byte[] part = new byte[dataLen - latestStartIndex];
      			System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
      			byte[] decryptPart = decryptByPublicKey(part, publicKey);
      			for (byte b : decryptPart) {
      				allBytes.add(b);
      			}
      			latestStartIndex = i + splitLen;
      			i = latestStartIndex - 1;
      		} else if (bt == DEFAULT_SPLIT[0]) {
      			// 这个是以split[0]开头
      			if (splitLen > 1) {
      				if (i + splitLen < dataLen) {
      					// 没有超出data的范围
      					for (int j = 1; j < splitLen; j++) {
      						if (DEFAULT_SPLIT[j] != encrypted[i + j]) {
      							break;
      						}
      						if (j == splitLen - 1) {
      							// 验证到split的最后一位,都没有break,则表明已经确认是split段
      							isMatchSplit = true;
      						}
      					}
      				}
      			} else {
      				// split只有一位,则已经匹配了
      				isMatchSplit = true;
      			}
      		}
      		if (isMatchSplit) {
      			byte[] part = new byte[i - latestStartIndex];
      			System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
      			byte[] decryptPart = decryptByPublicKey(part, publicKey);
      			for (byte b : decryptPart) {
      				allBytes.add(b);
      			}
      			latestStartIndex = i + splitLen;
      			i = latestStartIndex - 1;
      		}
      	}
      	byte[] bytes = new byte[allBytes.size()];
      	int i = 0;
      	for (Byte b : allBytes) {
      		bytes[i++] = b.byteValue();
      	}
      	return bytes;
      }
    
      //私钥分段解密
      public static byte[] decryptByPrivateKeyForSpilt(byte[] encrypted, byte[] privateKey) throws Exception {
      	int splitLen = DEFAULT_SPLIT.length;
      	if (splitLen <= 0) {
      		return decryptByPrivateKey(encrypted, privateKey);
      	}
      	int dataLen = encrypted.length;
      	List<Byte> allBytes = new ArrayList<Byte>(1024);
      	int latestStartIndex = 0;
      	for (int i = 0; i < dataLen; i++) {
      		byte bt = encrypted[i];
      		boolean isMatchSplit = false;
      		if (i == dataLen - 1) {
      			// 到data的最后了
      			byte[] part = new byte[dataLen - latestStartIndex];
      			System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
      			byte[] decryptPart = decryptByPrivateKey(part, privateKey);
      			for (byte b : decryptPart) {
      				allBytes.add(b);
      			}
      			latestStartIndex = i + splitLen;
      			i = latestStartIndex - 1;
      		} else if (bt == DEFAULT_SPLIT[0]) {
      			// 这个是以split[0]开头
      			if (splitLen > 1) {
      				if (i + splitLen < dataLen) {
      					// 没有超出data的范围
      					for (int j = 1; j < splitLen; j++) {
      						if (DEFAULT_SPLIT[j] != encrypted[i + j]) {
      							break;
      						}
      						if (j == splitLen - 1) {
      							// 验证到split的最后一位,都没有break,则表明已经确认是split段
      							isMatchSplit = true;
      						}
      					}
      				}
      			} else {
      				// split只有一位,则已经匹配了
      				isMatchSplit = true;
      			}
      		}
      		if (isMatchSplit) {
      			byte[] part = new byte[i - latestStartIndex];
      			System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
      			byte[] decryptPart = decryptByPrivateKey(part, privateKey);
      			for (byte b : decryptPart) {
      				allBytes.add(b);
      			}
      			latestStartIndex = i + splitLen;
      			i = latestStartIndex - 1;
      		}
      	}
      	byte[] bytes = new byte[allBytes.size()];
      	int i = 0;
      	for (Byte b : allBytes) {
      		bytes[i++] = b.byteValue();
      	}
      	return bytes;
      }
    }
    

三、摘要算法

1.SHA

安全散列算法,数字签名工具。Glide在缓存key时就采用的此加密

固定长度摘要信息

包括:SHA-1
SHA-2(SHA-224,SHA-256,SHA-384,SHA-512)

SHA算法摘要长度实现方
SHA-1160 bitJDK
SHA-224(SHA-256的“阉割版)224 bitBouncy Castle
SHA-256256 bitJDK
SHA-384(SHA-512的“阉割版”)384 bitJDK
SHA-512512 bitJDK
  • 优点:破解难度高,不可逆

  • 缺点:可以通过穷举法进行破解

    public class SHAUtils {
      	//加密,不可逆
      	public static String encrypt(String data) {
      		byte[] dataBytes = data.getBytes();
      		MessageDigest md5 = null;
      		try {
      			md5 = MessageDigest.getInstance("SHA-512");
      			md5.update(dataBytes);
      		} catch (NoSuchAlgorithmException e) {
      			e.printStackTrace();
      		}
      		byte[] resultBytes = md5.digest();
      		StringBuilder sb = new StringBuilder();
      		for (byte b : resultBytes) {
      			String hex = Integer.toHexString(0xFF & b);
      			if(hex.length() == 1) {
      				sb.append("0").append(hex);
      			} else {
      				sb.append(hex);
      			}
      		}
      		return sb.toString();
      	}
    }
    
2.MD5

MD5算法,生成的摘要长度为 128 bit。

应用场景:一致性验证 / 生成摘要对摘要加密

  • 优点:不可逆,压缩性,不容易修改,容易计算

  • 缺点:穷举法可以破解

      public class MD5Utils {
      	//字符串加密
      	public static String encryptStr(String data) {
      			byte[] dataBytes = data.getBytes();
      			MessageDigest md5 = null;
      			try {
      				md5 = MessageDigest.getInstance("MD5");
      				md5.update(dataBytes);
      			} catch (NoSuchAlgorithmException e) {
      				e.printStackTrace();
      			}
      			byte[] resultBytes = md5.digest();
      			StringBuilder sb = new StringBuilder();
      			for (byte b : resultBytes) {
      				String hex = Integer.toHexString(0xFF & b);
      				if(hex.length() == 1) {
      					sb.append("0").append(hex);
      				} else {
      					sb.append(hex);
      				}
      			}
      			return sb.toString();
      	}
    
      //文件加密
      public static String encryptFile(String filePath) {
      		String result = "";
      		FileInputStream fis = null;
      		File file = new File(filePath);
      		StringBuilder sb = new StringBuilder();
      		try {
      			fis = new FileInputStream(file);
      			MappedByteBuffer byteBuffer = fis.getChannel().map(FileChannel.MapMode.READ_ONLY,0,file.length());
      			MessageDigest md5 = MessageDigest.getInstance("MD5");
      			md5.update(byteBuffer);
      			byte[] resultBytes = md5.digest();
      			for (byte b : resultBytes) {
      				String hex = Integer.toHexString(0xFF & b);
      				if(hex.length() == 1) {
      					sb.append("0").append(hex);
      				} else {
      					sb.append(hex);
      				}
      			}
      		} catch (Exception e) {
      			e.printStackTrace();
      		} finally {
      			if (fis != null) {
      				try {
      					fis.close();
      				} catch (IOException e) {
      					e.printStackTrace();
      				}
      			}
      		}
      		return sb.toString();
      }
    
      /**
       * 多次MD5加密
       * @param repeatTimes 重复加密次数
       */
      public static String repeatEncrypt(String data,int repeatTimes) {
      	if(TextUtils.isEmpty(data)) {
      		return "";
      	}
      	String result = encryptStr(data);
      	for (int i = 0; i < repeatTimes - 1; i++) {
      		result = encryptStr(result);
      	}
      	return encryptStr(result);
      }
    
      /**
       * MD5加盐
       * 方式:
       *  1. string + key(盐值) 然后MD5加密
       *  2. 用 string 明文的 hashcode 作为盐,然后MD5加密
       *  3. 随机生成一串字符串作为盐值,然后MD5加密
       *
       * 该方法采用 string + key
       * @param data
       * @param salt
       * @return
       */
      public static String encryptSalt(String data, String salt) {
      	if(TextUtils.isEmpty(data)) {
      		return "";
      	}
      	StringBuilder sb = new StringBuilder();
      	try {
      		MessageDigest md5 = MessageDigest.getInstance("MD5");
      		byte[] resultBytes = md5.digest((data + salt).getBytes());
      		for (byte b : resultBytes) {
      			String hex = Integer.toHexString(0xFF & b);
      			if(hex.length() == 1) {
      				sb.append("0").append(hex);
      			} else {
      				sb.append(hex);
      			}
      		}
      	} catch (NoSuchAlgorithmException e) {
      		e.printStackTrace();
      	}
      	return sb.toString();
      }
    }
    
3、MAC算法

HMAC(keyed-Hash Message Authentication Code):含有密钥的散列函数算法

包含了 MD、SHA 两个系列的消息摘要算法,只是在原有的MD和SHA算法的基础上添加了密钥。

融合了MD,SHA

MD系列:HmacMD2,HmacMD4,HmacMD5

SHA系列:HmacSHA1,HmacSHA224,HmacSHA256,HmacSHA38,HmacSHA512

算法摘要长度实现方
HmacMD2128 bitBouncy Castle
HmacMD4128 bitBouncy Castle
HmacMD5128 bitJDK
HmacSHA1160 bitJDK
HmacSHA224224 bitBouncy Castle
HmacSHA256256 bitJDK
HmacSHA384384 bitJDK
HmacSHA512512 bitJDK
3.XOR

概述:异或加密

原字符或数字 m 与一个数值 k 进行异或运算得到结果 r
则用 r 与 k 做异或运算即可还原到 m

public class XORUtils {
	//固定key方式加解密
	public static String encrypt(String data, int key) {
		byte[] dataBytes = data.getBytes();
		int length = dataBytes.length;
		for (int i = 0; i < length; i++) {
			dataBytes[i] ^= key;
		}
		return new String(dataBytes);
	}

	//固定key方式解密
	public byte[] decrypt(byte[] bytes, int key) {
		int len = bytes.length;
		for (int i = len - 1; i > 0; i--) {
			bytes[i] = (byte) (bytes[i] ^ bytes[i - 1]);
		}
		bytes[0] = (byte) (bytes[0] ^ key);
		return bytes;
	}

	//不固定key方式加密
	public byte[] encrypt(byte[] bytes) {
		int len = bytes.length;
		int key = 0x12;
		for (int i = 0; i < len; i++) {
			bytes[i] = (byte) (bytes[i] ^ key);
			key = bytes[i];
		}
		return bytes;
	}

	//不固定key方式解密
	public byte[] decrypt(byte[] bytes) {
		int len = bytes.length;
		int key = 0x12;
		for (int i = len - 1; i > 0; i--) {
			bytes[i] = (byte) (bytes[i] ^ bytes[i - 1]);
		}
		bytes[0] = (byte) (bytes[0] ^ key);
		return bytes;
	}
}
  • 优点:两个变量的互换(不借助第三个变量),简单的数据加密

  • 缺点:加密方式简单

4.Base64

概述:算不上什么加密算法,只是对数据进行编码传输

public class Base64Utils {

	//字符串编码
	public static String encodedStr(String data) {
		return Base64.encodeToString(data.getBytes(), Base64.DEFAULT);
	}

	//字符串解码
	public static String decodedStr(String data) {
		return new String(Base64.decode(data, Base64.DEFAULT));
	}

	//文件编码
	public static String encodedFile(String filePath) {
		String result = "";
		File file = new File(filePath);
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(file);
			byte[] buffer = new byte[(int) file.length()];
			fis.read(buffer);
			result = Base64.encodeToString(buffer, Base64.DEFAULT);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return result;
	}

	/**
	 * 文件解码
	 * 解码后保存到指定目录,并返回解码后的内容
	 */
	public static String decodedFile(String filePath, String data) {
		String result = "";
		File file = new File(filePath);
		FileOutputStream fos = null;
		try {
			byte[] decodeBytes = Base64.decode(data.getBytes(), Base64.DEFAULT);
			result = new String(decodeBytes);
			fos = new FileOutputStream(file);
			fos.write(decodeBytes);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return result;
	}
}
从上述简单的介绍,我们发现,算法分为了两大类:

1)对称加密算法

对称加密算法可以互逆,即通过key加密,也可以通过key来解密

2)非对称加密算法

非对称加密则不可互逆

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值