几种常见的加密算法

墨蓝 2023-06-29 13:58 160阅读 0赞

一、概念

  1. [数据加密][Link 1]的基本过程就是对原来为明文的文件或数据按某种[算法][Link 2]进行处理,使其成为不可读的一段代码为“密文”,使其只能在输入相应的[密钥][Link 3]之后才能显示出原容,通过这样的途径来达到保护数据不被非法人窃取、阅读的目的。 该过程的逆过程为解密,即将该[编码][Link 4]信息转化为其原来数据的过程。

简单来说,就是把某一段数据(明文),按照“某种规则”转换成另外一段不可读的数据(密文)。这里选定的“规则”,就是加密算法。理所当然,当别人拿到“密文”,解析出“明文”的难度取决于加密算法的破解难度。

二、几种常见的加密算法

1、Base64算法

原码

  1. /**
  2. * Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一。
  3. */
  4. public class Base64Util {
  5. /*
  6. 我们知道Java中是用"8个二进制数字"表示一个实际的字节。
  7. 比如:我要用Base64编码一个字符串“abc”,实际算法如下:
  8. 'a','b','c'的ASCII标准编码分别为(十进制)97,98,99,因此用二进制表示“abc”字符串就是:
  9. 01100001,01100010,01100011 ---3组,每组8字节
  10. Base64的原理:将这三组8字节,分成4组6字节
  11. 011000,010110, 001001,100011 ---4组,每组6字节
  12. 高位补0
  13. 00011000,00010110, 00001001,00100011
  14. 这四个二进制数组对应十进制的数值分别是:24,22,9,35,RFC2045(Base64解码表)分别为:Y,W,J,j
  15. 即:"abc"经过Base64编码后,为"YWJj"。这个过程是可逆的。
  16. ---每次Base64编码都会扩容33%
  17. */
  18. /**
  19. * Base64编码
  20. * @param message 待Base64编码的字符串
  21. * @return 编码后的字符串
  22. */
  23. public static String encode(String message){
  24. if (message == null){
  25. return null;
  26. }
  27. byte[] bytes = message.getBytes();
  28. byte[] result = Base64.encodeBase64(bytes);
  29. return new String(result);
  30. }
  31. /**
  32. * Base64解码
  33. * @param message 待Base64解码的字符串
  34. * @return 解码后的字符串
  35. */
  36. public static String decode(String message){
  37. if (message == null){
  38. return null;
  39. }
  40. byte[] bytes = message.getBytes();
  41. byte[] result = Base64.decodeBase64(bytes);
  42. return new String(result);
  43. }
  44. }

例子:

  1. public class Base64Test {
  2. public static void main(String[] args){
  3. String str = "1234" ;
  4. System.out.println("加密前: " + str );
  5. String str1= Base64Util.encodeToString(str);
  6. System.out.println("加密后: " + str1 );
  7. String str2 = Base64Util.decodeToString(str1);
  8. System.out.println(" 解密后 " +str2);
  9. }
  10. }

20200113102813760.png

特点:

  1. 1、将数据按照 3个字节一组的形式进行处理,每三个字节在编码之后被转换为4个字节。

    即:如果一个数据有6个字节,可编码后将包含6/3*4=8个字节

  1. 2、当数据的长度无法满足3的倍数的情况下,最后的数据需要进行填充操作,即补“=” ,这里“=”是填充字符,不要理解为第65个字符

Base64算法的实现原理是公开的(工具类源码中有解释),对于开发人员来说,拿到密文,很容易就能够解析成明文。因此严格来说,Base64不能称之为加密算法,仅仅是一种编码方式。它常常用于发送Http请求时对URL中参数的编码,保证不是一眼就看出来了这些参数的意义。

2、MD5算法

  1. 原理
  2. MD5算法的原理可简要的叙述为:MD5码以512位分组来处理输入的信息,且每一分组又被划分为1632位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位[散列值][Link 5]。
  3. MD5算法总结

MD5,是一种信息摘要算法。简单来说,就是把一段信息(明文),通过一种有损的方式压缩成定长的字符(32位密文)。因为这种压缩方式是会损失信息的,所以是无法还原出“明文”的。虽然无法从数学上破解MD5算法,但由于现在计算机具备强大的计算能力,还是可以通过“穷举法”破解该算法。如果想用该算法加密,还可以通过“加盐”的方式提高解密难度。该算法允许多传一个参数”salt”,指定通过MD5加密的次数,这样是能够提高解密难度的。

  1. 应用场景

用于密码管理、电子签名、

SHA算法

  1. public class SHAUtil {
  2. /*
  3. SHA与MD5均有MD4导出,因此强度和特性比较相似的,都是不可逆的算法。
  4. SHA与MD5的不同:
  5. 1.对强行攻击的安全性,SHA-1摘要比MD5摘长,对强行攻击有更大的强度。
  6. 2.对密码分析的安全性,由于MD5的设计,易受密码分析的攻击,SHA-1显得不易受这样的攻击。
  7. 3.在相同的硬件上,SHA-1的运行速度比MD5慢。
  8. */
  9. /**
  10. * SHA加密,即安全散列算法加密
  11. * @param bytes 要加密的信息
  12. * @return 40位字符
  13. */
  14. public static String encrypt(byte[] bytes){
  15. try {
  16. MessageDigest messageDigest = MessageDigest.getInstance("SHA");
  17. byte[] resultBytes = messageDigest.digest(bytes);
  18. return Hex.encodeHexString(resultBytes);
  19. } catch (NoSuchAlgorithmException e) {
  20. e.printStackTrace();
  21. }
  22. return null;
  23. }
  24. }

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3liNTQ2ODIyNjEy_size_16_color_FFFFFF_t_70

安全散列算法(英语:Secure Hash Algorithm,缩写为SHA)是一个密码散列函数家族,是FIPS所认证的安全散列算法。能计算出一个数字消息所对应到的,长度固定的字符串(又称消息摘要)的算法。且若输入的消息不同,它们对应到不同字符串的机率很高。

SHA家族的五个算法,分别是SHA-1、SHA-224、SHA-256、SHA-384,和SHA-512,由美国国家安全局(NSA)所设计,并由美国国家标准与技术研究院(NIST)发布;是美国的政府标准。后四者有时并称为SHA-2。SHA-1在许多安全协定中广为使用,包括TLS和SSL、PGP、SSH、S/MIME和IPsec,曾被视为是MD5(更早之前被广为使用的杂凑函数)的后继者。但SHA-1的安全性如今被密码学家严重质疑;虽然至今尚未出现对SHA-2有效的攻击,它的算法跟SHA-1基本上仍然相似;因此有些人开始发展其他替代的杂凑算法。 [1]

总结

SHA,安全散列算法。与MD5算法的特点是一致的,不过生成的密文长度是40位,因此更难破解。

AES算法

  1. AES技术是一种对称的分组加密技术,使用128位分组加密数据,提供比WEP/TKIPSRC4算法更高的加密强度。AES的加密码表和解密码表是分开的,并且支持子密钥加密,这种做法优于以前用一个特殊的密钥解密的做法。AES算法支持任意分组大小,初始时间快。特别是它具有的并行性可以有效地利用处理器资源。

AES具有应用范围广、等待时间短、相对容易隐藏、吞吐量高等优点,在性能等各方面都优于WEP算法。利用此算法加密,WLAN的安全性将会获得大幅度提高。AES算法已经在802.11i标准中得到最终确认,成为取代WEP的新一代的加密算法。但是由于AES算法对硬件要求比较高,因此AES无法通过在原有设备上升级固件实现,必须重新设计芯片

源码

  1. import org.apache.commons.codec.binary.Base64;
  2. import org.springframework.util.StringUtils;
  3. import sun.security.provider.SecureRandom;
  4. import javax.crypto.*;
  5. import javax.crypto.spec.SecretKeySpec;
  6. import java.security.InvalidKeyException;
  7. import java.security.NoSuchAlgorithmException;
  8. /**
  9. * @ClassName AESUtil
  10. * @Description TODO
  11. * @Date 2020/1/13/01311:24
  12. * @Version 1.0
  13. **/
  14. public class AESUtil {
  15. /*
  16. AES加密算法作为新一代的数据加密标准汇聚了强安全性、高性能、高效率、易用和灵活等优点。
  17. AES设计有三个密钥长度:128,192,256 位。
  18. 相对而言,AES的128密钥比DES的56密钥强了1021倍
  19. */
  20. /**
  21. * 用户自定义的密钥,由前后端协商确定
  22. * !!!(不应该在加解密方法的参数中暴露),AES的安全性,取决于密钥的安全性。
  23. */
  24. private static final String KEY = "agdfscxcvz";
  25. /**
  26. * AES:算法,ECB:模式,PKCS5Padding:补码方式
  27. */
  28. private static final String ALGORITHM = "AES/ECB/PKCS5Padding";
  29. /**
  30. * AES加密
  31. * @param message 要加密的信息
  32. * @return 加密后的字符串
  33. */
  34. public static String encrypt(String message){
  35. return doAES(message,KEY, Cipher.ENCRYPT_MODE);
  36. }
  37. /**
  38. * AES解密
  39. * @param message 要解密的信息
  40. * @return 解密后的字符串
  41. */
  42. public static String decrypt(String message){
  43. return doAES(message,KEY,Cipher.DECRYPT_MODE);
  44. }
  45. /**
  46. * 加密或解密的实际操作过程
  47. * @param message 待处理的信息
  48. * @param key AES加解密过程需要的密钥
  49. * @param mode 加解密mode
  50. * @return 加密或解密后的信息
  51. */
  52. private static String doAES(String message,String key, int mode){
  53. try {
  54. if (StringUtils.isBlank(message) || StringUtils.isBlank(key)){
  55. return null;
  56. }
  57. // 由于AES算法要求密钥的长度为16的倍数,(1,2,3,4)步的目的: 把用户自定义的密钥替换成16位的密钥
  58. // 1. 构造密钥生成器,指定为AES算法
  59. KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
  60. // 2. 根据用户自定义密钥对应的字节数组,生成一个128位的随机源(只能是128 or 192 or 256中的一个)
  61. keyGenerator.init(128, new SecureRandom(key.getBytes()));
  62. // 3. 生成AES算法的原始对称密钥
  63. SecretKey secretKey = keyGenerator.generateKey();
  64. // 4. 获取原始对称密钥的字节数组
  65. byte[] enCodeFormat = secretKey.getEncoded();
  66. // 5. 根据字节数组生成AES密钥
  67. SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat,"AES");
  68. // 6.根据指定算法AES自成密码器
  69. Cipher cipher = Cipher.getInstance(ALGORITHM);
  70. // 7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二个参数为使用的KEY
  71. cipher.init(mode, secretKeySpec);
  72. if (mode == Cipher.ENCRYPT_MODE) {
  73. byte[] content = message.getBytes();
  74. byte[] result = cipher.doFinal(content);
  75. // !!! 加密,AES加密后的结果默认是Base64格式的字节数组
  76. return Base64.encodeBase64String(result);
  77. } else {
  78. byte[] content = Base64.decodeBase64(message);
  79. byte[] result = cipher.doFinal(content);
  80. return new String(result);
  81. }
  82. } catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException | InvalidKeyException e) {
  83. e.printStackTrace();
  84. }
  85. return null;
  86. }
  87. }

测试效果如下

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3liNTQ2ODIyNjEy_size_16_color_FFFFFF_t_70 1

总结

AES,高级加密标准,对称算法。它的原理是:加密方和解密方保有同一个16位长的密钥,使用AES算法加解密时需要传入该密钥参数,通过Java实现AES算法提供的工具包加密后返回的是一个Base64格式的字节数组。因此为保证密文“可读性”,需要在加密后对密文进行Base64编码,解密前进行Base64解码成密文。AES算法的安全性,取决于密钥的安全性。因此一定不要在加解密的URL中传入该密钥参数,不然没有意义。一般的做法是:前后端协商好密钥,或者通过不对称加密的方式传递密钥。

RSA算法

源码

  1. package com.common;/**
  2. * Created by Administrator on 2020/1/13/013.
  3. */
  4. import org.apache.commons.codec.binary.Hex;
  5. import javax.crypto.BadPaddingException;
  6. import javax.crypto.Cipher;
  7. import javax.crypto.IllegalBlockSizeException;
  8. import javax.crypto.NoSuchPaddingException;
  9. import java.security.*;
  10. import java.security.interfaces.RSAPrivateKey;
  11. import java.security.interfaces.RSAPublicKey;
  12. import java.security.spec.InvalidKeySpecException;
  13. import java.security.spec.PKCS8EncodedKeySpec;
  14. import java.security.spec.X509EncodedKeySpec;
  15. import java.util.HashMap;
  16. import java.util.Map;
  17. /**
  18. * @ClassName RSAUtil
  19. * @Description TODO
  20. * @Author yb
  21. * @Date 2020/1/13/01314:25
  22. * @Version 1.0
  23. **/
  24. public class RSAUtil {
  25. /*
  26. RSA算法,需要两个密钥来进行加密和解密,分别是公钥和私钥。
  27. 需要注意的一点,这个公钥和私钥必须是一对的,如果用公钥对数据进行加密,那么只有使用对应的私钥才能解密,反之亦然。
  28. 由于加密和解密使用的是两个不同的密钥,因此,这种算法叫做非对称加密算法。
  29. 其算法具体实现基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
  30. */
  31. //
  32. // private static RSAPublicKey rsaPublicKey;
  33. // private static RSAPrivateKey rsaPrivateKey;
  34. public static Map<String,Object> generateKey(){
  35. try {
  36. KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
  37. // ‘512’,表示生成的是128位字符
  38. keyPairGenerator.initialize(512);
  39. KeyPair keyPair = keyPairGenerator.generateKeyPair();
  40. RSAPublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
  41. RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
  42. Map<String,Object> keyPairs = new HashMap<>();
  43. keyPairs.put("publicKey",rsaPublicKey);
  44. keyPairs.put("privateKey",rsaPrivateKey);
  45. return keyPairs;
  46. } catch (NoSuchAlgorithmException e) {
  47. e.printStackTrace();
  48. }
  49. return null;
  50. }
  51. /**
  52. * RSA私钥加密
  53. * @param message 要加密的信息
  54. * @return 加密后的字符串
  55. */
  56. public static String encrypt(String message, RSAPrivateKey rsaPrivateKey){
  57. try {
  58. PKCS8EncodedKeySpec pkcs8EncodedKeySpec
  59. = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
  60. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  61. PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
  62. Cipher cipher = Cipher.getInstance("RSA");
  63. cipher.init(Cipher.ENCRYPT_MODE, privateKey);
  64. byte[] resultBytes = cipher.doFinal(message.getBytes());
  65. return Hex.encodeHexString(resultBytes);
  66. } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
  67. e.printStackTrace();
  68. }
  69. return null;
  70. }
  71. /**
  72. * RSA公钥解密
  73. * @param message 要解密的信息
  74. * @return 解密后的字符串
  75. */
  76. public static String decrypt(String message, RSAPublicKey rsaPublicKey){
  77. try {
  78. X509EncodedKeySpec x509EncodedKeySpec =
  79. new X509EncodedKeySpec(rsaPublicKey.getEncoded());
  80. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  81. PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
  82. Cipher cipher = Cipher.getInstance("RSA");
  83. cipher.init(Cipher.DECRYPT_MODE, publicKey);
  84. byte[] resultBytes = cipher.doFinal(Hex.decodeHex(message.toCharArray()));
  85. return new String(resultBytes);
  86. } catch (Exception e) {
  87. e.printStackTrace();
  88. }
  89. return null;
  90. }
  91. }

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3liNTQ2ODIyNjEy_size_16_color_FFFFFF_t_70 2

总结

RSA算法,是一种非常常用的不对称加密算法。不对称加密算法指的是:需要两个密钥来进行加密和解密,分别是公钥和私钥(公钥和私钥必须是一对)。其算法具体实现基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

java-web项目使用RSA算法加密的场景再现:

为每个客户(User)生成一对密钥(keyPairs),
将公钥(publicKey)通过URL接口向前端公开,私钥(userId:privateKey)保存在数据库或redis中,
然后前端客户可以通过公钥加密自己的信息(前端用JS进行RSA公钥加密),后端通过该用户对应的私钥解析出用户信息(后端用Java进行RSA私钥解密),再将用户信息保存在数据库。
这样能够防止HTTP被劫持导致用户信息被泄露

发表评论

表情:
评论列表 (有 0 条评论,160人围观)

还没有评论,来说两句吧...

相关阅读

    相关 php 加密算法

    首先我们来了解一下为什么要加密? 在网络通信的过程中攻击者可以伪造请求和返回,从而达到不可告人的目的。如下图所示: ![8b4dba3cf9053b15054748f2e1

    相关 常见加密算法

     一、概念       [数据加密][Link 1]的基本过程就是对原来为明文的文件或数据按某种[算法][Link 2]进行处理,使其成为不可读的一段代码为“密文”,使其