Published source
Download source ZIP
CH-J Server Manager
Browse directories and files for a specific application release.
Source is provided under the CH-J Proprietary Software License 1.14. Its availability does not change the license terms or grant additional rights.
1
#define WIN32_LEAN_AND_MEAN2
#define NOMINMAX3
#include <windows.h>4
#include <wincred.h>5
#include <wincrypt.h>6
#include <UserConsentVerifierInterop.h>7
#include <winrt/base.h>8
#include <winrt/Windows.Foundation.h>9
#include <winrt/Windows.Data.Json.h>10
#include <winrt/Windows.Security.Credentials.UI.h>11
#include <iostream>12
#include <string>13
#include <vector>14
#include <stdexcept>15
using namespace winrt;16
using namespace Windows::Foundation;17
using namespace Windows::Data::Json;18
using namespace Windows::Security::Credentials::UI;19
struct Failure : std::runtime_error { using std::runtime_error::runtime_error; };20
void fail(char const* code) { throw Failure(code); }21
std::vector<BYTE> decode(hstring const& value) {22
DWORD size=0;23
if(!CryptStringToBinaryW(value.c_str(),static_cast<DWORD>(value.size()),CRYPT_STRING_BASE64|CRYPT_STRING_STRICT,nullptr,&size,nullptr,nullptr) || size!=32) fail("BIOMETRIC_INVALID_KEY");24
std::vector<BYTE> data(size);25
if(!CryptStringToBinaryW(value.c_str(),static_cast<DWORD>(value.size()),CRYPT_STRING_BASE64|CRYPT_STRING_STRICT,data.data(),&size,nullptr,nullptr)) fail("BIOMETRIC_INVALID_KEY");26
return data;27
}28
std::string encode(BYTE const* data,DWORD size) {29
DWORD count=0;check_bool(CryptBinaryToStringA(data,size,CRYPT_STRING_BASE64|CRYPT_STRING_NOCRLF,nullptr,&count));30
std::string out(count,'\0');check_bool(CryptBinaryToStringA(data,size,CRYPT_STRING_BASE64|CRYPT_STRING_NOCRLF,out.data(),&count));out.resize(count-1);return out;31
}32
void authenticate(JsonObject const& request) {33
HWND hwnd=reinterpret_cast<HWND>(std::stoull(to_string(request.GetNamedString(L"hwnd"))));34
DWORD owner=0;GetWindowThreadProcessId(hwnd,&owner);35
if(!IsWindow(hwnd) || owner!=static_cast<DWORD>(request.GetNamedNumber(L"pid"))) fail("BIOMETRIC_CANCELLED");36
auto interop=get_activation_factory<UserConsentVerifier,IUserConsentVerifierInterop>();37
IAsyncOperation<UserConsentVerificationResult> operation{nullptr};38
auto reason=request.GetNamedString(L"reason");39
check_hresult(interop->RequestVerificationForWindowAsync(hwnd,reinterpret_cast<HSTRING>(get_abi(reason)),guid_of<decltype(operation)>(),put_abi(operation)));40
auto result=operation.get();41
if(result==UserConsentVerificationResult::Verified) return; // Includes Hello PIN.42
if(result==UserConsentVerificationResult::Canceled) fail("BIOMETRIC_CANCELLED");43
if(result==UserConsentVerificationResult::DeviceBusy) fail("BIOMETRIC_DEVICE_UNAVAILABLE");44
if(result==UserConsentVerificationResult::RetriesExhausted) fail("BIOMETRIC_DEVICE_UNAVAILABLE");45
fail("BIOMETRIC_FAILED");46
}47
JsonObject run(JsonObject const& request) {48
auto op=request.GetNamedString(L"op");JsonObject response;response.SetNamedValue(L"ok",JsonValue::CreateBooleanValue(true));49
if(op==L"status") {50
auto result=UserConsentVerifier::CheckAvailabilityAsync().get();51
response.SetNamedValue(L"available",JsonValue::CreateBooleanValue(result==UserConsentVerifierAvailability::Available));52
response.SetNamedValue(L"code",JsonValue::CreateStringValue(result==UserConsentVerifierAvailability::Available?L"BIOMETRIC_AVAILABLE":result==UserConsentVerifierAvailability::NotConfiguredForUser?L"BIOMETRIC_NO_ENROLLMENT":result==UserConsentVerifierAvailability::DeviceBusy?L"BIOMETRIC_DEVICE_UNAVAILABLE":L"BIOMETRIC_UNAVAILABLE"));return response;53
}54
if(op==L"authenticate") {authenticate(request);return response;}55
auto entry=request.GetNamedString(L"entryId");if(entry.size()!=64 || std::wstring(entry).find_first_not_of(L"0123456789abcdef")!=std::wstring::npos)fail("BIOMETRIC_FAILED");56
auto target=L"CHJ.ServerManager.Vault.Biometry.v1:"+std::wstring(entry);57
DATA_BLOB entropy{static_cast<DWORD>(entry.size()*sizeof(wchar_t)),reinterpret_cast<BYTE*>(const_cast<wchar_t*>(entry.c_str()))};58
if(op==L"remove") {if(!CredDeleteW(target.c_str(),CRED_TYPE_GENERIC,0) && GetLastError()!=ERROR_NOT_FOUND)fail("BIOMETRIC_CREDENTIAL_FAILED");return response;}59
if(op==L"store") {60
auto bytes=decode(request.GetNamedString(L"key"));DATA_BLOB input{static_cast<DWORD>(bytes.size()),bytes.data()},output{};61
if(!CryptProtectData(&input,L"CH-J Vault",&entropy,nullptr,nullptr,CRYPTPROTECT_UI_FORBIDDEN,&output)){SecureZeroMemory(bytes.data(),bytes.size());fail("BIOMETRIC_CREDENTIAL_FAILED");}62
SecureZeroMemory(bytes.data(),bytes.size());63
CREDENTIALW credential{};credential.Type=CRED_TYPE_GENERIC;credential.TargetName=target.data();credential.CredentialBlobSize=output.cbData;credential.CredentialBlob=output.pbData;credential.Persist=CRED_PERSIST_LOCAL_MACHINE;credential.UserName=const_cast<LPWSTR>(L"CH-J Server Manager");64
BOOL ok=CredWriteW(&credential,0);SecureZeroMemory(output.pbData,output.cbData);LocalFree(output.pbData);if(!ok)fail("BIOMETRIC_CREDENTIAL_FAILED");return response;65
}66
if(op==L"retrieve") {67
authenticate(request);PCREDENTIALW credential=nullptr;68
if(!CredReadW(target.c_str(),CRED_TYPE_GENERIC,0,&credential))fail(GetLastError()==ERROR_NOT_FOUND?"BIOMETRIC_ENROLLMENT_INVALIDATED":"BIOMETRIC_CREDENTIAL_FAILED");69
DATA_BLOB input{credential->CredentialBlobSize,credential->CredentialBlob},output{};70
BOOL ok=CryptUnprotectData(&input,nullptr,&entropy,nullptr,nullptr,CRYPTPROTECT_UI_FORBIDDEN,&output);CredFree(credential);71
if(!ok)fail("BIOMETRIC_CREDENTIAL_FAILED");72
if(output.cbData!=32){SecureZeroMemory(output.pbData,output.cbData);LocalFree(output.pbData);fail("BIOMETRIC_INVALID_KEY");}73
auto encoded=encode(output.pbData,output.cbData);SecureZeroMemory(output.pbData,output.cbData);LocalFree(output.pbData);74
response.SetNamedValue(L"key",JsonValue::CreateStringValue(to_hstring(encoded)));SecureZeroMemory(encoded.data(),encoded.size());return response;75
}76
fail("BIOMETRIC_FAILED");return response;77
}78
int main() {79
try {80
init_apartment(apartment_type::multi_threaded);81
std::string input;std::getline(std::cin,input);if(input.size()>4096)fail("BIOMETRIC_FAILED");82
auto request=JsonObject::Parse(to_hstring(input));SecureZeroMemory(input.data(),input.size());83
auto response=run(request);std::cout<<to_string(response.Stringify());return 0;84
} catch(Failure const& e) {std::cout<<"{\"ok\":false,\"code\":\""<<e.what()<<"\"}";return 1;}85
catch(...) {std::cout<<"{\"ok\":false,\"code\":\"BIOMETRIC_UNAVAILABLE\"}";return 1;}86
}SHA-256: 56f46c87d75d9ddab5e27b5818a07224ba92ec0a11b28e246532d9cf279cb5fe
Archive SHA-256: 5ac91caf4fa32a6fdb114f2430deed486fbe7489d5eea343d1f034169fafb5e0