关于java:一文搞懂对称加密加密算法工作模式填充方式代码实现

6次阅读

共计 5335 个字符,预计需要花费 14 分钟才能阅读完成。

微信搜寻:码农 StayUp
主页地址:https://gozhuyinglong.github.io
源码分享:https://github.com/gozhuyinglong/blog-demos

上篇介绍了《单向散列加密》,它是一种音讯摘要算法。该算法在信息安全畛域,有很多重要的利用场景,比方:用户密码保护、数字签名、文件完整性校验、云盘妙传等。

单向散列加密只可能对音讯进行加密(严格来说是计算音讯的摘要),想要实现对密文解密,须要应用其它加密形式了。明天介绍一个在信息安全畛域中,比拟重要的加密形式——对称加密。

上面是本篇讲述内容:

加密、解密和密钥

加密 (Encrypt)是从明文生成密文的步骤, 解密 (Decrypt)是从密文还原成明文的步骤,而这两个步骤都须要用到 密钥(Key)。这和咱们事实中,用钥匙上锁和开锁是一样的。

什么是对称加密

对称加密(Symmetric Cryptography)是密码学中的一类加密算法,这类算法在加密和解密时,应用雷同的密钥。

对称加密又称为 共享密钥加密,其最大的毛病是,对称加密的安全性依赖于密钥,一旦泄露,就意味着任何人都能解密音讯。

对称加密的长处是加密速度快,所以在很多场合被应用。

常见算法

本节介绍对称加密的一些常见算法,包含 DES、3DES 和 AES。

DES 算法

DES(Data Encryption Standard,中文:数据加密规范),是一种对称加密算法。该算法在 1976 年被美国联邦政府的国家标准局确定为联邦材料解决规范(FIPS),并于 1977 年被公布,随后在国内上宽泛流传开来。然而,随着计算机的提高,DES 曾经可能被暴力破解,所以该算法曾经不平安了。

DES 是一种 分组明码 (Block Cipher,或者叫 块加密),行将明文按 64 比特进行分组加密,每组生成 64 位比特的密文。它的密钥长度为 56 比特(从规格上来说,密钥长度是 64 比特,但因为每隔 7 比特会设置一个用于谬误查看的比特,因而理论长度为 56 比特)。

3DES 算法

三重数据加密算法(Triple Data Encryption Algorithm,缩写为 TDEA),简称3DES(Triple-DES),是 DES 的增强版,相当于对每组数据利用了三次 DES 算法。

因为 DES 算法的密钥长度过短,容易被暴力破解,为了解决这一问题,设计出了该算法。它应用简略的办法,通过减少 DES 密钥长度的形式来防止相似攻打,而不是一种全新的明码算法。

该算法在每次利用 DES 时,应用不同的密钥,所以有三把独立密钥。这三把密钥组成一起,是一个长度为 168(56 + 56 + 56)比特的密钥,所以 3DES 算法的密钥总长度为 168 比特。

3DES 的加密过程,并不是进行三次 DES 加密(加密→加密→加密),而是以 密钥 1、密钥 2、密钥 3 的程序,进行 加密 解密 加密 的过程。

3DES 的解密过程和加密正好相同,是以 密钥 3、密钥 2、密钥 1 的程序,进行 解密 加密 解密 的操作。

AES 算法

AES(Advanced Encryption Standard),即高级加密规范,是取代 DES 算法的一种新的对称加密算法。AES 算法是从全世界的企业和明码学家,提交的对称明码算法中竞选进去的,最终 Rijndael 加密算法胜出,所以 AES 又称为 Rijndael 加密算法。

AES 也是一种分组明码,它的分组长度为 128 比特,密钥长度能够为 128 比特、192 比特或 256 比特。

分组明码的模式

下面介绍的 DES、3DES 和 AES 都属于分组明码,它们只能加密固定长度的明文。如果须要加密更长的明文,就须要对分组明码进行迭代,而分组明码的迭代办法称为分组明码的 模式(Model)。简而一句话:分组明码的模式,就是分组明码的迭代形式。

分组明码有很多种模式,这里次要介绍以下几种:ECB、CBC、CFB、OFB、CTR。

明文分组与密文分组

在上面对模式的介绍时,会用到两个术语,这里先介绍一下:

在分组明码中,咱们称每组的明文为 明文分组 ,每组生成的密文称为 密文分组

若将所有的明文分组合并起来就是残缺的明文(先疏忽填充),将所以的密文分组合并起来就是残缺的密文。

ECB 模式

ECB(Electronic CodeBook)模式,即电子密码本模式。该模式是将明文分组,加密后间接成为密文分组,分组之间没有关系。

ECB 模式是所有模式中最简略的一种,该模式的明文分组与密文分组是一一对应的关系,若明文分组雷同,其密文分组也肯定雷同。因而,ECB 模式也是最不平安的模式。

CBC 模式

CBC(Cipher Block Chaining)模式,即明码分组链接模式。该模式首先将明文分组与前一个密文分组进行 XOR 运算,而后再进行加密。只有第一个明文分组非凡,须要提前为其生成一个与分组长度雷同的比特序列,进行 XOR 运算,这个比特序列称为 初始化向量(Initialization Vector),简称IV

CFB 模式

CFB(Cipher FeedBack)模式,即密文反馈模式。该模式首先将前一个密文分组进行加密,再与以后明文分组进行 XOR 运算,来生成密文分组。同样 CFB 模式也须要一个 IV。

OFB 模式

OFB(Output FeedBack)模式,即输入反馈模式。该模式会产生一个密钥流,行将明码算法的前一个输入值,做为以后明码算法的输出值。该输出值再与明文分组进行 XOR 运行,计算得出密文分组。该模式须要一个 IV,进行加密后做为第一个分组的输出。

CTR 模式

CTR(CounTeR)模式,即计数器模式。该模式也会产生一个密钥流,它通过递增一个计数器来产生间断的密钥流。对该计数器进行加密,再与明文分组进行 XOR 运算,计算得出密文分组。

分组明码的填充

在分组明码中,当数据长度不合乎分组长度时,须要按肯定的形式,将尾部明文分组进行填充,这种将尾部分组数据填满的办法称为 填充(Padding)。

No Padding

即不填充,要求明文的长度,必须是加密算法分组长度的整数倍。

... | DD DD DD DD DD DD DD DD | DD DD DD DD DD DD DD DD |

ANSI X9.23

在填充字节序列中,最初一个字节 填充为 须要填充的字节长度,其余字节填充0

... | DD DD DD DD DD DD DD DD | DD DD DD DD 00 00 00 04 |

ISO 10126

在填充字节序列中,最初一个字节 填充为 须要填充的字节长度 ,其余字节填充 随机数

... | DD DD DD DD DD DD DD DD | DD DD DD DD 81 A6 23 04 |

PKCS#5 和 PKCS#7

在填充字节序列中,每个字节 填充为 须要填充的字节长度

... | DD DD DD DD DD DD DD DD | DD DD DD DD 04 04 04 04 |

ISO/IEC 7816-4

在填充字节序列中,第一个字节 填充固定值80,其余字节填充0。若只需填充一个字节,则间接填充80

... | DD DD DD DD DD DD DD DD | DD DD DD DD 80 00 00 00 |

... | DD DD DD DD DD DD DD DD | DD DD DD DD DD DD DD 80 |

Zero Padding

在填充字节序列中,每个字节 填充为0

... | DD DD DD DD DD DD DD DD | DD DD DD DD 00 00 00 00 |

Java 代码实现

Java 在底层曾经封装好了对称加密的实现,咱们只须要应用即可。当初介绍几个重要的类:

SecureRandom 类

SecureRandom 类是一个强平安的 随机数生成器(Random Number Generator,简称:RNG),加密相干的举荐应用此随机数生成器。

咱们能够通过构造方法生成一个实例,或者向构造方法传递一个种子来创立实例。

SecureRandom random = new SecureRandom();

KeyGenerator 类

KeyGenerator 类是对称明码的 密钥生成器,须要指定加密算法,来生成相应的密钥。

Java 中反对的算法:

  • AES (128)
  • DES (56)
  • DESede (168)
  • HmacSHA1
  • HmacSHA256

上面是一些规范算法的介绍:

生成密钥代码如下:

/**
 * 通过明码和算法获取 Key 对象
 *
 * @param key       密钥
 * @param algorithm 算法,例如:AES (128)、DES (56)、DESede (168)、HmacSHA1、HmacSHA256
 * @return 密钥 Key
 * @throws Exception
 */
private static Key getKey(byte[] key, String algorithm) throws Exception {
    // 通过算法获取 KeyGenerator 对象
    KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
    // 应用密钥做为随机数,初始化 KeyGenerator 对象
    keyGenerator.init(new SecureRandom(key));
    // 生成 Key
    return keyGenerator.generateKey();}

Cipher 类

Cipher 类提供了 加密和解密 的性能。该类须要指定一个转换(Transformation)来创立一个实例,转换的命名形式:算法名称 / 工作模式 / 填充形式

上面是 Java 反对的转换:

  • AES/CBC/NoPadding (128)
  • AES/CBC/PKCS5Padding (128)
  • AES/ECB/NoPadding (128)
  • AES/ECB/PKCS5Padding (128)
  • DES/CBC/NoPadding (56)
  • DES/CBC/PKCS5Padding (56)
  • DES/ECB/NoPadding (56)
  • DES/ECB/PKCS5Padding (56)
  • DESede/CBC/NoPadding (168)
  • DESede/CBC/PKCS5Padding (168)
  • DESede/ECB/NoPadding (168)
  • DESede/ECB/PKCS5Padding (168)
  • RSA/ECB/PKCS1Padding (1024, 2048)
  • RSA/ECB/OAEPWithSHA-1AndMGF1Padding (1024, 2048)
  • RSA/ECB/OAEPWithSHA-256AndMGF1Padding (1024, 2048)

上面是一些规范的模式:

上面是一些规范的填充:

加密代码如下:

private static final String DES_ALGORITHM = "DES";
private static final String DES_TRANSFORMATION = "DES/ECB/PKCS5Padding";

/**
 * DES 加密
 *
 * @param data 原始数据
 * @param key  密钥
 * @return 密文
 */
private static byte[] encryptDES(byte[] data, byte[] key) throws Exception {
    // 获取 DES Key
    Key secretKey = getKey(key, DES_ALGORITHM);

    // 通过规范转换获取 Cipher 对象, 由该对象实现理论的加密操作
    Cipher cipher = Cipher.getInstance(DES_TRANSFORMATION);
    // 通过加密模式、密钥,初始化 Cipher 对象
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    // 生成密文
    return cipher.doFinal(data);
}

解密代码如下:

private static final String DES_ALGORITHM = "DES";
private static final String DES_TRANSFORMATION = "DES/ECB/PKCS5Padding";

/**
 * DES 解密
 *
 * @param data 密文
 * @param key  密钥
 * @return 原始数据
 */
private static byte[] decryptDES(byte[] data, byte[] key) throws Exception {
    // 获取 DES Key
    Key secretKey = getKey(key, DES_ALGORITHM);
    // 通过规范转换获取 Cipher 对象, 由该对象实现理论的加密操作
    Cipher cipher = Cipher.getInstance(DES_TRANSFORMATION);
    // 通过解密模式、密钥,初始化 Cipher 对象
    cipher.init(Cipher.DECRYPT_MODE, secretKey);
    // 生成原始数据
    return cipher.doFinal(data);
}

残缺代码

残缺代码请拜访我的 Github,若对你有帮忙,欢送给个⭐,感激~~🌹🌹🌹

https://github.com/gozhuyinglong/blog-demos/blob/main/java-source-analysis/src/main/java/io/github/gozhuyinglong/utils/SymmetricKeyUtil.java

举荐浏览

  • 一文搞懂单向散列函数
  • Java 反射机制:跟着代码学反射
  • JDK 动静代理:不仅要学会用,更要把握其原理

正文完
 0