cryptotest_gcm.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. printf("using iv ");
  52. for (unsigned i = 0; i < sizeof(iv); i++)
  53. printf("%02x ", iv[i]);
  54. printf("\n");
  55. printf("using tag ");
  56. for (unsigned i = 0; i < sizeof(tag); i++)
  57. printf("%02x ", tag[i]);
  58. printf("\n");
  59. fseek(f, 0, SEEK_END);
  60. insize = ftell(f) + 4;
  61. fseek(f, 0, SEEK_SET);
  62. plain = malloc(insize);
  63. cipher = malloc(insize);
  64. fread(plain + 4, insize, 1, f);
  65. fclose(f);
  66. /* prepend signature */
  67. memcpy(plain, signature, 4);
  68. /* Encrypt the plaintext */
  69. ciphertext_len = gcm_encrypt(plain, insize, key, iv, sizeof(iv), cipher, tag);
  70. fwrite(iv, sizeof(iv), 1, o);
  71. fwrite(tag, sizeof(tag), 1, o);
  72. fwrite(cipher, ciphertext_len, 1, o);
  73. fclose(o);
  74. } else {
  75. fseek(f, 0, SEEK_END);
  76. insize = ftell(f) - sizeof(iv) - sizeof(tag);
  77. fseek(f, 0, SEEK_SET);
  78. cipher = malloc(insize);
  79. plain = malloc(insize);
  80. fread(iv, sizeof(iv), 1, f);
  81. fread(tag, sizeof(tag), 1, f);
  82. fread(cipher, insize, 1, f);
  83. fclose(f);
  84. printf("using iv ");
  85. for (unsigned i = 0; i < sizeof(iv); i++)
  86. printf("%02x ", iv[i]);
  87. printf("\n");
  88. printf("using tag ");
  89. for (unsigned i = 0; i < sizeof(tag); i++)
  90. printf("%02x ", tag[i]);
  91. printf("\n");
  92. decryptedtext_len = gcm_decrypt(cipher, insize, tag, key, iv, sizeof(iv), plain);
  93. if (decryptedtext_len < 0) {
  94. printf("decrypt failed\n");
  95. fclose(o);
  96. remove(argv[4]);
  97. } else if (memcmp(plain, signature, 4)) {
  98. printf("signature mismatch, expected ");
  99. for (int i = 0; i < sizeof(signature); i++)
  100. printf("%02x ", signature[i]);
  101. printf("but got ");
  102. for (int i = 0; i < sizeof(signature); i++)
  103. printf("%02x ", plain[i]);
  104. printf("\n");
  105. fclose(o);
  106. remove(argv[4]);
  107. } else {
  108. fwrite(plain + 4, decryptedtext_len - 4, 1, o);
  109. fclose(o);
  110. }
  111. }
  112. free(cipher);
  113. free(plain);
  114. printf("done\n");
  115. return 0;
  116. }
  117. void handleErrors(void) {
  118. ERR_print_errors_fp(stderr);
  119. abort();
  120. }
  121. int gcm_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, int iv_len, unsigned char *ciphertext, unsigned char *tag) {
  122. EVP_CIPHER_CTX *ctx;
  123. int len;
  124. int ciphertext_len;
  125. /* Create and initialise the context */
  126. if (!(ctx = EVP_CIPHER_CTX_new()))
  127. handleErrors();
  128. /* Initialise the encryption operation. */
  129. if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
  130. handleErrors();
  131. /*
  132. * Set IV length if default 12 bytes (96 bits) is not appropriate
  133. */
  134. if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
  135. handleErrors();
  136. /* Initialise key and IV */
  137. if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
  138. handleErrors();
  139. /*
  140. * Provide the message to be encrypted, and obtain the encrypted output.
  141. * EVP_EncryptUpdate can be called multiple times if necessary
  142. */
  143. if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
  144. handleErrors();
  145. ciphertext_len = len;
  146. /*
  147. * Finalise the encryption. Normally ciphertext bytes may be written at
  148. * this stage, but this does not occur in GCM mode
  149. */
  150. if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
  151. handleErrors();
  152. ciphertext_len += len;
  153. /* Get the tag */
  154. if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
  155. handleErrors();
  156. /* Clean up */
  157. EVP_CIPHER_CTX_free(ctx);
  158. return ciphertext_len;
  159. }
  160. int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *tag, unsigned char *key, unsigned char *iv, int iv_len,
  161. unsigned char *plaintext) {
  162. EVP_CIPHER_CTX *ctx;
  163. int len;
  164. int plaintext_len;
  165. int ret;
  166. /* Create and initialise the context */
  167. if (!(ctx = EVP_CIPHER_CTX_new()))
  168. handleErrors();
  169. /* Initialise the decryption operation. */
  170. if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
  171. handleErrors();
  172. /* Set IV length. Not necessary if this is 12 bytes (96 bits) */
  173. if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
  174. handleErrors();
  175. /* Initialise key and IV */
  176. if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
  177. handleErrors();
  178. /*
  179. * Provide the message to be decrypted, and obtain the plaintext output.
  180. * EVP_DecryptUpdate can be called multiple times if necessary
  181. */
  182. if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
  183. handleErrors();
  184. plaintext_len = len;
  185. /* Set expected tag value. Works in OpenSSL 1.0.1d and later */
  186. if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
  187. handleErrors();
  188. /*
  189. * Finalise the decryption. A positive return value indicates success,
  190. * anything else is a failure - the plaintext is not trustworthy.
  191. */
  192. ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
  193. /* Clean up */
  194. EVP_CIPHER_CTX_free(ctx);
  195. if (ret > 0) {
  196. /* Success */
  197. plaintext_len += len;
  198. return plaintext_len;
  199. } else {
  200. /* Verify failed */
  201. return -1;
  202. }
  203. }