opensslの暗号化を使う

ちょっとopensslの暗号化をさわる必要があったので、サンプルを書いてみた。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>

#define KEYGEN_SALT  NULL
#define KEYGEN_COUNT 2048

static void print_hexstring(unsigned char *data, int datal) {
  int i;

  for (i = 0; i < datal; i++) {
    printf("%02x", data[i]);
  }
}

static unsigned char *encrypt(const char *source, const char *passwd, int *crypted_len) {
  EVP_CIPHER_CTX ctx;
  const EVP_CIPHER *cipher = EVP_aes_256_ecb();
  unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
  unsigned char *crypted;
  int source_len, tail_len;

  EVP_CIPHER_CTX_init(&ctx);

  // passphrase -> key, iv
  if (EVP_BytesToKey(cipher, EVP_md5(), KEYGEN_SALT, passwd, strlen(passwd), KEYGEN_COUNT, key, iv) < 1) {
    fprintf(stderr, "EVP_BytesToKey: failure\n");
    exit(1);
  }

  printf("key: ");
  print_hexstring(key, EVP_MAX_KEY_LENGTH);
  printf("\n");

  if (EVP_CipherInit(&ctx, cipher, key, iv, 1) != 1) {
    fprintf(stderr, "EVP_CipherInit: failure\n");
  }

  source_len = strlen(source);
  crypted = (unsigned char *) malloc(source_len + EVP_CIPHER_block_size(cipher) * 2 + 1);
  
  if (EVP_CipherUpdate(&ctx, crypted, crypted_len, source, source_len) != 1) {
    fprintf(stderr, "EVP_CipherUpdate: failure\n");
    exit(1);
  }

  if (EVP_CipherFinal(&ctx, (crypted + *crypted_len), &tail_len) != 1) {
    fprintf(stderr, "EVP_CipherFinal: failure\n");
    exit(1);
  }

  if (EVP_CIPHER_CTX_cleanup(&ctx) != 1) {
    fprintf(stderr, "EVP_CIPHER_CTX_cleanup: failure\n");
    exit(1);
  }

  *crypted_len += tail_len;

  return crypted;
}

static char *decrypt(unsigned char *crypted, int crypted_len, const char *passwd, int *decrypted_len) {
  EVP_CIPHER_CTX ctx;
  const EVP_CIPHER *cipher = EVP_aes_256_ecb();
  unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
  unsigned char *decrypted;
  int tail_len;

  EVP_CIPHER_CTX_init(&ctx);

  // passphrase -> key, iv
  if (EVP_BytesToKey(cipher, EVP_md5(), KEYGEN_SALT, passwd, strlen(passwd), KEYGEN_COUNT, key, iv) < 1) {
    fprintf(stderr, "EVP_BytesToKey: failure\n");
    exit(1);
  }

  if (EVP_CipherInit(&ctx, cipher, key, iv, 0) != 1) {
    fprintf(stderr, "EVP_CipherInit: failure\n");
  }

  decrypted = (unsigned char *) malloc(crypted_len + EVP_CIPHER_block_size(cipher) * 2 + 1);
  
  if (EVP_CipherUpdate(&ctx, decrypted, decrypted_len, crypted, crypted_len) != 1) {
    fprintf(stderr, "EVP_CipherUpdate: failure\n");
    exit(1);
  }

  if (EVP_CipherFinal(&ctx, (decrypted + *decrypted_len), &tail_len) != 1) {
    fprintf(stderr, "EVP_CipherFinal: failure\n");
    exit(1);
  }

  if (EVP_CIPHER_CTX_cleanup(&ctx) != 1) {
    fprintf(stderr, "EVP_CIPHER_CTX_cleanup: failure\n");
    exit(1);
  }

  *decrypted_len += tail_len;
  decrypted[*decrypted_len] = 0;

  return decrypted;
}

int main() {
  char *source = "hogehogehoge";
  char *passwd = "foobarzoo";
  unsigned char *crypted;
  unsigned char *reverted;
  int crypted_len, reverted_len;

  printf("source: %s\n", source);
  printf("source len: %d\n", strlen(source));
  printf("password: %s\n", passwd);

  crypted = encrypt(source, passwd, &crypted_len);
  printf("crypted: ");
  print_hexstring(crypted, crypted_len);
  printf("\n");

  reverted = decrypt(crypted, crypted_len, passwd, &reverted_len);
  printf("reverted: %s\n", reverted);
  printf("reverted len: %d\n", strlen(reverted));

  free(crypted);
  free(reverted);

  return 0;
}

しかし、opensslの暗号化って独自仕様が多いような気がしてしまった。
そーゆーもんなのかな。