cryptotest_gcm.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #include <openssl/conf.h>
  2. #include <openssl/err.h>
  3. #include <openssl/evp.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. // based on OpenSSL sample
  7. // refer to https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption
  8. void handleErrors(void);
  9. int gcm_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, int iv_len, unsigned char *ciphertext, unsigned char *tag);
  10. int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *tag, unsigned char *key, unsigned char *iv, int iv_len, unsigned char *plaintext);
  11. int main(int argc, char **argv) {
  12. /*
  13. * Set up the key and iv. Do I need to say to not hard code these in a
  14. * real application? :-)
  15. */
  16. FILE *f, *o;
  17. unsigned char signature[4] = {'C', 'C', 'A', 'T'};
  18. unsigned char key[32];
  19. unsigned char iv[12];
  20. unsigned char tag[16];
  21. unsigned char *plain;
  22. unsigned char *cipher;
  23. unsigned insize, mode;
  24. int decryptedtext_len, ciphertext_len;
  25. if (argc < 4) {
  26. printf("not enough args. use %s mode key in out\n", argv[0]);
  27. return 1;
  28. }
  29. mode = strtoul(argv[1], NULL, 10);
  30. if (!(f = fopen(argv[2], "rb"))) {
  31. printf("cannot open key\n");
  32. return 1;
  33. }
  34. fread(key, sizeof(key), 1, f);
  35. fclose(f);
  36. if (!(f = fopen("/dev/urandom", "rb"))) {
  37. printf("cannot open urandom\n");
  38. return 1;
  39. }
  40. fread(iv, sizeof(iv), 1, f);
  41. fclose(f);
  42. if (!(f = fopen(argv[3], "rb"))) {
  43. printf("cannot open in\n");
  44. return 1;
  45. }
  46. if (!(o = fopen(argv[4], "wb"))) {
  47. printf("cannot open out\n");
  48. return 1;
  49. }
  50. if (mode) {
  51. fseek(f, 0, SEEK_END);
  52. insize = ftell(f) + 4;
  53. fseek(f, 0, SEEK_SET);
  54. plain = malloc(insize);
  55. cipher = malloc(insize);
  56. fread(plain + 4, insize, 1, f);
  57. fclose(f);
  58. /* prepend signature */
  59. memcpy(plain, signature, 4);
  60. /* Encrypt the plaintext */
  61. ciphertext_len = gcm_encrypt(plain, insize, key, iv, sizeof(iv), cipher, tag);
  62. fwrite(iv, sizeof(iv), 1, o);
  63. fwrite(tag, sizeof(tag), 1, o);
  64. fwrite(cipher, ciphertext_len, 1, o);
  65. fclose(o);
  66. } else {
  67. fseek(f, 0, SEEK_END);
  68. insize = ftell(f) - sizeof(iv) - sizeof(tag);
  69. fseek(f, 0, SEEK_SET);
  70. cipher = malloc(insize);
  71. plain = malloc(insize);
  72. fread(iv, sizeof(iv), 1, f);
  73. fread(tag, sizeof(tag), 1, f);
  74. fread(cipher, insize, 1, f);
  75. fclose(f);
  76. decryptedtext_len = gcm_decrypt(cipher, insize, tag, key, iv, sizeof(iv), plain);
  77. if (decryptedtext_len < 0) {
  78. printf("decrypt failed\n");
  79. fclose(o);
  80. remove(argv[4]);
  81. } else if (memcmp(plain, signature, 4)) {
  82. printf("signature mismatch, expected ");
  83. for (int i = 0; i < sizeof(signature); i++)
  84. printf("%02x ", signature[i]);
  85. printf("but got ");
  86. for (int i = 0; i < sizeof(signature); i++)
  87. printf("%02x ", plain[i]);
  88. printf("\n");
  89. fclose(o);
  90. remove(argv[4]);
  91. } else {
  92. fwrite(plain + 4, decryptedtext_len - 4, 1, o);
  93. fclose(o);
  94. }
  95. }
  96. free(cipher);
  97. free(plain);
  98. printf("done\n");
  99. return 0;
  100. }
  101. void handleErrors(void) {
  102. ERR_print_errors_fp(stderr);
  103. abort();
  104. }
  105. int gcm_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, int iv_len, unsigned char *ciphertext, unsigned char *tag) {
  106. EVP_CIPHER_CTX *ctx;
  107. int len;
  108. int ciphertext_len;
  109. /* Create and initialise the context */
  110. if (!(ctx = EVP_CIPHER_CTX_new()))
  111. handleErrors();
  112. /* Initialise the encryption operation. */
  113. if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
  114. handleErrors();
  115. /*
  116. * Set IV length if default 12 bytes (96 bits) is not appropriate
  117. */
  118. if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
  119. handleErrors();
  120. /* Initialise key and IV */
  121. if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
  122. handleErrors();
  123. /*
  124. * Provide the message to be encrypted, and obtain the encrypted output.
  125. * EVP_EncryptUpdate can be called multiple times if necessary
  126. */
  127. if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
  128. handleErrors();
  129. ciphertext_len = len;
  130. /*
  131. * Finalise the encryption. Normally ciphertext bytes may be written at
  132. * this stage, but this does not occur in GCM mode
  133. */
  134. if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
  135. handleErrors();
  136. ciphertext_len += len;
  137. /* Get the tag */
  138. if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
  139. handleErrors();
  140. /* Clean up */
  141. EVP_CIPHER_CTX_free(ctx);
  142. return ciphertext_len;
  143. }
  144. int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *tag, unsigned char *key, unsigned char *iv, int iv_len,
  145. unsigned char *plaintext) {
  146. EVP_CIPHER_CTX *ctx;
  147. int len;
  148. int plaintext_len;
  149. int ret;
  150. /* Create and initialise the context */
  151. if (!(ctx = EVP_CIPHER_CTX_new()))
  152. handleErrors();
  153. /* Initialise the decryption operation. */
  154. if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
  155. handleErrors();
  156. /* Set IV length. Not necessary if this is 12 bytes (96 bits) */
  157. if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
  158. handleErrors();
  159. /* Initialise key and IV */
  160. if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
  161. handleErrors();
  162. /*
  163. * Provide the message to be decrypted, and obtain the plaintext output.
  164. * EVP_DecryptUpdate can be called multiple times if necessary
  165. */
  166. if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
  167. handleErrors();
  168. plaintext_len = len;
  169. /* Set expected tag value. Works in OpenSSL 1.0.1d and later */
  170. if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
  171. handleErrors();
  172. /*
  173. * Finalise the decryption. A positive return value indicates success,
  174. * anything else is a failure - the plaintext is not trustworthy.
  175. */
  176. ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
  177. /* Clean up */
  178. EVP_CIPHER_CTX_free(ctx);
  179. if (ret > 0) {
  180. /* Success */
  181. plaintext_len += len;
  182. return plaintext_len;
  183. } else {
  184. /* Verify failed */
  185. return -1;
  186. }
  187. }