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
void CBC_Free(CBC_ContextRef  ctx)
{
    
    if(sCBC_ContextIsValid(ctx))
    {
        cbc_done(&ctx->state);
        ZERO(ctx, sizeof(CBC_Context));
        XFREE(ctx);
    }
}
static int sqlcipher_ltc_cipher(void *ctx, int mode, unsigned char *key, int key_sz, unsigned char *iv, unsigned char *in, int in_sz, unsigned char *out) {
  int rc, cipher_idx, hash_idx;
  symmetric_CBC cbc;

  if((cipher_idx = find_cipher(sqlcipher_ltc_get_cipher(ctx))) == -1) return SQLITE_ERROR;
  if((rc = cbc_start(cipher_idx, iv, key, key_sz, 0, &cbc)) != CRYPT_OK) return SQLITE_ERROR;
  rc = mode == 1 ? cbc_encrypt(in, out, in_sz, &cbc) : cbc_decrypt(in, out, in_sz, &cbc);
  if(rc != CRYPT_OK) return SQLITE_ERROR;
  cbc_done(&cbc);
  return SQLITE_OK;
}
Beispiel #4
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");
}
Beispiel #5
0
  void CAESModule::decrypt(Tools::CSecureMemory &rPlainText, Tools::CSecureMemory const &rCypherText) const
  {
    FASSERT(((rCypherText.getSize()-gIVSize) % gBlockSize) == 0);
    FASSERT(mKey.getSize() == gKeySize);

    Tools::CSecureMemory const IV(&rCypherText[0], gIVSize);

    int ErrorCode;
    int const Cipher = find_cipher("rijndael");
    FASSERT(Cipher != -1);

    symmetric_CBC CBCMode;
    ErrorCode = cbc_start(Cipher, &IV[0], &mKey[0], static_cast<unsigned long>(mKey.getSize()), 0, &CBCMode);
    if (ErrorCode != CRYPT_OK)
    {
    	throw ExInternalError(std::string("Cannot setup AES cipher: ") + std::string(error_to_string(ErrorCode)));
    }

    Tools::CSecureMemory PaddedPlainText;
    PaddedPlainText.allocate(rCypherText.getSize() - gIVSize);

    ErrorCode = cbc_decrypt(&rCypherText[gIVSize], &PaddedPlainText[0], static_cast<unsigned long>(PaddedPlainText.getSize()), &CBCMode);
    if (ErrorCode != CRYPT_OK)
    {
  	  throw ExInternalError(std::string("Error during decryption: ") + std::string(error_to_string(ErrorCode)));
    }

    ErrorCode = cbc_done(&CBCMode);
    if (ErrorCode != CRYPT_OK)
    {
    	throw ExInternalError(std::string("Error when closing decryption stream: ") + std::string(error_to_string(ErrorCode)));
    }

    try
    {
      Tools::getUnpaddedMemory(rPlainText, PaddedPlainText);
    }
    catch(Debug::ExAssert &rError)
    {
    	UNUSED_ARGUMENT(rError);

    	throw ExKeyError(std::string("{CAESModule} Memory structure of decrypted data is invalid. Cannot delete padding bytes."));
    }

  	return;
  }
Beispiel #6
0
  void CAESModule::encrypt(Tools::CSecureMemory &rCypherText, Tools::CSecureMemory const &rPlainText) const
  {
    FASSERT(mKey.getSize() == gKeySize);

    Tools::CSecureMemory IV;
    getRandomIV(IV);

    Tools::CSecureMemory PaddedPlainText;
    getPadding(PaddedPlainText, rPlainText);

    int ErrorCode;

    rCypherText.allocate(PaddedPlainText.getSize()+IV.getSize());
    std::memcpy(&rCypherText[0], &IV[0], IV.getSize());

    int const Cipher = find_cipher("rijndael");
    FASSERT(Cipher != -1);

    symmetric_CBC CBCMode;
    ErrorCode = cbc_start(Cipher, &IV[0], &mKey[0], static_cast<unsigned long>(mKey.getSize()), 0, &CBCMode);
    if (ErrorCode != CRYPT_OK)
    {
    	throw ExInternalError(std::string("Cannot setup AES cipher: ") + std::string(error_to_string(ErrorCode)));
    }

    ErrorCode = cbc_encrypt(&PaddedPlainText[0], &rCypherText[IV.getSize()], static_cast<unsigned long>(PaddedPlainText.getSize()), &CBCMode);
    if (ErrorCode != CRYPT_OK)
    {
    	throw ExInternalError(std::string("Error during encryption: ") + std::string(error_to_string(ErrorCode)));
    }

    ErrorCode = cbc_done(&CBCMode);
    if (ErrorCode != CRYPT_OK)
    {
    	throw ExInternalError(std::string("Error when closing encryption stream: ") + std::string(error_to_string(ErrorCode)));
    }

  	return;
  }
Beispiel #7
0
/*++

EncryptCBC
EncryptCFB
EncryptCTR
EncryptECB
EncryptOFB

    Encrypts data in the specified cipher mode and algorithm.

Arguments:
    cipher      - Index of the desired cipher.

    rounds      - Number of rounds.

    counterMode - The counter mode (CTR_COUNTER_LITTLE_ENDIAN or CTR_COUNTER_BIG_ENDIAN).

    iv          - The initial vector, must be the length of one block.

    key         - The secret key.

    keyLength   - Length of the secret key, in bytes.

    data        - Plain text (data to encrypt).

    dataLength  - Length of plain text, in bytes.

    dest        - Buffer to receive cipher text (encrypted data).

Return Value:
    A LibTomCrypt status code; CRYPT_OK will be returned if successful.

--*/
static int
EncryptCBC(
    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_CBC state;

    status = cbc_start(cipher, iv, key, keyLength, rounds, &state);
    if (status == CRYPT_OK) {
        status = cbc_encrypt(data, dest, dataLength, &state);
        cbc_done(&state);
    }

    return status;
}
Beispiel #8
0
static int RunCipherKAT(  katvector *kat)

{
    int err = CRYPT_OK;
    char* name = NULL;
    uint8_t *out = NULL;
    
    size_t  alloc_len =   MAX(kat->EBClen, kat->CBClen);
    
    symmetric_ECB ECB;
    symmetric_CBC CBC;
    
    out = malloc(alloc_len); 
    ZERO(out, alloc_len);
    
    
    //   err = cipher_is_valid(kat->algor); CKERR;
    
    name = cipher_name(kat->algor);
    
    printf("\t%-7s %d ", name, kat->keysize);
    
    printf("%6s", "ECB");
    
    DO( ecb_start(kat->algor, kat->key, kat->keysize>>3, 0, &ECB));
    
    DO( ecb_encrypt(kat->PT, out, kat->PTlen, &ECB))
    
    /* check against know-answer */
    DO( compareResults( kat->EBC, out, kat->EBClen , kResultFormat_Byte, "Symmetric Encrypt"));
    
    DO(ecb_decrypt(out, out, kat->PTlen, &ECB));
    
    /* check against orginal plain-text  */
    DO(compareResults( kat->PT, out, kat->PTlen , kResultFormat_Byte, "Symmetric Decrypt"));
    
    
    printf("%6s", "CBC");
    
    DO(cbc_start(kat->algor, kat->IV,  kat->key, kat->keysize>>3, 0, &CBC));
    
    DO(cbc_encrypt(kat->PT, out, kat->PTlen, &CBC));
    
    /* check against know-answer */
    DO(compareResults( kat->CBC, out, kat->CBClen , kResultFormat_Byte, "Symmetric Encrypt"));
    
    // reset CBC befire decrypt*/
    cbc_done(&CBC);
    DO(cbc_start(kat->algor, kat->IV,  kat->key, kat->keysize>>3, 0, &CBC));
    
    DO(cbc_decrypt(out, out, kat->PTlen, &CBC));
    
    /* check against orginal plain-text  */
    DO( compareResults( kat->PT, out, kat->PTlen , kResultFormat_Byte, "Symmetric Decrypt"));
    
done:
    
    ecb_done(&ECB);
    cbc_done(&CBC);
    
    free(out);
    
    printf("\n");
    return err;
}
// =========================================================================
// Decryption function
// Note: PlaintextLength must be set to the size of the PlaintextData buffer on
//       entry; on exit, this will be set to the size of the buffer used.
NTSTATUS
ImpCypherDecryptSectorData(
    IN      GUID* CypherGUID,
    IN      LARGE_INTEGER SectorID,  // Indexed from zero
    IN      int SectorSize, // In bytes
    IN      int KeyLength,  // In bits
    IN      FREEOTFEBYTE* Key,
    IN      char* KeyASCII,  // ASCII representation of "Key"
    IN      int IVLength,  // In bits
    IN      FREEOTFEBYTE* IV,
    IN      int CyphertextLength,  // In bytes
    IN      FREEOTFEBYTE* CyphertextData,
    OUT     FREEOTFEBYTE* PlaintextData
)
{
    NTSTATUS status = STATUS_SUCCESS;
    // libtomcrypt can't handle NULL IVs in CBC mode - it ASSERTs that IV != NULL
    char ltcNullIV[FREEOTFE_MAX_CYPHER_BLOCKSIZE];
    int cipher;
    symmetric_CBC *cbc;
    int errnum;

    DEBUGOUTCYPHERIMPL(DEBUGLEV_ENTER, (TEXT("ImpCypherDecryptData\n")));

	if (!(
		  (IsEqualGUID(&CIPHER_GUID_CAST5, CypherGUID))
		 ))
		{
		DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unsupported cipher GUID passed in.\n")));
        status = STATUS_INVALID_PARAMETER;
        }

    // libtomcrypt can't handle NULL IVs in CBC mode - it ASSERTs that IV != NULL
    if ( (IVLength == 0) || (IV == NULL) )
        {
        FREEOTFE_MEMZERO(&ltcNullIV, sizeof(ltcNullIV));
        IV = (char*)&ltcNullIV;
        }

    cbc = FREEOTFE_MEMALLOC(sizeof(symmetric_CBC));    
    FREEOTFE_MEMZERO(cbc, sizeof(symmetric_CBC));

  	if NT_SUCCESS(status) 
    		{
	    	status = InitLTCCypher(&cipher);
  		  }

    if NT_SUCCESS(status)
        {
        // Start a CBC session
        if ((errnum = cbc_start(
                                cipher, 
                                IV, 
                                Key, 
                                (KeyLength/8), 
                                0, 
                                cbc
                               )) != CRYPT_OK)
            {
            status = STATUS_UNSUCCESSFUL;
            DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to start CBC session (errnum: %d)\n"), errnum));
            }
        else
            {
            if ((errnum = cbc_decrypt(
                                      CyphertextData, 
                                      PlaintextData, 
                                      CyphertextLength, 
                                      cbc
                                     )) != CRYPT_OK)
                {
                DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to encrypt/decrypt block (errnum: %d)\n"), errnum));
                status = STATUS_UNSUCCESSFUL;
                }

            cbc_done(cbc);
            }
        }

    SecZeroMemory(cbc, sizeof(symmetric_CBC));
    FREEOTFE_FREE(cbc);

    DEBUGOUTCYPHERIMPL(DEBUGLEV_EXIT, (TEXT("ImpCypherDecryptData\n")));

    return status;
}
// =========================================================================
// Encrypt/Decrypt function
// Note: PlaintextLength must be set to the size of the PlaintextData buffer on
//       entry; on exit, this will be set to the size of the buffer used.
NTSTATUS
ImpCypherCryptData(
    IN      GUID* CypherGUID,
    IN      LARGE_INTEGER SectorID,
    IN      int SectorSize, // In bytes
    IN      int KeyLength,  // In bits
    IN      FREEOTFEBYTE* Key,
    IN      char* KeyASCII,  // ASCII representation of "Key"
    IN      int IVLength,  // In bits
    IN      FREEOTFEBYTE* IV,
    IN      BOOLEAN encryptNotDecrypt,  // TRUE = encrypt; FALSE = decrypt
    IN      int InLength,  // In bytes
    IN      FREEOTFEBYTE* InData,
    OUT     FREEOTFEBYTE* OutData
)
{
    NTSTATUS status = STATUS_SUCCESS;
    // libtomcrypt can't handle NULL IVs in CBC mode - it ASSERTs that IV != NULL
    char ltcNullIV[FREEOTFE_MAX_CYPHER_BLOCKSIZE];
    int cipher;
    symmetric_CBC *cbc;
    symmetric_LRW *lrw;
    symmetric_xts *xts;
    int errnum;
    CYPHER_MODE mode;
    int keySizeUnderlying;
    LARGE_INTEGER blockID64;
    INTEGER_128 blockID128;

    DEBUGOUTCYPHERIMPL(DEBUGLEV_ENTER, (TEXT("ImpCypherDecryptData\n")));

    status = DetermineCypherDetails(
                                    CypherGUID,
                                    &keySizeUnderlying,
                                    &mode
                                   );

    // libtomcrypt can't handle NULL IVs in CBC mode - it ASSERTs that IV != NULL
    if ( (IVLength == 0) || (IV == NULL) )
        {
        FREEOTFE_MEMZERO(&ltcNullIV, sizeof(ltcNullIV));
        IV = (char*)&ltcNullIV;
        }

    // Sanity check on key supplied
    if NT_SUCCESS(status) 
        {
        switch (mode)
            {
            case CYPHER_MODE_CBC:
                {
                if (KeyLength != keySizeUnderlying)
                    {
                    status = STATUS_INVALID_PARAMETER;
                    }

                break;
                }

            case CYPHER_MODE_XTS:
                {
                if (KeyLength != (2 * keySizeUnderlying))
                    {
                    status = STATUS_INVALID_PARAMETER;
                    }

                break;
                }

            case CYPHER_MODE_LRW:
                {
                if (KeyLength != (keySizeUnderlying + (twofish_desc.block_length * 8)))
                    {
                    status = STATUS_INVALID_PARAMETER;
                    }

                break;
                }

            }
        }

    if NT_SUCCESS(status) 
        {
        status = InitLTCCypher(&cipher);
        }

    if NT_SUCCESS(status)
        {
        switch (mode)
            {
            case CYPHER_MODE_CBC:
                {
                cbc = FREEOTFE_MEMALLOC(sizeof(symmetric_CBC));    
                FREEOTFE_MEMZERO(cbc, sizeof(symmetric_CBC));

                // Start a CBC session
                if ((errnum = cbc_start(
                                        cipher, 
                                        IV, 
                                        Key, 
                                        (keySizeUnderlying/8), 
                                        0, 
                                        cbc
                                       )) != CRYPT_OK)
                    {
                    status = STATUS_UNSUCCESSFUL;
                    DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to start CBC session (errnum: %d)\n"), errnum));
                    }
                else
                    {
                    if (encryptNotDecrypt)
                        {
                        if ((errnum = cbc_encrypt(
                                                  InData, 
                                                  OutData, 
                                                  InLength, 
                                                  cbc
                                                 )) != CRYPT_OK)
                            {
                            DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to encrypt block (errnum: %d)\n"), errnum));
                            status = STATUS_UNSUCCESSFUL;
                            } 
                        }
                    else
                        {
                        if ((errnum = cbc_decrypt(
                                              InData, 
                                              OutData, 
                                              InLength, 
                                              cbc
                                             )) != CRYPT_OK)
                            {
                            DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to decrypt block (errnum: %d)\n"), errnum));
                            status = STATUS_UNSUCCESSFUL;
                            } 
                        }

                    cbc_done(cbc);
                    }

                SecZeroMemory(cbc, sizeof(symmetric_CBC));
                FREEOTFE_FREE(cbc);

                break;
                }

            case CYPHER_MODE_LRW:
                {
                lrw = FREEOTFE_MEMALLOC(sizeof(symmetric_LRW));    
                FREEOTFE_MEMZERO(lrw, sizeof(symmetric_LRW));

                // Generate index in correct format
                // LRW uses:
                //   *) The block index (i.e. the number of 128 bit blocks)
                //   *) The first block has block index 1 - not 0!
                //   *) Bigendian format
                // Note: LTC increments this itself as it processes each block
                SectorIDToBlockIdx_64Bit(SectorID, SectorSize, &blockID64);
                LARGE_INTEGER__To__INTEGER_128_BigEndian(
                                                    blockID64,
                                                    blockID128
                                                   );
                IV = blockID128;

                // Start a LRW session
                if ((errnum = lrw_start(
                                        cipher, 
                                        IV, 
                                        Key, 
                                        (keySizeUnderlying/8), 
                                        // 128 bits tweak key begins after the
                                        // cypher key
                                        (Key + (keySizeUnderlying/8)),
                                        0, 
                                        lrw
                                       )) != CRYPT_OK)
                    {
                    status = STATUS_UNSUCCESSFUL;
                    DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to start LRW session (errnum: %d)\n"), errnum));
                    }
                else
                    {
                    if (encryptNotDecrypt)
                        {
                        if ((errnum = lrw_encrypt(
                                                  InData, 
                                                  OutData, 
                                                  InLength, 
                                                  lrw
                                                 )) != CRYPT_OK)
                            {
                            DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to encrypt block (errnum: %d)\n"), errnum));
                            status = STATUS_UNSUCCESSFUL;
                            } 
                        }
                    else 
                        {
                            if ((errnum = lrw_decrypt(
                                                  InData, 
                                                  OutData, 
                                                  InLength, 
                                                  lrw
                                                 )) != CRYPT_OK)
                            {
                            DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to decrypt block (errnum: %d)\n"), errnum));
                            status = STATUS_UNSUCCESSFUL;
                            } 
                        }

                    lrw_done(lrw);
                    }

                SecZeroMemory(lrw, sizeof(symmetric_LRW));
                FREEOTFE_FREE(lrw);

                break;
                }

            case CYPHER_MODE_XTS:
                {
                xts = FREEOTFE_MEMALLOC(sizeof(symmetric_xts));    
                FREEOTFE_MEMZERO(xts, sizeof(symmetric_xts));

                // Generate index in correct format
                // XTS uses:
                //   *) The sector index (i.e. the number of N-bit sectors)
                //   *) The first sector is sector 0
                //   *) Littleendian format
                LARGE_INTEGER__To__INTEGER_128_LittleEndian(
                                                    SectorID,
                                                    blockID128
                                                   );

                // Start an XTS session
                if ((errnum = xts_start(
                                        cipher, 
                                        Key, 
                                        &(Key[keySizeUnderlying/8]),
                                        (keySizeUnderlying/8), 
                                        0, 
                                        xts
                                       )) != CRYPT_OK)
                    {
                    status = STATUS_UNSUCCESSFUL;
                    DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to start XTS session (errnum: %d)\n"), errnum));
                    }
                else
                    {
                    if (encryptNotDecrypt)
                        {
                        if ((errnum = xts_encrypt(
                                                  InData, 
                                                  InLength, 
                                                  OutData, 
                                                  blockID128,
                                                  xts
                                                 )) != CRYPT_OK)
                            {
                            DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to encrypt block (errnum: %d)\n"), errnum));
                            status = STATUS_UNSUCCESSFUL;
                            } 
                        }
                    else 
                        {
                        if ((errnum = xts_decrypt(
                                              InData, 
                                              InLength, 
                                              OutData, 
                                              blockID128,
                                              xts
                                             )) != CRYPT_OK)
                            {
                            DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to decrypt block (errnum: %d)\n"), errnum));
                            status = STATUS_UNSUCCESSFUL;
                            } 
                        }

                    xts_done(xts);
                    }

                SecZeroMemory(xts, sizeof(symmetric_xts));
                FREEOTFE_FREE(xts);

                break;
                }

            }

        }

    DEBUGOUTCYPHERIMPL(DEBUGLEV_EXIT, (TEXT("ImpCypherDecryptData\n")));

    return status;
}
Beispiel #11
0
void ltc_cleanup_CBC(void)
{
    TRACE_DEBUG("LTC: Cleaning up CBC...\n\r");
    cbc_done(&sCBC);
    TRACE_DEBUG("LTC: Cleanup done.\n\r");
}
Beispiel #12
0
/*
 * Perform an encrypt/decrypt operation to/from files using AES+CBC+PKCS7 pad.
 * Set encrypt to 1 to encrypt, 0 to decrypt.
 *
 * Input:        in/out files, key, iv, and mode
 * Output:       CRYPT_OK if no error
 * Side Effects: bytes slurped from infile, pushed to outfile, fds updated.
 */
int do_crypt(FILE *infd, FILE *outfd, unsigned char *key, unsigned char *iv,
             int encrypt)
{
   union paddable inbuf, outbuf;
   int cipher, ret;
   symmetric_CBC cbc;
   size_t nb;

   /* Register your cipher! */
   cipher = register_cipher(&aes_desc);
   if(cipher == -1)
      return CRYPT_INVALID_CIPHER;

   /* Start a CBC session with cipher/key/val params */
   ret = cbc_start(cipher, iv, key, KEY_LENGTH, 0, &cbc);
   if( ret != CRYPT_OK )
      return -1;

   do {
      /* Get bytes from the source */
      nb = fread(inbuf.unpad, 1, sizeof(inbuf.unpad), infd);
      if(!nb)
         return encrypt ? CRYPT_OK : CRYPT_ERROR;

      /* Barf if we got a read error */
      if(ferror(infd))
         return CRYPT_ERROR;

      if(encrypt) {
         /* We're encrypting, so pad first (if at EOF) and then
            crypt */
         if(feof(infd))
            nb = pkcs7_pad(&inbuf, nb,
                           aes_desc.block_length, 1);

         ret = cbc_encrypt(inbuf.pad, outbuf.pad, nb, &cbc);
         if(ret != CRYPT_OK)
            return ret;

      } else {
         /* We're decrypting, so decrypt and then unpad if at
            EOF */
         ret = cbc_decrypt(inbuf.unpad, outbuf.unpad, nb, &cbc);
         if( ret != CRYPT_OK )
            return ret;

         if( feof(infd) )
            nb = pkcs7_pad(&outbuf, nb,
                           aes_desc.block_length, 0);
         if(nb == 0)
            /* The file didn't decrypt correctly */
            return CRYPT_ERROR;

      }

      /* Push bytes to outfile */
      if(fwrite(outbuf.unpad, 1, nb, outfd) != nb)
         return CRYPT_ERROR;

   } while(!feof(infd));

   /* Close up */
   cbc_done(&cbc);

   return CRYPT_OK;
}