OpenSSLを使ってAES CTR暗号をする

# はじめに
OpenSSLを使ってAES-128 CTR暗号を行います。
Cのcode exampleを示します。OSはUbuntu 14.04です。

# code example
key / iv / plaintext の具体値は [1] F.5.1 CTR-AES128.Encrypt に記載されている値を用います。
暗号データのサイズが16の倍数でなくても動作すること確認するために、データサイズは60とします。
OpenSSLの使用方法は [2] を参照します。

```:makefile
CFLAGS=-I. -Wall -Werror -O2 -march=native
INCS=
OBJS=test.c
LIBS=-lssl -lcrypto
TARGET=test

all: $(TARGET)

%.o: %.c $(INCS)
	$(CC) $(CFLAGS) -c -o $@ $<

$(TARGET): $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^ $(LIBS)

clean:
	rm -rf $(TARGET) *.o
```

```c:test.c
#include <openssl/evp.h>
#include <stdint.h>

void encrypt(uint8_t* out, const uint8_t* in, const uint8_t* key, const uint8_t* iv, int size)
{
  int out_len, in_len = size;
  EVP_CIPHER_CTX *ctx;
  
  if(!(ctx = EVP_CIPHER_CTX_new())) {
    printf("error EVP_CIPHER_CTX_new\n");
    return;
  }
  
  if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, key, iv)) {
    printf("error EVP_EncryptInit_ex\n");
    return;
  }
  
  if(1 != EVP_EncryptUpdate(ctx, out, &out_len, in, in_len)) {
    printf("error EVP_EncryptUpdate\n");
    return;
  }
  if (out_len != in_len) {
    printf("error encrypt out_len(%d) != in_len(%d)\n", out_len, in_len);
  }
  
  EVP_CIPHER_CTX_free(ctx);
}

void decrypt(uint8_t* out, const uint8_t* in, const uint8_t* key, const uint8_t* iv, int size)
{
  int out_len, in_len = size;
  EVP_CIPHER_CTX *ctx;
  
  if(!(ctx = EVP_CIPHER_CTX_new())) {
    printf("error EVP_CIPHER_CTX_new\n");
    return;
  }
  
  if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, key, iv)) {
    printf("error EVP_DecryptInit_ex\n");
    return;
  }
  
  if(1 != EVP_DecryptUpdate(ctx, out, &out_len, in, in_len)) {
    printf("error EVP_DecryptUpdate\n");
    return;
  }
  if (out_len != in_len) {
    printf("error decrypt out_len(%d) != in_len(%d)\n", out_len, in_len);
  }
  
  EVP_CIPHER_CTX_free(ctx);
}

void print(char* header, uint8_t* buf, int size)
{
  int i;
  printf("%s", header);
  for (i=0; i<size; i++) {
    printf("%02x", buf[i]);
  }
  printf("\n");
}

/*
  NIST Special Publication 800-38A Recommendation for Block 2001 Edition Cipher Modes of Operation
  F.5.1 CTR-AES128.Encrypt
   Key           2b7e151628aed2a6abf7158809cf4f3c
   Init. Counter f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
   Plaintext     6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710
   Ciphertext    874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee
 */
int main(int argc, char* argv[])
{
#define LEN (64)
  int len = LEN - 4; /* is not multiples of 16. */
  static uint8_t key[16] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
  static uint8_t iv[16]  = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff};
  static uint8_t in[LEN] = {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};
  static uint8_t out[LEN];
  static uint8_t out2[LEN];
  
  encrypt(out, in, key, iv, len);
  decrypt(out2, out, key, iv, len);
  
  print("ky:", key, 16);
  print("iv:", iv, 16);
  print("encrypt\nin:", in, len);
  print("ou:", out, len);
  print("decrypt\nou:", out2, len);
  
  return 0;
}
```

```bash:console
$ gcc --version&&make clean&&make&&./test
gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

rm -rf test *.o
cc -I. -Wall -Werror -O2 -march=native -o test test.c -lssl -lcrypto
ky:2b7e151628aed2a6abf7158809cf4f3c
iv:f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
encrypt
in:6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417b
ou:874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0
decrypt
ou:6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417b
```

# references
- [1] NIST Special Publication 800-38A Recommendation for Block 2001 Edition Cipher Modes of Operation
- [2] https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption