//--------------------------------------------------------------------------- #include #pragma hdrstop #include "Security.h" //--------------------------------------------------------------------------- #pragma package(smart_init) //--------------------------------------------------------------------------- #define PWALG_SIMPLE_INTERNAL 0x00 #define PWALG_SIMPLE_EXTERNAL 0x01 #define PWALG_SIMPLE_INTERNAL2 0x02 static RawByteString PWALG_SIMPLE_STRING("0123456789ABCDEF"); //--------------------------------------------------------------------------- RawByteString SimpleEncryptChar(unsigned char Ch) { Ch = (unsigned char)((~Ch) ^ PWALG_SIMPLE_MAGIC); RawByteString Result(".."); Result[1] = PWALG_SIMPLE_STRING[((Ch & 0xF0) >> 4) + 1]; Result[2] = PWALG_SIMPLE_STRING[((Ch & 0x0F) >> 0) + 1]; return Result; } //--------------------------------------------------------------------------- unsigned char SimpleDecryptNextChar(RawByteString &Str) { if (Str.Length() > 0) { unsigned char Result = (unsigned char) ~((((PWALG_SIMPLE_STRING.Pos(Str.c_str()[0])-1) << 4) + ((PWALG_SIMPLE_STRING.Pos(Str.c_str()[1])-1) << 0)) ^ PWALG_SIMPLE_MAGIC); Str.Delete(1, 2); return Result; } else return 0x00; } //--------------------------------------------------------------------------- RawByteString EncryptPassword(UnicodeString UnicodePassword, UnicodeString UnicodeKey, Integer /* Algorithm */) { UTF8String Password = UnicodePassword; UTF8String Key = UnicodeKey; RawByteString Result; if (!RandSeed) Randomize(); Password = Key + Password; Result += SimpleEncryptChar((unsigned char)PWALG_SIMPLE_FLAG); // Flag int Len = Password.Length(); if (Len > std::numeric_limits::max()) { Result += SimpleEncryptChar((unsigned char)PWALG_SIMPLE_INTERNAL2); Result += SimpleEncryptChar((unsigned char)(Len >> 8)); Result += SimpleEncryptChar((unsigned char)(Len & 0xFF)); } else { Result += SimpleEncryptChar((unsigned char)PWALG_SIMPLE_INTERNAL); Result += SimpleEncryptChar((unsigned char)Len); } int DataLen = (Result.Length() / 2) + 1 + // Shift Password.Length(); int Shift = (DataLen < PWALG_SIMPLE_MAXLEN) ? random(PWALG_SIMPLE_MAXLEN - DataLen) : 0; Result += SimpleEncryptChar((unsigned char)Shift); for (int Index = 0; Index < Shift; Index++) Result += SimpleEncryptChar((unsigned char)random(256)); for (int Index = 0; Index < Password.Length(); Index++) Result += SimpleEncryptChar(Password.c_str()[Index]); while (Result.Length() < PWALG_SIMPLE_MAXLEN * 2) Result += SimpleEncryptChar((unsigned char)random(256)); return Result; } //--------------------------------------------------------------------------- UnicodeString DecryptPassword(RawByteString Password, UnicodeString UnicodeKey, Integer /* Algorithm */) { int Length; unsigned char Flag = SimpleDecryptNextChar(Password); if (Flag == PWALG_SIMPLE_FLAG) { unsigned char Version = SimpleDecryptNextChar(Password); if (Version == PWALG_SIMPLE_INTERNAL) { Length = SimpleDecryptNextChar(Password); } else if (Version == PWALG_SIMPLE_INTERNAL2) { Length = (int(SimpleDecryptNextChar(Password)) << 8) + SimpleDecryptNextChar(Password); } else { Length = -1; } } else { Length = Flag; } UTF8String Result; if (Length >= 0) { Password.Delete(1, ((Integer)SimpleDecryptNextChar(Password))*2); for (int Index = 0; Index < Length; Index++) { Result += (char)SimpleDecryptNextChar(Password); } if (Flag == PWALG_SIMPLE_FLAG) { UTF8String Key = UnicodeKey; if (Result.SubString(1, Key.Length()) != Key) { Result = UTF8String(); } else { Result.Delete(1, Key.Length()); } } } return UnicodeString(Result); } //--------------------------------------------------------------------------- RawByteString SetExternalEncryptedPassword(RawByteString Password) { RawByteString Result; Result += SimpleEncryptChar((unsigned char)PWALG_SIMPLE_FLAG); Result += SimpleEncryptChar((unsigned char)PWALG_SIMPLE_EXTERNAL); Result += UTF8String(BytesToHex(reinterpret_cast(Password.c_str()), Password.Length())); return Result; } //--------------------------------------------------------------------------- bool GetExternalEncryptedPassword(RawByteString Encrypted, RawByteString & Password) { bool Result = (SimpleDecryptNextChar(Encrypted) == PWALG_SIMPLE_FLAG) && (SimpleDecryptNextChar(Encrypted) == PWALG_SIMPLE_EXTERNAL); if (Result) { Password = HexToBytes(UTF8ToString(Encrypted)); } return Result; } //--------------------------------------------------------------------------- bool WindowsValidateCertificate(const unsigned char * Certificate, size_t Len, UnicodeString & Error) { bool Result = false; // Parse the certificate into a context. const CERT_CONTEXT * CertContext = CertCreateCertificateContext( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, Certificate, Len); if (CertContext == NULL) { Error = L"Cannot create certificate context"; } else { CERT_CHAIN_PARA ChainPara; // Retrieve the certificate chain of the certificate // (a certificate without a valid root does not have a chain). memset(&ChainPara, 0, sizeof(ChainPara)); ChainPara.cbSize = sizeof(ChainPara); CERT_CHAIN_ENGINE_CONFIG ChainConfig; memset(&ChainConfig, 0, sizeof(ChainConfig)); const size_t ChainConfigSize = reinterpret_cast(&ChainConfig.CycleDetectionModulus) + sizeof(ChainConfig.CycleDetectionModulus) - reinterpret_cast(&ChainConfig); // The hExclusiveRoot and hExclusiveTrustedPeople were added in Windows 7. // The CertGetCertificateChain fails with E_INVALIDARG when we include them to ChainConfig.cbSize. // The dwExclusiveFlags was added in Windows 8 DebugAssert(ChainConfigSize == 40); DebugAssert(ChainConfigSize == sizeof(CERT_CHAIN_ENGINE_CONFIG) - sizeof(ChainConfig.hExclusiveRoot) - sizeof(ChainConfig.hExclusiveTrustedPeople) - sizeof(ChainConfig.dwExclusiveFlags)); ChainConfig.cbSize = ChainConfigSize; ChainConfig.hRestrictedRoot = NULL; ChainConfig.hRestrictedTrust = NULL; ChainConfig.hRestrictedOther = NULL; ChainConfig.cAdditionalStore = 0; ChainConfig.rghAdditionalStore = NULL; ChainConfig.dwFlags = CERT_CHAIN_CACHE_END_CERT; ChainConfig.dwUrlRetrievalTimeout = 0; ChainConfig.MaximumCachedCertificates =0; ChainConfig.CycleDetectionModulus = 0; HCERTCHAINENGINE ChainEngine; bool ChainEngineResult = CertCreateCertificateChainEngine(&ChainConfig, &ChainEngine); if (!ChainEngineResult) { Error = L"Cannot create certificate chain engine"; } else { const CERT_CHAIN_CONTEXT * ChainContext = NULL; if (!CertGetCertificateChain(ChainEngine, CertContext, NULL, NULL, &ChainPara, CERT_CHAIN_CACHE_END_CERT | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, NULL, &ChainContext)) { Error = L"Cannot get certificate chain"; } else { CERT_CHAIN_POLICY_PARA PolicyPara; PolicyPara.cbSize = sizeof(PolicyPara); PolicyPara.dwFlags = 0; PolicyPara.pvExtraPolicyPara = NULL; CERT_CHAIN_POLICY_STATUS PolicyStatus; PolicyStatus.cbSize = sizeof(PolicyStatus); if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, ChainContext, &PolicyPara, &PolicyStatus)) { Error = L"Cannot verify certificate chain policy"; } else { int PolicyError = PolicyStatus.dwError; // Windows thinks the certificate is valid. Result = (PolicyError == S_OK); if (!Result) { UnicodeString ErrorStr = SysErrorMessage(PolicyError); Error = FORMAT(L"Error: %x (%s), Chain index: %d, Element index: %d", (PolicyError, ErrorStr, PolicyStatus.lChainIndex, PolicyStatus.lElementIndex)); } } CertFreeCertificateChain(ChainContext); } CertFreeCertificateChainEngine(ChainEngine); } CertFreeCertificateContext(CertContext); } return Result; } //---------------------------------------------------------------------------