现在的位置: 首页 > 综合 > 正文

OpenSSL之Blowfish对称加密

2013年08月22日 ⁄ 综合 ⁄ 共 2818字 ⁄ 字号 评论关闭

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

什么是对称加密?

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

什么是Blowfish?

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

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

我们先看API

  1. #include <openssl/blowfish.h>
  2. void BF_set_key(BF_KEY *key, int len, const unsigned char *data);
  3. void BF_ecb_encrypt(const unsigned char *in, unsigned char *out,
  4. BF_KEY *key, int enc);
  5. void BF_cbc_encrypt(const unsigned char *in, unsigned char *out,
  6. long length, BF_KEY *schedule, unsigned char *ivec, int enc);
  7. void BF_cfb64_encrypt(const unsigned char *in, unsigned char *out,
  8. long length, BF_KEY *schedule, unsigned char *ivec, int *num,
  9. int enc);
  10. void BF_ofb64_encrypt(const unsigned char *in, unsigned char *out,
  11. long length, BF_KEY *schedule, unsigned char *ivec, int *num,
  12. int enc);
  13. const char *BF_options(void);
  14. void BF_encrypt(BF_LONG *data,const BF_KEY *key);
  15. void BF_decrypt(BF_LONG *data,const BF_KEY *key);

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

我们先看最先的那个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. void BF_ecb_encrypt(const unsigned char *in, unsigned char *out, BF_KEY *key, int enc);
  2. void BF_cbc_encrypt(const unsigned char *in, unsigned char *out, long length, BF_KEY *schedule, unsigned char *ivec, int enc);
  3. void BF_cfb64_encrypt(const unsigned char *in, unsigned char *out, long length, BF_KEY *schedule, unsigned char *ivec, int *num, int enc);
  4. void BF_ofb64_encrypt(const unsigned char *in, unsigned char *out, long length, BF_KEY *schedule, unsigned char *ivec, int *num, int enc);

这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. void BF_cfb64_encrypt(const unsigned char *in, unsigned char *out, long length, BF_KEY *schedule, unsigned char *ivec, int *num, int enc);
  2. void BF_ofb64_encrypt(const unsigned char *in, unsigned char *out, long length, BF_KEY *schedule, unsigned char *ivec, int *num, int enc);

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

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

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

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

【上篇】
【下篇】

抱歉!评论已关闭.