void EncryptionModeLRW::DecryptSectorsCurrentThread (byte *data, uint64 sectorIndex, uint64 sectorCount, size_t sectorSize) const
	{
		if_debug (ValidateState ());
		if_debug (ValidateParameters (data, sectorCount, sectorSize));

		DecryptBuffer (data,
			sectorCount * sectorSize,
			SectorToBlockIndex (sectorIndex));
	}
int LogBookData::SaveData(void)
{
	FILE		*fp;
	_TCHAR		path[_MAX_PATH];
	
	_stprintf(path,_T("%s\\config\\%s.lbk"),FalconDataDirectory,Pilot.Callsign);

	if((fp = _tfopen(path,_T("wb"))) == NULL)
	{
		MonoPrint(_T("Couldn't save logbook"));
		return FALSE;
	}

	EncryptBuffer(0x58,(uchar*)&Pilot,sizeof(LB_PILOT));
	
	fwrite(&Pilot, sizeof(LB_PILOT), 1, fp);
	fclose(fp);

	DecryptBuffer(0x58,(uchar*)&Pilot,sizeof(LB_PILOT));

	if(gCommsMgr)
	{
		sprintf(path,"%s\\config\\%s.plc",FalconDataDirectory,Pilot.Callsign);
		gCommsMgr->SetStatsFile(path);
	}

#if _USE_REGISTRY_
	DWORD size;
	HKEY theKey;
	long retval;

	retval = RegOpenKeyEx(HKEY_LOCAL_MACHINE, FALCON_REGISTRY_KEY,
		0, KEY_ALL_ACCESS, &theKey);
	size = _NAME_LEN_;
	if(retval == ERROR_SUCCESS)
		retval = RegSetValueEx  (theKey, "PilotName", 0, REG_BINARY, (LPBYTE)Name(), size);	
	size = _CALLSIGN_LEN_;
	if(retval == ERROR_SUCCESS)
		retval = RegSetValueEx  (theKey, "PilotCallsign", 0, REG_BINARY, (LPBYTE)Callsign(), size);	
	RegCloseKey(theKey);
#endif

	if(this == &LogBook)
	{
		FalconLocalSession->SetPlayerName(NameWRank());
	 	FalconLocalSession->SetPlayerCallsign(Callsign());
		FalconLocalSession->SetAceFactor(AceFactor());
		FalconLocalSession->SetInitAceFactor(LogBook.AceFactor());
		FalconLocalSession->SetVoiceID(static_cast<uchar>(Voice()));
	}

	return TRUE;
}
/** Loads settings from the configuration file */
void FTaskBrowserSettings::LoadSettings()
{
	GConfig->GetString( TEXT( "TaskBrowser" ), TEXT( "ServerName" ), ServerName, GEditorUserSettingsIni );
		
	GConfig->GetInt( TEXT( "TaskBrowser" ), TEXT( "ServerPort" ), ServerPort, GEditorUserSettingsIni );

	GConfig->GetString( TEXT( "TaskBrowser" ), TEXT( "UserName" ), UserName, GEditorUserSettingsIni );

	// Load encrypted password from disk
	FString EncryptedPasswordBlob = GConfig->GetStr( TEXT( "TaskBrowser" ), TEXT( "Password" ), GEditorUserSettingsIni );
	Password = TEXT( "" );
	const uint32 MaxEncryptedPasswordSize = 2048;
	uint8 EncryptedPasswordBuffer[ MaxEncryptedPasswordSize ];
	if( FString::ToBlob( EncryptedPasswordBlob, EncryptedPasswordBuffer, MaxEncryptedPasswordSize ) )
	{
		const uint32 MaxDecryptedPasswordSize = 2048;
		uint8 DecryptedPasswordBuffer[ MaxDecryptedPasswordSize ];
		const uint32 ExpectedEncryptedPasswordSize = EncryptedPasswordBlob.Len() / 3;
		uint32 DecryptedPasswordSize = MaxDecryptedPasswordSize;
		if( DecryptBuffer(
				EncryptedPasswordBuffer,
				ExpectedEncryptedPasswordSize,
				DecryptedPasswordBuffer,
				DecryptedPasswordSize ) )
		{
			FString DecryptedPassword = ( const TCHAR* )DecryptedPasswordBuffer;

			// Store password
			Password = DecryptedPassword;
		}
	}

	GConfig->GetString( TEXT( "TaskBrowser" ), TEXT( "ProjectName" ), ProjectName, GEditorUserSettingsIni );

	GConfig->GetBool( TEXT( "TaskBrowser" ), TEXT( "AutoConnectAtStartup" ), bAutoConnectAtStartup, GEditorUserSettingsIni );

	GConfig->GetBool( TEXT( "TaskBrowser" ), TEXT( "UseSingleSignOn" ), bUseSingleSignOn, GEditorUserSettingsIni );

	GConfig->GetString( TEXT( "TaskBrowser" ), TEXT( "DBFilterName" ), DBFilterName, GEditorUserSettingsIni );

	GConfig->GetBool( TEXT( "TaskBrowser" ), TEXT( "FilterOnlyOpen" ), bFilterOnlyOpen, GEditorUserSettingsIni );

	GConfig->GetBool( TEXT( "TaskBrowser" ), TEXT( "FilterAssignedToMe" ), bFilterAssignedToMe, GEditorUserSettingsIni );
	
	GConfig->GetBool( TEXT( "TaskBrowser" ), TEXT( "FilterCreatedByMe" ), bFilterCreatedByMe, GEditorUserSettingsIni );

	GConfig->GetBool( TEXT( "TaskBrowser" ), TEXT( "FilterCurrentMap" ), bFilterCurrentMap, GEditorUserSettingsIni );

	GConfig->GetInt( TEXT( "TaskBrowser" ), TEXT( "TaskListSortColumn" ), TaskListSortColumn, GEditorUserSettingsIni );

	GConfig->GetBool( TEXT( "TaskBrowser" ), TEXT( "TaskListSortAscending" ), bTaskListSortAscending, GEditorUserSettingsIni );
}
/*----------------------------------------------------------------------
|   AP4_CbcStreamCipher::ProcessBuffer
+---------------------------------------------------------------------*/
AP4_Result
AP4_CbcStreamCipher::ProcessBuffer(const AP4_UI08* in, 
                                   AP4_Size        in_size,
                                   AP4_UI08*       out, 
                                   AP4_Size*       out_size,
                                   bool            is_last_buffer)
{
    // check the parameters
    if (out_size == NULL) return AP4_ERROR_INVALID_PARAMETERS; 
    
    // check the state
    if (m_BlockCipher == NULL || m_Eos) {
        *out_size = 0;
        return AP4_ERROR_INVALID_STATE;
    }
    if (is_last_buffer) m_Eos = true;
    
    if (m_BlockCipher->GetDirection() == AP4_BlockCipher::ENCRYPT) {
        return EncryptBuffer(in, in_size, out, out_size, is_last_buffer);
    } else {
        return DecryptBuffer(in, in_size, out, out_size, is_last_buffer);
    }
}
	void EncryptionModeXTS::DecryptSectorsCurrentThread (byte *data, uint64 sectorIndex, uint64 sectorCount, size_t sectorSize) const
	{
		DecryptBuffer (data, sectorCount * sectorSize, sectorIndex * sectorSize / ENCRYPTION_DATA_UNIT_SIZE);
	}
	void EncryptionModeXTS::Decrypt (byte *data, uint64 length) const
	{
		DecryptBuffer (data, length, 0);
	}
Exemple #7
0
int ReadVolumeHeader (BOOL bBoot, char *header, Password *password, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo)
{
#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
	char dk[32 * 2];			// 2 * 256-bit key
	char masterKey[32 * 2];
#else
	char dk[32 * 2 * 3];		// 6 * 256-bit key
	char masterKey[32 * 2 * 3];
#endif

	PCRYPTO_INFO cryptoInfo;
	int status;

	if (retHeaderCryptoInfo != NULL)
		cryptoInfo = retHeaderCryptoInfo;
	else
		cryptoInfo = *retInfo = crypto_open ();

	// PKCS5 PRF
	derive_key_ripemd160 (password->Text, (int) password->Length, header + HEADER_SALT_OFFSET,
		PKCS5_SALT_SIZE, bBoot ? 1000 : 2000, dk, sizeof (dk));

	// Mode of operation
	cryptoInfo->mode = FIRST_MODE_OF_OPERATION_ID;

	// Test all available encryption algorithms
	for (cryptoInfo->ea = EAGetFirst (); cryptoInfo->ea != 0; cryptoInfo->ea = EAGetNext (cryptoInfo->ea))
	{
		status = EAInit (cryptoInfo->ea, dk, cryptoInfo->ks);
		if (status == ERR_CIPHER_INIT_FAILURE)
			goto err;

		// Secondary key schedule
		EAInit (cryptoInfo->ea, dk + EAGetKeySize (cryptoInfo->ea), cryptoInfo->ks2);

		// Try to decrypt header 
		DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);
		
		// Check magic 'TRUE' and CRC-32 of header fields and master keydata
		if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545
			|| (GetHeaderField16 (header, TC_HEADER_OFFSET_VERSION) >= 4 && GetHeaderField32 (header, TC_HEADER_OFFSET_HEADER_CRC) != GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC))
			|| GetHeaderField32 (header, TC_HEADER_OFFSET_KEY_AREA_CRC) != GetCrc32 (header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE))
		{
			EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);
			continue;
		}

		// Header decrypted
		status = 0;

		// Hidden volume status
		cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_HIDDEN_VOLUME_SIZE);
		cryptoInfo->hiddenVolume = (cryptoInfo->VolumeSize.LowPart != 0 || cryptoInfo->VolumeSize.HighPart != 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);

		memcpy (masterKey, header + HEADER_MASTER_KEYDATA_OFFSET, sizeof (masterKey));
		EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);

		if (retHeaderCryptoInfo)
			goto ret;

		// Init the encryption algorithm with the decrypted master key
		status = EAInit (cryptoInfo->ea, masterKey, cryptoInfo->ks);
		if (status == ERR_CIPHER_INIT_FAILURE)
			goto err;

		// The secondary master key (if cascade, multiple concatenated)
		EAInit (cryptoInfo->ea, masterKey + EAGetKeySize (cryptoInfo->ea), cryptoInfo->ks2);
		goto ret;
	}

	status = ERR_PASSWORD_WRONG;

err:
	if (cryptoInfo != retHeaderCryptoInfo)
	{
		crypto_close(cryptoInfo);
		*retInfo = NULL; 
	}

ret:
	burn (dk, sizeof(dk));
	burn (masterKey, sizeof(masterKey));
	return status;
}
Exemple #8
0
int ReadVolumeHeader (BOOL bBoot, char *encryptedHeader, Password *password, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo)
{
	char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE];
	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 (retHeaderCryptoInfo != NULL)
	{
		cryptoInfo = retHeaderCryptoInfo;
	}
	else
	{
		cryptoInfo = *retInfo = crypto_open ();
		if (cryptoInfo == NULL)
			return ERR_OUTOFMEMORY;
	}

	if (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)
	{
		BOOL lrw64InitDone = FALSE;		// Deprecated/legacy
		BOOL lrw128InitDone = FALSE;	// Deprecated/legacy

		if (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, 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, 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, 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 SHA1:
				// Deprecated/legacy
				derive_key_sha1 (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;

			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)
			{
			case LRW:
			case CBC:
			case INNER_CBC:
			case OUTER_CBC:

				// For LRW (deprecated/legacy), copy the tweak key 
				// For CBC (deprecated/legacy), copy the IV/whitening seed 
				memcpy (cryptoInfo->k2, dk, LEGACY_VOL_IV_SIZE);
				primaryKeyOffset = LEGACY_VOL_IV_SIZE;
				break;

			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 if (cryptoInfo->mode == LRW
					&& (blockSize == 8 && !lrw64InitDone || blockSize == 16 && !lrw128InitDone))
				{
					// Deprecated/legacy

					if (!EAInitMode (cryptoInfo))
					{
						status = ERR_MODE_INIT_FAILED;
						goto err;
					}

					if (blockSize == 8)
						lrw64InitDone = TRUE;
					else if (blockSize == 16)
						lrw128InitDone = TRUE;
				}

				// 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 'TRUE'
				if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545)
					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);
				cryptoInfo->LegacyVolume = cryptoInfo->RequiredProgramVersion < 0x600;

				// 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 (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;
						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;

				// 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)
				{
				case LRW:
				case CBC:
				case INNER_CBC:
				case OUTER_CBC:

					// For LRW (deprecated/legacy), the tweak key
					// For CBC (deprecated/legacy), the IV/whitening seed
					memcpy (cryptoInfo->k2, keyInfo.master_keydata, LEGACY_VOL_IV_SIZE);
					break;

				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 (encryptionThreadCount > 1)
	{
		TC_WAIT_EVENT (noOutstandingWorkItemEvent);

		burn (keyDerivationWorkItems, sizeof (KeyDerivationWorkItem) * pkcs5PrfCount);
		TCfree (keyDerivationWorkItems);

#ifndef DEVICE_DRIVER
		CloseHandle (keyDerivationCompletedEvent);
		CloseHandle (noOutstandingWorkItemEvent);
#endif
	}

	return status;
}
Exemple #9
0
///
///	Note: if there are Keyfiles, these must be applied already to the password!
/// int __declspec(dllexport)  __stdcall  CheckVolumeHeaderPassword (BOOL bBoot, char *encryptedHeader, Password *password) 
int __declspec(dllexport)  __cdecl  CheckVolumeHeaderPassword (BOOL bBoot, char *encryptedHeader, Password *password)
{
	char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE];
	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;

	cryptoInfo = crypto_open();
	if (cryptoInfo == NULL)
		return ERR_OUTOFMEMORY;


	if (encryptionThreadCount > 1)
	{
		keyDerivationWorkItems = TCalloc (sizeof (KeyDerivationWorkItem) * pkcs5PrfCount);
		if (!keyDerivationWorkItems)
			return ERR_OUTOFMEMORY;

		for (i = 0; i < pkcs5PrfCount; ++i)
			keyDerivationWorkItems[i].Free = TRUE;


		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;
		}
	}
		

	VirtualLock (&keyInfo, sizeof (keyInfo));
	VirtualLock (&dk, sizeof (dk));

	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)
	{
		BOOL lrw64InitDone = FALSE;		// Deprecated/legacy
		BOOL lrw128InitDone = FALSE;	// Deprecated/legacy

		if (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, 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, 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, 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 SHA1:
				// Deprecated/legacy
				derive_key_sha1 (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;

			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)
			{
			case LRW:
			case CBC:
			case INNER_CBC:
			case OUTER_CBC:

				// For LRW (deprecated/legacy), copy the tweak key 
				// For CBC (deprecated/legacy), copy the IV/whitening seed 
				memcpy (cryptoInfo->k2, dk, LEGACY_VOL_IV_SIZE);
				primaryKeyOffset = LEGACY_VOL_IV_SIZE;
				break;

			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 if (cryptoInfo->mode == LRW
					&& (blockSize == 8 && !lrw64InitDone || blockSize == 16 && !lrw128InitDone))
				{
					// Deprecated/legacy

					if (!EAInitMode (cryptoInfo))
					{
						status = ERR_MODE_INIT_FAILED;
						goto err;
					}

					if (blockSize == 8)
						lrw64InitDone = TRUE;
					else if (blockSize == 16)
						lrw128InitDone = TRUE;
				}

				// 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 'TRUE'
				if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) == 0x54525545){
					status = ERR_SUCCESS;
					goto ret;
				}
			}
		}
	}
	status = ERR_PASSWORD_WRONG;

err:
ret:
	burn (&keyInfo, sizeof (keyInfo));
	burn (dk, sizeof(dk));

	VirtualUnlock (&keyInfo, sizeof (keyInfo));
	VirtualUnlock (&dk, sizeof (dk));

	if (encryptionThreadCount > 1)
	{
	//	TC_WAIT_EVENT (noOutstandingWorkItemEvent);

		burn (keyDerivationWorkItems, sizeof (KeyDerivationWorkItem) * pkcs5PrfCount);
		TCfree (keyDerivationWorkItems);

		CloseHandle (keyDerivationCompletedEvent);
		CloseHandle (noOutstandingWorkItemEvent);
	}

	return status;
}
Exemple #10
0
int ReadVolumeHeader (BOOL bBoot, char *header, Password *password, int pim, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo)
{
#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
    char dk[32 * 2];			// 2 * 256-bit key
#else
    char dk[32 * 2 * 3];		// 6 * 256-bit key
#endif

    PCRYPTO_INFO cryptoInfo;
    int status = ERR_SUCCESS;
    uint32 iterations = pim;
    iterations <<= 16;
    iterations |= bBoot;

    if (retHeaderCryptoInfo != NULL)
        cryptoInfo = retHeaderCryptoInfo;
    else
        cryptoInfo = *retInfo = crypto_open ();

    // PKCS5 PRF
#ifdef TC_WINDOWS_BOOT_SHA2
    derive_key_sha256 (password->Text, (int) password->Length, header + HEADER_SALT_OFFSET,
                       PKCS5_SALT_SIZE, iterations, dk, sizeof (dk));
#else
    derive_key_ripemd160 (password->Text, (int) password->Length, header + HEADER_SALT_OFFSET,
                          PKCS5_SALT_SIZE, iterations, dk, sizeof (dk));
#endif

    // Mode of operation
    cryptoInfo->mode = FIRST_MODE_OF_OPERATION_ID;

#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
    cryptoInfo->ea = 1;
#else
    // Test all available encryption algorithms
    for (cryptoInfo->ea = EAGetFirst (); cryptoInfo->ea != 0; cryptoInfo->ea = EAGetNext (cryptoInfo->ea))
#endif
    {
#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
#if defined (TC_WINDOWS_BOOT_SERPENT)
        serpent_set_key (dk, cryptoInfo->ks);
#elif defined (TC_WINDOWS_BOOT_TWOFISH)
        twofish_set_key ((TwofishInstance *) cryptoInfo->ks, (const u4byte *) dk);
#elif defined (TC_WINDOWS_BOOT_CAMELLIA)
        camellia_set_key (dk, cryptoInfo->ks);
#else
        status = EAInit (dk, cryptoInfo->ks);
        if (status == ERR_CIPHER_INIT_FAILURE)
            goto err;
#endif
#else
        status = EAInit (cryptoInfo->ea, dk, cryptoInfo->ks);
        if (status == ERR_CIPHER_INIT_FAILURE)
            goto err;
#endif
        // Secondary key schedule
#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
#if defined (TC_WINDOWS_BOOT_SERPENT)
        serpent_set_key (dk + 32, cryptoInfo->ks2);
#elif defined (TC_WINDOWS_BOOT_TWOFISH)
        twofish_set_key ((TwofishInstance *)cryptoInfo->ks2, (const u4byte *) (dk + 32));
#elif defined (TC_WINDOWS_BOOT_CAMELLIA)
        camellia_set_key (dk + 32, cryptoInfo->ks2);
#else
        EAInit (dk + 32, cryptoInfo->ks2);
#endif
#else
        EAInit (cryptoInfo->ea, dk + EAGetKeySize (cryptoInfo->ea), cryptoInfo->ks2);
#endif

        // Try to decrypt header
        DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);

        // Check magic 'VERA' and CRC-32 of header fields and master keydata
        if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x56455241
                || (GetHeaderField16 (header, TC_HEADER_OFFSET_VERSION) >= 4 && GetHeaderField32 (header, TC_HEADER_OFFSET_HEADER_CRC) != GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC))
                || GetHeaderField32 (header, TC_HEADER_OFFSET_KEY_AREA_CRC) != GetCrc32 (header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE))
        {
            EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);
#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
            status = ERR_PASSWORD_WRONG;
            goto err;
#else
            continue;
#endif
        }

        // Header decrypted
        status = 0;

        // Hidden volume status
        cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_HIDDEN_VOLUME_SIZE);
        cryptoInfo->hiddenVolume = (cryptoInfo->VolumeSize.LowPart != 0 || cryptoInfo->VolumeSize.HighPart != 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);

#ifdef TC_WINDOWS_BOOT_SHA2
        cryptoInfo->pkcs5 = SHA256;
#else
        cryptoInfo->pkcs5 = RIPEMD160;
#endif

        memcpy (dk, header + HEADER_MASTER_KEYDATA_OFFSET, sizeof (dk));
        EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);

        if (retHeaderCryptoInfo)
            goto ret;

        // Init the encryption algorithm with the decrypted master key
#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
#if defined (TC_WINDOWS_BOOT_SERPENT)
        serpent_set_key (dk, cryptoInfo->ks);
#elif defined (TC_WINDOWS_BOOT_TWOFISH)
        twofish_set_key ((TwofishInstance *) cryptoInfo->ks, (const u4byte *) dk);
#elif defined (TC_WINDOWS_BOOT_CAMELLIA)
        camellia_set_key (dk, cryptoInfo->ks);
#else
        status = EAInit (dk, cryptoInfo->ks);
        if (status == ERR_CIPHER_INIT_FAILURE)
            goto err;
#endif
#else
        status = EAInit (cryptoInfo->ea, dk, cryptoInfo->ks);
        if (status == ERR_CIPHER_INIT_FAILURE)
            goto err;
#endif

        // The secondary master key (if cascade, multiple concatenated)
#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
#if defined (TC_WINDOWS_BOOT_SERPENT)
        serpent_set_key (dk + 32, cryptoInfo->ks2);
#elif defined (TC_WINDOWS_BOOT_TWOFISH)
        twofish_set_key ((TwofishInstance *)cryptoInfo->ks2, (const u4byte *) (dk + 32));
#elif defined (TC_WINDOWS_BOOT_CAMELLIA)
        camellia_set_key (dk + 32, cryptoInfo->ks2);
#else
        EAInit (dk + 32, cryptoInfo->ks2);
#endif
#else
        EAInit (cryptoInfo->ea, dk + EAGetKeySize (cryptoInfo->ea), cryptoInfo->ks2);
#endif
        goto ret;
    }

    status = ERR_PASSWORD_WRONG;

err:
    if (cryptoInfo != retHeaderCryptoInfo)
    {
        crypto_close(cryptoInfo);
        *retInfo = NULL;
    }

ret:
    burn (dk, sizeof(dk));
    return status;
}
Exemple #11
0
u32 SdPadgen()
{
    u32 result;

    SdInfo *info = (SdInfo*)0x20316000;

    u8 movable_seed[0x120] = {0};

    // Load console 0x34 keyY from movable.sed if present on SD card
    if (DebugFileOpen("/movable.sed")) {
        if (!DebugFileRead(&movable_seed, 0x120, 0)) {
            FileClose();
            return 1;
        }
        FileClose();
        if (memcmp(movable_seed, "SEED", 4) != 0) {
            Debug("movable.sed is too corrupt!");
            return 1;
        }
        setup_aeskey(0x34, AES_BIG_INPUT|AES_NORMAL_INPUT, &movable_seed[0x110]);
        use_aeskey(0x34);
    }

    if (!DebugFileOpen("/SDinfo.bin"))
        return 1;
    if (!DebugFileRead(info, 4, 0)) {
        FileClose();
        return 1;
    }

    if (!info->n_entries || info->n_entries > MAX_ENTRIES) {
        Debug("Too many/few entries!");
        return 1;
    }

    Debug("Number of entries: %i", info->n_entries);

    if (!DebugFileRead(info->entries, info->n_entries * sizeof(SdInfoEntry), 4)) {
        FileClose();
        return 1;
    }
    FileClose();

    for(u32 i = 0; i < info->n_entries; i++) {
        Debug ("Creating pad number: %i. Size (MB): %i", i+1, info->entries[i].size_mb);

        PadInfo padInfo = {.keyslot = 0x34, .setKeyY = 0, .size_mb = info->entries[i].size_mb};
        memcpy(padInfo.CTR, info->entries[i].CTR, 16);
        memcpy(padInfo.filename, info->entries[i].filename, 180);

        result = CreatePad(&padInfo);
        if (!result)
            Debug("Done!");
        else
            return 1;
    }

    return 0;
}

static u8* FindNandCtr()
{
    static const char* versions[] = {"4.x", "5.x", "6.x", "7.x", "8.x", "9.x"};
    static const u8* version_ctrs[] = {
        (u8*)0x080D7CAC,
        (u8*)0x080D858C,
        (u8*)0x080D748C,
        (u8*)0x080D740C,
        (u8*)0x080D74CC,
        (u8*)0x080D794C
    };
    static const u32 version_ctrs_len = sizeof(version_ctrs) / sizeof(u32);

    for (u32 i = 0; i < version_ctrs_len; i++) {
        if (*(u32*)version_ctrs[i] == 0x5C980) {
            Debug("System version %s", versions[i]);
            return (u8*)(version_ctrs[i] + 0x30);
        }
    }

    // If value not in previous list start memory scanning (test range)
    for (u8* c = (u8*)0x080D8FFF; c > (u8*)0x08000000; c--) {
        if (*(u32*)c == 0x5C980 && *(u32*)(c + 1) == 0x800005C9) {
            Debug("CTR Start 0x%08X", c + 0x30);
            return c + 0x30;
        }
    }

    return NULL;
}

u32 DumpPartition(char* filename, u32 offset, u32 size, u32 keyslot) {
    DecryptBufferInfo info;
    u8* buffer = BUFFER_ADDRESS;
    u8* ctrStart = FindNandCtr();
    u32 result = 0;

    Debug("Dumping System NAND Partition. Size (MB): %u", size / (1024 * 1024));
    Debug("Filename: %s", filename);

    if (ctrStart == NULL)
        return 1;

    info.keyslot = keyslot;
    info.setKeyY = 0;
    info.size = SECTORS_PER_READ * NAND_SECTOR_SIZE;
    info.buffer = buffer;
    for (u32 i = 0; i < 16; i++) {
        info.CTR[i] = *(ctrStart + (0xF - i)); // The CTR is stored backwards in memory.
    }

    add_ctr(info.CTR, offset / 0x10);

    if (!DebugFileCreate(filename, true))
        return 1;

    u32 n_sectors = size / NAND_SECTOR_SIZE;
    u32 start_sector = offset / NAND_SECTOR_SIZE;
    for (u32 i = 0; i < n_sectors; i += SECTORS_PER_READ) {
        ShowProgress(i, n_sectors);
        sdmmc_nand_readsectors(start_sector + i, SECTORS_PER_READ, buffer);
        DecryptBuffer(&info);
        if (!DebugFileWrite(buffer, NAND_SECTOR_SIZE * SECTORS_PER_READ, i * NAND_SECTOR_SIZE)) {
            result = 1;
            break;
        }
    }

    ShowProgress(0, 0);
    FileClose();

    return result;
}
	void EncryptionModeLRW::Decrypt (byte *data, uint64 length) const
	{
		if_debug (ValidateState ());
		DecryptBuffer (data, length, 1);
	}
int LogBookData::LoadData (_TCHAR *callsign)
{
	DWORD size;
	FILE *fp;
	size_t		success = 0;
	_TCHAR		path[_MAX_PATH];

	ShiAssert(callsign);

	_stprintf(path,_T("%s\\config\\%s.lbk"),FalconDataDirectory,callsign);
	
	fp = _tfopen(path,_T("rb"));
	if(!fp)
	{
		MonoPrint(_T("Couldn't open %s's logbook.\n"),callsign);
		Initialize();
		return FALSE;
	}
	
	fseek(fp,0,SEEK_END);
	size = ftell(fp);
	fseek(fp,0,SEEK_SET);

	if(size != sizeof(LB_PILOT))
	{
		MonoPrint(_T("%s's logbook is old file format.\n"),callsign);
		fclose(fp);
		Initialize();
		return FALSE;
	}

	success = fread(&Pilot, sizeof(LB_PILOT), 1, fp);
	fclose(fp);
	if(success != 1)
	{
		MonoPrint(_T("Failed to read %s's logbook.\n"),callsign);
		Initialize();
		return BAD_READ;
	}

	DecryptBuffer(0x58,(uchar*)&Pilot,sizeof(LB_PILOT));


	if(Pilot.CheckSum) // Somebody changed the data... init
	{
		MonoPrint("Failed checksum");
		Initialize();
		return(FALSE);
	}
	if(gCommsMgr)
	{
		sprintf(path,"%s\\config\\%s.plc",FalconDataDirectory,callsign);
		gCommsMgr->SetStatsFile(path);
	}	

	if(this == &LogBook)
	{
		FalconLocalSession->SetPlayerName(NameWRank());
	 	FalconLocalSession->SetPlayerCallsign(Callsign());
		FalconLocalSession->SetAceFactor(AceFactor());
		FalconLocalSession->SetInitAceFactor(AceFactor());
		FalconLocalSession->SetVoiceID(static_cast<uchar>(Voice()));
		PlayerOptions.LoadOptions ();
		LoadAllRules(Callsign());
		LogState |= LB_LOADED_ONCE;
	}

	return TRUE;
}