You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
307 lines
6.2 KiB
307 lines
6.2 KiB
/*++
|
|
|
|
Copyright (c) 2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
crypt.hxx
|
|
|
|
Abstract:
|
|
|
|
CSecureString: Encrypted string for holding passwords
|
|
|
|
History:
|
|
|
|
12-April-2002 MattRim Created
|
|
6-June-2002 MattRim Adapted for ADMT use
|
|
|
|
--*/
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include <wincrypt.h>
|
|
#include <comutil.h>
|
|
#include "crypt.hxx"
|
|
|
|
#define BAIL() goto exit;
|
|
|
|
CSecureString::CSecureString() :
|
|
m_fEncrypted(false),
|
|
m_fEmpty(true),
|
|
m_pszUnencryptedString(NULL)
|
|
{
|
|
m_EncryptedData.pbData = NULL;
|
|
m_EncryptedData.cbData = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
CSecureString::~CSecureString()
|
|
{
|
|
Reset();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
CSecureString::Reset()
|
|
{
|
|
if (m_pszUnencryptedString) {
|
|
|
|
SecureZeroMemory(m_pszUnencryptedString, wcslen(m_pszUnencryptedString) * sizeof(WCHAR));
|
|
delete [] m_pszUnencryptedString;
|
|
m_pszUnencryptedString = NULL;
|
|
}
|
|
|
|
if (m_EncryptedData.pbData) {
|
|
|
|
SecureZeroMemory(m_EncryptedData.pbData, m_EncryptedData.cbData);
|
|
LocalFree(m_EncryptedData.pbData);
|
|
|
|
m_EncryptedData.pbData = NULL;
|
|
m_EncryptedData.cbData = 0;
|
|
}
|
|
|
|
m_fEmpty = true;
|
|
|
|
return;
|
|
}
|
|
|
|
CSecureString&
|
|
CSecureString::operator=(const CSecureString& rhs)
|
|
{
|
|
bool fSucceeded = false;
|
|
|
|
//
|
|
// Free up our existing contents and reset to an empty state
|
|
//
|
|
Reset();
|
|
|
|
|
|
//
|
|
// Copy the object
|
|
//
|
|
m_fEncrypted = rhs.m_fEncrypted;
|
|
m_fEmpty = rhs.m_fEmpty;
|
|
|
|
if (rhs.m_pszUnencryptedString) {
|
|
|
|
m_pszUnencryptedString = new WCHAR[wcslen(rhs.m_pszUnencryptedString)+1];
|
|
if (!m_pszUnencryptedString) {
|
|
|
|
BAIL();
|
|
}
|
|
|
|
wcscpy(m_pszUnencryptedString, rhs.m_pszUnencryptedString);
|
|
}
|
|
|
|
|
|
if (rhs.m_EncryptedData.pbData) {
|
|
|
|
m_EncryptedData.pbData = new BYTE[rhs.m_EncryptedData.cbData];
|
|
if (!m_EncryptedData.pbData) {
|
|
|
|
BAIL();
|
|
}
|
|
|
|
m_EncryptedData.cbData = rhs.m_EncryptedData.cbData;
|
|
memcpy(m_EncryptedData.pbData, rhs.m_EncryptedData.pbData, rhs.m_EncryptedData.cbData);
|
|
}
|
|
|
|
fSucceeded = true;
|
|
|
|
exit:
|
|
|
|
if (!fSucceeded) {
|
|
|
|
Reset();
|
|
_com_issue_error(E_OUTOFMEMORY);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
CSecureString&
|
|
CSecureString::operator=(const PWCHAR& rhs)
|
|
{
|
|
bool fSucceeded = false;
|
|
|
|
//
|
|
// Free up our existing contents and reset to an empty state
|
|
//
|
|
Reset();
|
|
|
|
//
|
|
// If we're being set to an empty string, nothing much
|
|
// to do.
|
|
//
|
|
|
|
if (rhs == NULL || rhs[0] == L'\0') {
|
|
|
|
// we're done, empty string
|
|
return *this;
|
|
}
|
|
|
|
//
|
|
// Non-empty string, do the encryption
|
|
//
|
|
if (GenerateEncryptedData(rhs)) {
|
|
|
|
fSucceeded = true;
|
|
}
|
|
|
|
|
|
if (!fSucceeded) {
|
|
|
|
Reset();
|
|
_com_issue_error(E_OUTOFMEMORY);
|
|
}
|
|
|
|
m_fEncrypted = true;
|
|
m_fEmpty = false;
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
bool
|
|
CSecureString::Decrypt()
|
|
{
|
|
|
|
DATA_BLOB DecryptedData = {0, NULL};
|
|
DWORD dwStringLength = 0;
|
|
|
|
bool fSuccess = false;
|
|
|
|
//
|
|
// Validate
|
|
//
|
|
|
|
// if already decrypted, or nothing to decrypt, nothing to do
|
|
if (!m_fEncrypted || m_EncryptedData.pbData == NULL) {
|
|
|
|
m_fEncrypted = false;
|
|
fSuccess = true;
|
|
BAIL();
|
|
}
|
|
|
|
|
|
//
|
|
// Try to decrypt the data
|
|
//
|
|
if (!CryptUnprotectData(&m_EncryptedData, // encrypted data
|
|
NULL, // description
|
|
NULL, // entropy
|
|
NULL, // reserved
|
|
NULL, // prompt structure
|
|
CRYPTPROTECT_UI_FORBIDDEN, // no UI
|
|
&DecryptedData)) {
|
|
|
|
BAIL()
|
|
}
|
|
|
|
|
|
//
|
|
// Copy the decrypted string into m_pszUnencryptedString
|
|
//
|
|
dwStringLength = DecryptedData.cbData / sizeof(WCHAR);
|
|
m_pszUnencryptedString = new WCHAR[dwStringLength];
|
|
if (!m_pszUnencryptedString) {
|
|
|
|
BAIL();
|
|
}
|
|
|
|
memcpy(m_pszUnencryptedString, DecryptedData.pbData, DecryptedData.cbData);
|
|
|
|
m_fEncrypted = false;
|
|
fSuccess = true;
|
|
|
|
exit:
|
|
|
|
if (DecryptedData.pbData) {
|
|
|
|
SecureZeroMemory (DecryptedData.pbData, DecryptedData.cbData);
|
|
LocalFree(DecryptedData.pbData);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
void
|
|
CSecureString::ReleaseString()
|
|
{
|
|
|
|
//
|
|
// We always store an encrypted copy of the data, so this is basically a no-op.
|
|
// We just need to destroy the unencrypted buffer.
|
|
//
|
|
|
|
if (m_pszUnencryptedString) {
|
|
|
|
SecureZeroMemory(m_pszUnencryptedString, wcslen(m_pszUnencryptedString) * sizeof(WCHAR));
|
|
delete [] m_pszUnencryptedString;
|
|
m_pszUnencryptedString = NULL;
|
|
}
|
|
|
|
m_fEncrypted = true;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
bool
|
|
CSecureString::GetString(PWCHAR *ppszString)
|
|
{
|
|
|
|
*ppszString = NULL;
|
|
|
|
if (m_fEncrypted) {
|
|
|
|
if (!Decrypt()) {
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
*ppszString = m_pszUnencryptedString;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool
|
|
CSecureString::GenerateEncryptedData(const PWCHAR pszSource)
|
|
{
|
|
DATA_BLOB RawData = {0, NULL};
|
|
bool fSuccess = false;
|
|
|
|
_ASSERT(pszSource != NULL);
|
|
|
|
RawData.pbData = reinterpret_cast<PBYTE>(const_cast<PWCHAR>(pszSource));
|
|
RawData.cbData = (wcslen(pszSource)+1) * sizeof(WCHAR);
|
|
|
|
if (!CryptProtectData(&RawData, // unencrypted data
|
|
L"", // description -- note: this cannot be NULL before XP
|
|
NULL, // entropy
|
|
NULL, // reserved
|
|
NULL, // prompt structure
|
|
CRYPTPROTECT_UI_FORBIDDEN | CRYPTPROTECT_LOCAL_MACHINE, // flags
|
|
&m_EncryptedData)) {
|
|
|
|
BAIL()
|
|
}
|
|
|
|
_ASSERT(m_EncryptedData.pbData != NULL);
|
|
_ASSERT(m_EncryptedData.cbData != 0);
|
|
|
|
fSuccess = true;
|
|
|
|
exit:
|
|
|
|
return fSuccess;
|
|
}
|
|
|