123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
- /* SPDX-License-Identifier: Unlicense */
- #include "tomcrypt.h"
- /**
- @file gcm_filehandle.c
- GCM process a filehandle, Steffen Jaeckel
- */
- #ifdef LTC_GCM_MODE
- #ifndef LTC_NO_FILE
- #if defined(_MSC_VER)
- #define ftruncate _chsize
- #else
- #include <unistd.h>
- #endif
- /**
- Process a filehandle.
- This uses the widely established scheme where the tag is appended
- to the ciphertext.
- encrypted_file = aesgcm(plain_file) | aesgcm_tag(plain_file)
- Depending on 'direction' this function does:
- Encrypt file 'in' to 'out' and append the tag of length 'taglen'
- to 'out'.
- or
- Decrypt file 'in' to 'out' and check the tag of length 'taglen'
- and strip the tag from 'in'.
- In error-cases 'out' will be zeroed out first and then truncated to
- a length of 0.
- @param cipher Index of cipher to use
- @param key The secret key
- @param keylen The length of the secret key
- @param IV The initial vector
- @param IVlen The length of the initial vector
- @param adata The additional authentication data (header)
- @param adatalen The length of the adata
- @param in The input file
- @param out The output file
- @param taglen The MAC tag length
- @param direction Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT)
- @param res [out] Result of the operation, 1==valid, 0==invalid
- @return CRYPT_OK on success
- */
- int gcm_filehandle( int cipher,
- const unsigned char *key, unsigned long keylen,
- const unsigned char *IV, unsigned long IVlen,
- const unsigned char *adata, unsigned long adatalen,
- FILE *in,
- FILE *out,
- unsigned long taglen,
- int direction,
- int *res)
- {
- void *orig;
- gcm_state *gcm;
- int err;
- unsigned char *buf, tag[16];
- size_t x, tot_data;
- unsigned long tag_len;
- LTC_ARGCHK(in != NULL);
- LTC_ARGCHK(out != NULL);
- LTC_ARGCHK(res != NULL);
- *res = 0;
- if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
- return err;
- }
- #ifndef LTC_GCM_TABLES_SSE2
- orig = gcm = XMALLOC(sizeof(*gcm));
- #else
- orig = gcm = XMALLOC(sizeof(*gcm) + 16);
- #endif
- if (gcm == NULL) {
- return CRYPT_MEM;
- }
- if ((buf = XMALLOC(LTC_FILE_READ_BUFSIZE)) == NULL) {
- XFREE(gcm);
- return CRYPT_MEM;
- }
- /* Force GCM to be on a multiple of 16 so we can use 128-bit aligned operations
- * note that we only modify gcm and keep orig intact. This code is not portable
- * but again it's only for SSE2 anyways, so who cares?
- */
- #ifdef LTC_GCM_TABLES_SSE2
- gcm = LTC_ALIGN_BUF(gcm, 16);
- #endif
- if ((err = gcm_init(gcm, cipher, key, keylen)) != CRYPT_OK) {
- goto LBL_ERR;
- }
- if ((err = gcm_add_iv(gcm, IV, IVlen)) != CRYPT_OK) {
- goto LBL_ERR;
- }
- if ((err = gcm_add_aad(gcm, adata, adatalen)) != CRYPT_OK) {
- goto LBL_ERR;
- }
- fseek(in, 0, SEEK_END);
- tot_data = ftell(in);
- if (direction == GCM_DECRYPT) {
- tot_data -= taglen;
- }
- fseek(in, 0, SEEK_SET);
- do {
- x = MIN(tot_data, LTC_FILE_READ_BUFSIZE);
- x = fread(buf, 1, x, in);
- tot_data -= x;
- if ((err = gcm_process(gcm, buf, (unsigned long)x, buf, direction)) != CRYPT_OK) {
- goto LBL_CLEANBUF;
- }
- if(fwrite(buf, 1, x, out) != x) {
- err = CRYPT_ERROR;
- goto LBL_CLEANBUF;
- }
- } while (x == LTC_FILE_READ_BUFSIZE);
- tag_len = taglen;
- if ((err = gcm_done(gcm, tag, &tag_len)) != CRYPT_OK) {
- goto LBL_CLEANBUF;
- }
- if (tag_len != taglen) {
- err = CRYPT_ERROR;
- goto LBL_CLEANBUF;
- }
- if (direction == GCM_DECRYPT) {
- if (feof(in) || ferror(in)) {
- err = CRYPT_ERROR;
- goto LBL_CLEANBUF;
- }
- x = fread(buf, 1, taglen, in);
- if (x != taglen) {
- err = CRYPT_ERROR;
- goto LBL_CLEANBUF;
- }
- if (XMEM_NEQ(buf, tag, taglen) == 0) {
- *res = 1;
- }
- } else {
- if(fwrite(tag, 1, taglen, out) != taglen) {
- err = CRYPT_ERROR;
- goto LBL_CLEANBUF;
- }
- *res = 1;
- }
- LBL_CLEANBUF:
- zeromem(buf, LTC_FILE_READ_BUFSIZE);
- zeromem(tag, sizeof(tag));
- LBL_ERR:
- #ifdef LTC_CLEAN_STACK
- #ifndef LTC_GCM_TABLES_SSE2
- zeromem(orig, sizeof(*gcm));
- #else
- zeromem(orig, sizeof(*gcm) + 16);
- #endif
- #endif
- if(*res == 0) {
- x = ftell(out);
- fseek(in, 0, SEEK_SET);
- while((size_t)ftell(out) < x) {
- fwrite(buf, 1, LTC_FILE_READ_BUFSIZE, out);
- }
- if(ftruncate(fileno(out), 0)) {
- /* well, what shall we do here... */
- }
- }
- fflush(out);
- XFREE(buf);
- XFREE(orig);
- return err;
- }
- #endif
- #endif
|