pwmanager.cpp

来自「一款密码保险箱源码」· C++ 代码 · 共 2,201 行 · 第 1/5 页

CPP
2,201
字号
/*
  KeePass Password Safe - The Open-Source Password Manager
  Copyright (C) 2003-2007 Dominik Reichl <dominik.reichl@t-online.de>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "StdAfx.h"
#include "PwManager.h"
#include "Crypto/TwofishClass.h"
#include "Crypto/SHA2/SHA2.h"
#include "Crypto/ARCFour.h"
#include "Util/PwUtil.h"
#include "Util/MemUtil.h"
#include "Util/StrUtil.h"
#include "Util/TranslateEx.h"

static const BYTE g_uuidZero[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
static PW_TIME g_pwTimeNever = { 2999, 12, 28, 23, 59, 59 };
static char g_pNullString[4] = { 0, 0, 0, 0 };

CPwManager::CPwManager()
{
	m_pEntries = NULL;
	m_dwNumEntries = 0;
	m_dwMaxEntries = 0;

	m_pGroups = NULL;
	m_dwNumGroups = 0;
	m_dwMaxGroups = 0;

	m_pLastEditedEntry = NULL;
	m_nAlgorithm = ALGO_AES;
	m_dwKeyEncRounds = PWM_STD_KEYENCROUNDS;

	memset(m_pMasterKey, 0, 32);

	_AllocGroups(PWM_NUM_INITIAL_GROUPS);
	_AllocEntries(PWM_NUM_INITIAL_ENTRIES);

	m_random.GetRandomBuffer(m_pSessionKey, PWM_SESSION_KEY_SIZE);
}

CPwManager::~CPwManager()
{
	this->CleanUp();
}

void CPwManager::InitPrimaryInstance()
{
	ASSERT((m_pLastEditedEntry == NULL) && (memcmp(m_pMasterKey, g_pNullString, 4) == 0));
	ASSERT((m_nAlgorithm == ALGO_AES) && (m_dwKeyEncRounds == PWM_STD_KEYENCROUNDS));

	DWORD dwInitXorShift[4];
	m_random.GetRandomBuffer((BYTE *)&dwInitXorShift, 16);
	srandXorShift(dwInitXorShift);

	ASSERT(sizeof(BYTE) == 1);
}

void CPwManager::CleanUp()
{
	_DeleteEntryList(TRUE);
	m_dwNumEntries = 0;
	m_dwMaxEntries = 0;

	_DeleteGroupList(TRUE);
	m_dwNumGroups = 0;
	m_dwMaxGroups = 0;

	m_pLastEditedEntry = NULL;

	mem_erase(m_pMasterKey, 32);
}

int CPwManager::SetMasterKey(const TCHAR *pszMasterKey, BOOL bDiskDrive, const TCHAR *pszSecondKey, const CNewRandomInterface *pARI, BOOL bOverwrite)
{
	size_t uKeyLen, uKeyLen2 = 0, uFileSize, uRead;
	TCHAR szFile[2048];
	sha256_ctx sha32;
	char *paKey = NULL;
	char *paKey2 = NULL;
	unsigned char aFileKey[32];
	unsigned char aPasswordKey[32];
	BOOL bReadNormal;

	ASSERT(pszMasterKey != NULL); if(pszMasterKey == NULL) return PWE_INVALID_PARAM;

#ifdef _UNICODE
	ASSERT(sizeof(TCHAR) >= 2);
	paKey = _StringToAnsi(pszMasterKey);
#else
	ASSERT(sizeof(TCHAR) == 1);
	size_t sizeANSIKeyBuffer = _tcslen(pszMasterKey) + 1;
	paKey = new char[sizeANSIKeyBuffer];
	ASSERT(paKey != NULL); if(paKey == NULL) return PWE_NO_MEM;
	strcpy_s(paKey, sizeANSIKeyBuffer, pszMasterKey);
#endif

	ASSERT(paKey != NULL); if(paKey == NULL) return PWE_NO_MEM;

	if(pszSecondKey != NULL)
	{
#ifdef _UNICODE
		ASSERT(sizeof(TCHAR) >= 2);
		paKey2 = _StringToAnsi(pszSecondKey);
#else
		ASSERT(sizeof(TCHAR) == 1);
		size_t sizeByteBuffer = _tcslen(pszSecondKey) + 1;
		paKey2 = new char[sizeByteBuffer];
		ASSERT(paKey2 != NULL); if(paKey2 == NULL) return PWE_NO_MEM;
		strcpy_s(paKey2, sizeByteBuffer, pszSecondKey);
#endif

		ASSERT(paKey2 != NULL); if(paKey2 == NULL) return PWE_NO_MEM;

		uKeyLen2 = szlen(paKey2);
		ASSERT(uKeyLen2 != 0);
	}

	uKeyLen = strlen(paKey);
	ASSERT(uKeyLen != 0);
	if(uKeyLen == 0) { SAFE_DELETE_ARRAY(paKey); return PWE_INVALID_KEY; }

	if(bDiskDrive == FALSE)
	{
		sha256_begin(&sha32);
		sha256_hash((unsigned char *)paKey, static_cast<unsigned long>(uKeyLen),
			&sha32);
		sha256_end((unsigned char *)m_pMasterKey, &sha32);

		mem_erase((unsigned char *)paKey, uKeyLen);
		SAFE_DELETE_ARRAY(paKey);
		return PWE_SUCCESS;
	}
	else
	{
		if(pszSecondKey == NULL)
		{
			mem_erase((unsigned char *)paKey, uKeyLen);
			SAFE_DELETE_ARRAY(paKey); // Don't need ASCII key any more from on now

			_tcscpy_s(szFile, _countof(szFile), pszMasterKey);
			if(szFile[_tcslen(szFile) - 1] == _T('\\'))
				_tcscat_s(szFile, _countof(szFile), PWS_DEFAULT_KEY_FILENAME);

			if(pARI == NULL) // If pARI is NULL: load key from disk
			{
				FILE *fp = NULL;

				_tfopen_s(&fp, szFile, _T("rb"));
				if(fp == NULL) return PWE_NOFILEACCESS_READ_KEY;
				fseek(fp, 0, SEEK_END);
				uFileSize = (unsigned long)ftell(fp);
				fseek(fp, 0, SEEK_SET);

				bReadNormal = TRUE;

				if(uFileSize == 32)
				{
					if(fread(m_pMasterKey, 1, 32, fp) != 32)
					{
						fclose(fp); fp = NULL;
						return PWE_FILEERROR_READ;
					}

					bReadNormal = FALSE;
				}
				else if(uFileSize == 64)
				{
					if(LoadHexKey32(fp, m_pMasterKey) == FALSE)
					{
						fseek(fp, 0, SEEK_SET);
					}
					else bReadNormal = FALSE;
				}

				if(bReadNormal == TRUE)
				{
					sha256_begin(&sha32);
					while(1)
					{
						uRead = (unsigned long)fread((unsigned char *)szFile, 1, 2048, fp);
						if(uRead == 0) break;
						sha256_hash((unsigned char *)szFile,
							static_cast<unsigned long>(uRead), &sha32);
						if(uRead != 2048) break;
					}
					sha256_end((unsigned char *)m_pMasterKey, &sha32);
				}

				fclose(fp); fp = NULL;
				return PWE_SUCCESS;
			}
			else // pARI is not NULL: save key to disk
			{
				FILE *fp = NULL;
				unsigned char aRandomBytes[32];

				_tfopen_s(&fp, szFile, _T("rb")); // Does the file exist already?
				if((fp != NULL) && (bOverwrite == FALSE)) { fclose(fp); fp = NULL; return PWE_NOFILEACCESS_READ_KEY; }
				if(fp != NULL) { fclose(fp); fp = NULL; } // We must close it before opening for write

				if(pARI->GenerateRandomSequence(32, aRandomBytes) == FALSE) return PWE_INVALID_RANDOMSOURCE;

				fp = NULL;
				_tfopen_s(&fp, szFile, _T("wb"));
				if(fp == NULL) return PWE_NOFILEACCESS_WRITE;
				if(SaveHexKey32(fp, aRandomBytes) == FALSE) { fclose(fp); fp = NULL; return PWE_FILEERROR_WRITE; }
				fclose(fp); fp = NULL;

				memcpy(m_pMasterKey, aRandomBytes, 32);
				return PWE_SUCCESS;
			}
		}
		else // pszSecondKey != NULL
		{
			mem_erase((unsigned char *)paKey, uKeyLen);
			SAFE_DELETE_ARRAY(paKey); // Don't need ASCII key any more from on now

			_tcscpy_s(szFile, _countof(szFile), pszMasterKey);
			if(szFile[_tcslen(szFile) - 1] == _T('\\'))
				_tcscat_s(szFile, _countof(szFile), PWS_DEFAULT_KEY_FILENAME);

			if(pARI == NULL) // If pARI is NULL: load key from disk
			{
				FILE *fp = NULL;

				_tfopen_s(&fp, szFile, _T("rb"));
				if(fp == NULL) return PWE_NOFILEACCESS_READ_KEY;
				fseek(fp, 0, SEEK_END);
				uFileSize = (unsigned long)ftell(fp);
				fseek(fp, 0, SEEK_SET);

				bReadNormal = TRUE;

				if(uFileSize == 32)
				{
					if(fread(aFileKey, 1, 32, fp) != 32)
					{
						fclose(fp); fp = NULL;
						return PWE_FILEERROR_READ;
					}

					bReadNormal = FALSE;
				}
				else if(uFileSize == 64)
				{
					if(LoadHexKey32(fp, aFileKey) == FALSE)
					{
						fseek(fp, 0, SEEK_SET);
					}
					else bReadNormal = FALSE;
				}

				if(bReadNormal == TRUE)
				{
					sha256_begin(&sha32);
					while(1)
					{
						uRead = (unsigned long)fread((unsigned char *)szFile, 1, 2048, fp);
						if(uRead == 0) break;
						sha256_hash((unsigned char *)szFile,
							static_cast<unsigned long>(uRead), &sha32);
						if(uRead != 2048) break;
					}
					sha256_end((unsigned char *)aFileKey, &sha32);
				}

				fclose(fp); fp = NULL;

				sha256_begin(&sha32);
				sha256_hash((unsigned char *)paKey2,
					static_cast<unsigned long>(uKeyLen2), &sha32);
				sha256_end((unsigned char *)aPasswordKey, &sha32);

				mem_erase((unsigned char *)paKey2, uKeyLen2);
				SAFE_DELETE_ARRAY(paKey);

				sha256_begin(&sha32);
				sha256_hash(aPasswordKey, 32, &sha32);
				sha256_hash(aFileKey, 32, &sha32);
				sha256_end((unsigned char *)m_pMasterKey, &sha32);

				mem_erase((unsigned char *)aPasswordKey, 32);
				mem_erase((unsigned char *)aFileKey, 32);
				return PWE_SUCCESS;
			}
			else // pARI is not NULL: save key to disk
			{
				FILE *fp = NULL;
				unsigned char aRandomBytes[32];

				_tfopen_s(&fp, szFile, _T("rb")); // Does the file exist already?
				if((fp != NULL) && (bOverwrite == FALSE)) { fclose(fp); fp = NULL; return PWE_NOFILEACCESS_READ_KEY; }
				if(fp != NULL) { fclose(fp); fp = NULL; } // We must close it before opening for write

				if(pARI->GenerateRandomSequence(32, aRandomBytes) == FALSE) return PWE_INVALID_RANDOMSOURCE;

				_tfopen_s(&fp, szFile, _T("wb"));
				if(fp == NULL) return PWE_NOFILEACCESS_WRITE;
				if(SaveHexKey32(fp, aRandomBytes) == FALSE) { fclose(fp); fp = NULL; return PWE_FILEERROR_WRITE; }
				fclose(fp); fp = NULL;

				ASSERT(uKeyLen2 != 0);
				sha256_begin(&sha32);
				sha256_hash((unsigned char *)paKey2,
					static_cast<unsigned long>(uKeyLen2), &sha32);
				sha256_end((unsigned char *)aPasswordKey, &sha32);

				mem_erase((unsigned char *)paKey2, uKeyLen2);
				SAFE_DELETE_ARRAY(paKey);

				sha256_begin(&sha32);
				sha256_hash(aPasswordKey, 32, &sha32);
				sha256_hash(aRandomBytes, 32, &sha32);
				sha256_end((unsigned char *)m_pMasterKey, &sha32);

				mem_erase((unsigned char *)aPasswordKey, 32);
				mem_erase((unsigned char *)aFileKey, 32);
				return PWE_SUCCESS;
			}
		}
	}

	// return PWE_UNKNOWN; // Unreachable anyway
}

BOOL CPwManager::SetAlgorithm(int nAlgorithm)
{
	ASSERT((nAlgorithm == ALGO_AES) || (nAlgorithm == ALGO_TWOFISH));
	if((nAlgorithm != ALGO_AES) && (nAlgorithm != ALGO_TWOFISH)) return FALSE;

	m_nAlgorithm = nAlgorithm;
	return TRUE;
}

int CPwManager::GetAlgorithm()
{
	return m_nAlgorithm;
}

void CPwManager::_AllocEntries(DWORD uEntries)
{
	PW_ENTRY *p;
	DWORD dwEntries;

	ASSERT((uEntries != 0) && (uEntries != DWORD_MAX));
	if(uEntries == 0) return;

	dwEntries = m_dwNumEntries;

	// If we already have allocated enough entries just return
	if(uEntries <= m_dwMaxEntries) return;

	p = new PW_ENTRY[uEntries];
	if(p == NULL) { ASSERT(FALSE); return; }
	memset(p, 0, sizeof(PW_ENTRY) * uEntries);

	if((m_dwNumEntries > 0) && (m_pEntries != NULL))
	{
		memcpy(p, m_pEntries, sizeof(PW_ENTRY) * m_dwNumEntries);
		_DeleteEntryList(FALSE);
	}

	m_dwNumEntries = dwEntries;
	m_dwMaxEntries = uEntries;
	m_pEntries = p;
}

void CPwManager::_AllocGroups(DWORD uGroups)
{
	PW_GROUP *p;
	DWORD dwGroups;

	ASSERT((uGroups != 0) && (uGroups != DWORD_MAX));
	if((uGroups == 0) || (uGroups == DWORD_MAX)) return;

	dwGroups = m_dwNumGroups;

	// If we already have allocated enough entries just return
	if(uGroups <= m_dwMaxGroups) return;

	p = new PW_GROUP[uGroups];
	if(p == NULL) { ASSERT(FALSE); return; }
	memset(p, 0, sizeof(PW_GROUP) * uGroups);

	if((m_dwNumGroups > 0) && (m_pGroups != NULL))
	{
		memcpy(p, m_pGroups, sizeof(PW_GROUP) * m_dwNumGroups);
		_DeleteGroupList(FALSE);
	}

	m_dwNumGroups = dwGroups;
	m_dwMaxGroups = uGroups;
	m_pGroups = p;
}

void CPwManager::_DeleteEntryList(BOOL bFreeStrings)
{
	unsigned long uCurrentEntry;

	if(m_pEntries == NULL) return; // Nothing to delete

	if(bFreeStrings == TRUE)
	{
		for(uCurrentEntry = 0; uCurrentEntry < m_dwNumEntries; uCurrentEntry++)
		{
			SAFE_DELETE_ARRAY(m_pEntries[uCurrentEntry].pszTitle);
			SAFE_DELETE_ARRAY(m_pEntries[uCurrentEntry].pszURL);
			SAFE_DELETE_ARRAY(m_pEntries[uCurrentEntry].pszUserName);
			SAFE_DELETE_ARRAY(m_pEntries[uCurrentEntry].pszPassword);
			SAFE_DELETE_ARRAY(m_pEntries[uCurrentEntry].pszAdditional);
			SAFE_DELETE_ARRAY(m_pEntries[uCurrentEntry].pszBinaryDesc);
			SAFE_DELETE_ARRAY(m_pEntries[uCurrentEntry].pBinaryData);
		}
	}

	if(m_dwNumEntries != 0) // Erase ALL data
	{
		mem_erase((unsigned char *)m_pEntries,
			sizeof(PW_ENTRY) * m_dwNumEntries);
	}

	SAFE_DELETE_ARRAY(m_pEntries);

	m_dwNumEntries = 0;
	m_dwMaxEntries = 0;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?