読者です 読者をやめる 読者になる 読者になる

kkAyatakaのメモ帳。

誰かの役に立つかもしれない備忘録。

OpenSSLを使った暗号化

C++

OpenSSLを使ってAESで暗号化。

暗号化

#include <openssl/evp.h>

EVP_CIPHER_CTX ctx = {};
EVP_CIPHER_CTX_init(&ctx);

// 暗号化の設定で、EVP_aes_128_ecb等いろいろ
const unsigned char iv[16] = {};
EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv);

// ブロックサイズで割り切れる部分の処理
int outl = 0;
EVP_EncryptUpdate(&ctx, encrypted, &outl, data, data_size);

// 最後のブロックの処理で、PKCSパディングされる。
int pad = 0;
EVP_EncryptFinal_ex(&ctx, encrypted + outl, &pad);
  
EVP_CIPHER_CTX_cleanup(&ctx);

AESはブロック暗号で、16バイトづつ処理される。

16の倍数分はEVP_EncryptUpdateで処理されて、パディングを含んだ最後の部分はEVP_EncryptFinal_exで処理される。

OpenSSLはPKCSでパディングする。PKCSのパディング処理は足りないバイトの値で足りない分を埋めるんだけど、足りないバイトが0(データサイズが16の倍数)の場合は、1ブロックまるまるパディングが追加されるので、暗号化データのサイズには注意が必要になる。

復号化

EVP_CIPHER_CTX ctx = {};
EVP_CIPHER_CTX_init(&ctx);

// 暗号化の設定
const unsigned char iv[16] = {};
EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv);

// ブロックサイズで割り切れる部分の処理
int outl = 0;
EVP_DecryptUpdate(&ctx, decrypted, &outl, data, data_size);

// 最後のブロックの処理で、PKCSパディングのサイズを返す
// パディングのデータは処理されないので、後処理は自分で行う
int last = 0;
EVP_DecryptFinal_ex(&ctx, decrypted + outl, &last);
memset(decrypted + outl + last, 0, decrypted_size - outl - last); // remove padding
  
EVP_CIPHER_CTX_cleanup(&ctx);

復号もEVP_DecryptUpdateEVP_DecryptFinal_exに分かれていて、EVP_DecryptFinal_exはパディングの値を返す。ただ、サイズを返すだけでデータ自体は処理されないので適宜処理してやる。

参考