Как добавить IV (вектор инициализации) в шифрование AES-256 ECB для создания режима AES-256 CBC?

У меня есть следующий код, работающий для шифрования AES-256 ECB с использованием простой байт-ориентированной библиотеки AES-256, которую я нашел здесь.

Главный:

#define DUMP(s, i, buf, sz)  {printf(s); \
for (i = 0; i < (sz);i++) \
printf("%02x ", buf[i]); \
printf("\n");}

int main (int argc, char *argv[])
{
aes256_context ctx; 
uint8_t key[32] = "39P8TXDMBCYF4C1NI1CDFJ1WL6P5TTKZ";
uint8_t buf[16] = "KUC7EWG6M2D1WW8F";
uint8_t i;

DUMP("txt: ", i, buf, sizeof(buf));
DUMP("key: ", i, key, sizeof(key));
printf("---\n");

aes256_init(&ctx, key);
aes256_encrypt_ecb(&ctx, buf);

DUMP("enc: ", i, buf, sizeof(buf));

aes256_init(&ctx, key);
aes256_decrypt_ecb(&ctx, buf);
DUMP("dec: ", i, buf, sizeof(buf));

aes256_done(&ctx);
return 0;
}

Функция шифрования:

void aes256_encrypt_ecb(aes256_context *ctx, uint8_t *buf)
{
uint8_t i, rcon;
aes_addRoundKey_cpy(buf, ctx->enckey, ctx->key);
for(i = 1, rcon = 1; i < 14; ++i)
{
aes_subBytes(buf);
aes_shiftRows(buf);
aes_mixColumns(buf);
if( i & 1 ) aes_addRoundKey( buf, &ctx->key[16]);
else aes_expandEncKey(ctx->key, &rcon), aes_addRoundKey(buf, ctx->key);
}
aes_subBytes(buf);
aes_shiftRows(buf);
aes_expandEncKey(ctx->key, &rcon);
aes_addRoundKey(buf, ctx->key);
} /* aes256_encrypt */

Я хочу добавить IV к этой программе, чтобы создать режим AES-256 CBC. Из того, что я понимаю, IV реализация выглядит следующим образом:

  1. XOR первый блок с IV.
  2. XOR все последующие блоки с зашифрованным текстом предыдущего блока.

Мой вопрос в том, как выглядит логика? Как я могу реализовать это в моем коде?

1 ответ

Решение

Логика и объяснения можно найти в нескольких местах. Например, в режиме ECB против CBC или блочного шифра.

CBC = Cipher Block Chaining - это способ соединения блоков вместе.

Вместо того чтобы обрабатывать каждый блок отдельно, каждый блок будет XOR'ом с зашифрованным предыдущим блоком. Это фактически означает, что каждый блок зависит от вывода предыдущего блока.

Каждый блок XORed с зашифрованным текстом предыдущего блока, как это объясняется диаграммами в цитируемых статьях.

На практике один блок зашифровывается с помощью надписи ECB:

 Cipher((state_t*)buf, ctx->RoundKey);

как в

void AES_ECB_encrypt(struct AES_ctx *ctx,const uint8_t* buf)
{
  // The next function call encrypts the PlainText with the Key using AES algorithm.
  Cipher((state_t*)buf, ctx->RoundKey);
}

CBC достигается с помощью XOR с IV на блоке, ECB на том же блоке и перемещением вдоль блоков в буфере.

Пример XOR с IV:

static void XorWithIv(uint8_t* buf, 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];
  }
}

Пример CBC с использованием XOR с IV и ECB:

void AES_CBC_encrypt_buffer(struct AES_ctx *ctx,uint8_t* buf, uint32_t length)
{
  uintptr_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;
    //printf("Step %d - %d", i/16, i);
  }
  /* store Iv in ctx for next call */
  memcpy(ctx->Iv, Iv, AES_BLOCKLEN);
}

Вышеуказанная реализация взята из крошечного AES, и вы можете изучить его и адаптировать к вашим потребностям. Я надеюсь, что это помогает.

Другие вопросы по тегам