bool TestAltivecOps() { std::cout << "\nTesting Altivec operations...\n\n"; if (HasAltivec() == false) { std::cout << "\nAltivec not available, skipping test." << std::endl; return true; } // These tests may seem superflous, but we really want to test the // Altivec/POWER4 implementation. That does not happen when POWER7 // or POWER8 is available because we use POWER7's unaligned loads // and stores with POWER8's AES, SHA, etc. These tests enage // Altivec/POWER4 without POWER7, like on an old PowerMac. //********** Unaligned loads and stores **********// bool pass1=true; CRYPTOPP_ALIGN_DATA(16) byte dest[20], src[20] = {23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4}; const byte st1[16] = {22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7}; const byte st2[16] = {21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6}; const byte st3[16] = {20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5}; VecStore(VecLoad(src), dest); pass1 = (0 == std::memcmp(src, dest, 16)) && pass1; CRYPTOPP_ASSERT(pass1); VecStore(VecLoad(src+1), dest+1); pass1 = (0 == std::memcmp(st1, dest+1, 16)) && pass1; CRYPTOPP_ASSERT(pass1); VecStore(VecLoad(src+2), dest+2); pass1 = (0 == std::memcmp(st2, dest+2, 16)) && pass1; CRYPTOPP_ASSERT(pass1); VecStore(VecLoad(src+3), dest+3); pass1 = (0 == std::memcmp(st3, dest+3, 16)) && pass1; CRYPTOPP_ASSERT(pass1); VecStoreBE(VecLoadBE(src), dest); pass1 = (0 == std::memcmp(src, dest, 16)) && pass1; CRYPTOPP_ASSERT(pass1); VecStoreBE(VecLoadBE(src+1), dest+1); pass1 = (0 == std::memcmp(st1, dest+1, 16)) && pass1; CRYPTOPP_ASSERT(pass1); VecStoreBE(VecLoadBE(src+2), dest+2); pass1 = (0 == std::memcmp(st2, dest+2, 16)) && pass1; CRYPTOPP_ASSERT(pass1); VecStoreBE(VecLoadBE(src+3), dest+3); pass1 = (0 == std::memcmp(st3, dest+3, 16)) && pass1; CRYPTOPP_ASSERT(pass1); #if (CRYPTOPP_LITTLE_ENDIAN) VecStore(VecLoadBE(src), dest); pass1 = (0 != std::memcmp(src, dest, 16)) && pass1; CRYPTOPP_ASSERT(pass1); VecStoreBE(VecLoad(src), dest); pass1 = (0 != std::memcmp(src, dest, 16)) && pass1; CRYPTOPP_ASSERT(pass1); #endif if (!pass1) std::cout << "FAILED:"; else std::cout << "passed:"; std::cout << " Altivec loads and stores" << std::endl; //********** Shifts **********// bool pass2=true; uint8x16_p val = {0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff}; pass2 = (VecEqual(val, VecShiftLeftOctet<0>(val))) && pass2; CRYPTOPP_ASSERT(pass2); pass2 = (VecEqual(val, VecShiftRightOctet<0>(val))) && pass2; CRYPTOPP_ASSERT(pass2); uint8x16_p lsh1 = {0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00}; uint8x16_p rsh1 = {0x00,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff}; pass2 = (VecEqual(lsh1, VecShiftLeftOctet<1>(val))) && pass2; CRYPTOPP_ASSERT(pass2); pass2 = (VecEqual(rsh1, VecShiftRightOctet<1>(val))) && pass2; CRYPTOPP_ASSERT(pass2); uint8x16_p lsh15 = {0xff,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00}; uint8x16_p rsh15 = {0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xff}; pass2 = (VecEqual(lsh15, VecShiftLeftOctet<15>(val))) && pass2; CRYPTOPP_ASSERT(pass2); pass2 = (VecEqual(rsh15, VecShiftRightOctet<15>(val))) && pass2; CRYPTOPP_ASSERT(pass2); uint8x16_p lsh16 = {0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00}; uint8x16_p rsh16 = {0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00}; pass2 = (VecEqual(lsh16, VecShiftLeftOctet<16>(val))) && pass2; CRYPTOPP_ASSERT(pass2); pass2 = (VecEqual(rsh16, VecShiftRightOctet<16>(val))) && pass2; CRYPTOPP_ASSERT(pass2); if (!pass2) std::cout << "FAILED:"; else std::cout << "passed:"; std::cout << " Altivec left and right shifts" << std::endl; //********** Extraction **********// bool pass3=true; const byte bex1[] = {0x1f,0x1e,0x1d,0x1c, 0x1b,0x1a,0x19,0x18, 0x17,0x16,0x15,0x14, 0x13,0x12,0x11,0x10}; const byte bex2[] = {0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x17,0x16,0x15,0x14, 0x13,0x12,0x11,0x10}; const byte bex3[] = {0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x1f,0x1e,0x1d,0x1c, 0x1b,0x1a,0x19,0x18}; const uint8x16_p ex1 = (uint8x16_p)VecLoad(bex1); const uint8x16_p ex2 = (uint8x16_p)VecLoad(bex2); const uint8x16_p ex3 = (uint8x16_p)VecLoad(bex3); pass3 = VecEqual(ex2, VecGetLow(ex1)) && pass3; CRYPTOPP_ASSERT(pass3); pass3 = VecEqual(ex3, VecGetHigh(ex1)) && pass3; CRYPTOPP_ASSERT(pass3); uint8x16_p ex4 = VecShiftRightOctet<8>(VecShiftLeftOctet<8>(ex1)); pass3 = VecEqual(ex4, VecGetLow(ex1)) && pass3; CRYPTOPP_ASSERT(pass3); uint8x16_p ex5 = VecShiftRightOctet<8>(ex1); pass3 = VecEqual(ex5, VecGetHigh(ex1)) && pass3; CRYPTOPP_ASSERT(pass3); if (!pass3) std::cout << "FAILED:"; else std::cout << "passed:"; std::cout << " Altivec vector extraction" << std::endl; return pass1 && pass2 && pass3; }
int ReadVolumeHeader (BOOL bBoot, char *encryptedHeader, Password *password, int selected_pkcs5_prf, int pim, BOOL truecryptMode, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo) { char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE]; CRYPTOPP_ALIGN_DATA(16) KEY_INFO keyInfo; PCRYPTO_INFO cryptoInfo; char dk[MASTER_KEYDATA_SIZE]; int enqPkcs5Prf, pkcs5_prf; uint16 headerVersion; int status = ERR_PARAMETER_INCORRECT; int primaryKeyOffset; TC_EVENT keyDerivationCompletedEvent; TC_EVENT noOutstandingWorkItemEvent; KeyDerivationWorkItem *keyDerivationWorkItems; KeyDerivationWorkItem *item; int pkcs5PrfCount = LAST_PRF_ID - FIRST_PRF_ID + 1; size_t encryptionThreadCount = GetEncryptionThreadCount(); size_t queuedWorkItems = 0; LONG outstandingWorkItemCount = 0; int i; // if no PIM specified, use default value if (pim < 0) pim = 0; if (truecryptMode) { // SHA-256 not supported in TrueCrypt mode if (selected_pkcs5_prf == SHA256) return ERR_PARAMETER_INCORRECT; pkcs5PrfCount--; // don't count SHA-256 in case of TrueCrypt mode } if (retHeaderCryptoInfo != NULL) { cryptoInfo = retHeaderCryptoInfo; } else { if (!retInfo) return ERR_PARAMETER_INCORRECT; cryptoInfo = *retInfo = crypto_open (); if (cryptoInfo == NULL) return ERR_OUTOFMEMORY; } /* use thread pool only if no PRF was specified */ if ((selected_pkcs5_prf == 0) && (encryptionThreadCount > 1)) { keyDerivationWorkItems = TCalloc (sizeof (KeyDerivationWorkItem) * pkcs5PrfCount); if (!keyDerivationWorkItems) return ERR_OUTOFMEMORY; for (i = 0; i < pkcs5PrfCount; ++i) keyDerivationWorkItems[i].Free = TRUE; #ifdef DEVICE_DRIVER KeInitializeEvent (&keyDerivationCompletedEvent, SynchronizationEvent, FALSE); KeInitializeEvent (&noOutstandingWorkItemEvent, SynchronizationEvent, TRUE); #else keyDerivationCompletedEvent = CreateEvent (NULL, FALSE, FALSE, NULL); if (!keyDerivationCompletedEvent) { TCfree (keyDerivationWorkItems); return ERR_OUTOFMEMORY; } noOutstandingWorkItemEvent = CreateEvent (NULL, FALSE, TRUE, NULL); if (!noOutstandingWorkItemEvent) { CloseHandle (keyDerivationCompletedEvent); TCfree (keyDerivationWorkItems); return ERR_OUTOFMEMORY; } #endif } #ifndef DEVICE_DRIVER VirtualLock (&keyInfo, sizeof (keyInfo)); VirtualLock (&dk, sizeof (dk)); #endif crypto_loadkey (&keyInfo, password->Text, (int) password->Length); // PKCS5 is used to derive the primary header key(s) and secondary header key(s) (XTS mode) from the password memcpy (keyInfo.salt, encryptedHeader + HEADER_SALT_OFFSET, PKCS5_SALT_SIZE); // Test all available PKCS5 PRFs for (enqPkcs5Prf = FIRST_PRF_ID; enqPkcs5Prf <= LAST_PRF_ID || queuedWorkItems > 0; ++enqPkcs5Prf) { // if a PRF is specified, we skip all other PRFs if (selected_pkcs5_prf != 0 && enqPkcs5Prf != selected_pkcs5_prf) continue; // skip SHA-256 in case of TrueCrypt mode if (truecryptMode && (enqPkcs5Prf == SHA256)) continue; if ((selected_pkcs5_prf == 0) && (encryptionThreadCount > 1)) { // Enqueue key derivation on thread pool if (queuedWorkItems < encryptionThreadCount && enqPkcs5Prf <= LAST_PRF_ID) { for (i = 0; i < pkcs5PrfCount; ++i) { item = &keyDerivationWorkItems[i]; if (item->Free) { item->Free = FALSE; item->KeyReady = FALSE; item->Pkcs5Prf = enqPkcs5Prf; EncryptionThreadPoolBeginKeyDerivation (&keyDerivationCompletedEvent, &noOutstandingWorkItemEvent, &item->KeyReady, &outstandingWorkItemCount, enqPkcs5Prf, keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, get_pkcs5_iteration_count (enqPkcs5Prf, pim, truecryptMode, bBoot), item->DerivedKey); ++queuedWorkItems; break; } } if (enqPkcs5Prf < LAST_PRF_ID) continue; } else --enqPkcs5Prf; // Wait for completion of a key derivation while (queuedWorkItems > 0) { for (i = 0; i < pkcs5PrfCount; ++i) { item = &keyDerivationWorkItems[i]; if (!item->Free && InterlockedExchangeAdd (&item->KeyReady, 0) == TRUE) { pkcs5_prf = item->Pkcs5Prf; keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5_prf, pim, truecryptMode, bBoot); memcpy (dk, item->DerivedKey, sizeof (dk)); item->Free = TRUE; --queuedWorkItems; goto KeyReady; } } if (queuedWorkItems > 0) TC_WAIT_EVENT (keyDerivationCompletedEvent); } continue; KeyReady: ; } else { pkcs5_prf = enqPkcs5Prf; keyInfo.noIterations = get_pkcs5_iteration_count (enqPkcs5Prf, pim, truecryptMode, bBoot); switch (pkcs5_prf) { case RIPEMD160: derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); break; case SHA512: derive_key_sha512 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); break; case WHIRLPOOL: derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); break; case SHA256: derive_key_sha256 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); break; default: // Unknown/wrong ID TC_THROW_FATAL_EXCEPTION; } } // Test all available modes of operation for (cryptoInfo->mode = FIRST_MODE_OF_OPERATION_ID; cryptoInfo->mode <= LAST_MODE_OF_OPERATION; cryptoInfo->mode++) { switch (cryptoInfo->mode) { default: primaryKeyOffset = 0; } // Test all available encryption algorithms for (cryptoInfo->ea = EAGetFirst (); cryptoInfo->ea != 0; cryptoInfo->ea = EAGetNext (cryptoInfo->ea)) { int blockSize; if (!EAIsModeSupported (cryptoInfo->ea, cryptoInfo->mode)) continue; // This encryption algorithm has never been available with this mode of operation blockSize = CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea)); status = EAInit (cryptoInfo->ea, dk + primaryKeyOffset, cryptoInfo->ks); if (status == ERR_CIPHER_INIT_FAILURE) goto err; // Init objects related to the mode of operation if (cryptoInfo->mode == XTS) { // Copy the secondary key (if cascade, multiple concatenated) memcpy (cryptoInfo->k2, dk + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); // Secondary key schedule if (!EAInitMode (cryptoInfo)) { status = ERR_MODE_INIT_FAILED; goto err; } } else { continue; } // Copy the header for decryption memcpy (header, encryptedHeader, sizeof (header)); // Try to decrypt header DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); // Magic 'VERA' or 'TRUE' depending if we are in TrueCrypt mode or not if ((truecryptMode && GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545) || (!truecryptMode && GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x56455241) ) continue; // Header version headerVersion = GetHeaderField16 (header, TC_HEADER_OFFSET_VERSION); if (headerVersion > VOLUME_HEADER_VERSION) { status = ERR_NEW_VERSION_REQUIRED; goto err; } // Check CRC of the header fields if (!ReadVolumeHeaderRecoveryMode && headerVersion >= 4 && GetHeaderField32 (header, TC_HEADER_OFFSET_HEADER_CRC) != GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC)) continue; // Required program version cryptoInfo->RequiredProgramVersion = GetHeaderField16 (header, TC_HEADER_OFFSET_REQUIRED_VERSION); if (truecryptMode) { if (cryptoInfo->RequiredProgramVersion < 0x600 || cryptoInfo->RequiredProgramVersion > 0x71a) { status = ERR_UNSUPPORTED_TRUECRYPT_FORMAT | (((int)cryptoInfo->RequiredProgramVersion) << 16); goto err; } cryptoInfo->LegacyVolume = FALSE; } else cryptoInfo->LegacyVolume = cryptoInfo->RequiredProgramVersion < 0x10b; // Check CRC of the key set if (!ReadVolumeHeaderRecoveryMode && GetHeaderField32 (header, TC_HEADER_OFFSET_KEY_AREA_CRC) != GetCrc32 (header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE)) continue; // Now we have the correct password, cipher, hash algorithm, and volume type // Check the version required to handle this volume if (!truecryptMode && (cryptoInfo->RequiredProgramVersion > VERSION_NUM)) { status = ERR_NEW_VERSION_REQUIRED; goto err; } // Header version cryptoInfo->HeaderVersion = headerVersion; // Volume creation time (legacy) cryptoInfo->volume_creation_time = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_CREATION_TIME).Value; // Header creation time (legacy) cryptoInfo->header_creation_time = GetHeaderField64 (header, TC_HEADER_OFFSET_MODIFICATION_TIME).Value; // Hidden volume size (if any) cryptoInfo->hiddenVolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_HIDDEN_VOLUME_SIZE).Value; // Hidden volume status cryptoInfo->hiddenVolume = (cryptoInfo->hiddenVolumeSize != 0); // Volume size cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_SIZE); // Encrypted area size and length cryptoInfo->EncryptedAreaStart = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_START); cryptoInfo->EncryptedAreaLength = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH); // Flags cryptoInfo->HeaderFlags = GetHeaderField32 (header, TC_HEADER_OFFSET_FLAGS); // Sector size if (headerVersion >= 5) cryptoInfo->SectorSize = GetHeaderField32 (header, TC_HEADER_OFFSET_SECTOR_SIZE); else cryptoInfo->SectorSize = TC_SECTOR_SIZE_LEGACY; if (cryptoInfo->SectorSize < TC_MIN_VOLUME_SECTOR_SIZE || cryptoInfo->SectorSize > TC_MAX_VOLUME_SECTOR_SIZE || cryptoInfo->SectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0) { status = ERR_PARAMETER_INCORRECT; goto err; } // Preserve scheduled header keys if requested if (retHeaderCryptoInfo) { if (retInfo == NULL) { cryptoInfo->pkcs5 = pkcs5_prf; cryptoInfo->noIterations = keyInfo.noIterations; cryptoInfo->bTrueCryptMode = truecryptMode; cryptoInfo->volumePim = pim; goto ret; } cryptoInfo = *retInfo = crypto_open (); if (cryptoInfo == NULL) { status = ERR_OUTOFMEMORY; goto err; } memcpy (cryptoInfo, retHeaderCryptoInfo, sizeof (*cryptoInfo)); } // Master key data memcpy (keyInfo.master_keydata, header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE); memcpy (cryptoInfo->master_keydata, keyInfo.master_keydata, MASTER_KEYDATA_SIZE); // PKCS #5 memcpy (cryptoInfo->salt, keyInfo.salt, PKCS5_SALT_SIZE); cryptoInfo->pkcs5 = pkcs5_prf; cryptoInfo->noIterations = keyInfo.noIterations; cryptoInfo->bTrueCryptMode = truecryptMode; cryptoInfo->volumePim = pim; // Init the cipher with the decrypted master key status = EAInit (cryptoInfo->ea, keyInfo.master_keydata + primaryKeyOffset, cryptoInfo->ks); if (status == ERR_CIPHER_INIT_FAILURE) goto err; switch (cryptoInfo->mode) { default: // The secondary master key (if cascade, multiple concatenated) memcpy (cryptoInfo->k2, keyInfo.master_keydata + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); } if (!EAInitMode (cryptoInfo)) { status = ERR_MODE_INIT_FAILED; goto err; } status = ERR_SUCCESS; goto ret; } } } status = ERR_PASSWORD_WRONG; err: if (cryptoInfo != retHeaderCryptoInfo) { crypto_close(cryptoInfo); *retInfo = NULL; } ret: burn (&keyInfo, sizeof (keyInfo)); burn (dk, sizeof(dk)); #ifndef DEVICE_DRIVER VirtualUnlock (&keyInfo, sizeof (keyInfo)); VirtualUnlock (&dk, sizeof (dk)); #endif if ((selected_pkcs5_prf == 0) && (encryptionThreadCount > 1)) { TC_WAIT_EVENT (noOutstandingWorkItemEvent); burn (keyDerivationWorkItems, sizeof (KeyDerivationWorkItem) * pkcs5PrfCount); TCfree (keyDerivationWorkItems); #ifndef DEVICE_DRIVER CloseHandle (keyDerivationCompletedEvent); CloseHandle (noOutstandingWorkItemEvent); #endif } return status; }