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

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

unix.superglobalmegacorp.com

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