Example #1
0
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;
}