newrandom.cpp

来自「一款密码保险箱源码」· C++ 代码 · 共 293 行

CPP
293
字号
/*
  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"

#if (defined(_WIN32) || defined(_WIN64))

#include "../Util/NewRandom.h"
#include "../Util/MemUtil.h"

static DWORD g_dwNewRandomInstanceCounter = 0;

static unsigned long g_xorW = 0;
static unsigned long g_xorX = 0;
static unsigned long g_xorY = 0;
static unsigned long g_xorZ = 0;

CNewRandom::CNewRandom()
{
	ASSERT(m_vPseudoRandom.size() == 0);

	m_dwCounter = 0;
}

CNewRandom::~CNewRandom()
{
	m_vPseudoRandom.clear();
	
	this->ClearUserEntropyPool();
}

void CNewRandom::Initialize()
{
	g_dwNewRandomInstanceCounter++;

	DWORD dw;
	dw = GetTickCount();
	AddRandomObject(&dw, 4);

	LARGE_INTEGER li;
	QueryPerformanceCounter(&li);
	AddRandomObject(&li, sizeof(LARGE_INTEGER));

	SYSTEMTIME st;
	GetLocalTime(&st);
	AddRandomObject(&st, sizeof(SYSTEMTIME));

	POINT pt;
	GetCursorPos(&pt);
	AddRandomObject(&pt, sizeof(POINT));

	WORD ww;
	ww = (WORD)(rand());
	AddRandomObject(&ww, 2);
	ww = (WORD)(rand());
	AddRandomObject(&ww, 2);
	ww = (WORD)(rand());
	AddRandomObject(&ww, 2);

	GetCaretPos(&pt);
	AddRandomObject(&pt, sizeof(POINT));

	MEMORYSTATUS ms;
	GlobalMemoryStatus(&ms);
	AddRandomObject(&ms, sizeof(MEMORYSTATUS));

	dw = (DWORD)(UINT_PTR)GetActiveWindow();
	AddRandomObject(&dw, 4);

	dw = (DWORD)(UINT_PTR)GetCapture();
	AddRandomObject(&dw, 4);

	dw = (DWORD)(UINT_PTR)GetClipboardOwner();
	AddRandomObject(&dw, 4);

#ifndef _WIN32_WCE
	// No support under Windows CE
	dw = (DWORD)(UINT_PTR)GetClipboardViewer();
	AddRandomObject(&dw, 4);
#endif

	dw = GetCurrentProcessId();
	AddRandomObject(&dw, 4);

	dw = (DWORD)(UINT_PTR)GetCurrentProcess();
	AddRandomObject(&dw, 4);

	dw = (DWORD)(UINT_PTR)GetActiveWindow();
	AddRandomObject(&dw, 4);

	dw = GetCurrentThreadId();
	AddRandomObject(&dw, 4);

	dw = (DWORD)(UINT_PTR)GetCurrentThread();
	AddRandomObject(&dw, 4);

	dw = (DWORD)(UINT_PTR)GetDesktopWindow();
	AddRandomObject(&dw, 4);

	dw = (DWORD)(UINT_PTR)GetFocus();
	AddRandomObject(&dw, 4);

	dw = (DWORD)(UINT_PTR)GetForegroundWindow();
	AddRandomObject(&dw, 4);

#ifndef _WIN32_WCE
	dw = (DWORD)GetInputState();
	AddRandomObject(&dw, 4); 
#endif

	dw = GetMessagePos();
	AddRandomObject(&dw, 4);

#ifndef _WIN32_WCE
	dw = (DWORD)GetMessageTime();
	AddRandomObject(&dw, 4);
#endif

	dw = (DWORD)(UINT_PTR)GetOpenClipboardWindow();
	AddRandomObject(&dw, 4);

	dw = (DWORD)(UINT_PTR)GetProcessHeap();
	AddRandomObject(&dw, 4);

	SYSTEM_INFO si;
	GetSystemInfo(&si);
	AddRandomObject(&si, sizeof(SYSTEM_INFO));

	dw = (DWORD)randXorShift();
	AddRandomObject(&dw, 4);

#ifndef _WIN32_WCE
	STARTUPINFO sui;
	GetStartupInfo(&sui);
	AddRandomObject(&sui, sizeof(STARTUPINFO));
#endif

	AddRandomObject(&g_dwNewRandomInstanceCounter, 4);
}

void CNewRandom::AddRandomObject(__in_bcount(uSize) const void *pObj, size_t uSize)
{
	ASSERT(pObj != NULL); if(pObj == NULL) return;

	const BYTE *p = (const BYTE *)pObj;
	for(size_t i = 0; i < uSize; ++i)
	{
		m_vPseudoRandom.push_back(*p);
		++p;
	}
}

void CNewRandom::AddToUserEntropyPool(const BYTE *pData, DWORD dwSize)
{
	ASSERT(pData != NULL); if(pData == NULL) return;

	for(DWORD i = 0; i < dwSize; ++i)
		m_vUserRandom.push_back(pData[i]);
}

void CNewRandom::ClearUserEntropyPool()
{
	m_vUserRandom.clear();
}

void CNewRandom::GetRandomBuffer(__out_bcount(dwSize) BYTE *pBuf, DWORD dwSize)
{
	sha256_ctx hashctx;
	BYTE aTemp[32];
	DWORD dw;

	ASSERT(pBuf != NULL); if(pBuf == NULL) return;

	if(m_vPseudoRandom.size() == 0) this->Initialize();

	while(dwSize != 0)
	{
		m_dwCounter++;
		sha256_begin(&hashctx);

		if(m_vPseudoRandom.size() > 0)
			sha256_hash(&m_vPseudoRandom[0], (unsigned long)m_vPseudoRandom.size(),
				&hashctx);
		else { ASSERT(FALSE); }

		if(m_vUserRandom.size() > 0)
			sha256_hash(&m_vUserRandom[0], (unsigned long)m_vUserRandom.size(),
				&hashctx);

		sha256_hash((BYTE *)&m_dwCounter, 4, &hashctx);
		sha256_end(aTemp, &hashctx);

		dw = (dwSize < 32) ? dwSize : 32;
		memcpy(pBuf, aTemp, dw);
		pBuf += dw;
		dwSize -= dw;
	}
}

// Seed the xorshift random number generator
void srandXorShift(unsigned long *pSeed128)
{
#ifdef _DEBUG
	static BOOL _bOnceOnly = FALSE;
	ASSERT(_bOnceOnly == FALSE);
	_bOnceOnly = TRUE;
#endif

	ASSERT(pSeed128 != NULL); // No NULL parameter allowed
	if(pSeed128 == NULL) return;

	if((g_xorW == 0) && (g_xorX == 0) && (g_xorY == 0) && (g_xorZ == 0))
	{
		g_xorW = pSeed128[0];
		g_xorX = pSeed128[1];
		g_xorY = pSeed128[2];
		g_xorZ = pSeed128[3];

		if((g_xorW + g_xorX + g_xorY + g_xorZ) == 0) g_xorX += 0xB7E15163;
	}
}

// Fast XorShift random number generator
unsigned long randXorShift()
{
	unsigned long tmp;

	tmp = (g_xorX ^ (g_xorX << 15));
	g_xorX = g_xorY; g_xorY = g_xorZ; g_xorZ = g_xorW;
	g_xorW = (g_xorW ^ (g_xorW >> 21)) ^ (tmp ^ (tmp >> 4));

	return g_xorW;
}

void randCreateUUID(BYTE *pUUID16, CNewRandom *pRandomSource)
{
	BYTE *p = pUUID16;
	DWORD *pdw1 = (DWORD *)pUUID16, *pdw2 = (DWORD *)&pUUID16[4],
		*pdw3 = (DWORD *)&pUUID16[8], *pdw4 = (DWORD *)&pUUID16[12];
	DWORD dw1, dw2, dw3, dw4;

	ASSERT(pRandomSource != NULL); if(pRandomSource == NULL) return;

	ASSERT((sizeof(DWORD) == 4) && (sizeof(USHORT) == 2) && (pUUID16 != NULL));
	if(pUUID16 == NULL) return;

	SYSTEMTIME st;
	ZeroMemory(&st, sizeof(SYSTEMTIME));
	GetSystemTime(&st);

	_PackTimeToStruct(p, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
	p += 5; // +5 => 5 bytes filled
	*p = (BYTE)((st.wMilliseconds >> 2) & 0xFF); // Store milliseconds
	++p; // +1 => 6 bytes filled

	// Use the xorshift random number generator as pseudo-counter
	DWORD dwPseudoCounter = randXorShift();
	memcpy(p, &dwPseudoCounter, 2); // Use only 2/4 bytes
	p += 2; // +2 => 8 bytes filled

	pRandomSource->GetRandomBuffer(p, 8); // +8 => 16 bytes filled

	dw1 = *pdw1; dw2 = *pdw2; dw3 = *pdw3; dw4 = *pdw4; // Load to local

	// Mix buffer using PHTs for better read- and processability
	dw1 += dw2; dw2 += dw1; dw3 += dw4; dw4 += dw3;
	dw2 += dw3; dw3 += dw2; dw1 += dw4; dw4 += dw1;
	dw1 += dw3; dw3 += dw1; dw2 += dw4; dw4 += dw2;
	dw1 += dw2; dw2 += dw1; dw3 += dw4; dw4 += dw3;
	dw2 += dw3; dw3 += dw2; dw1 += dw4; dw4 += dw1;
	dw1 += dw3; dw3 += dw1; dw2 += dw4; dw4 += dw2;

	*pdw1 = dw1; *pdw2 = dw2; *pdw3 = dw3; *pdw4 = dw4; // Save
}

#endif // (defined(_WIN32) || defined(_WIN64))

⌨️ 快捷键说明

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