Click here to Skip to main content
15,892,298 members
Articles / Desktop Programming / MFC

Data encryption with DPAPI

Rate me:
Please Sign up or sign in to vote.
3.73/5 (6 votes)
21 May 2002CPOL4 min read 179.4K   3.9K   44  
A wrapper class for the Data Protection API
//
// (w)ritten by andreas saurwein 2002, mailto:saurwein@uniwares.com
//
#include "StdAfx.h"
#include "protecteddata.h"

CProtectedData::CProtectedData(BOOL bSilent, BOOL bLocal, BOOL bAudit) : 
	m_bSilent(bSilent), 
	m_bLocal(bLocal),
	m_bAudit(bAudit)
{
	m_ProtectedData.cbData = 0;
	m_ProtectedData.pbData = NULL;

	m_Prompt.cbSize = sizeof(m_Prompt);
	m_Prompt.hwndApp = NULL;
	m_Prompt.szPrompt = NULL;
}

CProtectedData::~CProtectedData()
{
#ifndef _UNICODE
	if(m_Prompt.szPrompt)	// only non-unicode builds allocate memory for the conversion
		delete[] m_Prompt.szPrompt;
#endif

	// call FreeProtectedData() before dtor
	ASSERT(m_ProtectedData.cbData==0 && m_ProtectedData.pbData == NULL);
}

void CProtectedData::SetAudit(BOOL bAudit)
{
	m_bAudit = bAudit;
}

void CProtectedData::SetLocal(BOOL bLocal)
{
	m_bLocal = bLocal;
}

void CProtectedData::SetUI(HWND hWnd, LPCTSTR pPrompt)
{
	// setting the UI params clears the silence flag
	m_bSilent = FALSE;

	m_Prompt.hwndApp = hWnd;
#ifdef _UNICODE
	m_Prompt.szPrompt = pPrompt;
#else
	// Convert to Unicode, free if existing
	if(m_Prompt.szPrompt)
		delete[] m_Prompt.szPrompt;

	size_t nLen = strlen(pPrompt);
	m_Prompt.szPrompt = new WCHAR[nLen+1];
	::MultiByteToWideChar(CP_ACP, 0, pPrompt, -1, (LPWSTR)m_Prompt.szPrompt, (int)nLen+1);
#endif
}

void CProtectedData::SetData(LPBYTE pData, DWORD dwSize)
{
	m_pData = pData;
	m_dwSize = dwSize;
}

const DATA_BLOB* CProtectedData::ProtectData()
{
	return ProtectData(NULL, NULL, 0);
}

const DATA_BLOB* CProtectedData::ProtectData(LPCTSTR pDesc)
{
	return ProtectData(pDesc, NULL, 0);
}

const DATA_BLOB* CProtectedData::ProtectData(LPCTSTR pDesc, const CString& rString)
{
	return ProtectData(pDesc, (LPBYTE)(LPCTSTR)rString, rString.GetLength());
}

const DATA_BLOB* CProtectedData::ProtectData(LPCTSTR pDesc, LPCTSTR pString)
{
	return ProtectData(pDesc, (LPBYTE)pString, (DWORD)_tcslen(pString));
}

const DATA_BLOB* CProtectedData::ProtectData(LPCTSTR pDesc, LPBYTE pEntropy, DWORD dwEntropySize)
{
	PCRYPTPROTECT_PROMPTSTRUCT pps = NULL;
	DATA_BLOB dbIn;
	DATA_BLOB dbEntropy;
	PDATA_BLOB pdbEntropy=NULL;

	// cryptoapi takes UNICODE strings, so we need to convert.
	LPWSTR pwDesc = NULL;

	ASSERT(m_dwSize > 0);
	ASSERT(m_pData != NULL);

	// set up the data
	dbIn.cbData = m_dwSize;
	dbIn.pbData = m_pData;

	// set up the entropy
	if(dwEntropySize)
	{
		dbEntropy.cbData = dwEntropySize;
		dbEntropy.pbData = pEntropy;
		pdbEntropy = &dbEntropy;
	}

	// set up the prompt if needed
	if(!m_bSilent)
	{
		m_Prompt.dwPromptFlags = CRYPTPROTECT_PROMPT_ON_PROTECT;
		pps = &m_Prompt;
	}

	// if we have a description for the data_blob, prepare it for use
	if(pDesc && _tcslen(pDesc))
	{

#ifndef _UNICODE
		size_t nLen = strlen(pDesc);
		pwDesc = new WCHAR[nLen+1];
		::MultiByteToWideChar(CP_ACP, 0, pDesc, -1, pwDesc, (int)nLen+1);
#else
		pwDesc = (LPWSTR)pDesc;
#endif
	}

	m_ProtectedData.cbData = 0;
	m_ProtectedData.pbData = NULL;

	//
	// prepare the flags
	//
	DWORD dwFlags = NULL;
	if(m_bSilent)
		dwFlags |= CRYPTPROTECT_UI_FORBIDDEN;

	if(m_bLocal)
		dwFlags |= CRYPTPROTECT_LOCAL_MACHINE;

	if(m_bAudit)
		dwFlags |= CRYPTPROTECT_AUDIT;

	// do the encryption
	::CryptProtectData(&dbIn, pwDesc, pdbEntropy, NULL, pps, dwFlags, &m_ProtectedData);

#ifndef _UNICODE
	if(pwDesc) delete[] pwDesc;
#endif

	return &m_ProtectedData;
}

void CProtectedData::FreeProtectedData()
{
	if(m_ProtectedData.pbData)
	{
		::LocalFree(m_ProtectedData.pbData);
		m_ProtectedData.pbData = NULL;
		m_ProtectedData.cbData = 0;
	}
}

DATA_BLOB* CProtectedData::UnprotectData()
{
	return UnprotectData(NULL, NULL, 0);
}

DATA_BLOB* CProtectedData::UnprotectData(LPTSTR* pDesc)
{
	return UnprotectData(pDesc, NULL, 0);
}

DATA_BLOB* CProtectedData::UnprotectData(LPTSTR* pDesc, const CString& rString)
{
	return UnprotectData(pDesc, (LPBYTE)(LPCTSTR)rString, rString.GetLength());
}

DATA_BLOB* CProtectedData::UnprotectData(LPTSTR* pDesc, LPCTSTR pString)
{
	return UnprotectData(pDesc, (LPBYTE)pString, (DWORD)_tcslen(pString));
}

DATA_BLOB* CProtectedData::UnprotectData(LPTSTR* pDesc, LPBYTE pEntropy, DWORD dwEntropySize)
{
	PCRYPTPROTECT_PROMPTSTRUCT pps = NULL;
	DATA_BLOB dbIn;
	DATA_BLOB dbEntropy;
	PDATA_BLOB pdbEntropy=NULL;
	LPWSTR pwDesc = NULL;

	ASSERT(m_dwSize > 0);
	ASSERT(m_pData != NULL);

	// set up the data
	dbIn.cbData = m_dwSize;
	dbIn.pbData = m_pData;

	// set up the entropy
	if(dwEntropySize)
	{
		dbEntropy.cbData = dwEntropySize;
		dbEntropy.pbData = pEntropy;
		pdbEntropy = &dbEntropy;
	}

	// set up the prompt if needed
	if(!m_bSilent)
	{
		m_Prompt.dwPromptFlags = CRYPTPROTECT_PROMPT_ON_UNPROTECT;
		pps = &m_Prompt;
	}

	m_ProtectedData.cbData = 0;
	m_ProtectedData.pbData = NULL;

	//
	// prepare the flags
	//
	DWORD dwFlags = NULL;
	if(m_bSilent)
		dwFlags |= CRYPTPROTECT_UI_FORBIDDEN;

	if(m_bLocal)
		dwFlags |= CRYPTPROTECT_LOCAL_MACHINE;

	if(m_bAudit)
		dwFlags |= CRYPTPROTECT_AUDIT;

	// do the encryption
	if(::CryptUnprotectData(&dbIn, pDesc ? &pwDesc : NULL, pdbEntropy, NULL, pps, dwFlags, &m_ProtectedData) && pDesc)
	{
		// if pDesc actuall points to somewhere, put the description there if available in pwDesc
		if(pwDesc && wcslen(pwDesc))
		{
#ifndef _UNICODE
			BOOL bDefault;
			size_t nLen = wcslen(pwDesc);
			LPSTR p = (LPSTR) ::LocalAlloc(LPTR, nLen+1);
			::WideCharToMultiByte(CP_ACP, 0, pwDesc, -1, p, (int)nLen+1, _T(""), &bDefault);
			*pDesc = p;
#else
			*pDesc = pwDesc;
#endif
		}
	}
	return &m_ProtectedData;
}

void CProtectedData::FreeUnprotectedData()
{
	if(m_ProtectedData.pbData)
	{
		::LocalFree(m_ProtectedData.pbData);
		m_ProtectedData.pbData = NULL;
		m_ProtectedData.cbData = 0;
	}
}

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Portugal Portugal
Software Smith, Blacksmith, Repeat Founder, Austrian, Asgardian.

Comments and Discussions