|
|
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: /* For low-memory environments, define XTS_LOW_RESOURCE_VERSION, which will save ! 10: 0.5 KB of RAM, but the speed will be 15-20% lower. However, on multi-core CPUs, ! 11: the XTS_LOW_RESOURCE_VERSION code might eventually be faster when parallelized, ! 12: because it processes the buffer continuously as a whole -- it does not divide the ! 13: buffer into data units (nevertheless, note that GenerateWhiteningValues supports ! 14: more than one data unit). ! 15: ! 16: Note that when TC_NO_COMPILER_INT64 is defined, XTS_LOW_RESOURCE_VERSION is implicitly ! 17: defined as well (because the non-low-resource version needs 64-bit types). ! 18: ! 19: For big-endian platforms (PowerPC, SPARC, etc.) define BYTE_ORDER as BIG_ENDIAN. */ ! 20: ! 21: ! 22: #ifdef TC_MINIMIZE_CODE_SIZE ! 23: # define XTS_LOW_RESOURCE_VERSION ! 24: #endif ! 25: ! 26: #ifdef TC_NO_COMPILER_INT64 ! 27: # ifndef XTS_LOW_RESOURCE_VERSION ! 28: # define XTS_LOW_RESOURCE_VERSION ! 29: # endif ! 30: #endif ! 31: ! 32: ! 33: #include "Xts.h" ! 34: ! 35: ! 36: #ifndef XTS_LOW_RESOURCE_VERSION ! 37: ! 38: // length: number of bytes to encrypt; may be larger than one data unit and must be divisible by the cipher block size ! 39: // ks: the primary key schedule ! 40: // ks2: the secondary key schedule ! 41: // startDataUnitNo: The sequential number of the data unit with which the buffer starts. ! 42: // startCipherBlockNo: The sequential number of the first plaintext block to encrypt inside the data unit startDataUnitNo. ! 43: // When encrypting the data unit from its first block, startCipherBlockNo is 0. ! 44: // The startCipherBlockNo value applies only to the first data unit in the buffer; each successive ! 45: // data unit is encrypted from its first block. The start of the buffer does not have to be ! 46: // aligned with the start of a data unit. If it is aligned, startCipherBlockNo must be 0; if it ! 47: // is not aligned, startCipherBlockNo must reflect the misalignment accordingly. ! 48: void EncryptBufferXTS (unsigned __int8 *buffer, ! 49: TC_LARGEST_COMPILER_UINT length, ! 50: const UINT64_STRUCT *startDataUnitNo, ! 51: unsigned int startCipherBlockNo, ! 52: unsigned __int8 *ks, ! 53: unsigned __int8 *ks2, ! 54: int cipher) ! 55: { ! 56: unsigned __int8 finalCarry; ! 57: unsigned __int8 whiteningValues [ENCRYPTION_DATA_UNIT_SIZE]; ! 58: unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK]; ! 59: unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK]; ! 60: unsigned __int64 *whiteningValuesPtr64 = (unsigned __int64 *) whiteningValues; ! 61: unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; ! 62: unsigned __int64 *bufPtr = (unsigned __int64 *) buffer; ! 63: unsigned int startBlock = startCipherBlockNo, endBlock, block; ! 64: unsigned __int64 *const finalInt64WhiteningValuesPtr = whiteningValuesPtr64 + sizeof (whiteningValues) / sizeof (*whiteningValuesPtr64) - 1; ! 65: TC_LARGEST_COMPILER_UINT blockCount, dataUnitNo; ! 66: ! 67: /* The encrypted data unit number (i.e. the resultant ciphertext block) is to be multiplied in the ! 68: finite field GF(2^128) by j-th power of n, where j is the sequential plaintext/ciphertext block ! 69: number and n is 2, a primitive element of GF(2^128). This can be (and is) simplified and implemented ! 70: as a left shift of the preceding whitening value by one bit (with carry propagating). In addition, if ! 71: the shift of the highest byte results in a carry, 135 is XORed into the lowest byte. The value 135 is ! 72: derived from the modulus of the Galois Field (x^128+x^7+x^2+x+1). */ ! 73: ! 74: // Convert the 64-bit data unit number into a little-endian 16-byte array. ! 75: // Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes. ! 76: dataUnitNo = startDataUnitNo->Value; ! 77: *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); ! 78: *((unsigned __int64 *) byteBufUnitNo + 1) = 0; ! 79: ! 80: if (length % BYTES_PER_XTS_BLOCK) ! 81: TC_THROW_FATAL_EXCEPTION; ! 82: ! 83: blockCount = length / BYTES_PER_XTS_BLOCK; ! 84: ! 85: // Process all blocks in the buffer ! 86: // When length > ENCRYPTION_DATA_UNIT_SIZE, this can be parallelized (one data unit per core) ! 87: while (blockCount > 0) ! 88: { ! 89: if (blockCount < BLOCKS_PER_XTS_DATA_UNIT) ! 90: endBlock = startBlock + (unsigned int) blockCount; ! 91: else ! 92: endBlock = BLOCKS_PER_XTS_DATA_UNIT; ! 93: ! 94: whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; ! 95: whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; ! 96: ! 97: // Encrypt the data unit number using the secondary key (in order to generate the first ! 98: // whitening value for this data unit) ! 99: *whiteningValuePtr64 = *((unsigned __int64 *) byteBufUnitNo); ! 100: *(whiteningValuePtr64 + 1) = 0; ! 101: EncipherBlock (cipher, whiteningValue, ks2); ! 102: ! 103: // Generate subsequent whitening values for blocks in this data unit. Note that all generated 128-bit ! 104: // whitening values are stored in memory as a sequence of 64-bit integers in reverse order. ! 105: for (block = 0; block < endBlock; block++) ! 106: { ! 107: if (block >= startBlock) ! 108: { ! 109: *whiteningValuesPtr64-- = *whiteningValuePtr64++; ! 110: *whiteningValuesPtr64-- = *whiteningValuePtr64; ! 111: } ! 112: else ! 113: whiteningValuePtr64++; ! 114: ! 115: // Derive the next whitening value ! 116: ! 117: #if BYTE_ORDER == LITTLE_ENDIAN ! 118: ! 119: // Little-endian platforms (Intel, AMD, etc.) ! 120: ! 121: finalCarry = ! 122: (*whiteningValuePtr64 & 0x8000000000000000) ? ! 123: 135 : 0; ! 124: ! 125: *whiteningValuePtr64-- <<= 1; ! 126: ! 127: if (*whiteningValuePtr64 & 0x8000000000000000) ! 128: *(whiteningValuePtr64 + 1) |= 1; ! 129: ! 130: *whiteningValuePtr64 <<= 1; ! 131: ! 132: #else ! 133: // Big-endian platforms (PowerPC, Motorola, etc.) ! 134: ! 135: finalCarry = ! 136: (*whiteningValuePtr64 & 0x80) ? ! 137: 135 : 0; ! 138: ! 139: *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); ! 140: ! 141: whiteningValuePtr64--; ! 142: ! 143: if (*whiteningValuePtr64 & 0x80) ! 144: *(whiteningValuePtr64 + 1) |= 0x0100000000000000; ! 145: ! 146: *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); ! 147: #endif ! 148: ! 149: whiteningValue[0] ^= finalCarry; ! 150: } ! 151: ! 152: whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; ! 153: ! 154: // Encrypt all blocks in this data unit ! 155: // TO DO: This should be parallelized (one block per core) ! 156: for (block = startBlock; block < endBlock; block++) ! 157: { ! 158: // Pre-whitening ! 159: *bufPtr++ ^= *whiteningValuesPtr64--; ! 160: *bufPtr-- ^= *whiteningValuesPtr64++; ! 161: ! 162: // Actual encryption ! 163: EncipherBlock (cipher, bufPtr, ks); ! 164: ! 165: // Post-whitening ! 166: *bufPtr++ ^= *whiteningValuesPtr64--; ! 167: *bufPtr++ ^= *whiteningValuesPtr64--; ! 168: ! 169: blockCount--; ! 170: } ! 171: ! 172: startBlock = 0; ! 173: ! 174: dataUnitNo++; ! 175: ! 176: *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); ! 177: } ! 178: ! 179: FAST_ERASE64 (whiteningValue, sizeof(whiteningValue)); ! 180: FAST_ERASE64 (whiteningValues, sizeof(whiteningValues)); ! 181: } ! 182: ! 183: ! 184: // For descriptions of the input parameters, see EncryptBufferXTS(). ! 185: void DecryptBufferXTS (unsigned __int8 *buffer, ! 186: TC_LARGEST_COMPILER_UINT length, ! 187: const UINT64_STRUCT *startDataUnitNo, ! 188: unsigned int startCipherBlockNo, ! 189: unsigned __int8 *ks, ! 190: unsigned __int8 *ks2, ! 191: int cipher) ! 192: { ! 193: unsigned __int8 finalCarry; ! 194: unsigned __int8 whiteningValues [ENCRYPTION_DATA_UNIT_SIZE]; ! 195: unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK]; ! 196: unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK]; ! 197: unsigned __int64 *whiteningValuesPtr64 = (unsigned __int64 *) whiteningValues; ! 198: unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; ! 199: unsigned __int64 *bufPtr = (unsigned __int64 *) buffer; ! 200: unsigned int startBlock = startCipherBlockNo, endBlock, block; ! 201: unsigned __int64 *const finalInt64WhiteningValuesPtr = whiteningValuesPtr64 + sizeof (whiteningValues) / sizeof (*whiteningValuesPtr64) - 1; ! 202: TC_LARGEST_COMPILER_UINT blockCount, dataUnitNo; ! 203: ! 204: // Convert the 64-bit data unit number into a little-endian 16-byte array. ! 205: // Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes. ! 206: dataUnitNo = startDataUnitNo->Value; ! 207: *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); ! 208: *((unsigned __int64 *) byteBufUnitNo + 1) = 0; ! 209: ! 210: if (length % BYTES_PER_XTS_BLOCK) ! 211: TC_THROW_FATAL_EXCEPTION; ! 212: ! 213: blockCount = length / BYTES_PER_XTS_BLOCK; ! 214: ! 215: // Process all blocks in the buffer ! 216: // When length > ENCRYPTION_DATA_UNIT_SIZE, this can be parallelized (one data unit per core) ! 217: while (blockCount > 0) ! 218: { ! 219: if (blockCount < BLOCKS_PER_XTS_DATA_UNIT) ! 220: endBlock = startBlock + (unsigned int) blockCount; ! 221: else ! 222: endBlock = BLOCKS_PER_XTS_DATA_UNIT; ! 223: ! 224: whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; ! 225: whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; ! 226: ! 227: // Encrypt the data unit number using the secondary key (in order to generate the first ! 228: // whitening value for this data unit) ! 229: *whiteningValuePtr64 = *((unsigned __int64 *) byteBufUnitNo); ! 230: *(whiteningValuePtr64 + 1) = 0; ! 231: EncipherBlock (cipher, whiteningValue, ks2); ! 232: ! 233: // Generate subsequent whitening values for blocks in this data unit. Note that all generated 128-bit ! 234: // whitening values are stored in memory as a sequence of 64-bit integers in reverse order. ! 235: for (block = 0; block < endBlock; block++) ! 236: { ! 237: if (block >= startBlock) ! 238: { ! 239: *whiteningValuesPtr64-- = *whiteningValuePtr64++; ! 240: *whiteningValuesPtr64-- = *whiteningValuePtr64; ! 241: } ! 242: else ! 243: whiteningValuePtr64++; ! 244: ! 245: // Derive the next whitening value ! 246: ! 247: #if BYTE_ORDER == LITTLE_ENDIAN ! 248: ! 249: // Little-endian platforms (Intel, AMD, etc.) ! 250: ! 251: finalCarry = ! 252: (*whiteningValuePtr64 & 0x8000000000000000) ? ! 253: 135 : 0; ! 254: ! 255: *whiteningValuePtr64-- <<= 1; ! 256: ! 257: if (*whiteningValuePtr64 & 0x8000000000000000) ! 258: *(whiteningValuePtr64 + 1) |= 1; ! 259: ! 260: *whiteningValuePtr64 <<= 1; ! 261: ! 262: #else ! 263: // Big-endian platforms (PowerPC, Motorola, etc.) ! 264: ! 265: finalCarry = ! 266: (*whiteningValuePtr64 & 0x80) ? ! 267: 135 : 0; ! 268: ! 269: *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); ! 270: ! 271: whiteningValuePtr64--; ! 272: ! 273: if (*whiteningValuePtr64 & 0x80) ! 274: *(whiteningValuePtr64 + 1) |= 0x0100000000000000; ! 275: ! 276: *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); ! 277: #endif ! 278: ! 279: whiteningValue[0] ^= finalCarry; ! 280: } ! 281: ! 282: whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; ! 283: ! 284: // Decrypt blocks in this data unit ! 285: // TO DO: This should be parallelized (one block per core) ! 286: for (block = startBlock; block < endBlock; block++) ! 287: { ! 288: *bufPtr++ ^= *whiteningValuesPtr64--; ! 289: *bufPtr-- ^= *whiteningValuesPtr64++; ! 290: ! 291: DecipherBlock (cipher, bufPtr, ks); ! 292: ! 293: *bufPtr++ ^= *whiteningValuesPtr64--; ! 294: *bufPtr++ ^= *whiteningValuesPtr64--; ! 295: ! 296: blockCount--; ! 297: } ! 298: ! 299: startBlock = 0; ! 300: ! 301: dataUnitNo++; ! 302: ! 303: *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); ! 304: } ! 305: ! 306: FAST_ERASE64 (whiteningValue, sizeof(whiteningValue)); ! 307: FAST_ERASE64 (whiteningValues, sizeof(whiteningValues)); ! 308: } ! 309: ! 310: ! 311: #if 0 // The following function is currently unused but may be useful in future ! 312: ! 313: // Generates XTS whitening values. Use this function if you need to generate whitening values for more than ! 314: // one data unit in one pass (the value 'length' may be greater than the data unit size). 'buffer' must point ! 315: // to the LAST 8 bytes of the buffer for the whitening values. Note that the generated 128-bit whitening values ! 316: // are stored in memory as a sequence of 64-bit integers in reverse order. For descriptions of the input ! 317: // parameters, see EncryptBufferXTS(). ! 318: static void GenerateWhiteningValues (unsigned __int64 *bufPtr64, ! 319: TC_LARGEST_COMPILER_UINT length, ! 320: const UINT64_STRUCT *startDataUnitNo, ! 321: unsigned int startBlock, ! 322: unsigned __int8 *ks2, ! 323: int cipher) ! 324: { ! 325: unsigned int block; ! 326: unsigned int endBlock; ! 327: unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK]; ! 328: unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK]; ! 329: unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; ! 330: unsigned __int8 finalCarry; ! 331: unsigned __int64 *const finalInt64WhiteningValuePtr = whiteningValuePtr64 + sizeof (whiteningValue) / sizeof (*whiteningValuePtr64) - 1; ! 332: TC_LARGEST_COMPILER_UINT blockCount, dataUnitNo; ! 333: ! 334: dataUnitNo = startDataUnitNo->Value; ! 335: ! 336: blockCount = length / BYTES_PER_XTS_BLOCK; ! 337: ! 338: // Convert the 64-bit data unit number into a little-endian 16-byte array. ! 339: // Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes. ! 340: *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); ! 341: *((unsigned __int64 *) byteBufUnitNo + 1) = 0; ! 342: ! 343: // Generate the whitening values. ! 344: // When length > ENCRYPTION_DATA_UNIT_SIZE, this can be parallelized (one data unit per core) ! 345: while (blockCount > 0) ! 346: { ! 347: if (blockCount < BLOCKS_PER_XTS_DATA_UNIT) ! 348: endBlock = startBlock + (unsigned int) blockCount; ! 349: else ! 350: endBlock = BLOCKS_PER_XTS_DATA_UNIT; ! 351: ! 352: // Encrypt the data unit number using the secondary key (in order to generate the first ! 353: // whitening value for this data unit) ! 354: memcpy (whiteningValue, byteBufUnitNo, BYTES_PER_XTS_BLOCK); ! 355: EncipherBlock (cipher, whiteningValue, ks2); ! 356: ! 357: // Process all blocks in this data unit ! 358: for (block = 0; block < endBlock; block++) ! 359: { ! 360: if (block >= startBlock) ! 361: { ! 362: whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; ! 363: ! 364: *bufPtr64-- = *whiteningValuePtr64++; ! 365: *bufPtr64-- = *whiteningValuePtr64; ! 366: ! 367: blockCount--; ! 368: } ! 369: ! 370: // Derive the next whitening value ! 371: ! 372: whiteningValuePtr64 = finalInt64WhiteningValuePtr; ! 373: ! 374: #if BYTE_ORDER == LITTLE_ENDIAN ! 375: ! 376: // Little-endian platforms (Intel, AMD, etc.) ! 377: ! 378: finalCarry = ! 379: (*whiteningValuePtr64 & 0x8000000000000000) ? ! 380: 135 : 0; ! 381: ! 382: *whiteningValuePtr64-- <<= 1; ! 383: ! 384: if (*whiteningValuePtr64 & 0x8000000000000000) ! 385: *(whiteningValuePtr64 + 1) |= 1; ! 386: ! 387: *whiteningValuePtr64 <<= 1; ! 388: ! 389: #else ! 390: // Big-endian platforms (PowerPC, Motorola, etc.) ! 391: ! 392: finalCarry = ! 393: (*whiteningValuePtr64 & 0x80) ? ! 394: 135 : 0; ! 395: ! 396: *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); ! 397: ! 398: whiteningValuePtr64--; ! 399: ! 400: if (*whiteningValuePtr64 & 0x80) ! 401: *(whiteningValuePtr64 + 1) |= 0x0100000000000000; ! 402: ! 403: *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); ! 404: #endif ! 405: ! 406: whiteningValue[0] ^= finalCarry; ! 407: } ! 408: ! 409: startBlock = 0; ! 410: ! 411: dataUnitNo++; ! 412: ! 413: // Convert the 64-bit data unit number into a little-endian 16-byte array. ! 414: *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); ! 415: } ! 416: ! 417: FAST_ERASE64 (whiteningValue, sizeof(whiteningValue)); ! 418: } ! 419: #endif // #if 0 ! 420: ! 421: ! 422: #else // XTS_LOW_RESOURCE_VERSION ! 423: ! 424: ! 425: #if BYTE_ORDER == BIG_ENDIAN ! 426: #error XTS_LOW_RESOURCE_VERSION is not compatible with big-endian platforms ! 427: #endif ! 428: ! 429: ! 430: // Increases a 64-bit value by one in a way compatible with non-64-bit environments/platforms ! 431: static void IncUint64Struct (UINT64_STRUCT *uint64Struct) ! 432: { ! 433: #ifdef TC_NO_COMPILER_INT64 ! 434: if (!++uint64Struct->LowPart) ! 435: { ! 436: uint64Struct->HighPart++; ! 437: } ! 438: #else ! 439: uint64Struct->Value++; ! 440: #endif ! 441: } ! 442: ! 443: ! 444: // Converts a 64-bit unsigned integer (passed as two 32-bit integers for compatibility with non-64-bit ! 445: // environments/platforms) into a little-endian 16-byte array. ! 446: static void Uint64ToLE16ByteArray (unsigned __int8 *byteBuf, unsigned __int32 highInt32, unsigned __int32 lowInt32) ! 447: { ! 448: unsigned __int32 *bufPtr32 = (unsigned __int32 *) byteBuf; ! 449: ! 450: *bufPtr32++ = lowInt32; ! 451: *bufPtr32++ = highInt32; ! 452: ! 453: // We're converting a 64-bit number into a little-endian 16-byte array so we can zero the last 8 bytes ! 454: *bufPtr32++ = 0; ! 455: *bufPtr32 = 0; ! 456: } ! 457: ! 458: ! 459: // Generates and XORs XTS whitening values into blocks in the buffer. ! 460: // For descriptions of the input parameters, see EncryptBufferXTS(). ! 461: static void WhiteningPass (unsigned __int8 *buffer, ! 462: TC_LARGEST_COMPILER_UINT length, ! 463: const UINT64_STRUCT *startDataUnitNo, ! 464: unsigned int startBlock, ! 465: unsigned __int8 *ks2, ! 466: int cipher) ! 467: { ! 468: TC_LARGEST_COMPILER_UINT blockCount; ! 469: UINT64_STRUCT dataUnitNo; ! 470: unsigned int block; ! 471: unsigned int endBlock; ! 472: unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK]; ! 473: unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK]; ! 474: unsigned __int32 *bufPtr32 = (unsigned __int32 *) buffer; ! 475: unsigned __int32 *whiteningValuePtr32 = (unsigned __int32 *) whiteningValue; ! 476: unsigned __int8 finalCarry; ! 477: unsigned __int32 *const finalDwordWhiteningValuePtr = whiteningValuePtr32 + sizeof (whiteningValue) / sizeof (*whiteningValuePtr32) - 1; ! 478: ! 479: // Store the 64-bit data unit number in a way compatible with non-64-bit environments/platforms ! 480: dataUnitNo.HighPart = startDataUnitNo->HighPart; ! 481: dataUnitNo.LowPart = startDataUnitNo->LowPart; ! 482: ! 483: blockCount = length / BYTES_PER_XTS_BLOCK; ! 484: ! 485: // Convert the 64-bit data unit number into a little-endian 16-byte array. ! 486: // (Passed as two 32-bit integers for compatibility with non-64-bit environments/platforms.) ! 487: Uint64ToLE16ByteArray (byteBufUnitNo, dataUnitNo.HighPart, dataUnitNo.LowPart); ! 488: ! 489: // Generate whitening values for all blocks in the buffer ! 490: while (blockCount > 0) ! 491: { ! 492: if (blockCount < BLOCKS_PER_XTS_DATA_UNIT) ! 493: endBlock = startBlock + (unsigned int) blockCount; ! 494: else ! 495: endBlock = BLOCKS_PER_XTS_DATA_UNIT; ! 496: ! 497: // Encrypt the data unit number using the secondary key (in order to generate the first ! 498: // whitening value for this data unit) ! 499: memcpy (whiteningValue, byteBufUnitNo, BYTES_PER_XTS_BLOCK); ! 500: EncipherBlock (cipher, whiteningValue, ks2); ! 501: ! 502: // Generate subsequent whitening values and XOR each whitening value into corresponding ! 503: // ciphertext/plaintext block ! 504: ! 505: for (block = 0; block < endBlock; block++) ! 506: { ! 507: if (block >= startBlock) ! 508: { ! 509: whiteningValuePtr32 = (unsigned __int32 *) whiteningValue; ! 510: ! 511: // XOR the whitening value into this ciphertext/plaintext block ! 512: *bufPtr32++ ^= *whiteningValuePtr32++; ! 513: *bufPtr32++ ^= *whiteningValuePtr32++; ! 514: *bufPtr32++ ^= *whiteningValuePtr32++; ! 515: *bufPtr32++ ^= *whiteningValuePtr32; ! 516: ! 517: blockCount--; ! 518: } ! 519: ! 520: // Derive the next whitening value ! 521: ! 522: finalCarry = 0; ! 523: ! 524: for (whiteningValuePtr32 = finalDwordWhiteningValuePtr; ! 525: whiteningValuePtr32 >= (unsigned __int32 *) whiteningValue; ! 526: whiteningValuePtr32--) ! 527: { ! 528: if (*whiteningValuePtr32 & 0x80000000) // If the following shift results in a carry ! 529: { ! 530: if (whiteningValuePtr32 != finalDwordWhiteningValuePtr) // If not processing the highest double word ! 531: { ! 532: // A regular carry ! 533: *(whiteningValuePtr32 + 1) |= 1; ! 534: } ! 535: else ! 536: { ! 537: // The highest byte shift will result in a carry ! 538: finalCarry = 135; ! 539: } ! 540: } ! 541: ! 542: *whiteningValuePtr32 <<= 1; ! 543: } ! 544: ! 545: whiteningValue[0] ^= finalCarry; ! 546: } ! 547: ! 548: startBlock = 0; ! 549: ! 550: // Increase the data unit number by one ! 551: IncUint64Struct (&dataUnitNo); ! 552: ! 553: // Convert the 64-bit data unit number into a little-endian 16-byte array. ! 554: Uint64ToLE16ByteArray (byteBufUnitNo, dataUnitNo.HighPart, dataUnitNo.LowPart); ! 555: } ! 556: ! 557: FAST_ERASE64 (whiteningValue, sizeof(whiteningValue)); ! 558: } ! 559: ! 560: ! 561: // length: number of bytes to encrypt; may be larger than one data unit and must be divisible by the cipher block size ! 562: // ks: the primary key schedule ! 563: // ks2: the secondary key schedule ! 564: // dataUnitNo: The sequential number of the data unit with which the buffer starts. ! 565: // startCipherBlockNo: The sequential number of the first plaintext block to encrypt inside the data unit dataUnitNo. ! 566: // When encrypting the data unit from its first block, startCipherBlockNo is 0. ! 567: // The startCipherBlockNo value applies only to the first data unit in the buffer; each successive ! 568: // data unit is encrypted from its first block. The start of the buffer does not have to be ! 569: // aligned with the start of a data unit. If it is aligned, startCipherBlockNo must be 0; if it ! 570: // is not aligned, startCipherBlockNo must reflect the misalignment accordingly. ! 571: void EncryptBufferXTS (unsigned __int8 *buffer, ! 572: TC_LARGEST_COMPILER_UINT length, ! 573: const UINT64_STRUCT *dataUnitNo, ! 574: unsigned int startCipherBlockNo, ! 575: unsigned __int8 *ks, ! 576: unsigned __int8 *ks2, ! 577: int cipher) ! 578: { ! 579: TC_LARGEST_COMPILER_UINT blockCount; ! 580: unsigned __int8 *bufPtr = buffer; ! 581: ! 582: if (length % BYTES_PER_XTS_BLOCK) ! 583: TC_THROW_FATAL_EXCEPTION; ! 584: ! 585: // Pre-whitening (all plaintext blocks in the buffer) ! 586: WhiteningPass (buffer, length, dataUnitNo, startCipherBlockNo, ks2, cipher); ! 587: ! 588: // Encrypt all plaintext blocks in the buffer ! 589: for (blockCount = 0; blockCount < length / BYTES_PER_XTS_BLOCK; blockCount++) ! 590: { ! 591: EncipherBlock (cipher, bufPtr, ks); ! 592: bufPtr += BYTES_PER_XTS_BLOCK; ! 593: } ! 594: ! 595: // Post-whitening (all ciphertext blocks in the buffer) ! 596: WhiteningPass (buffer, length, dataUnitNo, startCipherBlockNo, ks2, cipher); ! 597: } ! 598: ! 599: ! 600: // For descriptions of the input parameters, see EncryptBufferXTS(). ! 601: void DecryptBufferXTS (unsigned __int8 *buffer, ! 602: TC_LARGEST_COMPILER_UINT length, ! 603: const UINT64_STRUCT *dataUnitNo, ! 604: unsigned int startCipherBlockNo, ! 605: unsigned __int8 *ks, ! 606: unsigned __int8 *ks2, ! 607: int cipher) ! 608: { ! 609: TC_LARGEST_COMPILER_UINT blockCount; ! 610: unsigned __int8 *bufPtr = buffer; ! 611: ! 612: if (length % BYTES_PER_XTS_BLOCK) ! 613: TC_THROW_FATAL_EXCEPTION; ! 614: ! 615: WhiteningPass (buffer, length, dataUnitNo, startCipherBlockNo, ks2, cipher); ! 616: ! 617: for (blockCount = 0; blockCount < length / BYTES_PER_XTS_BLOCK; blockCount++) ! 618: { ! 619: DecipherBlock (cipher, bufPtr, ks); ! 620: bufPtr += BYTES_PER_XTS_BLOCK; ! 621: } ! 622: ! 623: WhiteningPass (buffer, length, dataUnitNo, startCipherBlockNo, ks2, cipher); ! 624: } ! 625: ! 626: #endif // XTS_LOW_RESOURCE_VERSION
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.