OpenSSL之Blowfish对称加密

释放双眼,带上耳机,听听看~!

今天我们来看看如何用OpenSSL的API来实现Blowfish对称加解密。

什么是对称加密?

对称加密:简单来说,“加密”就是把容易识别的信息变成不易识别的信息;而“对称”则表示加密者和解密者之间拥有相同的密钥。当然,既然有“对称”的加密,那肯定有“非对称”的加密,这个我们后续再详细讨论。

什么是Blowfish?

Blowfish是一个对称的块加密算法。它的块大小是64bit(8字节),同时Blowfish支持变长的密钥,Blowfish算法的主要优点是加解密速度快。

如何用OpenSSL来实现Blowfish加解密?

我们先看API


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
1
2
3
4  
5  #include <openssl/blowfish.h>
6  
7  void BF_set_key(BF_KEY *key, int len, const unsigned char *data);
8  
9  void BF_ecb_encrypt(const unsigned char *in, unsigned char *out,
10  
11  BF_KEY *key, int enc);
12  
13  void BF_cbc_encrypt(const unsigned char *in, unsigned char *out,
14  
15  long length, BF_KEY *schedule, unsigned char *ivec, int enc);
16  
17  void BF_cfb64_encrypt(const unsigned char *in, unsigned char *out,
18  
19  long length, BF_KEY *schedule, unsigned char *ivec, int *num,
20  
21  int enc);
22  
23  void BF_ofb64_encrypt(const unsigned char *in, unsigned char *out,
24  
25  long length, BF_KEY *schedule, unsigned char *ivec, int *num,
26  
27  int enc);
28  
29  const char *BF_options(void);
30  
31  void BF_encrypt(BF_LONG *data,const BF_KEY *key);
32  
33  void BF_decrypt(BF_LONG *data,const BF_KEY *key);
34
35
36

乍一看,感觉挺复杂,其实不复杂。

我们先看最先的那个BF_set_key函数,它是用来初始化密钥的,把密钥信息(首地址是data,长度为len的字节数组)设置到BF_KEY结构里。设置之后,我们只需要使用BF_KEY结构就可以表征密钥了,在后续调用加解密函数时,我们只需要把这个结构传递进去就可以了。这里需要注意的一点是Blowfish实际使用的密钥是根据用户的密钥信息进行运算产生的,这是一个比较耗时的过程,这个BF_set_key函数就进行了密钥初始化的过程,所以,我们应该调用一次BF_set_key,然后重复使用经过初始化后的BF_KEY结构,而不是每次需要加解密时都用data和len来重新初始化一把BF_KEY。

我们再来看最后那2个BF_encrypt和BF_decrypt函数,这2个函数是中间那4个函数调用的内部函数,我们一般无需关心,除非你想重新实现Blowfish算法。

接下来,我们把注意力集中到中间的那4个函数身上。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4  
5  void BF_ecb_encrypt(const unsigned char *in, unsigned char *out, BF_KEY *key, int enc);
6  
7  void BF_cbc_encrypt(const unsigned char *in, unsigned char *out, long length, BF_KEY *schedule, unsigned char *ivec, int enc);
8  
9  void BF_cfb64_encrypt(const unsigned char *in, unsigned char *out, long length, BF_KEY *schedule, unsigned char *ivec, int *num, int enc);
10  
11  void BF_ofb64_encrypt(const unsigned char *in, unsigned char *out, long length, BF_KEY *schedule, unsigned char *ivec, int *num, int enc);
12
13
14

这4个函数里的enc、in、out参数的语义是一样的,enc填BF_ENCRYPT时表示加密,填BF_DECRYPT时表示解密,参数in为输入数据的地址(待加密或待解密的数据),out为输出数据的地址(加密后或解密后的数据)。

我们先看BF_ecb_encrypt,它也是一个中间函数,因为它只能加解密一个“块”的数据,也就是8个字节,所以这个函数不需要调用者传入待加解密数据的长度。我们一般不使用它。

接下来是BF_cbc_encrypt,它比BF_ecb_encrypt封装的层次更高,不过,它虽然有个length,但它要求待加解密的数据长度必须为块大小(8字节)的整数倍,这个对普通用户是不方便的,因为涉及到了尾部数据的填充策略,所以我们一般也不用这个函数。这个函数有个ivec参数,这个参数要求拥有8字节的空间,我们可以把这个ivec也看作是密钥的一部分,因为ivec指向的8字节的内容会影响到加解密的结果,虽然ivec具体是什么内容由调用者决定,但调用者必须保证加密者和解密者之间对ivec的取值达成一致,不然将会导致解密失败。比较高级的做法可以让加密者和解密者之间约定这个ivec指向的内容如何进行同步的变化,这样做可以增强安全性;比较简单的做法,可以让加密者和解密者都把这个参数所指向的内容设置为字节0,然后一直保持不变。

我们最常用,同时也是最好用的是最后那2个函数,它们提供了比前面几个函数更高层次的封装。


1
2
3
4
5
6
7
8
9
10
1
2
3
4  
5  void BF_cfb64_encrypt(const unsigned char *in, unsigned char *out, long length, BF_KEY *schedule, unsigned char *ivec, int *num, int enc);
6  
7  void BF_ofb64_encrypt(const unsigned char *in, unsigned char *out, long length, BF_KEY *schedule, unsigned char *ivec, int *num, int enc);
8
9
10

它们不要求length必须为8的整数倍,所以使用很方便。这2个函数多了个num参数,我们只需要保证这num指向一个int整数,初始化为0,后续一直把这个num传递给相应的函数即可。

至于这2个函数之间的区别,其实是个加密反馈的概念,简单的说,就是已经加密的数据对后续加密结果的影响策略。

其实前面BF_cbc_encrypt和BF_ecb_encrypt的加密反馈策略也是不同。

cbc、ecb、cfb、ofb这些名称都代表了一种加密反馈模式,这个我们后续再详细讨论。

给TA打赏
共{{data.count}}人
人已打赏
安全技术安全运维

Windows服务器如何发现被黑

2018-5-20 12:24:31

安全技术

JavaScript面向对象编程(9)快速构建继承关系之整合原型链

2021-12-21 16:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索