You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

aesgcm.c 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <unistd.h>
  4. #include <openssl/evp.h>
  5. #define TAG_LENGTH 16
  6. #define BYTES_PER_READ 32 * 1024 // 32kb
  7. #define INITIAL_BUFFER_SIZE 256 * 1024 // 256kb, must be at least 2*BYTES_PER_READ
  8. unsigned int hex2string(char *src, unsigned char **dst_p)
  9. {
  10. unsigned int byte_length = strlen(src)/2;
  11. *dst_p = malloc(byte_length);
  12. unsigned char *dst = *dst_p;
  13. unsigned char *end = dst + (strlen(src)/2);
  14. unsigned int u;
  15. while (dst < end && sscanf(src, "%2x", &u) == 1) {
  16. *dst++ = u;
  17. src += 2;
  18. }
  19. return byte_length;
  20. }
  21. int main(int argc, char **argv)
  22. {
  23. unsigned char *gcm_ivkey, *gcm_ct, *gcm_pt;
  24. int outlen, rv = 0, final_outlen, decrypt = 1;
  25. size_t read, actual_size = 0, total_size = INITIAL_BUFFER_SIZE;
  26. if (argc < 2) {
  27. fprintf(stderr, "Usage: %s <key> [enc]\n", argv[0]);
  28. return 1;
  29. }
  30. // this means we want to encrypt, not decrypt
  31. if (argc > 2 && strcmp("enc", argv[2]) == 0)
  32. decrypt = 0;
  33. unsigned int byte_length = hex2string(argv[1], &gcm_ivkey);
  34. unsigned int iv_length;
  35. if(byte_length == 48) {
  36. iv_length = 16;
  37. } else if(byte_length == 44) {
  38. iv_length = 12;
  39. } else {
  40. fprintf(stderr, "Invalid key length %d only 44 or 48 bytes supported\n", byte_length);
  41. return 1;
  42. }
  43. gcm_ct = malloc(total_size);
  44. while ((read = fread(gcm_ct + actual_size, 1, BYTES_PER_READ, stdin)) > 0) {
  45. actual_size += read;
  46. if ((actual_size + BYTES_PER_READ) > total_size) {
  47. total_size = total_size * 1.5;
  48. gcm_ct = realloc(gcm_ct,total_size);
  49. }
  50. }
  51. if (actual_size < (decrypt ? 17 : 1)) {
  52. fprintf(stderr, "File too small for %scryption\n", decrypt ? "de" : "en");
  53. return 1;
  54. }
  55. if(decrypt)
  56. actual_size -= TAG_LENGTH;
  57. gcm_pt = malloc(decrypt ? actual_size : (actual_size + TAG_LENGTH));
  58. EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
  59. /* Select cipher */
  60. if(decrypt)
  61. EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
  62. else
  63. EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
  64. /* Set IV length, omit for 96 bits */
  65. EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_length, NULL);
  66. if(decrypt) {
  67. /* Specify key and IV */
  68. EVP_DecryptInit_ex(ctx, NULL, NULL, gcm_ivkey + iv_length, gcm_ivkey);
  69. /* Set expected tag value. */
  70. EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, TAG_LENGTH, gcm_ct + actual_size);
  71. /* Decrypt plaintext */
  72. EVP_DecryptUpdate(ctx, gcm_pt, &outlen, gcm_ct, actual_size);
  73. /* Finalise: note get no output for GCM */
  74. rv = EVP_DecryptFinal_ex(ctx, gcm_pt, &final_outlen);
  75. } else {
  76. /* Specify key and IV */
  77. EVP_EncryptInit_ex(ctx, NULL, NULL, gcm_ivkey + iv_length, gcm_ivkey);
  78. /* Encrypt plaintext */
  79. EVP_EncryptUpdate(ctx, gcm_pt, &outlen, gcm_ct, actual_size);
  80. /* Finalise: note get no output for GCM */
  81. rv = EVP_EncryptFinal_ex(ctx, gcm_pt, &final_outlen);
  82. /* Get expected tag value. */
  83. EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAG_LENGTH, gcm_pt + actual_size);
  84. }
  85. EVP_CIPHER_CTX_free(ctx);
  86. free(gcm_ivkey);
  87. free(gcm_ct);
  88. if (rv > 0) {
  89. // success!
  90. fwrite(gcm_pt, 1, decrypt ? outlen : (outlen + TAG_LENGTH), stdout);
  91. free(gcm_pt);
  92. return 0;
  93. } else {
  94. fprintf(stderr, "File integrity check failed\n");
  95. free(gcm_pt);
  96. return 1;
  97. }
  98. }
  99. // compile with: gcc aesgcm.c -lcrypto -o aesgcm