Annotation of truecrypt/volume/encryptionmodexts.cpp, revision 1.1.1.1

1.1       root        1: /*
                      2:  Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
                      3: 
                      4:  Governed by the TrueCrypt License 2.4 the full text of which is contained
                      5:  in the file License.txt included in TrueCrypt binary and source code
                      6:  distribution packages.
                      7: */
                      8: 
                      9: #include "EncryptionModeXTS.h"
                     10: #include "Common/Crypto.h"
                     11: 
                     12: namespace TrueCrypt
                     13: {
                     14:        void EncryptionModeXTS::Decrypt (byte *data, uint64 length) const
                     15:        {
                     16:                DecryptBuffer (data, length, 0);
                     17:        }
                     18: 
                     19:        void EncryptionModeXTS::DecryptBuffer (byte *data, uint64 length, uint64 startDataUnitNo) const
                     20:        {
                     21:                if_debug (ValidateState ());
                     22:                
                     23:                CipherList::const_iterator iSecondaryCipher = SecondaryCiphers.end();
                     24:                foreach_reverse_ref (const Cipher &cipher, Ciphers)
                     25:                {
                     26:                        --iSecondaryCipher;
                     27:                        DecryptBufferXTS (cipher, **iSecondaryCipher, data, length, startDataUnitNo, 0);
                     28:                }
                     29: 
                     30:                assert (iSecondaryCipher == SecondaryCiphers.begin());
                     31:        }
                     32: 
                     33:        void EncryptionModeXTS::DecryptBufferXTS (const Cipher &cipher, const Cipher &secondaryCipher, byte *buffer, uint64 length, uint64 startDataUnitNo, unsigned int startCipherBlockNo) const
                     34:        {
                     35:                byte finalCarry;
                     36:                byte whiteningValues [ENCRYPTION_DATA_UNIT_SIZE];
                     37:                byte whiteningValue [BYTES_PER_XTS_BLOCK];
                     38:                byte byteBufUnitNo [BYTES_PER_XTS_BLOCK];
                     39:                uint64 *whiteningValuesPtr64 = (uint64 *) whiteningValues;
                     40:                uint64 *whiteningValuePtr64 = (uint64 *) whiteningValue;
                     41:                uint64 *bufPtr = (uint64 *) buffer;
                     42:                unsigned int startBlock = startCipherBlockNo, endBlock, block;
                     43:                uint64 *const finalInt64WhiteningValuesPtr = whiteningValuesPtr64 + sizeof (whiteningValues) / sizeof (*whiteningValuesPtr64) - 1;
                     44:                uint64 blockCount, dataUnitNo;
                     45: 
                     46:                // Convert the 64-bit data unit number into a little-endian 16-byte array. 
                     47:                // Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes.
                     48:                dataUnitNo = startDataUnitNo;
                     49:                *((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo);
                     50:                *((uint64 *) byteBufUnitNo + 1) = 0;
                     51: 
                     52:                if (length % BYTES_PER_XTS_BLOCK)
                     53:                        TC_THROW_FATAL_EXCEPTION;
                     54: 
                     55:                blockCount = length / BYTES_PER_XTS_BLOCK;
                     56: 
                     57:                // Process all blocks in the buffer
                     58:                // When length > ENCRYPTION_DATA_UNIT_SIZE, this can be parallelized (one data unit per core)
                     59:                while (blockCount > 0)
                     60:                {
                     61:                        if (blockCount < BLOCKS_PER_XTS_DATA_UNIT)
                     62:                                endBlock = startBlock + (unsigned int) blockCount;
                     63:                        else
                     64:                                endBlock = BLOCKS_PER_XTS_DATA_UNIT;
                     65: 
                     66:                        whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
                     67:                        whiteningValuePtr64 = (uint64 *) whiteningValue;
                     68: 
                     69:                        // Encrypt the data unit number using the secondary key (in order to generate the first 
                     70:                        // whitening value for this data unit)
                     71:                        *whiteningValuePtr64 = *((uint64 *) byteBufUnitNo);
                     72:                        *(whiteningValuePtr64 + 1) = 0;
                     73:                        secondaryCipher.EncryptBlock (whiteningValue);
                     74: 
                     75:                        // Generate subsequent whitening values for blocks in this data unit. Note that all generated 128-bit
                     76:                        // whitening values are stored in memory as a sequence of 64-bit integers in reverse order.
                     77:                        for (block = 0; block < endBlock; block++)
                     78:                        {
                     79:                                if (block >= startBlock)
                     80:                                {
                     81:                                        *whiteningValuesPtr64-- = *whiteningValuePtr64++;
                     82:                                        *whiteningValuesPtr64-- = *whiteningValuePtr64;
                     83:                                }
                     84:                                else
                     85:                                        whiteningValuePtr64++;
                     86: 
                     87:                                // Derive the next whiteningValue
                     88: 
                     89: #if BYTE_ORDER != BIG_ENDIAN
                     90: 
                     91:                                finalCarry = 
                     92:                                        (*whiteningValuePtr64 & 0x8000000000000000ULL) ?
                     93:                                        135 : 0;
                     94: 
                     95:                                *whiteningValuePtr64-- <<= 1;
                     96: 
                     97:                                if (*whiteningValuePtr64 & 0x8000000000000000ULL)
                     98:                                        *(whiteningValuePtr64 + 1) |= 1;        
                     99: 
                    100:                                *whiteningValuePtr64 <<= 1;
                    101: 
                    102: #else
                    103: 
                    104:                                finalCarry = 
                    105:                                        (*whiteningValuePtr64 & 0x80) ?
                    106:                                        135 : 0;
                    107: 
                    108:                                *whiteningValuePtr64 = Endian::Little (Endian::Little (*whiteningValuePtr64) << 1);
                    109:                                --whiteningValuePtr64;
                    110: 
                    111:                                if (*whiteningValuePtr64 & 0x80)
                    112:                                        *(whiteningValuePtr64 + 1) |= 0x0100000000000000ULL;    
                    113: 
                    114:                                *whiteningValuePtr64 = Endian::Little (Endian::Little (*whiteningValuePtr64) << 1);
                    115: #endif
                    116: 
                    117:                                whiteningValue[0] ^= finalCarry;
                    118:                        }
                    119: 
                    120:                        whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
                    121: 
                    122:                        // Encrypt all blocks in this data unit
                    123:                        // TO DO: This should be parallelized (one block per core)
                    124:                        for (block = startBlock; block < endBlock; block++)
                    125:                        {
                    126:                                *bufPtr++ ^= *whiteningValuesPtr64--;
                    127:                                *bufPtr-- ^= *whiteningValuesPtr64++;
                    128: 
                    129:                                cipher.DecryptBlock (reinterpret_cast <byte *> (bufPtr));
                    130: 
                    131:                                *bufPtr++ ^= *whiteningValuesPtr64--;
                    132:                                *bufPtr++ ^= *whiteningValuesPtr64--;
                    133: 
                    134:                                blockCount--;
                    135:                        }
                    136: 
                    137:                        startBlock = 0;
                    138: 
                    139:                        dataUnitNo++;
                    140: 
                    141:                        *((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo);
                    142:                }
                    143: 
                    144:                FAST_ERASE64 (whiteningValue, sizeof(whiteningValue));
                    145:                FAST_ERASE64 (whiteningValues, sizeof(whiteningValues));
                    146:        }
                    147:        
                    148:        void EncryptionModeXTS::DecryptSectors (byte *data, uint64 sectorIndex, uint64 sectorCount, size_t sectorSize) const
                    149:        {
                    150:                DecryptBuffer (data, sectorCount * sectorSize, sectorIndex * sectorSize / ENCRYPTION_DATA_UNIT_SIZE);
                    151:        }
                    152: 
                    153:        void EncryptionModeXTS::Encrypt (byte *data, uint64 length) const
                    154:        {
                    155:                EncryptBuffer (data, length, 0);
                    156:        }
                    157: 
                    158:        void EncryptionModeXTS::EncryptBuffer (byte *data, uint64 length, uint64 startDataUnitNo) const
                    159:        {
                    160:                if_debug (ValidateState ());
                    161:                
                    162:                CipherList::const_iterator iSecondaryCipher = SecondaryCiphers.begin();
                    163:                foreach_ref (const Cipher &cipher, Ciphers)
                    164:                {
                    165:                        EncryptBufferXTS (cipher, **iSecondaryCipher, data, length, startDataUnitNo, 0);
                    166:                        ++iSecondaryCipher;
                    167:                }
                    168: 
                    169:                assert (iSecondaryCipher == SecondaryCiphers.end());
                    170:        }
                    171: 
                    172:        void EncryptionModeXTS::EncryptBufferXTS (const Cipher &cipher, const Cipher &secondaryCipher, byte *buffer, uint64 length, uint64 startDataUnitNo, unsigned int startCipherBlockNo) const
                    173:        {
                    174:                byte finalCarry;
                    175:                byte whiteningValues [ENCRYPTION_DATA_UNIT_SIZE];
                    176:                byte whiteningValue [BYTES_PER_XTS_BLOCK];
                    177:                byte byteBufUnitNo [BYTES_PER_XTS_BLOCK];
                    178:                uint64 *whiteningValuesPtr64 = (uint64 *) whiteningValues;
                    179:                uint64 *whiteningValuePtr64 = (uint64 *) whiteningValue;
                    180:                uint64 *bufPtr = (uint64 *) buffer;
                    181:                unsigned int startBlock = startCipherBlockNo, endBlock, block;
                    182:                uint64 *const finalInt64WhiteningValuesPtr = whiteningValuesPtr64 + sizeof (whiteningValues) / sizeof (*whiteningValuesPtr64) - 1;
                    183:                uint64 blockCount, dataUnitNo;
                    184: 
                    185:                /* The encrypted data unit number (i.e. the resultant ciphertext block) is to be multiplied in the
                    186:                finite field GF(2^128) by j-th power of n, where j is the sequential plaintext/ciphertext block
                    187:                number and n is 2, a primitive element of GF(2^128). This can be (and is) simplified and implemented
                    188:                as a left shift of the preceding whitening value by one bit (with carry propagating). In addition, if
                    189:                the shift of the highest byte results in a carry, 135 is XORed into the lowest byte. The value 135 is
                    190:                derived from the modulus of the Galois Field (x^128+x^7+x^2+x+1). */
                    191: 
                    192:                // Convert the 64-bit data unit number into a little-endian 16-byte array. 
                    193:                // Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes.
                    194:                dataUnitNo = startDataUnitNo;
                    195:                *((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo);
                    196:                *((uint64 *) byteBufUnitNo + 1) = 0;
                    197: 
                    198:                if (length % BYTES_PER_XTS_BLOCK)
                    199:                        TC_THROW_FATAL_EXCEPTION;
                    200: 
                    201:                blockCount = length / BYTES_PER_XTS_BLOCK;
                    202: 
                    203:                // Process all blocks in the buffer
                    204:                // When length > ENCRYPTION_DATA_UNIT_SIZE, this can be parallelized (one data unit per core)
                    205:                while (blockCount > 0)
                    206:                {
                    207:                        if (blockCount < BLOCKS_PER_XTS_DATA_UNIT)
                    208:                                endBlock = startBlock + (unsigned int) blockCount;
                    209:                        else
                    210:                                endBlock = BLOCKS_PER_XTS_DATA_UNIT;
                    211: 
                    212:                        whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
                    213:                        whiteningValuePtr64 = (uint64 *) whiteningValue;
                    214: 
                    215:                        // Encrypt the data unit number using the secondary key (in order to generate the first 
                    216:                        // whitening value for this data unit)
                    217:                        *whiteningValuePtr64 = *((uint64 *) byteBufUnitNo);
                    218:                        *(whiteningValuePtr64 + 1) = 0;
                    219:                        secondaryCipher.EncryptBlock (whiteningValue);
                    220: 
                    221:                        // Generate subsequent whitening values for blocks in this data unit. Note that all generated 128-bit
                    222:                        // whitening values are stored in memory as a sequence of 64-bit integers in reverse order.
                    223:                        for (block = 0; block < endBlock; block++)
                    224:                        {
                    225:                                if (block >= startBlock)
                    226:                                {
                    227:                                        *whiteningValuesPtr64-- = *whiteningValuePtr64++;
                    228:                                        *whiteningValuesPtr64-- = *whiteningValuePtr64;
                    229:                                }
                    230:                                else
                    231:                                        whiteningValuePtr64++;
                    232: 
                    233:                                // Derive the next whiteningValue
                    234: 
                    235: #if BYTE_ORDER != BIG_ENDIAN
                    236: 
                    237:                                finalCarry = 
                    238:                                        (*whiteningValuePtr64 & 0x8000000000000000ULL) ?
                    239:                                        135 : 0;
                    240: 
                    241:                                *whiteningValuePtr64-- <<= 1;
                    242: 
                    243:                                if (*whiteningValuePtr64 & 0x8000000000000000ULL)
                    244:                                        *(whiteningValuePtr64 + 1) |= 1;        
                    245: 
                    246:                                *whiteningValuePtr64 <<= 1;
                    247: 
                    248: #else
                    249: 
                    250:                                finalCarry = 
                    251:                                        (*whiteningValuePtr64 & 0x80) ?
                    252:                                        135 : 0;
                    253: 
                    254:                                *whiteningValuePtr64 = Endian::Little (Endian::Little (*whiteningValuePtr64) << 1);
                    255:                                --whiteningValuePtr64;
                    256: 
                    257:                                if (*whiteningValuePtr64 & 0x80)
                    258:                                        *(whiteningValuePtr64 + 1) |= 0x0100000000000000ULL;    
                    259: 
                    260:                                *whiteningValuePtr64 = Endian::Little (Endian::Little (*whiteningValuePtr64) << 1);
                    261: #endif
                    262: 
                    263:                                whiteningValue[0] ^= finalCarry;
                    264:                        }
                    265: 
                    266:                        whiteningValuesPtr64 = finalInt64WhiteningValuesPtr;
                    267: 
                    268:                        // Decrypt blocks in this data unit
                    269:                        // TO DO: This should be parallelized (one block per core)
                    270:                        for (block = startBlock; block < endBlock; block++)
                    271:                        {
                    272:                                *bufPtr++ ^= *whiteningValuesPtr64--;
                    273:                                *bufPtr-- ^= *whiteningValuesPtr64++;
                    274: 
                    275:                                cipher.EncryptBlock (reinterpret_cast <byte *> (bufPtr));
                    276: 
                    277:                                *bufPtr++ ^= *whiteningValuesPtr64--;
                    278:                                *bufPtr++ ^= *whiteningValuesPtr64--;
                    279: 
                    280:                                blockCount--;
                    281:                        }
                    282: 
                    283:                        startBlock = 0;
                    284: 
                    285:                        dataUnitNo++;
                    286: 
                    287:                        *((uint64 *) byteBufUnitNo) = Endian::Little (dataUnitNo);
                    288:                }
                    289: 
                    290:                FAST_ERASE64 (whiteningValue, sizeof(whiteningValue));
                    291:                FAST_ERASE64 (whiteningValues, sizeof(whiteningValues));
                    292:        }
                    293: 
                    294:        void EncryptionModeXTS::EncryptSectors (byte *data, uint64 sectorIndex, uint64 sectorCount, size_t sectorSize) const
                    295:        {
                    296:                EncryptBuffer (data, sectorCount * sectorSize, sectorIndex * sectorSize / ENCRYPTION_DATA_UNIT_SIZE);
                    297:        }
                    298:        
                    299:        size_t EncryptionModeXTS::GetKeySize () const
                    300:        {
                    301:                if (Ciphers.empty())
                    302:                        throw NotInitialized (SRC_POS);
                    303:                
                    304:                size_t keySize = 0;
                    305:                foreach_ref (const Cipher &cipher, SecondaryCiphers)
                    306:                {
                    307:                        keySize += cipher.GetKeySize();
                    308:                }
                    309: 
                    310:                return keySize;
                    311:        }
                    312: 
                    313:        void EncryptionModeXTS::SetCiphers (const CipherList &ciphers)
                    314:        {
                    315:                EncryptionMode::SetCiphers (ciphers);
                    316: 
                    317:                SecondaryCiphers.clear();
                    318: 
                    319:                foreach_ref (const Cipher &cipher, ciphers)
                    320:                {
                    321:                        SecondaryCiphers.push_back (cipher.GetNew());
                    322:                }
                    323: 
                    324:                if (SecondaryKey.Size() > 0)
                    325:                        SetSecondaryCipherKeys();
                    326:        }
                    327: 
                    328:        void EncryptionModeXTS::SetKey (const ConstBufferPtr &key)
                    329:        {
                    330:                SecondaryKey.Allocate (key.Size());
                    331:                SecondaryKey.CopyFrom (key);
                    332: 
                    333:                if (!SecondaryCiphers.empty())
                    334:                        SetSecondaryCipherKeys();
                    335:        }
                    336:        
                    337:        void EncryptionModeXTS::SetSecondaryCipherKeys ()
                    338:        {
                    339:                size_t keyOffset = 0;
                    340:                foreach_ref (Cipher &cipher, SecondaryCiphers)
                    341:                {
                    342:                        cipher.SetKey (SecondaryKey.GetRange (keyOffset, cipher.GetKeySize()));
                    343:                        keyOffset += cipher.GetKeySize();
                    344:                }
                    345: 
                    346:                KeySet = true;
                    347:        }
                    348: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.