mirror of
https://github.com/winscp/winscp.git
synced 2026-10-24 02:28:55 +03:00
Mostly:
– incorrectly identified uninitialized variables
– explicit static global variables
– const, sign and down casts and safety
– typename use
– semicolon after function implementation
– unused variables, fields, arguments and macros
– field initialization order
– exact include filename case
– redundant in code macros already defined at project level
(cherry picked from commit f7f00c631e)
Source commit: 90ad9390853aba308abe73cf02e0281238c53c87
240 lines
8.5 KiB
C++
240 lines
8.5 KiB
C++
//---------------------------------------------------------------------------
|
|
#include <vcl.h>
|
|
#pragma hdrstop
|
|
|
|
#include <limits>
|
|
#include "Common.h"
|
|
#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<unsigned char>::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<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, 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<const char *>(&ChainConfig.CycleDetectionModulus) + sizeof(ChainConfig.CycleDetectionModulus) -
|
|
reinterpret_cast<const char *>(&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;
|
|
}
|
|
//---------------------------------------------------------------------------
|