1
0
mirror of https://github.com/winscp/winscp.git synced 2026-10-24 02:28:55 +03:00
Files
winscp/source/core/Security.cpp
Martin Prikryl 3f4e41fee0 Clang imposed changes that should be noop and have no effect on classic compiler
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
2025-03-13 16:46:26 +01:00

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;
}
//---------------------------------------------------------------------------