cryptotest-gcm.c 6.4 KB

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