gcm_filehandle.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /* LibTomCrypt, modular cryptographic library -- Tom St Denis
  2. *
  3. * LibTomCrypt is a library that provides various cryptographic
  4. * algorithms in a highly modular and flexible manner.
  5. *
  6. * The library is free for all purposes without any express
  7. * guarantee it works.
  8. */
  9. #include "tomcrypt.h"
  10. /**
  11. @file gcm_filehandle.c
  12. GCM process a filehandle, Steffen Jaeckel
  13. */
  14. #ifdef LTC_GCM_MODE
  15. #ifndef LTC_NO_FILE
  16. #if defined(_MSC_VER)
  17. #define ftruncate _chsize
  18. #else
  19. #include <unistd.h>
  20. #endif
  21. /**
  22. Process a filehandle.
  23. This uses the widely established scheme where the tag is appended
  24. to the ciphertext.
  25. encrypted_file = aesgcm(plain_file) | aesgcm_tag(plain_file)
  26. Depending on 'direction' this function does:
  27. Encrypt file 'in' to 'out' and append the tag of length 'taglen'
  28. to 'out'.
  29. or
  30. Decrypt file 'in' to 'out' and check the tag of length 'taglen'
  31. and strip the tag from 'in'.
  32. In error-cases 'out' will be zeroed out first and then truncated to
  33. a length of 0.
  34. @param cipher Index of cipher to use
  35. @param key The secret key
  36. @param keylen The length of the secret key
  37. @param IV The initial vector
  38. @param IVlen The length of the initial vector
  39. @param adata The additional authentication data (header)
  40. @param adatalen The length of the adata
  41. @param in The input file
  42. @param out The output file
  43. @param taglen The MAC tag length
  44. @param direction Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT)
  45. @param res [out] Result of the operation, 1==valid, 0==invalid
  46. @return CRYPT_OK on success
  47. */
  48. int gcm_filehandle( int cipher,
  49. const unsigned char *key, unsigned long keylen,
  50. const unsigned char *IV, unsigned long IVlen,
  51. const unsigned char *adata, unsigned long adatalen,
  52. FILE *in,
  53. FILE *out,
  54. unsigned long taglen,
  55. int direction,
  56. int *res)
  57. {
  58. void *orig;
  59. gcm_state *gcm;
  60. int err;
  61. unsigned char *buf, tag[16];
  62. size_t x, tot_data;
  63. unsigned long tag_len;
  64. LTC_ARGCHK(in != NULL);
  65. LTC_ARGCHK(out != NULL);
  66. LTC_ARGCHK(res != NULL);
  67. *res = 0;
  68. if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
  69. return err;
  70. }
  71. #ifndef LTC_GCM_TABLES_SSE2
  72. orig = gcm = XMALLOC(sizeof(*gcm));
  73. #else
  74. orig = gcm = XMALLOC(sizeof(*gcm) + 16);
  75. #endif
  76. if (gcm == NULL) {
  77. return CRYPT_MEM;
  78. }
  79. if ((buf = XMALLOC(LTC_FILE_READ_BUFSIZE)) == NULL) {
  80. XFREE(gcm);
  81. return CRYPT_MEM;
  82. }
  83. /* Force GCM to be on a multiple of 16 so we can use 128-bit aligned operations
  84. * note that we only modify gcm and keep orig intact. This code is not portable
  85. * but again it's only for SSE2 anyways, so who cares?
  86. */
  87. #ifdef LTC_GCM_TABLES_SSE2
  88. if ((unsigned long)gcm & 15) {
  89. gcm = (gcm_state *)((unsigned long)gcm + (16 - ((unsigned long)gcm & 15)));
  90. }
  91. #endif
  92. if ((err = gcm_init(gcm, cipher, key, keylen)) != CRYPT_OK) {
  93. goto LBL_ERR;
  94. }
  95. if ((err = gcm_add_iv(gcm, IV, IVlen)) != CRYPT_OK) {
  96. goto LBL_ERR;
  97. }
  98. if ((err = gcm_add_aad(gcm, adata, adatalen)) != CRYPT_OK) {
  99. goto LBL_ERR;
  100. }
  101. fseek(in, 0, SEEK_END);
  102. tot_data = ftell(in);
  103. if (direction == GCM_DECRYPT) {
  104. tot_data -= taglen;
  105. }
  106. rewind(in);
  107. do {
  108. x = MIN(tot_data, LTC_FILE_READ_BUFSIZE);
  109. x = fread(buf, 1, x, in);
  110. tot_data -= x;
  111. if ((err = gcm_process(gcm, buf, (unsigned long)x, buf, direction)) != CRYPT_OK) {
  112. goto LBL_CLEANBUF;
  113. }
  114. if(fwrite(buf, 1, x, out) != x) {
  115. err = CRYPT_ERROR;
  116. goto LBL_CLEANBUF;
  117. }
  118. } while (x == LTC_FILE_READ_BUFSIZE);
  119. tag_len = taglen;
  120. if ((err = gcm_done(gcm, tag, &tag_len)) != CRYPT_OK) {
  121. goto LBL_CLEANBUF;
  122. }
  123. if (tag_len != taglen) {
  124. err = CRYPT_ERROR;
  125. goto LBL_CLEANBUF;
  126. }
  127. if (direction == GCM_DECRYPT) {
  128. x = fread(buf, 1, taglen, in);
  129. if (x != taglen) {
  130. err = CRYPT_ERROR;
  131. goto LBL_CLEANBUF;
  132. }
  133. if (XMEM_NEQ(buf, tag, taglen) == 0) {
  134. *res = 1;
  135. }
  136. } else {
  137. if(fwrite(tag, 1, taglen, out) != taglen) {
  138. err = CRYPT_ERROR;
  139. goto LBL_CLEANBUF;
  140. }
  141. *res = 1;
  142. }
  143. LBL_CLEANBUF:
  144. zeromem(buf, LTC_FILE_READ_BUFSIZE);
  145. zeromem(tag, sizeof(tag));
  146. LBL_ERR:
  147. #ifdef LTC_CLEAN_STACK
  148. #ifndef LTC_GCM_TABLES_SSE2
  149. zeromem(orig, sizeof(*gcm));
  150. #else
  151. zeromem(orig, sizeof(*gcm) + 16);
  152. #endif
  153. #endif
  154. if(*res == 0) {
  155. x = ftell(out);
  156. rewind(out);
  157. while((size_t)ftell(out) < x) {
  158. fwrite(buf, 1, LTC_FILE_READ_BUFSIZE, out);
  159. }
  160. if(ftruncate(fileno(out), 0)) {
  161. /* well, what shall we do here... */
  162. }
  163. }
  164. fflush(out);
  165. XFREE(buf);
  166. XFREE(orig);
  167. return err;
  168. }
  169. #endif
  170. #endif
  171. /* ref: $Format:%D$ */
  172. /* git commit: $Format:%H$ */
  173. /* commit time: $Format:%ai$ */