mirror of
https://github.com/winscp/winscp.git
synced 2026-10-24 02:28:55 +03:00
237 lines
8.4 KiB
C++
237 lines
8.4 KiB
C++
//---------------------------------------------------------------------------
|
|
#include <CorePCH.h>
|
|
#pragma hdrstop
|
|
|
|
#include "Security.h"
|
|
//---------------------------------------------------------------------------
|
|
#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 = static_cast<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 = static_cast<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(static_cast<unsigned char>(PWALG_SIMPLE_FLAG)); // Flag
|
|
int Len = Password.Length();
|
|
if (Len > std::numeric_limits<unsigned char>::max())
|
|
{
|
|
Result += SimpleEncryptChar(static_cast<unsigned char>(PWALG_SIMPLE_INTERNAL2));
|
|
Result += SimpleEncryptChar(static_cast<unsigned char>(Len >> 8));
|
|
Result += SimpleEncryptChar(static_cast<unsigned char>(Len & 0xFF));
|
|
}
|
|
else
|
|
{
|
|
Result += SimpleEncryptChar(static_cast<unsigned char>(PWALG_SIMPLE_INTERNAL));
|
|
Result += SimpleEncryptChar(static_cast<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(static_cast<unsigned char>(Shift));
|
|
for (int Index = 0; Index < Shift; Index++)
|
|
Result += SimpleEncryptChar(static_cast<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(static_cast<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, static_cast<Integer>(SimpleDecryptNextChar(Password))*2);
|
|
for (int Index = 0; Index < Length; Index++)
|
|
{
|
|
Result += static_cast<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(static_cast<unsigned char>(PWALG_SIMPLE_FLAG));
|
|
Result += SimpleEncryptChar(static_cast<unsigned char>(PWALG_SIMPLE_EXTERNAL));
|
|
Result += UTF8String(BytesToHex(reinterpret_cast<const unsigned char *>(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, SizeToIntChecked(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));
|
|
// 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
|
|
const size_t ChainConfigSize = RTL_SIZEOF_THROUGH_FIELD(CERT_CHAIN_ENGINE_CONFIG, CycleDetectionModulus);
|
|
#ifdef _WIN64
|
|
DebugAssert(ChainConfigSize == 64);
|
|
#else
|
|
DebugAssert(ChainConfigSize == 40);
|
|
#endif
|
|
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;
|
|
}
|
|
//---------------------------------------------------------------------------
|