Click here to Skip to main content
15,884,237 members
Articles / Desktop Programming / MFC

Exile 1.8 - The Password Manager

Rate me:
Please Sign up or sign in to vote.
4.57/5 (51 votes)
6 Mar 20058 min read 255K   7.4K   111  
Yet another password manager.
/********************************************************************
	Created:	27/3/2004, 21:37
	File name: 	D:\Projects\Exile\Exile\security.cpp
	File path:	D:\Projects\Exile\Exile
	File base:	security
	File ext:	cpp
	Author:		Gogolev Anton
*********************************************************************/

#include "StdAfx.h"
#include "../MD5/MD5.h"
#include "Security.h"

void GeneratePrivateKey(CString &rstrUserName, CString &rstrPassword, int nKeyLength, KEYINFO &rKeyInfo)
{
	rKeyInfo.pbKey = new BYTE[nKeyLength / 8];
	rKeyInfo.nKeySize = nKeyLength;
	MD5HASH hs[8]; // This is maximum as 1024 bit key is the longest available

	size_t sUserName = rstrUserName.GetLength() * sizeof(TCHAR);
	size_t sPassword = rstrPassword.GetLength() * sizeof(TCHAR);

	BYTE *pBuffer = 0; // Buffer for holding data which is to be hashed

	for(int n = 0; n < nKeyLength / 8 / 16; ++n)
	{
		// In each round we use User Name, Password and all previous 
		// hashes to get a new hash.
		// Md5GetExpandedBufferSize() calculates the size of a buffer we'll need.
		size_t sBuffer = ::Md5GetExpandedBufferSize(sUserName + sPassword + sizeof(MD5HASH) * n);
		pBuffer = new BYTE[sBuffer];

		// This is always like that
		memmove(pBuffer, rstrUserName.LockBuffer(), sUserName);
		memmove(pBuffer + sUserName, rstrPassword.LockBuffer(), sPassword);

		// And now append previous hashes
		for(int i = 0; i < n; ++i)
		{
			memmove(pBuffer + sUserName + sPassword + sizeof(MD5HASH) * i, (void *)&hs[i], sizeof(MD5HASH));
		} // for

		// Now hash what we have
		size_t sSgSize = sUserName + sPassword + sizeof(MD5HASH) * n;
		::Md5ExpandData(pBuffer, sSgSize, sBuffer);
		::Md5HashData((MD5_WORD *)pBuffer, sBuffer / 64, hs[n]);

		// When we have this loop for the first time, hs[0]
		// equals to "User Name + Password" hash which is exactly what
		// we need
		if(0 == n)
			rKeyInfo.hsPassword = hs[0];

		FreeBuffer(pBuffer, sBuffer);
	} // for

	// Now moving to buffer we allocated...
	memmove(rKeyInfo.pbKey, hs, nKeyLength / 8);

	// ...and cleaning up
	CleanBuffer(hs, sizeof(MD5HASH) * 8);
}

void GeneratePasswordHash(CString &rstrUserName, CString &rstrPassword, MD5HASH &rhsPassword)
{
	size_t sUserName = rstrUserName.GetLength() * sizeof(TCHAR);
	size_t sPassword = rstrPassword.GetLength() * sizeof(TCHAR);

	BYTE *pBuffer = 0; // Buffer for holding data which is to be hashed

	size_t sBuffer = ::Md5GetExpandedBufferSize(sUserName + sPassword);
	pBuffer = new BYTE[sBuffer];

	memmove(pBuffer, rstrUserName.LockBuffer(), sUserName);
	memmove(pBuffer + sUserName, rstrPassword.LockBuffer(), sPassword);

	::Md5ExpandData(pBuffer, sUserName + sPassword, sBuffer);
	::Md5HashData((MD5_WORD *)pBuffer, sBuffer / 64, rhsPassword);

	FreeBuffer(pBuffer, sUserName + sPassword);
}

void GeneratePassword(TCHAR *pszCharSet, int nCharSetLength, DWORD *pdwData,
					  int nDataLength, int nPasswordLength, TCHAR *pszPassword)
{
	if((0 == pszCharSet) || (0 == nCharSetLength) || (0 == pdwData) || (0 == nDataLength) || 
		(0 == nPasswordLength) || (0 == pszPassword))
		return;

	// First, hash ;) data we have and a character set
	size_t sData, sBuffer;
	sData = sizeof(TCHAR) * nCharSetLength;
	sBuffer = ::Md5GetExpandedBufferSize(sData);

	// Character set
	BYTE *pBuffer = new BYTE[sBuffer];
	MD5HASH hsCharset, hsData;

	memmove(pBuffer, (void *)pszCharSet, sData);

	::Md5ExpandData(pBuffer, sData, sBuffer);
	::Md5HashData((MD5_WORD *)pBuffer, sBuffer / 64, hsCharset);

	FreeBuffer(pBuffer, sBuffer);

	// Input data
	sData = sizeof(DWORD) * nDataLength;
	sBuffer = ::Md5GetExpandedBufferSize(sData);

	pBuffer = new BYTE[sBuffer];

	memmove(pBuffer, (void *)pdwData, sData);

	::Md5ExpandData(pBuffer, sData, sBuffer);
	::Md5HashData((MD5_WORD *)pBuffer, sBuffer / 64, hsData);

	FreeBuffer(pBuffer, sBuffer);

	// Done with preparations. Now generating password
	unsigned int nChar = 0;

	for(int n = 0; n < nPasswordLength; ++n)
	{
		// Have several versions
		switch(n % 4) 
		{
		case 0:
			nChar = hsCharset.wA ^ pdwData[n % nDataLength] ^ hsData.wD;
			break;
		case 1:
			nChar = hsCharset.wB ^ pdwData[n % nDataLength] ^ hsData.wC;
			break;
		case 2:
			nChar = hsCharset.wC ^ pdwData[n % nDataLength] ^ hsData.wB;
			break;
		case 3:
			nChar = hsCharset.wD ^ pdwData[n % nDataLength] ^ hsData.wA;
			break;
		default:
			break;
		} // switch

		nChar %= nCharSetLength;
		pszPassword[n] = pszCharSet[nChar];
	} // for

	// Done
	CleanBuffer(&hsCharset, sizeof(MD5HASH));
	CleanBuffer(&hsData, sizeof(MD5HASH));
}

void FreeBuffer(void *pBuffer, size_t sBuffer)
{
	// Do it a couple of times
	memset(pBuffer, 0, sBuffer);
	memset(pBuffer, 0xFFFF, sBuffer);

	delete [] pBuffer;
}

void CleanBuffer(void *pBuffer, size_t sBuffer)
{
	// Do it a couple of times
	memset(pBuffer, 0, sBuffer);
	memset(pBuffer, 0xFFFF, sBuffer);
}

void CleanString(CString &rstrS)
{
	for(int n = 0; n < rstrS.GetLength(); ++n)
	{
		rstrS.SetAt(n, _T('0'));
	} // for
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Russian Federation Russian Federation
I'll think about it later on...

Comments and Discussions