bool SecurityUser::IsPasswordUpdated(SecurityUserSPtr const & other) { bool needUpdate = false; if(this->AccountType == SecurityPrincipalAccountType::DomainUser) { if(other) { wstring originalPswd = password_; wstring currentPswd = other->Password; if(this->isPasswordEncrypted_) { SecureString pswd; CryptoUtility::DecryptText(password_, pswd); originalPswd = pswd.GetPlaintext(); } if(other->isPasswordEncrypted_) { SecureString pswd; CryptoUtility::DecryptText(other->password_, pswd); currentPswd = pswd.GetPlaintext(); } needUpdate = (originalPswd != currentPswd); originalPswd.clear(); currentPswd.clear(); } } return needUpdate; }
ErrorCode AccountHelper::GeneratePasswordForNTLMAuthenticatedUser(wstring const& accountName, SecureString const & passwordSecret, __inout SecureString & password) { #if defined(PLATFORM_UNIX) wstring str = move(accountName + passwordSecret.GetPlaintext()); auto hashInput = StringToByteBuffer(str); SecureZeroMemory((void*)str.c_str(), str.size() * sizeof(wchar_t)); ByteBuffer hashedData; auto errorCode = LinuxCryptUtil().ComputeHash(hashInput, hashedData); SecureZeroMemory(hashInput.data(), hashInput.size()); if (!errorCode.IsSuccess()) return errorCode; #else // TODO: improve password generation by using a secret HCRYPTPROV hCryptProv = NULL; HCRYPTHASH hHash = NULL; BOOL result = CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT); KFinally([=] { if(hCryptProv) CryptReleaseContext(hCryptProv, 0); }); if(result) { result = CryptCreateHash(hCryptProv, CALG_SHA_512, 0, 0, &hHash); } KFinally([=] { if (hHash) CryptDestroyHash(hHash); }); if(result) { wstring hashData = move(accountName + passwordSecret.GetPlaintext()); result = CryptHashData(hHash, (BYTE *)hashData.c_str(), (DWORD)hashData.size() * sizeof(WCHAR), 0); SecureZeroMemory((void *)hashData.c_str(), hashData.size() * sizeof(WCHAR)); } DWORD dataSize = 0; DWORD dataSizeLength = sizeof(dataSize); if(result) { result = CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&dataSize, &dataSizeLength, 0); } vector<BYTE> hashedData(dataSize); if(result) { ASSERT_IF(dataSize == 0, "dataSize should be set to a positive value"); result = CryptGetHashParam(hHash, HP_HASHVAL, hashedData.data(), &dataSize, 0); if(!result) { Common::Assert::CodingError("Unable to retrieve hash value from the crypt framework"); } } else { TraceWarning( TraceTaskCodes::Common, TraceType_AccountHelper, "Error generating password"); return ErrorCodeValue::OperationFailed; } #endif wstring value; StringWriter writer(value); writer.Write("{0}", PasswordPrefix); for(auto it = hashedData.begin(); it != hashedData.end(); ++it) { writer.Write("{0:x}", (*it)); } password = SecureString(move(value)); return ErrorCodeValue::Success; }
ErrorCode AccountHelper::GeneratePasswordForNTLMAuthenticatedUser( wstring const& accountName, SecureString const & passwordSecret, X509StoreLocation::Enum storeLocation, wstring const & x509StoreName, wstring const & x509Thumbprint, __inout SecureString & password) { TraceInfo( TraceTaskCodes::Common, TraceType_AccountHelper, "GeneratePasswordForNTLMAuthenticatedUser: AccountName={0}, StoreLocation={1}, StoreName={2}, Thumbprint={3}", accountName, storeLocation, x509StoreName, x509Thumbprint); shared_ptr<X509FindValue> findValue; auto errorCode = X509FindValue::Create(X509FindType::FindByThumbprint, x509Thumbprint, findValue); if(!errorCode.IsSuccess()) { TraceWarning( TraceTaskCodes::Common, TraceType_AccountHelper, "The thumbprint is invalid. Thumbprint={0}, ErrorCode={1}", x509Thumbprint, errorCode); return errorCode; } CertContextUPtr certContext; errorCode = CryptoUtility::GetCertificate( storeLocation, x509StoreName, findValue, certContext); if(!errorCode.IsSuccess()) { TraceWarning( TraceTaskCodes::Common, TraceType_AccountHelper, "GetCertificate for {0} failed with {1}", x509Thumbprint, errorCode); return errorCode; } ByteBuffer signedMessageBuffer; errorCode = CryptoUtility::SignMessage(passwordSecret.GetPlaintext(), certContext, signedMessageBuffer); if(!errorCode.IsSuccess()) { TraceWarning( TraceTaskCodes::Common, TraceType_AccountHelper, "SignMessage failed with {0}. Thumbprint={1}", errorCode, x509Thumbprint); return errorCode; } ResourceHolder<vector<BYTE>> signedMessageBufferHolder( move(signedMessageBuffer), [](ResourceHolder<vector<BYTE>> * thisPtr) { SecureZeroMemory((void *)thisPtr->Value.data(), thisPtr->Value.size()); }); #ifdef PLATFORM_UNIX ByteBuffer hashedSignedMsg; LinuxCryptUtil cryptoUtil; errorCode = cryptoUtil.ComputeHash(signedMessageBuffer, hashedSignedMsg); if(!errorCode.IsSuccess()) return errorCode; ByteBuffer derivedKey; errorCode = cryptoUtil.DeriveKey(hashedSignedMsg, derivedKey); if(!errorCode.IsSuccess()) return errorCode; wstring str = move(accountName + passwordSecret.GetPlaintext()); auto dataInputForHmac = StringToByteBuffer(str); SecureZeroMemory((void*)str.c_str(), str.size() * sizeof(wchar_t)); ByteBuffer hashedData; errorCode = cryptoUtil.ComputeHmac(dataInputForHmac, derivedKey, hashedData); SecureZeroMemory(dataInputForHmac.data(), dataInputForHmac.size()); if (!errorCode.IsSuccess()) return errorCode; #else HCRYPTPROV hCryptProv = NULL; if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { errorCode = ErrorCode::FromWin32Error(); TraceWarning( TraceTaskCodes::Common, TraceType_AccountHelper, "CryptAcquireContext failed with {0}", errorCode); return errorCode; } ResourceHolder<HCRYPTPROV> hCryptProvHolder( hCryptProv, [](ResourceHolder<HCRYPTPROV> * thisPtr) { CryptReleaseContext(thisPtr->Value, 0); }); HCRYPTHASH hHash = NULL; if(!CryptCreateHash(hCryptProv, CALG_SHA_512, 0, 0, &hHash)) { errorCode = ErrorCode::FromWin32Error(); TraceWarning( TraceTaskCodes::Common, TraceType_AccountHelper, "CryptCreateHash failed with {0}", errorCode); return errorCode; } ResourceHolder<HCRYPTHASH> hHashHolder( hHash, [](ResourceHolder<HCRYPTHASH> * thisPtr) { CryptDestroyHash(thisPtr->Value); }); if(!CryptHashData(hHash, signedMessageBufferHolder.Value.data(), static_cast<DWORD>(signedMessageBufferHolder.Value.size()), 0)) { errorCode = ErrorCode::FromWin32Error(); TraceWarning( TraceTaskCodes::Common, TraceType_AccountHelper, "CryptHashData failed with {0}", ErrorCode::FromWin32Error()); return errorCode; } HCRYPTKEY hKey = NULL; if(!CryptDeriveKey(hCryptProv, CALG_AES_256, hHash, 0, &hKey)) { errorCode = ErrorCode::FromWin32Error(); TraceWarning( TraceTaskCodes::Common, TraceType_AccountHelper, "CryptDeriveKey failed with {0}", errorCode); return errorCode; } ResourceHolder<HCRYPTKEY> hKeyHolder( hKey, [](ResourceHolder<HCRYPTKEY> * thisPtr) { CryptDestroyKey(thisPtr->Value); }); HCRYPTHASH hHmacHash = NULL; if(!CryptCreateHash(hCryptProv, CALG_HMAC, hKey, 0, &hHmacHash)) { errorCode = ErrorCode::FromWin32Error(); TraceWarning( TraceTaskCodes::Common, TraceType_AccountHelper, "CryptCreateHash failed with {0}", errorCode); return errorCode; } ResourceHolder<HCRYPTHASH> hHmacHashHolder( hHmacHash, [](ResourceHolder<HCRYPTHASH> * thisPtr) { CryptDestroyHash(thisPtr->Value); }); HMAC_INFO hmacInfo; ::ZeroMemory(&hmacInfo, sizeof(hmacInfo)); hmacInfo.HashAlgid = CALG_SHA_512; if(!CryptSetHashParam(hHmacHash, HP_HMAC_INFO, (BYTE*)&hmacInfo, 0)) { errorCode = ErrorCode::FromWin32Error(); TraceWarning( TraceTaskCodes::Common, TraceType_AccountHelper, "CryptGetHashParam failed with {0}", errorCode); return errorCode; } wstring hashData = move(accountName + passwordSecret.GetPlaintext()); auto result = CryptHashData( hHmacHash, (BYTE *)hashData.c_str(), (DWORD)hashData.size() * sizeof(WCHAR), 0); SecureZeroMemory((void *)hashData.c_str(), hashData.size() * sizeof(WCHAR)); if(!result) { errorCode = ErrorCode::FromWin32Error(); TraceWarning( TraceTaskCodes::Common, TraceType_AccountHelper, "CryptHashData failed with {0}", errorCode); return errorCode; } DWORD dataSize = 0; DWORD dataSizeLength = sizeof(dataSize); if(!CryptGetHashParam(hHmacHash, HP_HASHSIZE, (BYTE *)&dataSize, &dataSizeLength, 0)) { errorCode = ErrorCode::FromWin32Error(); TraceWarning( TraceTaskCodes::Common, TraceType_AccountHelper, "CryptGetHashParam failed with {0}", errorCode); return errorCode; } ASSERT_IF(dataSize == 0, "dataSize should be set to a positive value"); vector<BYTE> hashedData(dataSize); if(!CryptGetHashParam(hHmacHash, HP_HASHVAL, hashedData.data(), &dataSize, 0)) { Common::Assert::CodingError("Unable to retrieve hash value from the crypt framework, error: {0}", ErrorCode::FromWin32Error()); } #endif wstring value; StringWriter writer(value); writer.Write("{0}", PasswordPrefix); for(auto it = hashedData.begin(); it != hashedData.end(); ++it) { writer.Write("{0:x}", (*it)); //todo, length depends byte values, will this be an issue? } password = SecureString(move(value)); return ErrorCodeValue::Success; }