Beispiel #1
0
void tee_cipher_final(void *ctx, uint32_t algo)
{
	switch (algo) {
	case TEE_ALG_AES_ECB_NOPAD:
	case TEE_ALG_DES_ECB_NOPAD:
	case TEE_ALG_DES3_ECB_NOPAD:
		ecb_done((symmetric_ECB *)ctx);
		break;

	case TEE_ALG_AES_CBC_NOPAD:
	case TEE_ALG_DES_CBC_NOPAD:
	case TEE_ALG_DES3_CBC_NOPAD:
		cbc_done((symmetric_CBC *)ctx);
		break;

	case TEE_ALG_AES_CTR:
		ctr_done((symmetric_CTR *)ctx);
		break;

	case TEE_ALG_AES_XTS:
		xts_done((symmetric_xts *)ctx);
		break;

	case TEE_ALG_AES_CTS:
		cbc_done(&(((struct symmetric_CTS *)ctx)->cbc));
		ecb_done(&(((struct symmetric_CTS *)ctx)->ecb));
		break;

	default:
		/* TEE_ERROR_NOT_SUPPORTED; */
		break;
	}
}
Beispiel #2
0
int main(int argc, char *argv[]){
  /* Similar situation as before,
     only the test vector is more complex.*/
  unsigned char key[32];
  bzero(key, 32);
  unsigned char initcount[16];
  bzero(initcount,16);
  initcount[15]=1; //For test usage
  unsigned char input[32];
  bzero(input, 32);
  unsigned char output[32]; //counter mode: assume xor works
  bzero(output, 32);
  aes256ctr(output, input, 32, key, initcount);
  for(int i=0; i<32; i++) printf("%02x ", output[i]);
  printf("\n");
  symmetric_CTR ctr;
  bzero(output, 32);
  register_cipher(&aes_desc);
  ctr_start(find_cipher("aes"), initcount, key, 32, 0, CTR_COUNTER_BIG_ENDIAN,
            &ctr);
  ctr_encrypt(input, output, 32, &ctr);
  ctr_done(&ctr);
  for(int i=0; i<32; i++) printf("%02x ", output[i]);
  printf("\n");
  exit(0);
}
Beispiel #3
0
int eax_done( unsigned char tag[], unsigned long tag_len, eax_state eax[1] )
{
    int err = EXIT_FAILURE;
    unsigned char *headermac, *ctmac;
    unsigned long x, len;

    if( ( headermac = malloc( AES_BLOCK_SIZE ) ) == NULL )
        goto exit3;
    if( ( ctmac = malloc( AES_BLOCK_SIZE ) ) == NULL )
        goto exit2;

    len = AES_BLOCK_SIZE;
    if( (err = omac_done( ctmac, &len, eax->ctx_omac )) != EXIT_SUCCESS )
        goto exit1;

    if( (err = omac_done( headermac, &len, eax->hdr_omac )) != EXIT_SUCCESS )
        goto exit1;

    if( (err = ctr_done( eax->ctr )) != 0 )
        goto exit1;

    for( x = 0; x < len && x < tag_len; x++ )
        tag[x] = eax->nv[x] ^ headermac[x] ^ ctmac[x];

    err = EXIT_SUCCESS;
exit1:
    free( ctmac );
exit2:
    free( headermac );
exit3:
    return err;
}
Beispiel #4
0
int ctr_test(void)
{
#ifdef LTC_NO_TEST
    return CRYPT_NOP;
#else
    static const struct {
        int keylen, msglen;
        unsigned char key[32], IV[16], pt[64], ct[64];
    } tests[] = {
        /* 128-bit key, 16-byte pt */
        {
            16, 16,
            {0xAE,0x68,0x52,0xF8,0x12,0x10,0x67,0xCC,0x4B,0xF7,0xA5,0x76,0x55,0x77,0xF3,0x9E },
            {0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
            {0x53,0x69,0x6E,0x67,0x6C,0x65,0x20,0x62,0x6C,0x6F,0x63,0x6B,0x20,0x6D,0x73,0x67 },
            {0xE4,0x09,0x5D,0x4F,0xB7,0xA7,0xB3,0x79,0x2D,0x61,0x75,0xA3,0x26,0x13,0x11,0xB8 },
        },

        /* 128-bit key, 36-byte pt */
        {
            16, 36,
            {0x76,0x91,0xBE,0x03,0x5E,0x50,0x20,0xA8,0xAC,0x6E,0x61,0x85,0x29,0xF9,0xA0,0xDC },
            {0x00,0xE0,0x01,0x7B,0x27,0x77,0x7F,0x3F,0x4A,0x17,0x86,0xF0,0x00,0x00,0x00,0x00 },
            {   0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
                0x20,0x21,0x22,0x23
            },
            {   0xC1,0xCF,0x48,0xA8,0x9F,0x2F,0xFD,0xD9,0xCF,0x46,0x52,0xE9,0xEF,0xDB,0x72,0xD7,
                0x45,0x40,0xA4,0x2B,0xDE,0x6D,0x78,0x36,0xD5,0x9A,0x5C,0xEA,0xAE,0xF3,0x10,0x53,
                0x25,0xB2,0x07,0x2F
            },
        },
    };
    int idx, err, x;
    unsigned char buf[64];
    symmetric_CTR ctr;

    /* AES can be under rijndael or aes... try to find it */
    if ((idx = find_cipher("aes")) == -1) {
        if ((idx = find_cipher("rijndael")) == -1) {
            return CRYPT_NOP;
        }
    }

    for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
        if ((err = ctr_start(idx, tests[x].IV, tests[x].key, tests[x].keylen, 0, CTR_COUNTER_BIG_ENDIAN|LTC_CTR_RFC3686, &ctr)) != CRYPT_OK) {
            return err;
        }
        if ((err = ctr_encrypt(tests[x].pt, buf, tests[x].msglen, &ctr)) != CRYPT_OK) {
            return err;
        }
        ctr_done(&ctr);
        if (XMEMCMP(buf, tests[x].ct, tests[x].msglen)) {
            return CRYPT_FAIL_TESTVECTOR;
        }
    }
    return CRYPT_OK;
#endif
}
/**
  Terminate the PRNG
  @param prng   The PRNG to terminate
  @return CRYPT_OK if successful
*/  
int yarrow_done(prng_state *prng)
{
   LTC_ARGCHK(prng != NULL);

   /* call cipher done when we invent one ;-) */

   /* we invented one */
   return ctr_done(&prng->yarrow.ctr);
}
Beispiel #6
0
void Encrypt(PK0304* le, AE_EXTRA* ae, char* password)
{
 char *salt, *key1, *key2, *check, digest[40];
 u32 key_len = KeySize*2 + 2;
 u32 dig_len = 40;

 salt = BUF;
 key1 = salt+SaltSize;
 key2 = key1+KeySize;
 check = key2+KeySize;

 /* Gets a random salt (8-16 byte) */
 sprng_read(salt, SaltSize, 0);

 /* Generates 2 keys for AES and HMAC, plus 2-byte password verification value */
 if (pkcs_5_alg2(password, strlen(password), salt, SaltSize, 1000, 0, key1, &key_len) != CRYPT_OK)
  Z_ERROR("Failed to derive encryption keys");

// dump("salt", salt, SaltSize);
// dump("key", key1, KeySize);

 if (ctr_start(0, IV, key1, KeySize, 0, CTR_COUNTER_LITTLE_ENDIAN, &ctr) != CRYPT_OK)
  Z_ERROR("Failed to setup AES CTR encoder");
#ifdef GLADMAN_HMAC
 hmac_sha1_begin(&hmac);
 hmac_sha1_key(key2, KeySize, &hmac);
#else
 if (hmac_init(&hmac, 0, key2, KeySize) != CRYPT_OK)
  Z_ERROR("Failed to setup HMAC-SHA1");
#endif
 if (AE2) le->Crc32 = 0;
 le->Flag |= 1;
 le->CompMethod = 99;
 le->ExtraLen += 11;
 le->CompSize += SaltSize + 12; /* variable salt, fixed password check and hmac */

 safeWrite(ZOUT, le, sizeof(PK0304));
 fileCopy(ZOUT, ZIN, le->NameLen+le->ExtraLen-11);
 safeWrite(ZOUT, ae, 11);
 safeWrite(ZOUT, salt, SaltSize);
 safeWrite(ZOUT, check, 2);
 /* encrypt contents */
 fileFilter(ZOUT, ZIN, le->CompSize-SaltSize-12);
#ifdef GLADMAN_HMAC
 hmac_sha1_end(digest, dig_len, &hmac);
#else
 if (hmac_done(&hmac, digest, &dig_len) != CRYPT_OK)
  Z_ERROR("Failed to computate HMAC");
#endif
 safeWrite(ZOUT, digest, 10);
 ctr_done(&ctr);
}
Beispiel #7
0
void ltc_cleanup(void)
{
    TRACE_DEBUG("LTC: Cleaning up ...\n\r");

#if defined(ENCRYPTION_ECB)
    ecb_done(&sECB);
#elif defined(ENCRYPTION_CBC)
    cbc_done(&sCBC);
#elif defined(ENCRYPTION_CTR)
    ctr_done(&sCTR);
#endif

    TRACE_DEBUG("LTC: Cleanup done.\n\r");
}
/**
  Terminate the PRNG
  @param prng   The PRNG to terminate
  @return CRYPT_OK if successful
*/  
int yarrow_done(prng_state *prng)
{
   int err;
   LTC_ARGCHK(prng != NULL);

   LTC_MUTEX_LOCK(&prng->yarrow.prng_lock);

   /* call cipher done when we invent one ;-) */

   /* we invented one */
   err = ctr_done(&prng->yarrow.ctr);
   
   LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
   return err;
}
Beispiel #9
0
int symmetricEncrypt(unsigned char *key, unsigned long keylen, unsigned char *in, unsigned long len, unsigned char *IV, unsigned long ivlen)
{
    symmetric_CTR ctr;
    int err;

    /* register aes first */
    
    if ((err = register_cipher(&rijndael_desc)) == -1) {
        return ERROR_REG_AES;
    }
    
    /* start up CTR mode */
    if ((err = ctr_start(
        find_cipher("rijndael"),    /* index of desired cipher */
                             IV,    /* the initial vecoter */ 
                            key,    /* the secret key */
                         keylen,    /* length of secret key */
                              0,
      CTR_COUNTER_LITTLE_ENDIAN,
                           &ctr)
        ) != CRYPT_OK) {
        //printf("%s\n", error_to_string(err));
        return err;
    }
    /*
    printf("from libcrypt: \n");
    for(i = 0; i < 30; i++)
        printf("%02x ", in[i]);
    printf("\n");
    fflush(stdout);
    */
    if ((err = ctr_encrypt(     in, /* plaintext */
                                in, /* ciphertext */
                                   len, /* length of plaintext */
                                  &ctr) /* CTR state */
        ) != CRYPT_OK) {
        return err;
    }

    if ((err = ctr_done(&ctr)) != CRYPT_OK) {
        return err;
    }

    return CRYPT_OK;
}
Beispiel #10
0
int symmetricDecrypt(unsigned char *key, unsigned long keylen, unsigned char *in, unsigned long len, unsigned char *IV, unsigned long ivlen)
{
    symmetric_CTR ctr;
    int err;

    /* register aes first */
    if (register_cipher(&rijndael_desc) == -1) {
        return ERROR_REG_AES;
    }
    
    /* start up CTR mode */
    if ((err = ctr_start(
        find_cipher("rijndael"),    /* index of desired cipher */
                             IV,    /* the initial vecoter */ 
                            key,    /* the secret key */
                         keylen,    /* length of secret key */
                              0,
      CTR_COUNTER_LITTLE_ENDIAN,
                           &ctr)
        ) != CRYPT_OK) {
        return err;
    }

//    if ((err = ctr_setiv( IV, /* the initial IV we gave to ctr_start */
//                    16, /* the IV is 16 bytes long */
//                    &ctr) /* the ctr state we wish to modify */
//        ) != CRYPT_OK) {
//        printf("ctr_setiv error: %s\n", error_to_string(err));
//        return -1;
//    }

    if ((err = ctr_decrypt(     in, /* plaintext */
                                in, /* ciphertext */
                               len, /* length of plaintext */
                              &ctr) /* CTR state */
        ) != CRYPT_OK) {
        return err;
    }
    if ((err = ctr_done(&ctr)) != CRYPT_OK) {
        return err;
    }

    return CRYPT_OK;
}
Beispiel #11
0
static int
EncryptCTR(
    int cipher,
    int rounds,
    int counterMode,
    unsigned char *iv,
    unsigned char *key,
    unsigned long keyLength,
    unsigned char *data,
    unsigned long dataLength,
    unsigned char *dest
    )
{
    int status;
    symmetric_CTR state;

    status = ctr_start(cipher, iv, key, keyLength, rounds, counterMode, &state);
    if (status == CRYPT_OK) {
        status = ctr_encrypt(data, dest, dataLength, &state);
        ctr_done(&state);
    }

    return status;
}
Beispiel #12
0
int main(){
	char 			plaintext[] = "Hi I am an AES CTR test vector distributed on 4 128-bit blocks!";
	unsigned char 	key[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
	unsigned char 	iv[16] = {0x01, 0xff, 0x83, 0xf2, 0xf9, 0x98, 0xba, 0xa4, 0xda, 0xdc, 0xaa, 0xcc, 0x8e, 0x17, 0xa4, 0x1b};
	symmetric_CTR 	ctr;
	unsigned char 	ciphertext[sizeof(plaintext)];
	unsigned char 	deciphertext[sizeof(plaintext)];
	int 			err;

	if (register_cipher(&aes_desc) == -1) {
		printf("Error: in %s, unable to register cipher\n", __func__);
		return 0;
	}

	printf("Plaintext:      \"%s\"\n", plaintext);
	printf("IV:             ");
	fprintBuffer_raw(stdout, (char*)iv, sizeof(iv));
	printf("\nKey 128:        ");
	fprintBuffer_raw(stdout, (char*)key, sizeof(key));

	/* ENCRYPT */
	if ((err = ctr_start(find_cipher("aes"), iv, key, sizeof(key), 0, CTR_COUNTER_LITTLE_ENDIAN, &ctr)) != CRYPT_OK){
		printf("ERROR: in %s, %s\n", __func__, error_to_string(err));
		return 0;
	}

	if ((err = ctr_encrypt((unsigned char*)plaintext, ciphertext, sizeof(plaintext), &ctr)) != CRYPT_OK){
		printf("ERROR: in %s, %s\n", __func__, error_to_string(err));
		return 0;
	}

	if ((err = ctr_done(&ctr)) != CRYPT_OK){
		printf("ERROR: in %s, %s\n", __func__, error_to_string(err));
		return 0;
	}

	/* DECRYPT */
	if ((err = ctr_start(find_cipher("aes"), iv, key, sizeof(key), 0, CTR_COUNTER_LITTLE_ENDIAN, &ctr)) != CRYPT_OK){
		printf("ERROR: in %s, %s\n", __func__, error_to_string(err));
		return 0;
	}

	if ((err = ctr_decrypt(ciphertext, deciphertext, sizeof(plaintext), &ctr)) != CRYPT_OK){
		printf("ERROR: in %s, %s\n", __func__, error_to_string(err));
		return 0;
	}

	if ((err = ctr_done(&ctr)) != CRYPT_OK){
		printf("ERROR: in %s, %s\n", __func__, error_to_string(err));
		return 0;
	}

	printf("\nCiphertext CTR: ");
	fprintBuffer_raw(stdout, (char*)ciphertext, sizeof(plaintext));

	if (memcmp(deciphertext, plaintext, sizeof(plaintext)) == 0){
		printf("\nRecovery:       OK\n");
	}
	else{
		printf("\nRecovery:       FAIL\n");
	}
	return 0;
}
Beispiel #13
0
void Decrypt(PK0304 *le, char *password)
{
 char *salt, *key1, *key2, *check, digest[40];
 u32 key_len, dig_len = 40, start, xlen;
 AE_EXTRA ae;

 start = ftell(ZIN);
 /* Searches for AE-1 header */
 fseek(ZIN, le->NameLen, SEEK_CUR);
 for(xlen=le->ExtraLen; xlen;)
 {
  safeRead(&ae, ZIN, 4);
  xlen -= (4 + ae.Size);
  if (ae.Sig == 0x9901)
  {
   safeRead(&ae.Version, ZIN, 7);
   continue;
  }
  fseek(ZIN, ae.Size, SEEK_CUR);
 }
 if (ae.Sig != 0x9901)
  Z_ERROR("Fatal! Can't find AE extra header!");
 if (ae.Strength < 1 || ae.Strength > 3)
  Z_ERROR("Bad encryption strength");
 SaltSize = KS[ae.Strength].Salt;
 KeySize = KS[ae.Strength].Key;

 salt = BUF;
 key1 = salt+SaltSize;
 key2 = key1+KeySize;
 check = key2+KeySize;
 key_len = KeySize*2+2;

 /* Loads salt and password check value, and regenerates original crypto material */
 fseek(ZIN, start+le->NameLen+le->ExtraLen, SEEK_SET);
 safeRead(salt, ZIN, SaltSize);
 safeRead(check+2, ZIN, 2);
point1:
 if (pkcs_5_alg2(password, strlen(password), salt, SaltSize, 1000, 0, key1, &key_len) != CRYPT_OK)
  Z_ERROR("Failed to derive encryption keys");
 if (memcmp(check, check+2, 2))
 {
  printf("\nCan't decrypt data: try another password.\nNew password: "******"\n");
  goto point1;
 }
 if (ctr_start(0, IV, key1, KeySize, 0, CTR_COUNTER_LITTLE_ENDIAN, &ctr) != CRYPT_OK)
  Z_ERROR("Failed to setup AES CTR decoder");
#ifdef GLADMAN_HMAC
 hmac_sha1_begin(&hmac);
 hmac_sha1_key(key2, KeySize, &hmac);
#else
 if (hmac_init(&hmac, 0, key2, KeySize) != CRYPT_OK)
  Z_ERROR("Failed to setup HMAC-SHA1");
#endif
 /* Adjusts local header */
 le->Flag ^= 1;
 le->CompMethod = ae.CompMethod;
 le->ExtraLen -= 11;
 le->CompSize -= (SaltSize + 12);
 /* Writes local header and copies extra, except 0x9901 */
 safeWrite(ZOUT, le, sizeof(PK0304));
 fseek(ZIN, start, SEEK_SET);
 fileCopy(ZOUT, ZIN, le->NameLen);
 for(xlen=le->ExtraLen+11; xlen;)
 {
  safeRead(&ae, ZIN, 4);
  xlen -= (4 + ae.Size);
  if (ae.Sig == 0x9901)
  {
   safeRead(&ae.Version, ZIN, 7);
   continue;
  }
  safeWrite(ZOUT, &ae, 4);
  fileCopy(ZOUT, ZIN, ae.Size);
 }
 fseek(ZIN, SaltSize+2, SEEK_CUR);

 fileFilter(ZOUT, ZIN, le->CompSize);

#ifdef GLADMAN_HMAC
 hmac_sha1_end(digest, dig_len, &hmac);
#else
 if (hmac_done(&hmac, digest, &dig_len) != CRYPT_OK)
  Z_ERROR("Failed to computate HMAC");
#endif
 /* Retrieves and checks HMACs */
 safeRead(digest+10, ZIN, 10);
 if (memcmp(digest, digest+10, 10))
  printf(" authentication failed, contents were lost!");
 ctr_done(&ctr);
}
Beispiel #14
0
/**
   Terminate an EAX session and get the tag.
   @param eax       The EAX state
   @param tag       [out] The destination of the authentication tag
   @param taglen    [in/out] The max length and resulting length of the authentication tag
   @return CRYPT_OK if successful
*/
int eax_done(eax_state *eax, unsigned char *tag, unsigned long *taglen)
{
   int           err;
   unsigned char *headermac, *ctmac;
   unsigned long x, len;

   LTC_ARGCHK(eax    != NULL);
   LTC_ARGCHK(tag    != NULL);
   LTC_ARGCHK(taglen != NULL);

   /* allocate ram */
   headermac = XMALLOC(MAXBLOCKSIZE);
   ctmac     = XMALLOC(MAXBLOCKSIZE);

   if (headermac == NULL || ctmac == NULL) {
      if (headermac != NULL) {
         XFREE(headermac);
      }
      if (ctmac != NULL) {
         XFREE(ctmac);
      }
      return CRYPT_MEM;
   }

   /* finish ctomac */
   len = MAXBLOCKSIZE;
   if ((err = omac_done(&eax->ctomac, ctmac, &len)) != CRYPT_OK) {
      goto LBL_ERR; 
   }

   /* finish headeromac */

   /* note we specifically don't reset len so the two lens are minimal */

   if ((err = omac_done(&eax->headeromac, headermac, &len)) != CRYPT_OK) {
      goto LBL_ERR; 
   }

   /* terminate the CTR chain */
   if ((err = ctr_done(&eax->ctr)) != CRYPT_OK) {
      goto LBL_ERR;
   }

   /* compute N xor H xor C */
   for (x = 0; x < len && x < *taglen; x++) {
       tag[x] = eax->N[x] ^ headermac[x] ^ ctmac[x];
   }
   *taglen = x;

   err = CRYPT_OK;
LBL_ERR:
#ifdef LTC_CLEAN_STACK
   zeromem(ctmac,     MAXBLOCKSIZE);
   zeromem(headermac, MAXBLOCKSIZE);
   zeromem(eax,       sizeof(*eax));
#endif

   XFREE(ctmac);
   XFREE(headermac);

   return err;
}
Beispiel #15
0
void ltc_cleanup_CTR(void)
{
    TRACE_DEBUG("LTC: Cleaning up CTR...\n\r");
    ctr_done(&sCTR);
    TRACE_DEBUG("LTC: Cleanup done.\n\r");
}
Beispiel #16
0
/* IF YOU CALL THIS MULTIPLE TIMES WITH THE SAME KEY YOU MUST PROVIDE AN IV POINTER! */
int crypt_data(const unsigned char *data_in,
                     unsigned char *data_out,  size_t data_size,
               const unsigned char *data_mkey, size_t data_mkey_size,
                     unsigned char *data_new_hmac,
               const unsigned char *data_chk_hmac,
                     size_t data_hmac_size,
                     unsigned char **IV_start,
                     int mode) {
  if (mode != MODE_ENCRYPT && mode != MODE_DECRYPT) {
    fprintf(stderr, "crypt_data called with invalid mode %d\n", mode);
    return -1;
  }

  symmetric_CTR ctr;
#ifdef _POSIX_MEMLOCK_RANGE
  if (mlock(&ctr, sizeof(ctr)) != 0) {
    fprintf(stderr, "WARNING: mlock failed at %s:%d - ", __FILE__, __LINE__);
    perror("");
  }
#endif
  int err;
  int ret = 0; /* return code */
  unsigned char *IV;
  unsigned long  IV_size = 16;
  int hash_idx = find_hash("sha256");
  size_t data_ckey_size, data_hkey_size;
  data_ckey_size = data_hkey_size = data_mkey_size;
  unsigned char *subkeys = safe_malloc(data_ckey_size + data_hkey_size);
#ifdef _POSIX_MEMLOCK_RANGE
    if (mlock(subkeys, data_ckey_size + data_hkey_size) != 0) {
      fprintf(stderr, "WARNING: mlock failed at %s:%d - ", __FILE__, __LINE__);
      perror("");
    }
#endif
  unsigned char *data_ckey = subkeys + 0;
  unsigned char *data_hkey = subkeys + data_ckey_size;

  pbkdf2(data_mkey, data_mkey_size, "H", 1, SUBKEY_ITER, hash_idx, data_hkey, &data_hkey_size);
  pbkdf2(data_mkey, data_mkey_size, "C", 1, SUBKEY_ITER, hash_idx, data_ckey, &data_ckey_size);
  if (IV_start == NULL || *IV_start == NULL) {
    IV = safe_malloc(IV_size);
    /* fprintf(stderr, "Initializing key-based IV\n"); */
    /* This is at least as secure as starting with a zeroed IV */
    pbkdf2(data_mkey, data_mkey_size, "I", 1, SUBKEY_ITER, hash_idx, IV, &IV_size);
  }
  if (IV_start != NULL) {
    if (*IV_start != NULL) {
      /* fprintf(stderr, "IV = *IV_start\n"); */
      IV = *IV_start;
    } else {
      /* fprintf(stderr, "*IV_start = IV\n"); */
      *IV_start = IV;
    }
  }

  if (mode == MODE_DECRYPT && data_chk_hmac != NULL) {
    if ((err = hmac_vrfymem(hash_idx,
                            data_hkey, data_hkey_size,
                            data_in, data_size, data_chk_hmac,
                            (long unsigned int *)&data_hmac_size)) != CRYPT_OK) {
     crypt_data_return(THRCR_BADMAC);
    }
  }

  /* LTC_CTR_RFC3686 is needed to avoid reusing a counter value. */
  if ((err = ctr_start(find_cipher("aes"), IV, data_ckey, data_ckey_size, 0,
                       CTR_COUNTER_BIG_ENDIAN | LTC_CTR_RFC3686, &ctr)) != CRYPT_OK) {
    fprintf(stderr, "Error initializing cipher: %d\n", err);
    crypt_data_return(-1);
  }

  /* ctr_encrypt is used for both encryption and decryption */
  if ((err = ctr_encrypt(data_in, data_out, data_size, &ctr)) != CRYPT_OK) {
    fprintf(stderr, "ctr_encrypt error: %s\n", error_to_string(err));
    ctr_done(&ctr); /* done with cipher, clean up keys */
    crypt_data_return(-1);
  }
  ctr_done(&ctr); /* done with cipher, clean up keys */

  if (mode == MODE_ENCRYPT && data_new_hmac != NULL) {
    if ((err = hmac_memory(hash_idx,
                           data_hkey, data_hkey_size,
                           data_out, data_size, data_new_hmac,
                           (long unsigned int *)&data_hmac_size)) != CRYPT_OK) {
      fprintf(stderr, "hmac error: %s\n", error_to_string(err));
      crypt_data_return(-1);
    }
  }

  crypt_data_return:
  /* before actually returning, make sure key material isn't in memory */
  MEMWIPE(&ctr, sizeof(ctr));
  MEMWIPE(subkeys, data_ckey_size + data_hkey_size);
#ifdef _POSIX_MEMLOCK_RANGE
  munlock(subkeys, data_ckey_size + data_hkey_size);
#endif
  safe_free(subkeys);
  /* save the IV */
  if (IV_start != NULL && *IV_start != NULL) {
    /* fprintf(stderr, "*IV_start = ctr.ctr\n"); */
    ctr_getiv(*IV_start, &IV_size, &ctr);
  } else {
    safe_free(IV);
  }
  return ret;
}