Linux下使用openssl的AES加密-CBC模式

最近需要用到AES加密,为了图方便就打算使用openssl自带的AES加密算法的API来实现。
主要用到了ECB和CBC两种加密模式。
ECB模式之前一篇已经写过了。这篇就写一下CBC模式。

代码

#include 
#include 
#include 
#include 
#include 

void my_AES_cbc_encrypt(unsigned char *in, unsigned char *out,
                           size_t len, const void *key,
                           unsigned char *ivec)
{
    size_t n;
    const unsigned char *iv = ivec;

    if (len == 0)
        return;

    while (len) {
        for (n = 0; n < 16 && n < len; ++n)
            out[n] = in[n] ^ iv[n];
        for (; n < 16; ++n)
            out[n] = iv[n];
        AES_encrypt(out, out, key);
        iv = out;
        if (len <= 16)
            break;
        len -= 16;
        in += 16;
        out += 16;
    }
    memcpy(ivec, iv, 16);
}

void my_AES_cbc_decrypt(unsigned char *in, unsigned char *out,
                           size_t len, const void *key,
                           unsigned char *ivec)
{
    size_t n;
    union {
        size_t t[16 / sizeof(size_t)];
        unsigned char c[16];
    } tmp;

    if (len == 0)
        return;

    while (len) {
        unsigned char c;
        AES_decrypt(in, tmp.c, key);
        for (n = 0; n < 16 && n < len; ++n) {
            c = in[n];
            out[n] = tmp.c[n] ^ ivec[n];
            ivec[n] = c;
        }
        if (len <= 16) {
            for (; n < 16; ++n)
                ivec[n] = in[n];
            break;
        }
        len -= 16;
        in += 16;
        out += 16;
    }
}

int main(int argc, char**argv) {
  if(argc != 2) {
    printf("使用方法为:\n./cbc text\ntext为待加密的明文。\n");
    return -1;
  }

  unsigned char *data = argv[1];
  printf("原始数据:%s\n",data);

  size_t len = strlen(data);
  printf("明文长度:%d\n",len);
  size_t length = ((len+AES_BLOCK_SIZE-1)/AES_BLOCK_SIZE)*AES_BLOCK_SIZE;  //对齐分组

  char userkey[AES_BLOCK_SIZE];
  unsigned char *iv1 = malloc(AES_BLOCK_SIZE);
  unsigned char *iv2 = malloc(AES_BLOCK_SIZE);
  unsigned char *encrypt_result = malloc(length);
  unsigned char *decrypt_result = malloc(length);
  AES_KEY en_key;
  AES_KEY de_key;
  memset((char*)userkey,'k',AES_BLOCK_SIZE);
  memset((unsigned char*)iv1,'m',AES_BLOCK_SIZE);
  memset((unsigned char*)iv2,'m',AES_BLOCK_SIZE);
  memset((unsigned char*)encrypt_result, 0, length);
  memset((unsigned char*)decrypt_result, 0, length);

  AES_set_encrypt_key(userkey, AES_BLOCK_SIZE*8, &en_key);
  printf("加密密钥:%d\n",en_key);
  my_AES_cbc_encrypt(data, encrypt_result, len, &en_key, iv1);
  printf("加密结果:%s\n",encrypt_result);

  AES_set_decrypt_key(userkey, AES_BLOCK_SIZE*8, &de_key);
  printf("解密密钥:%d\n",de_key);
  my_AES_cbc_decrypt(encrypt_result, decrypt_result, len, &de_key, iv2);
  printf("解密结果:%s\n",decrypt_result);
}

代码说明

  • openssl库其实已经实现了CBC模式的AES,但是我实际使用时,发现最后一个分组总是解密不对,没有找到问题的根本,所以干脆自己写了CBC的实现。

  • 对齐分组的作用是把实际长度扩充成16(AES_BLOCK_SIZE)的整数倍。

  • iv1iv2其实是一样的,但是因为加密之后直接解密,导致解密时iv值被加密过程污染了。具体表现就是解密的iv变成了加密时最后一个分组的结果。

你可能感兴趣的:(密码学)