/* Legal Notice: Some portions of the source code contained in this file were derived from the source code of TrueCrypt 7.1a, which is Copyright (c) 2003-2012 TrueCrypt Developers Association and which is governed by the TrueCrypt License 3.0, also from the source code of Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License Agreement for Encryption for the Masses' Modifications and additions to the original source code (contained in this file) and all other portions of this file are Copyright (c) 2013-2016 IDRIX and are governed by the Apache License 2.0 the full text of which is contained in the file License.txt included in VeraCrypt binary and source code distribution packages. */ #include "Tcdefs.h" #include "Crypto.h" #include "Xts.h" #include "Crc.h" #include "Common/Endian.h" #if !defined(_UEFI) #include #ifndef TC_WINDOWS_BOOT #include "EncryptionThreadPool.h" #endif #endif #include "Volumes.h" #include "cpu.h" #pragma warning (disable:4706) // assignment within conditional expression /* Update the following when adding a new cipher or EA: Crypto.h: ID #define MAX_EXPANDED_KEY #define Crypto.c: Ciphers[] EncryptionAlgorithms[] CipherInit() EncipherBlock() DecipherBlock() */ #ifndef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE // Cipher configuration static Cipher Ciphers[] = { // Block Size Key Size Key Schedule Size // ID Name (Bytes) (Bytes) (Bytes) #ifdef TC_WINDOWS_BOOT { AES, "AES", 16, 32, AES_KS }, { SERPENT, "Serpent", 16, 32, 140*4 }, { TWOFISH, "Twofish", 16, 32, TWOFISH_KS }, #else { AES, L"AES", 16, 32, AES_KS }, { SERPENT, L"Serpent", 16, 32, 140*4 }, { TWOFISH, L"Twofish", 16, 32, TWOFISH_KS }, { CAMELLIA, L"Camellia", 16, 32, CAMELLIA_KS }, #if defined(CIPHER_GOST89) { GOST89, L"GOST89", 16, 32, GOST_KS }, #endif // defined(CIPHER_GOST89) { KUZNYECHIK, L"Kuznyechik",16, 32, KUZNYECHIK_KS }, #endif { 0, 0, 0, 0, 0 } }; // Encryption algorithm configuration static EncryptionAlgorithm EncryptionAlgorithms[] = { // Cipher(s) Modes FormatEnabled #ifndef TC_WINDOWS_BOOT { { 0, 0 }, { 0, 0}, 0, 0 }, // Must be all-zero { { AES, 0 }, { XTS, 0 }, 1, 1 }, { { SERPENT, 0 }, { XTS, 0 }, 1, 1 }, { { TWOFISH, 0 }, { XTS, 0 }, 1, 1 }, { { CAMELLIA, 0 }, { XTS, 0 }, 1, 1 }, #if defined(CIPHER_GOST89) { { GOST89, 0 }, { XTS, 0 }, 0, 0 }, #endif // defined(CIPHER_GOST89) { { KUZNYECHIK, 0 }, { XTS, 0 }, 0, 1 }, { { TWOFISH, AES, 0 }, { XTS, 0 }, 1, 1 }, { { SERPENT, TWOFISH, AES, 0 }, { XTS, 0 }, 1, 1 }, { { AES, SERPENT, 0 }, { XTS, 0 }, 1, 1 }, { { AES, TWOFISH, SERPENT, 0 }, { XTS, 0 }, 1, 1 }, { { SERPENT, TWOFISH, 0 }, { XTS, 0 }, 1, 1 }, { { 0, 0 }, { 0, 0}, 0, 0 } // Must be all-zero #else // TC_WINDOWS_BOOT // Encryption algorithms available for boot drive encryption { { 0, 0 }, { 0, 0 }, 0 }, // Must be all-zero { { AES, 0 }, { XTS, 0 }, 1 }, { { SERPENT, 0 }, { XTS, 0 }, 1 }, { { TWOFISH, 0 }, { XTS, 0 }, 1 }, { { TWOFISH, AES, 0 }, { XTS, 0 }, 1 }, { { SERPENT, TWOFISH, AES, 0 }, { XTS, 0 }, 1 }, { { AES, SERPENT, 0 }, { XTS, 0 }, 1 }, { { AES, TWOFISH, SERPENT, 0 }, { XTS, 0 }, 1 }, { { SERPENT, TWOFISH, 0 }, { XTS, 0 }, 1 }, { { 0, 0 }, { 0, 0 }, 0 }, // Must be all-zero #endif }; #ifndef TC_WINDOWS_BOOT // Hash algorithms static Hash Hashes[] = { // ID Name Deprecated System Encryption { SHA512, L"SHA-512", FALSE, FALSE }, { WHIRLPOOL, L"Whirlpool", FALSE, FALSE }, { SHA256, L"SHA-256", FALSE, TRUE }, { RIPEMD160, L"RIPEMD-160", TRUE, TRUE }, { STREEBOG, L"Streebog", FALSE, FALSE }, { 0, 0, 0 } }; #endif /* Return values: 0 = success, ERR_CIPHER_INIT_FAILURE (fatal), ERR_CIPHER_INIT_WEAK_KEY (non-fatal) */ int CipherInit (int cipher, unsigned char *key, unsigned __int8 *ks) { int retVal = ERR_SUCCESS; switch (cipher) { case AES: #ifndef TC_WINDOWS_BOOT if (aes_encrypt_key256 (key, (aes_encrypt_ctx *) ks) != EXIT_SUCCESS) return ERR_CIPHER_INIT_FAILURE; if (aes_decrypt_key256 (key, (aes_decrypt_ctx *) (ks + sizeof(aes_encrypt_ctx))) != EXIT_SUCCESS) return ERR_CIPHER_INIT_FAILURE; #else if (aes_set_key (key, (length_type) CipherGetKeySize(AES), (aes_context *) ks) != 0) return ERR_CIPHER_INIT_FAILURE; #endif break; case SERPENT: serpent_set_key (key, ks); break; case TWOFISH: twofish_set_key ((TwofishInstance *)ks, (const u4byte *)key); break; #if !defined (TC_WINDOWS_BOOT) || defined (TC_WINDOWS_BOOT_CAMELLIA) case CAMELLIA: camellia_set_key (key, ks); break; #endif #if !defined(TC_WINDOWS_BOOT) #if defined(CIPHER_GOST89) case GOST89: gost_set_key(key, (gost_kds*)ks, 1); break; #endif // && defined(CIPHER_GOST89) case KUZNYECHIK: kuznyechik_set_key(key, (kuznyechik_kds*)ks); break; #endif // !defined(TC_WINDOWS_BOOT) default: // Unknown/wrong cipher ID return ERR_CIPHER_INIT_FAILURE; } return retVal; } void EncipherBlock(int cipher, void *data, void *ks) { switch (cipher) { case AES: // In 32-bit kernel mode, due to KeSaveFloatingPointState() overhead, AES instructions can be used only when processing the whole data unit. #if (defined (_WIN64) || !defined (TC_WINDOWS_DRIVER)) && !defined (TC_WINDOWS_BOOT) if (IsAesHwCpuSupported()) aes_hw_cpu_encrypt (ks, data); else #endif aes_encrypt (data, data, ks); break; case TWOFISH: twofish_encrypt (ks, data, data); break; case SERPENT: serpent_encrypt (data, data, ks); break; #if !defined (TC_WINDOWS_BOOT) || defined (TC_WINDOWS_BOOT_CAMELLIA) case CAMELLIA: camellia_encrypt (data, data, ks); break; #endif #if !defined(TC_WINDOWS_BOOT) #if defined(CIPHER_GOST89) case GOST89: gost_encrypt(data, data, ks, 1); break; #endif // defined(CIPHER_GOST89) case KUZNYECHIK: kuznyechik_encrypt_block(data, data, ks); break; #endif // !defined(TC_WINDOWS_BOOT) default: TC_THROW_FATAL_EXCEPTION; // Unknown/wrong ID } } #ifndef TC_WINDOWS_BOOT void EncipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount) { byte *data = dataPtr; #if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) KFLOATING_SAVE floatingPointState; #endif if (cipher == AES && (blockCount & (32 - 1)) == 0 && IsAesHwCpuSupported() #if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) && NT_SUCCESS (KeSaveFloatingPointState (&floatingPointState)) #endif ) { while (blockCount > 0) { aes_hw_cpu_encrypt_32_blocks (ks, data); data += 32 * 16; blockCount -= 32; } #if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) KeRestoreFloatingPointState (&floatingPointState); #endif } #if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE && !defined (_UEFI) else if (cipher == SERPENT && (blockCount >= 4) && HasSSE2() #if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) && NT_SUCCESS (KeSaveFloatingPointState (&floatingPointState)) #endif ) { serpent_encrypt_blocks (data, data, blockCount, ks); #if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) KeRestoreFloatingPointState (&floatingPointState); #endif } #endif #if CRYPTOPP_BOOL_X64 else if (cipher == TWOFISH) { twofish_encrypt_blocks(ks, data, data, (uint32) blockCount); } #endif else if (cipher == GOST89) { gost_encrypt(data, data, ks, (int)blockCount); } else { size_t blockSize = CipherGetBlockSize (cipher); while (blockCount-- > 0) { EncipherBlock (cipher, data, ks); data += blockSize; } } } #endif // !TC_WINDOWS_BOOT void DecipherBlock(int cipher, void *data, void *ks) { switch (cipher) { case SERPENT: serpent_decrypt (data, data, ks); break; case TWOFISH: twofish_decrypt (ks, data, data); break; #if !defined (TC_WINDOWS_BOOT) || defined (TC_WINDOWS_BOOT_CAMELLIA) case CAMELLIA: camellia_decrypt (data, data, ks); break; #endif #if !defined(TC_WINDOWS_BOOT) #if defined(CIPHER_GOST89) case GOST89: gost_decrypt(data, data, ks, 1); break; #endif // defined(CIPHER_GOST89) case KUZNYECHIK: kuznyechik_decrypt_block(data, data, ks); break; #endif // !defined(TC_WINDOWS_BOOT) #ifndef TC_WINDOWS_BOOT case AES: #if defined (_WIN64) || !defined (TC_WINDOWS_DRIVER) if (IsAesHwCpuSupported()) aes_hw_cpu_decrypt ((byte *) ks + sizeof (aes_encrypt_ctx), data); else #endif aes_decrypt (data, data, (void *) ((char *) ks + sizeof(aes_encrypt_ctx))); break; #else case AES: aes_decrypt (data, data, ks); break; #endif default: TC_THROW_FATAL_EXCEPTION; // Unknown/wrong ID } } #ifndef TC_WINDOWS_BOOT void DecipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount) { byte *data = dataPtr; #if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) KFLOATING_SAVE floatingPointState; #endif if (cipher == AES && (blockCount & (32 - 1)) == 0 && IsAesHwCpuSupported() #if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) && NT_SUCCESS (KeSaveFloatingPointStat
/*
 ---------------------------------------------------------------------------
 Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved.

 LICENSE TERMS

 The free distribution and use of this software is allowed (with or without
 changes) provided that:

  1. source code distributions include the above copyright notice, this
     list of conditions and the following disclaimer;

  2. binary distributions include the above copyright notice, this list
     of conditions and the following disclaimer in their documentation;

  3. the name of the copyright holder is not used to endorse products
     built using this software without specific written permission.

 DISCLAIMER

 This software is provided 'as is' with no explicit or implied warranties
 in respect of its properties, including, but not limited to, correctness
 and/or fitness for purpose.
 ---------------------------------------------------------------------------
 Issue Date: 20/12/2007

 This file contains the code for declaring the tables needed to implement
 AES. The file aesopt.h is assumed to be included before this header file.
 If there are no global variables, the definitions here can be used to put
 the AES tables in a structure so that a pointer can then be added to the
 AES context to pass them to the AES routines that need them.   If this
 facility is used, the calling program has to ensure that this pointer is
 managed appropriately.  In particular, the value of the t_dec(in,it) item
 in the table structure must be set to zero in order to ensure that the
 tables are initialised. In practice the three code sequences in aeskey.c
 that control the calls to aes_init() and the aes_init() routine itself will
 have to be changed for a specific implementation. If global variables are
 available it will generally be preferable to use them with the precomputed
 FIXED_TABLES option that uses static global tables.

 The following defines can be used to control the way the tables
 are defined, initialised and used in embedded environments that
 require special features for these purposes

    the 't_dec' construction is used to declare fixed table arrays
    the 't_set' construction is used to set fixed table values
    the 't_use' construction is used to access fixed table values

    256 byte tables:

        t_xxx(s,box)    => forward S box
        t_xxx(i,box)    => inverse S box

    256 32-bit word OR 4 x 256 32-bit word tables:

        t_xxx(f,n)      => forward normal round
        t_xxx(f,l)      => forward last round
        t_xxx(i,n)      => inverse normal round
        t_xxx(i,l)      => inverse last round
        t_xxx(l,s)      => key schedule table
        t_xxx(i,m)      => key schedule table

    Other variables and tables:

        t_xxx(r,c)      => the rcon table
*/

#if !defined( _AESTAB_H )
#define _AESTAB_H

#define t_dec(m,n) t_##m##n
#define t_set(m,n) t_##m##n
#define t_use(m,n) t_##m##n

#if defined(FIXED_TABLES)
#  if !defined( __GNUC__ ) && (defined( __MSDOS__ ) || defined( __WIN16__ ))
/*   make tables far data to avoid using too much DGROUP space (PG) */
#    define CONST const far
#  else
#    define CONST const
#  endif
#else
#  define CONST
#endif

#if defined(__cplusplus)
#  define EXTERN extern "C"
#elif defined(DO_TABLES)
#  define EXTERN
#else
#  define EXTERN extern
#endif

#if defined(_MSC_VER) && defined(TABLE_ALIGN)
#define ALIGN __declspec(align(TABLE_ALIGN))
#else
#define ALIGN
#endif

#if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 )
#  define XP_DIR __cdecl
#else
#  define XP_DIR
#endif

#if defined(DO_TABLES) && defined(FIXED_TABLES)
#define d_1(t,n,b,e)       EXTERN ALIGN CONST XP_DIR t n[256]    =   b(e)
#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) }
EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH] = rc_data(w0);
#else
#define d_1(t,n,b,e)       EXTERN ALIGN CONST XP_DIR t n[256]
#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256]
EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH];
#endif

#if defined( SBX_SET )
    d_1(uint_8t, t_dec(s,box), sb_data, h0);
#endif
#if defined( ISB_SET )
    d_1(uint_8t, t_dec(i,box), isb_data, h0);
#endif

#if defined( FT1_SET )
    d_1(uint_32t, t_dec(f,n), sb_data, u0);
#endif
#if defined( FT4_SET )
    d_4(uint_32t, t_dec(f,n), sb_data, u0, u1, u2, u3);
#endif

#if defined( FL1_SET )
    d_1(uint_32t, t_dec(f,l), sb_data, w0);
#endif
#if defined( FL4_SET )
    d_4(uint_32t, t_dec(f,l), sb_data, w0, w1, w2, w3);
#endif

#if defined( IT1_SET )
    d_1(uint_32t, t_dec(i,n), isb_data, v0);
#endif
#if defined( IT4_SET )
    d_4(uint_32t, t_dec(i,n), isb_data, v0, v1, v2, v3);
#endif

#if defined( IL1_SET )
    d_1(uint_32t, t_dec(i,l), isb_data, w0);
#endif
#if defined( IL4_SET )
    d_4(uint_32t, t_dec(i,l), isb_data, w0, w1, w2, w3);
#endif

#if defined( LS1_SET )
#if defined( FL1_SET )
#undef  LS1_SET
#else
    d_1(uint_32t, t_dec(l,s), sb_data, w0);
#endif
#endif

#if defined( LS4_SET )
#if defined( FL4_SET )
#undef  LS4_SET
#else
    d_4(uint_32t, t_dec(l,s), sb_data, w0, w1, w2, w3);
#endif
#endif

#if defined( IM1_SET )
    d_1(uint_32t, t_dec(i,m), mm_data, v0);
#endif
#if defined( IM4_SET )
    d_4(uint_32t, t_dec(i,m), mm_data, v0, v1, v2, v3);
#endif

#endif