一、概述
在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yao)一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。
信息安全基本概念:
- DES(Data Encryption Standard,数据加密标准)
- 3DES(Triple DES,三重数据加密算法(TDEA,Triple Data Encryption Algorithm))
- AES(Advanced Encryption Standard,高级加密标准)
- Blowfish
- RC2
- RC4
1.1、加密的工作模式
加密模式(英文名称及简写)
|
优点
|
缺点
|
|
Electronic Code Book(ECB)
电子密码本模式
|
简单 快速 支持并行计算(加密、解密) |
明文中的重复排列会反映在密文中 通过删除、替换密文分组可以对明文进行操作 对包含某些比特错误的密文进行解密时,对应的分组会出错 |
必应使用 一般情况下很少用 |
Cipher Block Chaining(CBC)
密码分组链接模式
|
明文的重复排列不会反映在密文中
支持并行计算(仅解密) 能够解密任意密文分组 |
对包含某些错误比特的密文进行解密时, 第一个分组的全部比特以及后一个分组的相应比特会出 加密不支持并行计算 |
推荐使用 |
Cipher Feedback Mode(CFB)
加密反馈模式
|
不需要填充(padding)
支持并行计算(仅解密) 能够解密任意密文分组 |
加密不支持并行计算 对包含某些错误比特的密文进行解密时, 第一个分组的全部比特以及后一个分组的相应比特会出错 不能抵御重放攻击 |
现在已不使用 |
Output Feedback Mode(OFB)
输出反馈模式
|
不需要填充(padding) 可事先进行加密、解密的准备 加密、解密使用相同结构 对包含某些错误比特的密文进行解密时,只有铭文中相应的比特会出错 |
不支持并行运算 主动攻击这反转密文分组中的某些比特时, 明文分组中相对应的比特也会被反转 |
推荐用CTR模式代替 |
CRT模式
CounTeR计数器模式
|
不需要填充(padding) 可事先进行加密、解密的准备 加密、解密使用相同的结构 对包含某些错误比特的密文进行解密时,只有明文中相对应的比特会出错 支持并行计算(加密、解密) |
主动攻击者反转密文分组中的某些比特时, 明文分组中对应的比特也会被反转 |
推荐使用 |
1.1.1、ECB
1.1.2、CBC
明文被加密前要与前面的密文进行异或运算后再加密,因此只要选择不同的初始向量,相同的密文加密后会形成不同的密文,这是目前应用最广泛的模式。
CBC加密后的密文是上下文相关的,但明文的错误不会传递到后续分组,但如果一个分组丢失,后面的分组将全部作废(同步错误)。
在CBC模式下,在加密之前,每个明文块与先前的密文块进行异或。 这样,每个密文块依赖于直到那一点处理的所有明文块。 为了使每个消息唯一,必须在第一个块中使用初始化向量。
1.1.3、CFB
类似于自同步序列密码,分组加密后,按8位分组将密文和明文进行移位异或后得到输出同时反馈回移位寄存器,优点最小可以按字节进行加解密,也可以是n位的,CFB也是上下文相关的,CFB模式下,明文的一个错误会影响后面的密文(错误扩散)。
1.1.4、OFB
将分组密码作为同步序列密码运行,和CFB相似,不过OFB用的是前一个n位密文输出分组反馈回移位寄存器,OFB没有错误扩散问题。
1.2、长度、块的大小根据算法需求来决定。
DES秘钥长度:8个字符,DES 的数据块是64bits,也就是8 B,所以,块的大小是8字节。
AES秘钥长度:16个字符,AES 的数据块是128bits,也就是16B,所以,块的大小是16字节。
DES加密后密文长度是8的整数倍
AES加密后密文长度是16的整数倍
填充模式一般针对的是块加密模式(分组加密模式),MD5、SHA等散列方式没有填充模式。
1.3、填充模式
某些加密算法要求明文需要按一定长度对齐,叫做块大小(BlockSize),比如16字节,那么对于一段任意的数据,加密前需要对最后一个块填充到16 字节,解密后需要删除掉填充的数据。
某些模式(即ECB和CBC)要求在加密之前填补最终的块。存在几种填充方案。最简单的是将空字节添加到明文中以使其长度达到块大小的倍数,但必须注意可以恢复明文的原始长度,如果明文是一个C风格的字符串,除了最后不包含空字节。稍微复杂一点就是添加一个置一位,后面加上足够的零位来填写块。如果消息在块边界上结束,则将添加整个填充块。
CFB,OFB和CTR模式不需要任何特殊措施来处理长度不是块大小倍数的消息,因为这些模式通过将明文与块密码的输出进行异或工作。最后的部分明文块与最后一个密钥流块的前几个字节进行异或,产生与最终部分明文块大小相同的最终密文块。流密码的这种特性使得它们适用于需要加密密文数据与原始明文数据相同大小的应用程序,以及用于以不方便添加填充字节的流式传输数据的应用程序。
注意:常用的填充形式
1、填充数据为填充字节的长度
这种填充方式中,填充字符串由一个字节序列组成,每个字节填充该字节序列的长度。假定块长度为8,原文数据长度9,则填充字节数等于0x07;如果明文数据长度为8的整数倍,则填充字节数为0x08。
填充字符串如下:
原文数据1: FF FF FF FF FF FF FF FF FF
填充后数据1:FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07
因块长度为8 故填充后为8的倍数,原文长度为9,需要在填充 7个,填充的内容为 0x07
原文数据2: FF FF FF FF FF FF FF FF
填充后数据2:FF FF FF FF FF FF FF FF 08 08 08 08 08 08 08 08
因块长度为8 故填充后为8的倍数,原文长度为8,需要在填充 8个,填充的内容为 0x08
2、填充数据为0x80后加0x00
这种填充方式中,填充字符串的第一个字节数是0x80,后面的每个字节是0x00。假定块长度为8,原文数据长度为9或者为8的整数倍,则填充字符串如下:
原文数据1: FF FF FF FF FF FF FF FF FF
填充后数据1:FF FF FF FF FF FF FF FF FF 80 00 00 00 00 00 00
因块长度为8 故填充后为8的倍数,原文长度为9,需要在填充 7个,填充的内容为 0x80,其他6个为00
原文数据2: FF FF FF FF FF FF FF FF
填充后数据2:FF FF FF FF FF FF FF FF 80 00 00 00 00 00 00 00
因块长度为8 故填充后为8的倍数,原文长度为8,需要在填充 8个,填充的内容为 0x80,其他7个为00
3、填充数据的最后一个字节为填充字节序列的长度
这种填充方式中,填充字符串的最后一个字节为该字节序列的长度,而前面的字节可以是0x00,也可以是随机的字节序列。假定块长度为8,原文数据长度为9或者为8的整数倍,则填充字符串如下:
原文数据1:FF FF FF FF FF FF FF FF FF
填充后数据1:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 07
或: FF FF FF FF FF FF FF FF FF 58 B3 98 9B AD F4 07
原文数据2:FF FF FF FF FF FF FF FF
填充后数据2:FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 08
或: FF FF FF FF FF FF FF FF 32 58 B3 98 9B AD F4 08
4、填充数据为空格
这种填充方式中,填充字符串的每个字节为空格对应的字节数0x20。假定块长度为8,原文数据长度为9或者为8的整数倍,则填充字符串如下:
原文数据1:FF FF FF FF FF FF FF FF FF
填充后数据1:FF FF FF FF FF FF FF FF FF 20 20 20 20 20 20 20
原文数据2:FF FF FF FF FF FF FF FF
填充后数据2:FF FF FF FF FF FF FF FF 20 20 20 20 20 20 20 20
5、填充数据为0x00
这种填充方式中,填充字符串的每个字节为0x00。假定块长度为8,原文数据长度为9或者8的整数倍,则填充字符串如下:
原文数据1: FF FF FF FF FF FF FF FF FF
填充后数据1:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00
原文数据2: FF FF FF FF FF FF FF FF
填充后数据2:FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00
在填充方式 4 和方式 5 中,由于缺少填充数据长度的标识信息,如果原文数据的后几个字节本身包括空格或0,将不能够准确移去填充的数据。因此使用这样的填充方式时,对原文数据有一定的要求。
JCE中支持的补长方案包括:NoPadding、PKCS5Padding、ISO10126Padding、OAEPWithAndPadding和SSL3Padding,其中最常用的就是PKCS5Padding和ISO10126Padding。
1.3.1、ZeroPadding:数据长度不对齐时使用0填充,否则不填充。
1.3.2、PKCS7Padding:PKCS5Padding或PKCS7Padding是RSA公司的公钥密码学标准PKCS #5文档中定义的填充方式,使用上述方式1填充
1.3.3、PKCS5Padding:PKCS7Padding的子集,块大小固定为8字节。
1.3.4、ISO10126Padding:使用上述方式3填充
1.3.5、NoPadding:不补长
1.4、实例
以DES算法加密明文for为例
因for不足8bytes,所以需补长5bytes(for ?? ?? ?? ?? ??),则这5bytes可能选择(16进制):
i. 所有Padding以长度为值:66 6F 72 05 05 05 05 05
ii. Padding以0×80开始后面全部为0×00:66 6F 72 80 00 00 00 00
iii. 最后一个字节为Padding长度, 其它为0×00:66 6f 72 00 00 00 00 05
iv. 全部Padding为0×00:66 6f 72 00 00 00 00 00
简单的说PKCS5Padding就2个规则:
i. 补长的内容为待补长字节数
ii. 补长的字节数为:8 – 明文长度 % 8,即补长长度在1至8bytes之间
如前述的明文for将补长为:66 6F 72 05 05 05 05 05ISO10126Padding,具体规范请参考ISO10126。简单的说ISO10126Padding就是补长的长度作为补长内容的最后一个byte,之前的补长内容为随机数。
如前述的明文for可能补长为:66 6F 72 2A 75 EF F8 05
二、详细介绍
2.1、DES
DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦*的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级*通信中使用,随后该算法在国际上广泛流传开来。需要注意的是,在某些文献中,作为算法的DES称为数据加密算法(Data Encryption Algorithm,DEA),已与作为标准的DES区分开来。
DES算法的入口参数有三个:Key、Data、Mode。其中Key为7个字节共56位,是DES算法的工作密钥;Data为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密。
DES设计中使用了分组密码设计的两个原则:混淆(confusion)和扩散(diffusion),其目的是抗击敌手对密码系统的统计分析。混淆是使密文的统计特性与密钥的取值之间的关系尽可能复杂化,以使密钥和明文以及密文之间的依赖性对密码分析者来说是无法利用的。扩散的作用就是将每一位明文的影响尽可能迅速地作用到较多的输出密文位中,以便在大量的密文中消除明文的统计结构,并且使每一位密钥的影响尽可能迅速地扩展到较多的密文位中,以防对密钥进行逐段破译。
DES还是一种分组加密算法,该算法每次处理固定长度的数据段,称之为分组。DES分组的大小是64位,如果加密的数据长度不是64位的倍数,可以按照某种具体的规则来填充位。
2.1.1、jdk实现
路径:/algorithm-sign/algorithm-sign-impl/src/main/java/com/github/bjlhx15/security/symmetric001des
通过调试发现支持工作模式以及填充模式
// DES SupportedPaddings=NOPADDING|PKCS5PADDING|ISO10126PADDING,
// DES SupportedModes=ECB|CBC|PCBC|CTR|CTS|CFB|OFB|
// CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|
// OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64
编写测试程序
public class JdkSymmetricTest {
String msg = "测试数据2222";
Map.Entry<String, String> padding = null;
byte[] key = null;
byte[] iv = null;
byte[] encrypt = null;
byte[] decrypt = null; // DES SupportedPaddings=NOPADDING|PKCS5PADDING|ISO10126PADDING,
// DES SupportedModes=ECB|CBC|PCBC|CTR|CTS|CFB|OFB|
// CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|
// OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64
@Test
public void encryptAll() throws Exception {
System.out.println("原文:" + msg);
List<Map.Entry<String, String>> paddingListMap = new ArrayList<>();
paddingListMap.add(new AbstractMap.SimpleEntry<>("DES", "DES"));//相当于:DES/ECB/PKCS5PADDING
paddingListMap.add(new AbstractMap.SimpleEntry<>("DES", "DES/ECB/NOPADDING"));
paddingListMap.add(new AbstractMap.SimpleEntry<>("DES", "DES/ECB/PKCS5PADDING"));
paddingListMap.add(new AbstractMap.SimpleEntry<>("DES", "DES/ECB/ISO10126PADDING")); paddingListMap.add(new AbstractMap.SimpleEntry<>("DES", "DES/CBC/NOPADDING"));
paddingListMap.add(new AbstractMap.SimpleEntry<>("DES", "DES/CBC/PKCS5PADDING"));
paddingListMap.add(new AbstractMap.SimpleEntry<>("DES", "DES/CBC/ISO10126PADDING")); paddingListMap.add(new AbstractMap.SimpleEntry<>("DES", "DES/PCBC/NOPADDING"));
paddingListMap.add(new AbstractMap.SimpleEntry<>("DES", "DES/PCBC/PKCS5PADDING"));
paddingListMap.add(new AbstractMap.SimpleEntry<>("DES", "DES/PCBC/ISO10126PADDING")); paddingListMap.add(new AbstractMap.SimpleEntry<>("DES", "DES/CTR/NOPADDING"));
paddingListMap.add(new AbstractMap.SimpleEntry<>("DES", "DES/CTR/PKCS5PADDING"));
//paddingListMap.add(new AbstractMap.SimpleEntry<>("DES","DES/CTR/ISO10126PADDING"));//不支持 paddingListMap.add(new AbstractMap.SimpleEntry<>("DES", "DES/CTS/NOPADDING"));
paddingListMap.add(new AbstractMap.SimpleEntry<>("DES", "DES/CTS/PKCS5PADDING"));
// paddingListMap.add(new AbstractMap.SimpleEntry<>("DES","DES/CTS/ISO10126PADDING"));//不支持
for (Map.Entry<String, String> entry : paddingListMap) {
try {
boolean b = encryptCheck(entry);
if (b) {
System.out.println(entry.getValue() + ":支持");
}
} catch (Exception e) {
e.printStackTrace();
System.out.println(entry.getValue() + ":不支持");
}
}
} boolean encryptCheck(Map.Entry<String, String> entry) throws Exception {
padding = entry;
key = JdkSymmetric.initKey(padding);//Base64.getDecoder().decode("koY9NPFJGf4=");//
iv = JdkSymmetric.initIv();
System.out.println("key:" + Base64.getEncoder().encodeToString(key));
System.out.println("iv:" + Base64.getEncoder().encodeToString(iv));
encrypt = JdkSymmetric.encrypt(padding, key, iv, msg.getBytes("utf-8"));
System.out.println("encrypt:" + Base64.getEncoder().encodeToString(encrypt));
decrypt = JdkSymmetric.decrypt(padding, key, iv, this.encrypt);
//System.out.println("decrypt:" + Base64.getEncoder().encodeToString(encrypt));
//System.out.println("解密原文:" + new String(decrypt, "utf-8"));
return true;
}
}
注:BouncyCastleProvider 可以参看同级目录BcSymmetric
jdk支持
// SunJCE: Cipher.DES -> com.sun.crypto.provider.DESCipher
// attributes: {SupportedPaddings=NOPADDING|PKCS5PADDING|ISO10126PADDING,
// SupportedKeyFormats=RAW, SupportedModes=ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64
// |OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64}
2.1.2、算法原理
DES算法具体通过对明文进行一系列的排列和替换操作来将其加密。过程的关键就是从给定的初始密钥中得到16个子密钥的函数。要加密一组明文,每个子密钥按照顺序(1-16)以一系列的位操作施加于数据上,每个子密钥一次,一共重复16次。每一次迭代称之为一轮。要对密文进行解密可以采用同样的步骤,只是子密钥是按照逆向的顺序(16-1)对密文进行处理。
1、计算16个子密钥
DES算法的第一步就是从初始密钥中计算得出16个子密钥。图示1展示了这个过程。DES使用一个56位的初始密钥,但是这里提供的是一个64位的值,这是因为在硬件实现中每8位可以用于奇偶校验,在软件实现中多出的位只是简单的忽略掉。要获得一个56位的密钥,可以执照表1的方式执行密钥转换。解释一下表1,按照从左往右从上往下的方式看,表格中每个位置P包含初始密钥中位在转换后的密钥中所占的位置。比如,初始密钥中的第57位就是转换后的密钥中的第1位,而初始密钥中的第49位则变成转换后的密钥中的第2位,以此类推...。(数据位的计数顺序按照从左到右从1开始的)
表1:DES中密钥的转换表(DesTransform[56])
将密钥转换为56位后,接下来计算子密钥。首先,将56位的密钥分为两个28位的组。然后,针对每个子密钥,根据子密钥的序列值(也就是16个子密钥中的第几个)旋转这两组值(旋转的位数见表2),然后重新合并。之后,再按照表3所示对重组后的密钥进行置换,使56位的子密钥缩小为48位(注意表3只有48位,丢弃了8位)。这个排列过程就称为置换选择。
针对16个子密钥,每个子密钥重复一次该过程。这里的目的是保证将初始密钥中的不同位在每一轮排列后应用于加密的数据上。
表2:针对DES子密钥每一轮的旋转次数(Round轮,Rotations旋转次数)(DesRotations)
表3:DES子密钥的置换选择(Despermuted[48])
在DES中计算子密钥的过程
2、加密解密数据块
经过上述过程,我们已经准备好了子密钥。接着就可以加密和解密数据块了。图2展示了这个过程。
图2:DES中加密和解密数据块
从表4所示的方式置换64位的数据块开始,该置换过程称为初始置换。该过程并不会增加DES的安全性,但这种做法在16位和32位的总线出现之前将使得数据更容易加载到DES芯片中。虽然这种处理已经不合时宜,但该置换过程仍然保留以满足DES标准。
表4:DES中数据的初始置换(DesInitial[64])
经过初始置换后,64位的数据块分为两个32位的组,L0和R0。
完成初始置换后,数据块将重复执行16轮一系列的操作。每一轮操作(i)的目的是计算出Li和Ri ,这些结果将用在下一轮操作中直到最终得到数据R16和L16。
每一轮以Li-1和Ri-1开始,然后根据表5所示进行扩展置换,将Ri-1从32位扩展到48位。该置换的主要目的是在加密数据的过程中制造一些雪崩效应,使用数据块中的1位将在下一步操作中影响更多位,从而产生扩散效果。
一旦扩展置换完成,计算出48位的结果值与这一*密钥Ki的异或值(XOR,符号计为⊕)。这将产生48位的中间值,记为Rint。
如果将E计为扩展置换的结果,则本轮到目前为止的操作可以表示为:
Rint = E(Ri-1) ⊕ Ki
表5:DES中数据块的扩展置换(DesExpansion[48])
下一步,Rint 需要通过8个单独的S盒执行8次替换操作。每个S盒(j)从Rint的6j 到 6j+6 的位置取出6位,并为其在表6中查出1个4位的值,将该值写到缓冲区的4j位置处(如图3)。
图3:DES中的8个S盒
读表6,查找S盒(j)。通过前面取出的6位值,根据第1位和最后1位组成的2位值找到表6中的行号,而根据中间剩下的4位来确定表6中的列号。比如,在图3中,Rint中的第3个6位组是101011。因此,在表6中查找到的第3个S盒是9。因为行号等于112 = 3,列号等于01012 = 5(查表时从索引0开始计数)。S盒为数据增加了不确定性,除了给DES带来安全性外,没什么特别的。
表6:DES中数据块的S盒替换
一旦完成了S盒替换,得到的结果又变为一个32位的值。接下来再通过P盒来置换。如下表7所示。
表7:DES中数据块的P盒置换
到目前为止,我们把这一轮的操作想象为一个函数,一般记为f。如果 bj 代表Rint中的第j个6位组,Sj 代表第j个S盒,而P代表P盒置换,则该函数可以定义为:
f = P(S1(b1),S2(b2),...,S8(b8))
每一轮的最后一个操作是计算 f 的32位结果值与传入本轮操作的原始数据的左分组Li-1之间的异或值。
一旦完成,将左右两个分组交换然后开始下一轮。
在最后一轮中,不用交换左右分组。
把所有的步骤连起来,在每一轮中计算Li和Ri的步骤可以精确表示为:
Li = Ri-1
Ri = Li-1 ⊕ f(Ri-1,Ki)
当全部的16轮操作都结束后,将最后的右分组R16和最后剩下的左分组L16连接起来,组成一个64位的分组R16L16。(回顾一下,在最后一轮中左右分组并没有交换。最后的右分组在左边而最后的左分组在右边。)
最后一步是将R16L16按照表8所示的置换进行置换。简而言之,就是撤消之前的初始置换。
加密数据时,最终结果就是一个64位的密文,而当解密数据时,最终结果就是64位的明文了。
表8:DES中数据块的最终置换
2.2、3DES
3DES又称Triple DES,是DES加密算法的一种模式,它使用3条56位的密钥对3DES.3DES数据进行三次加密。数据加密标准(DES)是美国的一种由来已久的加密标准,它使用对称密钥加密法,并于1981年被ANSI组织规范为ANSI X.3.92。DES使用56位密钥和密码块的方法,而在密码块的方法中,文本被分成64位大小的文本块然后再进行加密。比起最初的DES,3DES更为安全。
3DES(即Triple DES)是DES向AES过渡的加密算法(1999年,NIST将3-DES指定为过渡的加密标准),加密算法,其具体实现如下:设Ek()和Dk()代表DES算法的加密和解密过程,K代表DES算法使用的密钥,M代表明文,C代表密文,这样:
3DES加密过程为:C=Ek3(Dk2(Ek1(M)))
3DES解密过程为:M=Dk1(EK2(Dk3(C)))
使用方式原理同上
jdk支持
// SunJCE: Cipher.DESede -> com.sun.crypto.provider.DESedeCipher
// aliases: [TripleDES]
// attributes: {SupportedPaddings=NOPADDING|PKCS5PADDING|ISO10126PADDING,
// SupportedKeyFormats=RAW, SupportedModes=ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64
// |OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64}
2.3、AES
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦*采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。
jdk支持
// SunJCE: Cipher.AES -> com.sun.crypto.provider.AESCipher$General
// aliases: [Rijndael]
// attributes: {SupportedPaddings=NOPADDING|PKCS5PADDING|ISO10126PADDING,
// SupportedKeyFormats=RAW, SupportedModes=ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64
// |OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64|GCM|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128|OFB72|OFB80
// |OFB88|OFB96|OFB104|OFB112|OFB120|OFB128}
Blowfish
Blowfish算法是一个64位分组及可变密钥长度的对称密钥分组密码算法,可用来加密64比特长度的字符串。
// SunJCE: Cipher.Blowfish -> com.sun.crypto.provider.BlowfishCipher
// attributes: {SupportedPaddings=NOPADDING|PKCS5PADDING|ISO10126PADDING,
// SupportedKeyFormats=RAW, SupportedModes=ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64
// |OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64}
RC2
// SunJCE: Cipher.RC2 -> com.sun.crypto.provider.RC2Cipher
// attributes: {SupportedPaddings=NOPADDING|PKCS5PADDING|ISO10126PADDING,
// SupportedKeyFormats=RAW, SupportedModes=ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64
// |OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64}
RC4
// SunJCE: Cipher.ARCFOUR -> com.sun.crypto.provider.ARCFOURCipher
// aliases: [RC4]
// attributes: {SupportedPaddings=NOPADDING, SupportedKeyFormats=RAW, SupportedModes=ECB}