Understanding of AES_CBC code implementation

Article directory

1. AES and CBC

AES stands for Advanced Encryption Standard and is a symmetric key encryption algorithm used to encrypt and decrypt electronic data. The examples in this blog use 128-bit keys to encrypt and decrypt data.

CBC mode is a commonly used block cipher encryption mode in symmetric encryption algorithms. The specific structure diagram of CBC is as follows:
Insert image description here
When we write an algorithm and need to implement this process, how should we do it? By referring to the two links below, we can gain some experience.
https://github.com/kokke/tiny-AES-c/blob/master/aes.c
https://github.com/kokke/tiny-AES-c/blob/master/test.c

2. aes.c

In aes.c, the corresponding AES algorithm is implemented using a variety of different block cipher modes. Here we focus on the implementation of CBC.

The first is AES_CBC_encrypt_bufferthe method.

void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t* buf, size_t length)
{
    
    
  size_t i;
  uint8_t *Iv = ctx->Iv;
  for (i = 0; i < length; i += AES_BLOCKLEN)
  {
    
    
    XorWithIv(buf, Iv);
    Cipher((state_t*)buf, ctx->RoundKey);
    Iv = buf;
    buf += AES_BLOCKLEN;
  }
  /* store Iv in ctx for next call */
  memcpy(ctx->Iv, Iv, AES_BLOCKLEN);
}

This code is a function implementation that uses the CBC mode of the AES algorithm for encryption.

The function name AES_CBC_encrypt_bufferaccepts three parameters: ctxa pointer to the AES context, bufthe data buffer to be encrypted, lengthand the length of the data to be encrypted.

The main logic of the function is as follows:

  1. Initialize a pointer Ivpointing to the initialization vector (Initialization Vector) in the context ctx.
  2. Use a loop to iterate through bufthe data in the data buffer, processing one AES block length (AES_BLOCKLEN) of data at a time.
  3. In each iteration, the data buffer is first XORed bufwith the initialization vector , which is one of the features of CBC mode that can increase the security of encryption.Iv
  4. Take the XORed data buffer as input and encrypt it bufusing the encryption function of the AES algorithm ( ), using the round key in the context ( ).CipherctxRoundKey
  5. Use the current encrypted data buffer bufas the initialization vector for the next iteration.
  6. Update the data buffer pointer bufto point to the next AES block.
  7. Loop until all data has been processed.
  8. Finally, the last encrypted data block is used as the initialization vector the next time the function is called, and is stored in the ctxinitialization vector ( Iv) in the context.

The corresponding XorWithIvmethods are as follows

static void XorWithIv(uint8_t* buf, const uint8_t* Iv)
{
    
    
  uint8_t i;
  for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size
  {
    
    
    buf[i] ^= Iv[i];
  }
}

buf[i] ^ Iv[i]It can be seen that every time this method is called, the corresponding position of buf will be replaced AES_BLOCKLENby cipher text

3. test.c

In the test program, we can see that the initialization vector Iv is defined, the key corresponding to AES with different digits, as well as the plaintext to be encrypted in and the expected output result out

static int test_encrypt_cbc(void)
{
    
    
#if defined(AES256)
    uint8_t key[] = {
    
     0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
                      0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 };
    uint8_t out[] = {
    
     0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6,
                      0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d,
                      0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61,
                      0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b };
#elif defined(AES192)
    uint8_t key[] = {
    
     0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b };
    uint8_t out[] = {
    
     0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d, 0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8,
                      0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4, 0xe5, 0xe7, 0x38, 0x76, 0x3f, 0x69, 0x14, 0x5a,
                      0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0, 0x7f, 0xa9, 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0,
                      0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81, 0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd };
#elif defined(AES128)
    uint8_t key[] = {
    
     0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
    uint8_t out[] = {
    
     0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
                      0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
                      0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
                      0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7 };
#endif
    uint8_t iv[]  = {
    
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
    uint8_t in[]  = {
    
     0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
                      0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
                      0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
                      0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 };
    struct AES_ctx ctx;

    AES_init_ctx_iv(&ctx, key, iv);
    AES_CBC_encrypt_buffer(&ctx, in, 64);

    printf("CBC encrypt: ");

    if (0 == memcmp((char*) out, (char*) in, 64)) {
    
    
        printf("SUCCESS!\n");
	return(0);
    } else {
    
    
        printf("FAILURE!\n");
	return(1);
    }
}

At the end of this method, the memcmp method is used to compare in and out to determine whether AES_CBC is executed correctly, which has achieved the verification function.

Guess you like

Origin blog.csdn.net/weixin_46841376/article/details/132163247