commit
014fab58e6
@ -36,14 +36,24 @@ set(SHARED_SRC
|
||||
../../src/StringUtils.cpp
|
||||
../../src/Log.cpp
|
||||
../../src/MCLogger.cpp
|
||||
../../src/Crypto.cpp
|
||||
../../src/PolarSSL++/AesCfb128Decryptor.cpp
|
||||
../../src/PolarSSL++/AesCfb128Encryptor.cpp
|
||||
../../src/PolarSSL++/CtrDrbgContext.cpp
|
||||
../../src/PolarSSL++/EntropyContext.cpp
|
||||
../../src/PolarSSL++/PublicKey.cpp
|
||||
../../src/PolarSSL++/RsaPrivateKey.cpp
|
||||
)
|
||||
set(SHARED_HDR
|
||||
../../src/ByteBuffer.h
|
||||
../../src/StringUtils.h
|
||||
../../src/Log.h
|
||||
../../src/MCLogger.h
|
||||
../../src/Crypto.h
|
||||
../../src/PolarSSL++/AesCfb128Decryptor.h
|
||||
../../src/PolarSSL++/AesCfb128Encryptor.h
|
||||
../../src/PolarSSL++/CtrDrbgContext.h
|
||||
../../src/PolarSSL++/EntropyContext.h
|
||||
../../src/PolarSSL++/PublicKey.h
|
||||
../../src/PolarSSL++/RsaPrivateKey.h
|
||||
)
|
||||
set(SHARED_OSS_SRC
|
||||
../../src/OSSupport/CriticalSection.cpp
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "Connection.h"
|
||||
#include "Server.h"
|
||||
#include <iostream>
|
||||
#include "PolarSSL++/PublicKey.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h> // For _mkdir()
|
||||
@ -471,7 +472,7 @@ bool cConnection::SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a
|
||||
|
||||
|
||||
|
||||
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer)
|
||||
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer)
|
||||
{
|
||||
DataLog(a_Data, a_Size, "Encrypting %d bytes to %s", a_Size, a_Peer);
|
||||
const Byte * Data = (const Byte *)a_Data;
|
||||
@ -495,7 +496,7 @@ bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryp
|
||||
|
||||
|
||||
|
||||
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer)
|
||||
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer)
|
||||
{
|
||||
AString All;
|
||||
a_Data.ReadAll(All);
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
#include "ByteBuffer.h"
|
||||
#include "OSSupport/Timer.h"
|
||||
#include "PolarSSL++/AesCfb128Decryptor.h"
|
||||
#include "PolarSSL++/AesCfb128Encryptor.h"
|
||||
|
||||
|
||||
|
||||
@ -66,8 +68,8 @@ protected:
|
||||
cByteBuffer m_ClientBuffer;
|
||||
cByteBuffer m_ServerBuffer;
|
||||
|
||||
cAESCFBDecryptor m_ServerDecryptor;
|
||||
cAESCFBEncryptor m_ServerEncryptor;
|
||||
cAesCfb128Decryptor m_ServerDecryptor;
|
||||
cAesCfb128Encryptor m_ServerEncryptor;
|
||||
|
||||
AString m_ServerEncryptionBuffer; // Buffer for the data to be sent to the server once encryption is established
|
||||
|
||||
@ -109,10 +111,10 @@ protected:
|
||||
bool SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a_Peer);
|
||||
|
||||
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
|
||||
bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer);
|
||||
bool SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer);
|
||||
|
||||
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
|
||||
bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer);
|
||||
bool SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer);
|
||||
|
||||
/// Decodes packets coming from the client, sends appropriate counterparts to the server; returns false if the connection is to be dropped
|
||||
bool DecodeClientsPackets(const char * a_Data, int a_Size);
|
||||
|
@ -216,6 +216,20 @@ typedef unsigned char Byte;
|
||||
// Pretty much the same as ASSERT() but stays in Release builds
|
||||
#define VERIFY( x ) ( !!(x) || ( LOGERROR("Verification failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), exit(1), 0 ) )
|
||||
|
||||
// Allow both Older versions of MSVC and newer versions of everything use a shared_ptr:
|
||||
// Note that we cannot typedef, because C++ doesn't allow (partial) templates to be typedeffed.
|
||||
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
|
||||
// MSVC before 2010 doesn't have std::shared_ptr, but has std::tr1::shared_ptr, defined in <memory> included earlier
|
||||
#define SharedPtr std::tr1::shared_ptr
|
||||
#elif (__cplusplus >= 201103L)
|
||||
// C++11 has std::shared_ptr in <memory>, included earlier
|
||||
#define SharedPtr std::shared_ptr
|
||||
#else
|
||||
// C++03 has std::tr1::shared_ptr in <tr1/memory>
|
||||
#include <tr1/memory>
|
||||
#define SharedPtr std::tr1::shared_ptr
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@ -232,12 +246,6 @@ public:
|
||||
|
||||
|
||||
|
||||
#include "../../src/Crypto.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define LOGERROR printf
|
||||
#define LOGINFO printf
|
||||
#define LOGWARNING printf
|
||||
|
@ -20,7 +20,7 @@ You need to set the server *not* to verify usernames ("online-mode=false" in ser
|
||||
|
||||
|
||||
ProtoProxy is not much dependent on the protocol - it will work with unknown packets, it just won't parse them into human-readable format.
|
||||
The latest protocol which has been tested is 1.6.1 (#73).
|
||||
The latest protocol which has been tested is 1.7.9 (#5).
|
||||
|
||||
|
||||
*/
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PolarSSL++/RsaPrivateKey.h"
|
||||
|
||||
|
||||
|
||||
|
||||
@ -17,7 +19,7 @@
|
||||
class cServer
|
||||
{
|
||||
SOCKET m_ListenSocket;
|
||||
cRSAPrivateKey m_PrivateKey;
|
||||
cRsaPrivateKey m_PrivateKey;
|
||||
AString m_PublicKeyDER;
|
||||
short m_ConnectPort;
|
||||
|
||||
@ -27,7 +29,7 @@ public:
|
||||
int Init(short a_ListenPort, short a_ConnectPort);
|
||||
void Run(void);
|
||||
|
||||
cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
|
||||
cRsaPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
|
||||
const AString & GetPublicKeyDER (void) { return m_PublicKeyDER; }
|
||||
|
||||
short GetConnectPort(void) const { return m_ConnectPort; }
|
||||
|
@ -171,7 +171,7 @@ cByteBuffer::~cByteBuffer()
|
||||
|
||||
|
||||
|
||||
bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
|
||||
bool cByteBuffer::Write(const void * a_Bytes, size_t a_Count)
|
||||
{
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
@ -187,13 +187,14 @@ bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
|
||||
}
|
||||
ASSERT(m_BufferSize >= m_WritePos);
|
||||
size_t TillEnd = m_BufferSize - m_WritePos;
|
||||
const char * Bytes = (const char *)a_Bytes;
|
||||
if (TillEnd <= a_Count)
|
||||
{
|
||||
// Need to wrap around the ringbuffer end
|
||||
if (TillEnd > 0)
|
||||
{
|
||||
memcpy(m_Buffer + m_WritePos, a_Bytes, TillEnd);
|
||||
a_Bytes += TillEnd;
|
||||
memcpy(m_Buffer + m_WritePos, Bytes, TillEnd);
|
||||
Bytes += TillEnd;
|
||||
a_Count -= TillEnd;
|
||||
WrittenBytes = TillEnd;
|
||||
}
|
||||
@ -203,7 +204,7 @@ bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
|
||||
// We're guaranteed that we'll fit in a single write op
|
||||
if (a_Count > 0)
|
||||
{
|
||||
memcpy(m_Buffer + m_WritePos, a_Bytes, a_Count);
|
||||
memcpy(m_Buffer + m_WritePos, Bytes, a_Count);
|
||||
m_WritePos += a_Count;
|
||||
WrittenBytes += a_Count;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
~cByteBuffer();
|
||||
|
||||
/// Writes the bytes specified to the ringbuffer. Returns true if successful, false if not
|
||||
bool Write(const char * a_Bytes, size_t a_Count);
|
||||
bool Write(const void * a_Bytes, size_t a_Count);
|
||||
|
||||
/// Returns the number of bytes that can be successfully written to the ringbuffer
|
||||
size_t GetFreeSpace(void) const;
|
||||
|
@ -5,7 +5,7 @@ include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/")
|
||||
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include")
|
||||
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/polarssl/include")
|
||||
|
||||
set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating)
|
||||
set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++)
|
||||
set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities Generating/Prefabs)
|
||||
|
||||
|
||||
@ -242,7 +242,7 @@ endif ()
|
||||
if (NOT MSVC)
|
||||
target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks)
|
||||
target_link_libraries(${EXECUTABLE} Protocol Generating Generating_Prefabs WorldStorage)
|
||||
target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities)
|
||||
target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities PolarSSL++)
|
||||
endif ()
|
||||
if (WIN32)
|
||||
target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib)
|
||||
|
509
src/Crypto.cpp
509
src/Crypto.cpp
@ -1,509 +0,0 @@
|
||||
|
||||
// Crypto.cpp
|
||||
|
||||
// Implements classes that wrap the cryptographic code library
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Crypto.h"
|
||||
|
||||
#include "polarssl/pk.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
// Self-test the hash formatting for known values:
|
||||
// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48
|
||||
// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1
|
||||
// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6
|
||||
|
||||
class Test
|
||||
{
|
||||
public:
|
||||
Test(void)
|
||||
{
|
||||
AString DigestNotch, DigestJeb, DigestSimon;
|
||||
Byte Digest[20];
|
||||
cSHA1Checksum Checksum;
|
||||
Checksum.Update((const Byte *)"Notch", 5);
|
||||
Checksum.Finalize(Digest);
|
||||
cSHA1Checksum::DigestToJava(Digest, DigestNotch);
|
||||
Checksum.Restart();
|
||||
Checksum.Update((const Byte *)"jeb_", 4);
|
||||
Checksum.Finalize(Digest);
|
||||
cSHA1Checksum::DigestToJava(Digest, DigestJeb);
|
||||
Checksum.Restart();
|
||||
Checksum.Update((const Byte *)"simon", 5);
|
||||
Checksum.Finalize(Digest);
|
||||
cSHA1Checksum::DigestToJava(Digest, DigestSimon);
|
||||
printf("Notch: \"%s\"\n", DigestNotch.c_str());
|
||||
printf("jeb_: \"%s\"\n", DigestJeb.c_str());
|
||||
printf("simon: \"%s\"\n", DigestSimon.c_str());
|
||||
assert(DigestNotch == "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48");
|
||||
assert(DigestJeb == "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1");
|
||||
assert(DigestSimon == "88e16a1019277b15d58faf0541e11910eb756f6");
|
||||
}
|
||||
} test;
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cRSAPrivateKey:
|
||||
|
||||
cRSAPrivateKey::cRSAPrivateKey(void)
|
||||
{
|
||||
rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
|
||||
InitRnd();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cRSAPrivateKey::cRSAPrivateKey(const cRSAPrivateKey & a_Other)
|
||||
{
|
||||
rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
|
||||
rsa_copy(&m_Rsa, &a_Other.m_Rsa);
|
||||
InitRnd();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cRSAPrivateKey::~cRSAPrivateKey()
|
||||
{
|
||||
entropy_free(&m_Entropy);
|
||||
rsa_free(&m_Rsa);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cRSAPrivateKey::InitRnd(void)
|
||||
{
|
||||
entropy_init(&m_Entropy);
|
||||
const unsigned char pers[] = "rsa_genkey";
|
||||
ctr_drbg_init(&m_Ctr_drbg, entropy_func, &m_Entropy, pers, sizeof(pers) - 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cRSAPrivateKey::Generate(unsigned a_KeySizeBits)
|
||||
{
|
||||
if (rsa_gen_key(&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, a_KeySizeBits, 65537) != 0)
|
||||
{
|
||||
// Key generation failed
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AString cRSAPrivateKey::GetPubKeyDER(void)
|
||||
{
|
||||
class cPubKey
|
||||
{
|
||||
public:
|
||||
cPubKey(rsa_context * a_Rsa) :
|
||||
m_IsValid(false)
|
||||
{
|
||||
pk_init(&m_Key);
|
||||
if (pk_init_ctx(&m_Key, pk_info_from_type(POLARSSL_PK_RSA)) != 0)
|
||||
{
|
||||
ASSERT(!"Cannot init PrivKey context");
|
||||
return;
|
||||
}
|
||||
if (rsa_copy(pk_rsa(m_Key), a_Rsa) != 0)
|
||||
{
|
||||
ASSERT(!"Cannot copy PrivKey to PK context");
|
||||
return;
|
||||
}
|
||||
m_IsValid = true;
|
||||
}
|
||||
|
||||
~cPubKey()
|
||||
{
|
||||
if (m_IsValid)
|
||||
{
|
||||
pk_free(&m_Key);
|
||||
}
|
||||
}
|
||||
|
||||
operator pk_context * (void) { return &m_Key; }
|
||||
|
||||
protected:
|
||||
bool m_IsValid;
|
||||
pk_context m_Key;
|
||||
} PkCtx(&m_Rsa);
|
||||
|
||||
unsigned char buf[3000];
|
||||
int res = pk_write_pubkey_der(PkCtx, buf, sizeof(buf));
|
||||
if (res < 0)
|
||||
{
|
||||
return AString();
|
||||
}
|
||||
return AString((const char *)(buf + sizeof(buf) - res), (size_t)res);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cRSAPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
|
||||
{
|
||||
if (a_EncryptedLength < m_Rsa.len)
|
||||
{
|
||||
LOGD("%s: Invalid a_EncryptedLength: got %u, exp at least %u",
|
||||
__FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
|
||||
);
|
||||
ASSERT(!"Invalid a_DecryptedMaxLength!");
|
||||
return -1;
|
||||
}
|
||||
if (a_DecryptedMaxLength < m_Rsa.len)
|
||||
{
|
||||
LOGD("%s: Invalid a_DecryptedMaxLength: got %u, exp at least %u",
|
||||
__FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
|
||||
);
|
||||
ASSERT(!"Invalid a_DecryptedMaxLength!");
|
||||
return -1;
|
||||
}
|
||||
size_t DecryptedLength;
|
||||
int res = rsa_pkcs1_decrypt(
|
||||
&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PRIVATE, &DecryptedLength,
|
||||
a_EncryptedData, a_DecryptedData, a_DecryptedMaxLength
|
||||
);
|
||||
if (res != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return (int)DecryptedLength;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cRSAPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
|
||||
{
|
||||
if (a_EncryptedMaxLength < m_Rsa.len)
|
||||
{
|
||||
LOGD("%s: Invalid a_EncryptedMaxLength: got %u, exp at least %u",
|
||||
__FUNCTION__, (unsigned)a_EncryptedMaxLength, (unsigned)(m_Rsa.len)
|
||||
);
|
||||
ASSERT(!"Invalid a_DecryptedMaxLength!");
|
||||
return -1;
|
||||
}
|
||||
if (a_PlainLength < m_Rsa.len)
|
||||
{
|
||||
LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u",
|
||||
__FUNCTION__, (unsigned)a_PlainLength, (unsigned)(m_Rsa.len)
|
||||
);
|
||||
ASSERT(!"Invalid a_PlainLength!");
|
||||
return -1;
|
||||
}
|
||||
int res = rsa_pkcs1_encrypt(
|
||||
&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PRIVATE,
|
||||
a_PlainLength, a_PlainData, a_EncryptedData
|
||||
);
|
||||
if (res != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return (int)m_Rsa.len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cPublicKey:
|
||||
|
||||
cPublicKey::cPublicKey(const AString & a_PublicKeyDER)
|
||||
{
|
||||
pk_init(&m_Pk);
|
||||
if (pk_parse_public_key(&m_Pk, (const Byte *)a_PublicKeyDER.data(), a_PublicKeyDER.size()) != 0)
|
||||
{
|
||||
ASSERT(!"Cannot parse PubKey");
|
||||
return;
|
||||
}
|
||||
InitRnd();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPublicKey::~cPublicKey()
|
||||
{
|
||||
pk_free(&m_Pk);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cPublicKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
|
||||
{
|
||||
size_t DecryptedLen = a_DecryptedMaxLength;
|
||||
int res = pk_decrypt(&m_Pk,
|
||||
a_EncryptedData, a_EncryptedLength,
|
||||
a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength,
|
||||
ctr_drbg_random, &m_Ctr_drbg
|
||||
);
|
||||
if (res != 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
return (int)DecryptedLen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cPublicKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
|
||||
{
|
||||
size_t EncryptedLength = a_EncryptedMaxLength;
|
||||
int res = pk_encrypt(&m_Pk,
|
||||
a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength,
|
||||
ctr_drbg_random, &m_Ctr_drbg
|
||||
);
|
||||
if (res != 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
return (int)EncryptedLength;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPublicKey::InitRnd(void)
|
||||
{
|
||||
entropy_init(&m_Entropy);
|
||||
const unsigned char pers[] = "rsa_genkey";
|
||||
ctr_drbg_init(&m_Ctr_drbg, entropy_func, &m_Entropy, pers, sizeof(pers) - 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cAESCFBDecryptor:
|
||||
|
||||
cAESCFBDecryptor::cAESCFBDecryptor(void) :
|
||||
m_IVOffset(0),
|
||||
m_IsValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cAESCFBDecryptor::~cAESCFBDecryptor()
|
||||
{
|
||||
// Clear the leftover in-memory data, so that they can't be accessed by a backdoor
|
||||
memset(&m_Aes, 0, sizeof(m_Aes));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAESCFBDecryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
|
||||
{
|
||||
ASSERT(!IsValid()); // Cannot Init twice
|
||||
|
||||
memcpy(m_IV, a_IV, 16);
|
||||
aes_setkey_enc(&m_Aes, a_Key, 128);
|
||||
m_IsValid = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAESCFBDecryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length)
|
||||
{
|
||||
ASSERT(IsValid()); // Must Init() first
|
||||
|
||||
// PolarSSL doesn't support AES-CFB8, need to implement it manually:
|
||||
for (size_t i = 0; i < a_Length; i++)
|
||||
{
|
||||
Byte Buffer[sizeof(m_IV)];
|
||||
aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
|
||||
for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
|
||||
{
|
||||
m_IV[idx] = m_IV[idx + 1];
|
||||
}
|
||||
m_IV[sizeof(m_IV) - 1] = a_EncryptedIn[i];
|
||||
a_DecryptedOut[i] = a_EncryptedIn[i] ^ Buffer[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cAESCFBEncryptor:
|
||||
|
||||
cAESCFBEncryptor::cAESCFBEncryptor(void) :
|
||||
m_IVOffset(0),
|
||||
m_IsValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cAESCFBEncryptor::~cAESCFBEncryptor()
|
||||
{
|
||||
// Clear the leftover in-memory data, so that they can't be accessed by a backdoor
|
||||
memset(&m_Aes, 0, sizeof(m_Aes));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAESCFBEncryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
|
||||
{
|
||||
ASSERT(!IsValid()); // Cannot Init twice
|
||||
ASSERT(m_IVOffset == 0);
|
||||
|
||||
memcpy(m_IV, a_IV, 16);
|
||||
aes_setkey_enc(&m_Aes, a_Key, 128);
|
||||
m_IsValid = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAESCFBEncryptor::ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length)
|
||||
{
|
||||
ASSERT(IsValid()); // Must Init() first
|
||||
|
||||
// PolarSSL doesn't do AES-CFB8, so we need to implement it ourselves:
|
||||
for (size_t i = 0; i < a_Length; i++)
|
||||
{
|
||||
Byte Buffer[sizeof(m_IV)];
|
||||
aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
|
||||
for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
|
||||
{
|
||||
m_IV[idx] = m_IV[idx + 1];
|
||||
}
|
||||
a_EncryptedOut[i] = a_PlainIn[i] ^ Buffer[0];
|
||||
m_IV[sizeof(m_IV) - 1] = a_EncryptedOut[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cSHA1Checksum:
|
||||
|
||||
cSHA1Checksum::cSHA1Checksum(void) :
|
||||
m_DoesAcceptInput(true)
|
||||
{
|
||||
sha1_starts(&m_Sha1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSHA1Checksum::Update(const Byte * a_Data, size_t a_Length)
|
||||
{
|
||||
ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
|
||||
|
||||
sha1_update(&m_Sha1, a_Data, a_Length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSHA1Checksum::Finalize(cSHA1Checksum::Checksum & a_Output)
|
||||
{
|
||||
ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
|
||||
|
||||
sha1_finish(&m_Sha1, a_Output);
|
||||
m_DoesAcceptInput = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSHA1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out)
|
||||
{
|
||||
Checksum Digest;
|
||||
memcpy(Digest, a_Digest, sizeof(Digest));
|
||||
|
||||
bool IsNegative = (Digest[0] >= 0x80);
|
||||
if (IsNegative)
|
||||
{
|
||||
// Two's complement:
|
||||
bool carry = true; // Add one to the whole number
|
||||
for (int i = 19; i >= 0; i--)
|
||||
{
|
||||
Digest[i] = ~Digest[i];
|
||||
if (carry)
|
||||
{
|
||||
carry = (Digest[i] == 0xff);
|
||||
Digest[i]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
a_Out.clear();
|
||||
a_Out.reserve(40);
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
AppendPrintf(a_Out, "%02x", Digest[i]);
|
||||
}
|
||||
while ((a_Out.length() > 0) && (a_Out[0] == '0'))
|
||||
{
|
||||
a_Out.erase(0, 1);
|
||||
}
|
||||
if (IsNegative)
|
||||
{
|
||||
a_Out.insert(0, "-");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSHA1Checksum::Restart(void)
|
||||
{
|
||||
sha1_starts(&m_Sha1);
|
||||
m_DoesAcceptInput = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
198
src/Crypto.h
198
src/Crypto.h
@ -1,198 +0,0 @@
|
||||
|
||||
// Crypto.h
|
||||
|
||||
// Declares classes that wrap the cryptographic code library
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polarssl/rsa.h"
|
||||
#include "polarssl/aes.h"
|
||||
#include "polarssl/entropy.h"
|
||||
#include "polarssl/ctr_drbg.h"
|
||||
#include "polarssl/sha1.h"
|
||||
#include "polarssl/pk.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Encapsulates an RSA private key used in PKI cryptography */
|
||||
class cRSAPrivateKey
|
||||
{
|
||||
public:
|
||||
/** Creates a new empty object, the key is not assigned */
|
||||
cRSAPrivateKey(void);
|
||||
|
||||
/** Deep-copies the key from a_Other */
|
||||
cRSAPrivateKey(const cRSAPrivateKey & a_Other);
|
||||
|
||||
~cRSAPrivateKey();
|
||||
|
||||
/** Generates a new key within this object, with the specified size in bits.
|
||||
Returns true on success, false on failure. */
|
||||
bool Generate(unsigned a_KeySizeBits = 1024);
|
||||
|
||||
/** Returns the public key part encoded in ASN1 DER encoding */
|
||||
AString GetPubKeyDER(void);
|
||||
|
||||
/** Decrypts the data using RSAES-PKCS#1 algorithm.
|
||||
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||
Returns the number of bytes decrypted, or negative number for error. */
|
||||
int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
|
||||
|
||||
/** Encrypts the data using RSAES-PKCS#1 algorithm.
|
||||
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||
Returns the number of bytes decrypted, or negative number for error. */
|
||||
int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
|
||||
|
||||
protected:
|
||||
rsa_context m_Rsa;
|
||||
entropy_context m_Entropy;
|
||||
ctr_drbg_context m_Ctr_drbg;
|
||||
|
||||
/** Initializes the m_Entropy and m_Ctr_drbg contexts
|
||||
Common part of this object's construction, called from all constructors. */
|
||||
void InitRnd(void);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cPublicKey
|
||||
{
|
||||
public:
|
||||
cPublicKey(const AString & a_PublicKeyDER);
|
||||
~cPublicKey();
|
||||
|
||||
/** Decrypts the data using the stored public key
|
||||
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||
Returns the number of bytes decrypted, or negative number for error. */
|
||||
int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
|
||||
|
||||
/** Encrypts the data using the stored public key
|
||||
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||
Returns the number of bytes decrypted, or negative number for error. */
|
||||
int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
|
||||
|
||||
protected:
|
||||
pk_context m_Pk;
|
||||
entropy_context m_Entropy;
|
||||
ctr_drbg_context m_Ctr_drbg;
|
||||
|
||||
/** Initializes the m_Entropy and m_Ctr_drbg contexts
|
||||
Common part of this object's construction, called from all constructors. */
|
||||
void InitRnd(void);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Decrypts data using the AES / CFB (128) algorithm */
|
||||
class cAESCFBDecryptor
|
||||
{
|
||||
public:
|
||||
Byte test;
|
||||
|
||||
cAESCFBDecryptor(void);
|
||||
~cAESCFBDecryptor();
|
||||
|
||||
/** Initializes the decryptor with the specified Key / IV */
|
||||
void Init(const Byte a_Key[16], const Byte a_IV[16]);
|
||||
|
||||
/** Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes */
|
||||
void ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length);
|
||||
|
||||
/** Returns true if the object has been initialized with the Key / IV */
|
||||
bool IsValid(void) const { return m_IsValid; }
|
||||
|
||||
protected:
|
||||
aes_context m_Aes;
|
||||
|
||||
/** The InitialVector, used by the CFB mode decryption */
|
||||
Byte m_IV[16];
|
||||
|
||||
/** Current offset in the m_IV, used by the CFB mode decryption */
|
||||
size_t m_IVOffset;
|
||||
|
||||
/** Indicates whether the object has been initialized with the Key / IV */
|
||||
bool m_IsValid;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Encrypts data using the AES / CFB (128) algorithm */
|
||||
class cAESCFBEncryptor
|
||||
{
|
||||
public:
|
||||
cAESCFBEncryptor(void);
|
||||
~cAESCFBEncryptor();
|
||||
|
||||
/** Initializes the decryptor with the specified Key / IV */
|
||||
void Init(const Byte a_Key[16], const Byte a_IV[16]);
|
||||
|
||||
/** Encrypts a_Length bytes of the plain data; produces a_Length output bytes */
|
||||
void ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length);
|
||||
|
||||
/** Returns true if the object has been initialized with the Key / IV */
|
||||
bool IsValid(void) const { return m_IsValid; }
|
||||
|
||||
protected:
|
||||
aes_context m_Aes;
|
||||
|
||||
/** The InitialVector, used by the CFB mode encryption */
|
||||
Byte m_IV[16];
|
||||
|
||||
/** Current offset in the m_IV, used by the CFB mode encryption */
|
||||
size_t m_IVOffset;
|
||||
|
||||
/** Indicates whether the object has been initialized with the Key / IV */
|
||||
bool m_IsValid;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Calculates a SHA1 checksum for data stream */
|
||||
class cSHA1Checksum
|
||||
{
|
||||
public:
|
||||
typedef Byte Checksum[20]; // The type used for storing the checksum
|
||||
|
||||
cSHA1Checksum(void);
|
||||
|
||||
/** Adds the specified data to the checksum */
|
||||
void Update(const Byte * a_Data, size_t a_Length);
|
||||
|
||||
/** Calculates and returns the final checksum */
|
||||
void Finalize(Checksum & a_Output);
|
||||
|
||||
/** Returns true if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
|
||||
bool DoesAcceptInput(void) const { return m_DoesAcceptInput; }
|
||||
|
||||
/** Converts a raw 160-bit SHA1 digest into a Java Hex representation
|
||||
According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802
|
||||
*/
|
||||
static void DigestToJava(const Checksum & a_Digest, AString & a_JavaOut);
|
||||
|
||||
/** Clears the current context and start a new checksum calculation */
|
||||
void Restart(void);
|
||||
|
||||
protected:
|
||||
/** True if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
|
||||
bool m_DoesAcceptInput;
|
||||
|
||||
sha1_context m_Sha1;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
@ -267,6 +267,20 @@ template class SizeChecker<UInt16, 2>;
|
||||
#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
|
||||
#endif
|
||||
|
||||
// Allow both Older versions of MSVC and newer versions of everything use a shared_ptr:
|
||||
// Note that we cannot typedef, because C++ doesn't allow (partial) templates to be typedeffed.
|
||||
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
|
||||
// MSVC before 2010 doesn't have std::shared_ptr, but has std::tr1::shared_ptr, defined in <memory> included earlier
|
||||
#define SharedPtr std::tr1::shared_ptr
|
||||
#elif (__cplusplus >= 201103L)
|
||||
// C++11 has std::shared_ptr in <memory>, included earlier
|
||||
#define SharedPtr std::shared_ptr
|
||||
#else
|
||||
// C++03 has std::tr1::shared_ptr in <tr1/memory>
|
||||
#include <tr1/memory>
|
||||
#define SharedPtr std::tr1::shared_ptr
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -295,7 +295,7 @@ bool cSocket::ConnectToLocalhostIPv4(unsigned short a_Port)
|
||||
|
||||
bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Port)
|
||||
{
|
||||
// First try IP Address string to hostent conversion, because it's faster
|
||||
// First try IP Address string to hostent conversion, because it's faster and local:
|
||||
unsigned long addr = inet_addr(a_HostNameOrAddr.c_str());
|
||||
if (addr == INADDR_NONE)
|
||||
{
|
||||
@ -307,10 +307,16 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por
|
||||
CloseSocket();
|
||||
return false;
|
||||
}
|
||||
// Should be optimised to a single word copy
|
||||
memcpy(&addr, hp->h_addr, hp->h_length);
|
||||
}
|
||||
|
||||
// If the socket is not created yet, create one:
|
||||
if (!IsValid())
|
||||
{
|
||||
m_Socket = socket((int)IPv4, SOCK_STREAM, 0);
|
||||
}
|
||||
|
||||
// Connect the socket:
|
||||
sockaddr_in server;
|
||||
server.sin_addr.s_addr = addr;
|
||||
server.sin_family = AF_INET;
|
||||
|
67
src/PolarSSL++/AesCfb128Decryptor.cpp
Normal file
67
src/PolarSSL++/AesCfb128Decryptor.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
|
||||
// AesCfb128Decryptor.cpp
|
||||
|
||||
// Implements the cAesCfb128Decryptor class decrypting data using AES CFB-128
|
||||
|
||||
#include "Globals.h"
|
||||
#include "AesCfb128Decryptor.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cAesCfb128Decryptor::cAesCfb128Decryptor(void) :
|
||||
m_IVOffset(0),
|
||||
m_IsValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cAesCfb128Decryptor::~cAesCfb128Decryptor()
|
||||
{
|
||||
// Clear the leftover in-memory data, so that they can't be accessed by a backdoor
|
||||
memset(&m_Aes, 0, sizeof(m_Aes));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAesCfb128Decryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
|
||||
{
|
||||
ASSERT(!IsValid()); // Cannot Init twice
|
||||
|
||||
memcpy(m_IV, a_IV, 16);
|
||||
aes_setkey_enc(&m_Aes, a_Key, 128);
|
||||
m_IsValid = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAesCfb128Decryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length)
|
||||
{
|
||||
ASSERT(IsValid()); // Must Init() first
|
||||
|
||||
// PolarSSL doesn't support AES-CFB8, need to implement it manually:
|
||||
for (size_t i = 0; i < a_Length; i++)
|
||||
{
|
||||
Byte Buffer[sizeof(m_IV)];
|
||||
aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
|
||||
for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
|
||||
{
|
||||
m_IV[idx] = m_IV[idx + 1];
|
||||
}
|
||||
m_IV[sizeof(m_IV) - 1] = a_EncryptedIn[i];
|
||||
a_DecryptedOut[i] = a_EncryptedIn[i] ^ Buffer[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
52
src/PolarSSL++/AesCfb128Decryptor.h
Normal file
52
src/PolarSSL++/AesCfb128Decryptor.h
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
// AesCfb128Decryptor.h
|
||||
|
||||
// Declares the cAesCfb128Decryptor class decrypting data using AES CFB-128
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polarssl/aes.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Decrypts data using the AES / CFB 128 algorithm */
|
||||
class cAesCfb128Decryptor
|
||||
{
|
||||
public:
|
||||
Byte test;
|
||||
|
||||
cAesCfb128Decryptor(void);
|
||||
~cAesCfb128Decryptor();
|
||||
|
||||
/** Initializes the decryptor with the specified Key / IV */
|
||||
void Init(const Byte a_Key[16], const Byte a_IV[16]);
|
||||
|
||||
/** Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes */
|
||||
void ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length);
|
||||
|
||||
/** Returns true if the object has been initialized with the Key / IV */
|
||||
bool IsValid(void) const { return m_IsValid; }
|
||||
|
||||
protected:
|
||||
aes_context m_Aes;
|
||||
|
||||
/** The InitialVector, used by the CFB mode decryption */
|
||||
Byte m_IV[16];
|
||||
|
||||
/** Current offset in the m_IV, used by the CFB mode decryption */
|
||||
size_t m_IVOffset;
|
||||
|
||||
/** Indicates whether the object has been initialized with the Key / IV */
|
||||
bool m_IsValid;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
68
src/PolarSSL++/AesCfb128Encryptor.cpp
Normal file
68
src/PolarSSL++/AesCfb128Encryptor.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
|
||||
// AesCfb128Encryptor.cpp
|
||||
|
||||
// Implements the cAesCfb128Encryptor class encrypting data using AES CFB-128
|
||||
|
||||
#include "Globals.h"
|
||||
#include "AesCfb128Encryptor.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cAesCfb128Encryptor::cAesCfb128Encryptor(void) :
|
||||
m_IVOffset(0),
|
||||
m_IsValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cAesCfb128Encryptor::~cAesCfb128Encryptor()
|
||||
{
|
||||
// Clear the leftover in-memory data, so that they can't be accessed by a backdoor
|
||||
memset(&m_Aes, 0, sizeof(m_Aes));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAesCfb128Encryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
|
||||
{
|
||||
ASSERT(!IsValid()); // Cannot Init twice
|
||||
ASSERT(m_IVOffset == 0);
|
||||
|
||||
memcpy(m_IV, a_IV, 16);
|
||||
aes_setkey_enc(&m_Aes, a_Key, 128);
|
||||
m_IsValid = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAesCfb128Encryptor::ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length)
|
||||
{
|
||||
ASSERT(IsValid()); // Must Init() first
|
||||
|
||||
// PolarSSL doesn't do AES-CFB8, so we need to implement it ourselves:
|
||||
for (size_t i = 0; i < a_Length; i++)
|
||||
{
|
||||
Byte Buffer[sizeof(m_IV)];
|
||||
aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
|
||||
for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
|
||||
{
|
||||
m_IV[idx] = m_IV[idx + 1];
|
||||
}
|
||||
a_EncryptedOut[i] = a_PlainIn[i] ^ Buffer[0];
|
||||
m_IV[sizeof(m_IV) - 1] = a_EncryptedOut[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
50
src/PolarSSL++/AesCfb128Encryptor.h
Normal file
50
src/PolarSSL++/AesCfb128Encryptor.h
Normal file
@ -0,0 +1,50 @@
|
||||
|
||||
// AesCfb128Encryptor.h
|
||||
|
||||
// Declares the cAesCfb128Encryptor class encrypting data using AES CFB-128
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polarssl/aes.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Encrypts data using the AES / CFB (128) algorithm */
|
||||
class cAesCfb128Encryptor
|
||||
{
|
||||
public:
|
||||
cAesCfb128Encryptor(void);
|
||||
~cAesCfb128Encryptor();
|
||||
|
||||
/** Initializes the decryptor with the specified Key / IV */
|
||||
void Init(const Byte a_Key[16], const Byte a_IV[16]);
|
||||
|
||||
/** Encrypts a_Length bytes of the plain data; produces a_Length output bytes */
|
||||
void ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length);
|
||||
|
||||
/** Returns true if the object has been initialized with the Key / IV */
|
||||
bool IsValid(void) const { return m_IsValid; }
|
||||
|
||||
protected:
|
||||
aes_context m_Aes;
|
||||
|
||||
/** The InitialVector, used by the CFB mode encryption */
|
||||
Byte m_IV[16];
|
||||
|
||||
/** Current offset in the m_IV, used by the CFB mode encryption */
|
||||
size_t m_IVOffset;
|
||||
|
||||
/** Indicates whether the object has been initialized with the Key / IV */
|
||||
bool m_IsValid;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
195
src/PolarSSL++/BlockingSslClientSocket.cpp
Normal file
195
src/PolarSSL++/BlockingSslClientSocket.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
|
||||
// BlockingSslClientSocket.cpp
|
||||
|
||||
// Implements the cBlockingSslClientSocket class representing a blocking TCP socket with client SSL encryption over it
|
||||
|
||||
#include "Globals.h"
|
||||
#include "BlockingSslClientSocket.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cBlockingSslClientSocket::cBlockingSslClientSocket(void) :
|
||||
m_Ssl(*this),
|
||||
m_IsConnected(false)
|
||||
{
|
||||
// Nothing needed yet
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBlockingSslClientSocket::Connect(const AString & a_ServerName, UInt16 a_Port)
|
||||
{
|
||||
// If already connected, report an error:
|
||||
if (m_IsConnected)
|
||||
{
|
||||
// TODO: Handle this better - if connected to the same server and port, and the socket is alive, return success
|
||||
m_LastErrorText = "Already connected";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Connect the underlying socket:
|
||||
m_Socket.CreateSocket(cSocket::IPv4);
|
||||
if (!m_Socket.ConnectIPv4(a_ServerName.c_str(), a_Port))
|
||||
{
|
||||
Printf(m_LastErrorText, "Socket connect failed: %s", m_Socket.GetLastErrorString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize the SSL:
|
||||
int ret = m_Ssl.Initialize(true);
|
||||
if (ret != 0)
|
||||
{
|
||||
Printf(m_LastErrorText, "SSL initialization failed: -0x%x", -ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we have been assigned a trusted CA root cert store, push it into the SSL context:
|
||||
if (m_CACerts.get() != NULL)
|
||||
{
|
||||
m_Ssl.SetCACerts(m_CACerts, m_ExpectedPeerName);
|
||||
}
|
||||
|
||||
ret = m_Ssl.Handshake();
|
||||
if (ret != 0)
|
||||
{
|
||||
Printf(m_LastErrorText, "SSL handshake failed: -0x%x", -ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_IsConnected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBlockingSslClientSocket::SetTrustedRootCertsFromString(const AString & a_CACerts, const AString & a_ExpectedPeerName)
|
||||
{
|
||||
// Warn if used multiple times, but don't signal an error:
|
||||
if (m_CACerts.get() != NULL)
|
||||
{
|
||||
LOGWARNING(
|
||||
"SSL: Trying to set multiple trusted CA root cert stores, only the last one will be used. Name: %s",
|
||||
a_ExpectedPeerName.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
// Parse the cert:
|
||||
m_CACerts.reset(new cX509Cert);
|
||||
int ret = m_CACerts->Parse(a_CACerts.data(), a_CACerts.size());
|
||||
if (ret < 0)
|
||||
{
|
||||
Printf(m_LastErrorText, "CA cert parsing failed: -0x%x", -ret);
|
||||
return false;
|
||||
}
|
||||
m_ExpectedPeerName = a_ExpectedPeerName;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBlockingSslClientSocket::Send(const void * a_Data, size_t a_NumBytes)
|
||||
{
|
||||
ASSERT(m_IsConnected);
|
||||
|
||||
// Keep sending the data until all of it is sent:
|
||||
const char * Data = (const char *)a_Data;
|
||||
size_t NumBytes = a_NumBytes;
|
||||
for (;;)
|
||||
{
|
||||
int res = m_Ssl.WritePlain(a_Data, a_NumBytes);
|
||||
if (res < 0)
|
||||
{
|
||||
ASSERT(res != POLARSSL_ERR_NET_WANT_READ); // This should never happen with callback-based SSL
|
||||
ASSERT(res != POLARSSL_ERR_NET_WANT_WRITE); // This should never happen with callback-based SSL
|
||||
Printf(m_LastErrorText, "Data cannot be written to SSL context: -0x%x", -res);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Data += res;
|
||||
NumBytes -= res;
|
||||
if (NumBytes == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cBlockingSslClientSocket::Receive(void * a_Data, size_t a_MaxBytes)
|
||||
{
|
||||
ASSERT(m_IsConnected);
|
||||
|
||||
int res = m_Ssl.ReadPlain(a_Data, a_MaxBytes);
|
||||
if (res < 0)
|
||||
{
|
||||
Printf(m_LastErrorText, "Data cannot be read form SSL context: -0x%x", -res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cBlockingSslClientSocket::Disconnect(void)
|
||||
{
|
||||
// Ignore if not connected
|
||||
if (!m_IsConnected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_Ssl.NotifyClose();
|
||||
m_Socket.CloseSocket();
|
||||
m_IsConnected = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cBlockingSslClientSocket::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
|
||||
{
|
||||
int res = m_Socket.Receive((char *)a_Buffer, a_NumBytes, 0);
|
||||
if (res < 0)
|
||||
{
|
||||
// PolarSSL's net routines distinguish between connection reset and general failure, we don't need to
|
||||
return POLARSSL_ERR_NET_RECV_FAILED;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cBlockingSslClientSocket::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes)
|
||||
{
|
||||
int res = m_Socket.Send((const char *)a_Buffer, a_NumBytes);
|
||||
if (res < 0)
|
||||
{
|
||||
// PolarSSL's net routines distinguish between connection reset and general failure, we don't need to
|
||||
return POLARSSL_ERR_NET_SEND_FAILED;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
80
src/PolarSSL++/BlockingSslClientSocket.h
Normal file
80
src/PolarSSL++/BlockingSslClientSocket.h
Normal file
@ -0,0 +1,80 @@
|
||||
|
||||
// BlockingSslClientSocket.h
|
||||
|
||||
// Declares the cBlockingSslClientSocket class representing a blocking TCP socket with client SSL encryption over it
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CallbackSslContext.h"
|
||||
#include "../OSSupport/Socket.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockingSslClientSocket :
|
||||
protected cCallbackSslContext::cDataCallbacks
|
||||
{
|
||||
public:
|
||||
cBlockingSslClientSocket(void);
|
||||
|
||||
/** Connects to the specified server and performs SSL handshake.
|
||||
Returns true if successful, false on failure. Sets internal error text on failure. */
|
||||
bool Connect(const AString & a_ServerName, UInt16 a_Port);
|
||||
|
||||
/** Sends the specified data over the connection.
|
||||
Returns true if successful, false on failure. Sets the internal error text on failure. */
|
||||
bool Send(const void * a_Data, size_t a_NumBytes);
|
||||
|
||||
/** Receives data from the connection.
|
||||
Blocks until there is any data available, then returns as much as possible.
|
||||
Returns the number of bytes actually received, negative number on failure.
|
||||
Sets the internal error text on failure. */
|
||||
int Receive(void * a_Data, size_t a_MaxBytes);
|
||||
|
||||
/** Disconnects the connection gracefully, if possible.
|
||||
Note that this also frees the internal SSL context, so all the certificates etc. are lost. */
|
||||
void Disconnect(void);
|
||||
|
||||
/** Sets the root certificates that are to be trusted. Forces the connection to use strict cert
|
||||
verification. Needs to be used before calling Connect().
|
||||
a_ExpectedPeerName is the name that we expect to receive in the SSL peer's cert; verification will fail if
|
||||
the presented name is different (possible MITM).
|
||||
Returns true on success, false on failure. Sets internal error text on failure. */
|
||||
bool SetTrustedRootCertsFromString(const AString & a_CACerts, const AString & a_ExpectedPeerName);
|
||||
|
||||
/** Returns the text of the last error that has occurred in this instance. */
|
||||
const AString & GetLastErrorText(void) const { return m_LastErrorText; }
|
||||
|
||||
protected:
|
||||
/** The SSL context used for the socket */
|
||||
cCallbackSslContext m_Ssl;
|
||||
|
||||
/** The underlying socket to the SSL server */
|
||||
cSocket m_Socket;
|
||||
|
||||
/** The trusted CA root cert store, if we are to verify the cert strictly. Set by SetTrustedRootCertsFromString(). */
|
||||
cX509CertPtr m_CACerts;
|
||||
|
||||
/** The expected SSL peer's name, if we are to verify the cert strictly. Set by SetTrustedRootCertsFromString(). */
|
||||
AString m_ExpectedPeerName;
|
||||
|
||||
/** Text of the last error that has occurred. */
|
||||
AString m_LastErrorText;
|
||||
|
||||
/** Set to true if the connection established successfully. */
|
||||
bool m_IsConnected;
|
||||
|
||||
|
||||
// cCallbackSslContext::cDataCallbacks overrides:
|
||||
virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override;
|
||||
virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
62
src/PolarSSL++/BufferedSslContext.cpp
Normal file
62
src/PolarSSL++/BufferedSslContext.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
|
||||
// BufferedSslContext.cpp
|
||||
|
||||
// Implements the cBufferedSslContext class representing a SSL context with the SSL peer data backed by a cByteBuffer
|
||||
|
||||
#include "Globals.h"
|
||||
#include "BufferedSslContext.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cBufferedSslContext::cBufferedSslContext(size_t a_BufferSize):
|
||||
m_OutgoingData(a_BufferSize),
|
||||
m_IncomingData(a_BufferSize)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cBufferedSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
|
||||
{
|
||||
// Called when PolarSSL wants to read encrypted data from the SSL peer
|
||||
// Read the data from the buffer inside this object, where the owner has stored them using WriteIncoming():
|
||||
size_t NumBytes = std::min(a_NumBytes, m_IncomingData.GetReadableSpace());
|
||||
if (NumBytes == 0)
|
||||
{
|
||||
return POLARSSL_ERR_NET_WANT_READ;
|
||||
}
|
||||
if (!m_IncomingData.ReadBuf(a_Buffer, NumBytes))
|
||||
{
|
||||
m_IncomingData.ResetRead();
|
||||
return POLARSSL_ERR_NET_RECV_FAILED;
|
||||
}
|
||||
m_IncomingData.CommitRead();
|
||||
return (int)NumBytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cBufferedSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes)
|
||||
{
|
||||
// Called when PolarSSL wants to write encrypted data to the SSL peer
|
||||
// Write the data into the buffer inside this object, where the owner can later read them using ReadOutgoing():
|
||||
if (!m_OutgoingData.CanWriteBytes(a_NumBytes))
|
||||
{
|
||||
return POLARSSL_ERR_NET_WANT_WRITE;
|
||||
}
|
||||
if (!m_OutgoingData.Write((const char *)a_Buffer, a_NumBytes))
|
||||
{
|
||||
return POLARSSL_ERR_NET_SEND_FAILED;
|
||||
}
|
||||
return (int)a_NumBytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
52
src/PolarSSL++/BufferedSslContext.h
Normal file
52
src/PolarSSL++/BufferedSslContext.h
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
// BufferedSslContext.h
|
||||
|
||||
// Declares the cBufferedSslContext class representing a SSL context with the SSL peer data backed by a cByteBuffer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SslContext.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cBufferedSslContext :
|
||||
public cSslContext
|
||||
{
|
||||
typedef cSslContext super;
|
||||
|
||||
public:
|
||||
/** Creates a new context with the buffers of specified size for the encrypted / decrypted data. */
|
||||
cBufferedSslContext(size_t a_BufferSize = 64000);
|
||||
|
||||
/** Stores the specified data in the "incoming" buffer, to be process by the SSL decryptor.
|
||||
This is the data received from the SSL peer.
|
||||
Returns the number of bytes actually stored. If 0 is returned, owner should check the error state. */
|
||||
size_t WriteIncoming(const void * a_Data, size_t a_NumBytes);
|
||||
|
||||
/** Retrieves data from the "outgoing" buffer, after being processed by the SSL encryptor.
|
||||
This is the data to be sent to the SSL peer.
|
||||
Returns the number of bytes actually retrieved. */
|
||||
size_t ReadOutgoing(void * a_Data, size_t a_DataMaxSize);
|
||||
|
||||
protected:
|
||||
/** Buffer for the data that has been encrypted into the SSL stream and should be sent out. */
|
||||
cByteBuffer m_OutgoingData;
|
||||
|
||||
/** Buffer for the data that has come in and needs to be decrypted from the SSL stream. */
|
||||
cByteBuffer m_IncomingData;
|
||||
|
||||
|
||||
// cSslContext overrides:
|
||||
virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override;
|
||||
virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
41
src/PolarSSL++/CMakeLists.txt
Normal file
41
src/PolarSSL++/CMakeLists.txt
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (MCServer)
|
||||
|
||||
include_directories ("${PROJECT_SOURCE_DIR}/../")
|
||||
|
||||
set(SOURCES
|
||||
AesCfb128Decryptor.cpp
|
||||
AesCfb128Encryptor.cpp
|
||||
BlockingSslClientSocket.cpp
|
||||
BufferedSslContext.cpp
|
||||
CallbackSslContext.cpp
|
||||
CtrDrbgContext.cpp
|
||||
EntropyContext.cpp
|
||||
PublicKey.cpp
|
||||
RsaPrivateKey.cpp
|
||||
Sha1Checksum.cpp
|
||||
SslContext.cpp
|
||||
X509Cert.cpp
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
AesCfb128Decryptor.h
|
||||
AesCfb128Encryptor.h
|
||||
BlockingSslClientSocket.h
|
||||
BufferedSslContext.h
|
||||
CallbackSslContext.h
|
||||
CtrDrbgContext.h
|
||||
EntropyContext.h
|
||||
PublicKey.h
|
||||
RsaPrivateKey.h
|
||||
SslContext.h
|
||||
Sha1Checksum.h
|
||||
X509Cert.h
|
||||
)
|
||||
|
||||
add_library(PolarSSL++ ${SOURCES} ${HEADERS})
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(PolarSSL++ polarssl)
|
||||
endif()
|
59
src/PolarSSL++/CallbackSslContext.cpp
Normal file
59
src/PolarSSL++/CallbackSslContext.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
|
||||
// CallbackSslContext.cpp
|
||||
|
||||
// Declares the cCallbackSslContext class representing a SSL context wrapper that uses callbacks to read and write SSL peer data
|
||||
|
||||
#include "Globals.h"
|
||||
#include "CallbackSslContext.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cCallbackSslContext::cCallbackSslContext(void)
|
||||
{
|
||||
// Nothing needed, but the constructor needs to exist so
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cCallbackSslContext::cCallbackSslContext(cCallbackSslContext::cDataCallbacks & a_Callbacks) :
|
||||
m_Callbacks(&a_Callbacks)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cCallbackSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
|
||||
{
|
||||
if (m_Callbacks == NULL)
|
||||
{
|
||||
LOGWARNING("SSL: Trying to receive data with no callbacks, aborting.");
|
||||
return POLARSSL_ERR_NET_RECV_FAILED;
|
||||
}
|
||||
return m_Callbacks->ReceiveEncrypted(a_Buffer, a_NumBytes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cCallbackSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes)
|
||||
{
|
||||
if (m_Callbacks == NULL)
|
||||
{
|
||||
LOGWARNING("SSL: Trying to send data with no callbacks, aborting.");
|
||||
return POLARSSL_ERR_NET_SEND_FAILED;
|
||||
}
|
||||
return m_Callbacks->SendEncrypted(a_Buffer, a_NumBytes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
61
src/PolarSSL++/CallbackSslContext.h
Normal file
61
src/PolarSSL++/CallbackSslContext.h
Normal file
@ -0,0 +1,61 @@
|
||||
|
||||
// CallbackSslContext.h
|
||||
|
||||
// Declares the cCallbackSslContext class representing a SSL context wrapper that uses callbacks to read and write SSL peer data
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SslContext.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cCallbackSslContext :
|
||||
public cSslContext
|
||||
{
|
||||
public:
|
||||
/** Interface used as a data sink for the SSL peer data. */
|
||||
class cDataCallbacks
|
||||
{
|
||||
public:
|
||||
/** Called when PolarSSL wants to read encrypted data from the SSL peer.
|
||||
The returned value is the number of bytes received, or a PolarSSL error on failure.
|
||||
The implementation can return POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE to indicate
|
||||
that there's currently no more data and that there might be more data in the future. In such cases the
|
||||
SSL operation that invoked this call will terminate with the same return value, so that the owner is
|
||||
notified of this condition and can potentially restart the operation later on. */
|
||||
virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) = 0;
|
||||
|
||||
/** Called when PolarSSL wants to write encrypted data to the SSL peer.
|
||||
The returned value is the number of bytes sent, or a PolarSSL error on failure.
|
||||
The implementation can return POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE to indicate
|
||||
that there's currently no more data and that there might be more data in the future. In such cases the
|
||||
SSL operation that invoked this call will terminate with the same return value, so that the owner is
|
||||
notified of this condition and can potentially restart the operation later on. */
|
||||
virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) = 0;
|
||||
} ;
|
||||
|
||||
|
||||
/** Creates a new SSL context with no callbacks assigned */
|
||||
cCallbackSslContext(void);
|
||||
|
||||
/** Creates a new SSL context with the specified callbacks */
|
||||
cCallbackSslContext(cDataCallbacks & a_Callbacks);
|
||||
|
||||
protected:
|
||||
/** The callbacks to use to send and receive SSL peer data */
|
||||
cDataCallbacks * m_Callbacks;
|
||||
|
||||
// cSslContext overrides:
|
||||
virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override;
|
||||
virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
49
src/PolarSSL++/CtrDrbgContext.cpp
Normal file
49
src/PolarSSL++/CtrDrbgContext.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
// CtrDrbgContext.cpp
|
||||
|
||||
// Implements the cCtrDrbgContext class representing a wrapper over CTR-DRBG implementation in PolarSSL
|
||||
|
||||
#include "Globals.h"
|
||||
#include "CtrDrbgContext.h"
|
||||
#include "EntropyContext.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cCtrDrbgContext::cCtrDrbgContext(void) :
|
||||
m_EntropyContext(new cEntropyContext),
|
||||
m_IsValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cCtrDrbgContext::cCtrDrbgContext(const SharedPtr<cEntropyContext> & a_EntropyContext) :
|
||||
m_EntropyContext(a_EntropyContext),
|
||||
m_IsValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cCtrDrbgContext::Initialize(const void * a_Custom, size_t a_CustomSize)
|
||||
{
|
||||
if (m_IsValid)
|
||||
{
|
||||
// Already initialized
|
||||
return 0;
|
||||
}
|
||||
|
||||
int res = ctr_drbg_init(&m_CtrDrbg, entropy_func, &(m_EntropyContext->m_Entropy), (const unsigned char *)a_Custom, a_CustomSize);
|
||||
m_IsValid = (res == 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
63
src/PolarSSL++/CtrDrbgContext.h
Normal file
63
src/PolarSSL++/CtrDrbgContext.h
Normal file
@ -0,0 +1,63 @@
|
||||
|
||||
// CtrDrbgContext.h
|
||||
|
||||
// Declares the cCtrDrbgContext class representing a wrapper over CTR-DRBG implementation in PolarSSL
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polarssl/ctr_drbg.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// fwd: EntropyContext.h
|
||||
class cEntropyContext;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cCtrDrbgContext
|
||||
{
|
||||
friend class cSslContext;
|
||||
friend class cRsaPrivateKey;
|
||||
friend class cPublicKey;
|
||||
|
||||
public:
|
||||
/** Constructs the context with a new entropy context. */
|
||||
cCtrDrbgContext(void);
|
||||
|
||||
/** Constructs the context with the specified entropy context. */
|
||||
cCtrDrbgContext(const SharedPtr<cEntropyContext> & a_EntropyContext);
|
||||
|
||||
/** Initializes the context.
|
||||
a_Custom is optional additional data to use for entropy, nullptr is accepted.
|
||||
Returns 0 if successful, PolarSSL error code on failure. */
|
||||
int Initialize(const void * a_Custom, size_t a_CustomSize);
|
||||
|
||||
/** Returns true if the object is valid (has been initialized properly) */
|
||||
bool IsValid(void) const { return m_IsValid; }
|
||||
|
||||
protected:
|
||||
/** The entropy source used for generating the random */
|
||||
SharedPtr<cEntropyContext> m_EntropyContext;
|
||||
|
||||
/** The random generator context */
|
||||
ctr_drbg_context m_CtrDrbg;
|
||||
|
||||
/** Set to true if the object is valid (has been initialized properly) */
|
||||
bool m_IsValid;
|
||||
|
||||
|
||||
/** Returns the internal context ptr. Only use in PolarSSL API calls. */
|
||||
ctr_drbg_context * GetInternal(void) { return &m_CtrDrbg; }
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
29
src/PolarSSL++/EntropyContext.cpp
Normal file
29
src/PolarSSL++/EntropyContext.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
// EntropyContext.cpp
|
||||
|
||||
// Implements the cEntropyContext class representing a wrapper over entropy contexts in PolarSSL
|
||||
|
||||
#include "Globals.h"
|
||||
#include "EntropyContext.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cEntropyContext::cEntropyContext(void)
|
||||
{
|
||||
entropy_init(&m_Entropy);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cEntropyContext::~cEntropyContext()
|
||||
{
|
||||
entropy_free(&m_Entropy);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
31
src/PolarSSL++/EntropyContext.h
Normal file
31
src/PolarSSL++/EntropyContext.h
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
// EntropyContext.h
|
||||
|
||||
// Declares the cEntropyContext class representing a wrapper over entropy contexts in PolarSSL
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polarssl/entropy.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntropyContext
|
||||
{
|
||||
friend class cCtrDrbgContext;
|
||||
public:
|
||||
cEntropyContext(void);
|
||||
~cEntropyContext();
|
||||
|
||||
protected:
|
||||
entropy_context m_Entropy;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
73
src/PolarSSL++/PublicKey.cpp
Normal file
73
src/PolarSSL++/PublicKey.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
// PublicKey.cpp
|
||||
|
||||
// Implements the cPublicKey class representing a RSA public key in PolarSSL
|
||||
|
||||
#include "Globals.h"
|
||||
#include "PublicKey.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPublicKey::cPublicKey(const AString & a_PublicKeyDER)
|
||||
{
|
||||
pk_init(&m_Pk);
|
||||
if (pk_parse_public_key(&m_Pk, (const Byte *)a_PublicKeyDER.data(), a_PublicKeyDER.size()) != 0)
|
||||
{
|
||||
ASSERT(!"Cannot parse PubKey");
|
||||
return;
|
||||
}
|
||||
m_CtrDrbg.Initialize("rsa_pubkey", 10);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPublicKey::~cPublicKey()
|
||||
{
|
||||
pk_free(&m_Pk);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cPublicKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
|
||||
{
|
||||
size_t DecryptedLen = a_DecryptedMaxLength;
|
||||
int res = pk_decrypt(&m_Pk,
|
||||
a_EncryptedData, a_EncryptedLength,
|
||||
a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength,
|
||||
ctr_drbg_random, m_CtrDrbg.GetInternal()
|
||||
);
|
||||
if (res != 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
return (int)DecryptedLen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cPublicKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
|
||||
{
|
||||
size_t EncryptedLength = a_EncryptedMaxLength;
|
||||
int res = pk_encrypt(&m_Pk,
|
||||
a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength,
|
||||
ctr_drbg_random, m_CtrDrbg.GetInternal()
|
||||
);
|
||||
if (res != 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
return (int)EncryptedLength;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
48
src/PolarSSL++/PublicKey.h
Normal file
48
src/PolarSSL++/PublicKey.h
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
// PublicKey.h
|
||||
|
||||
// Declares the cPublicKey class representing a RSA public key in PolarSSL
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CtrDrbgContext.h"
|
||||
#include "polarssl/pk.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cPublicKey
|
||||
{
|
||||
public:
|
||||
/** Constructs the public key out of the DER-encoded pubkey data */
|
||||
cPublicKey(const AString & a_PublicKeyDER);
|
||||
|
||||
~cPublicKey();
|
||||
|
||||
/** Decrypts the data using the stored public key
|
||||
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||
Returns the number of bytes decrypted, or negative number for error. */
|
||||
int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
|
||||
|
||||
/** Encrypts the data using the stored public key
|
||||
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||
Returns the number of bytes decrypted, or negative number for error. */
|
||||
int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
|
||||
|
||||
protected:
|
||||
/** The public key PolarSSL representation */
|
||||
pk_context m_Pk;
|
||||
|
||||
/** The random generator used in encryption and decryption */
|
||||
cCtrDrbgContext m_CtrDrbg;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
176
src/PolarSSL++/RsaPrivateKey.cpp
Normal file
176
src/PolarSSL++/RsaPrivateKey.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
|
||||
// RsaPrivateKey.cpp
|
||||
|
||||
#include "Globals.h"
|
||||
#include "RsaPrivateKey.h"
|
||||
#include "CtrDrbgContext.h"
|
||||
#include "polarssl/pk.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cRsaPrivateKey::cRsaPrivateKey(void)
|
||||
{
|
||||
rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
|
||||
m_CtrDrbg.Initialize("RSA", 3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cRsaPrivateKey::cRsaPrivateKey(const cRsaPrivateKey & a_Other)
|
||||
{
|
||||
rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
|
||||
rsa_copy(&m_Rsa, &a_Other.m_Rsa);
|
||||
m_CtrDrbg.Initialize("RSA", 3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cRsaPrivateKey::~cRsaPrivateKey()
|
||||
{
|
||||
rsa_free(&m_Rsa);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cRsaPrivateKey::Generate(unsigned a_KeySizeBits)
|
||||
{
|
||||
int res = rsa_gen_key(&m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), a_KeySizeBits, 65537);
|
||||
if (res != 0)
|
||||
{
|
||||
LOG("RSA key generation failed: -0x%x", -res);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AString cRsaPrivateKey::GetPubKeyDER(void)
|
||||
{
|
||||
class cPubKey
|
||||
{
|
||||
public:
|
||||
cPubKey(rsa_context * a_Rsa) :
|
||||
m_IsValid(false)
|
||||
{
|
||||
pk_init(&m_Key);
|
||||
if (pk_init_ctx(&m_Key, pk_info_from_type(POLARSSL_PK_RSA)) != 0)
|
||||
{
|
||||
ASSERT(!"Cannot init PrivKey context");
|
||||
return;
|
||||
}
|
||||
if (rsa_copy(pk_rsa(m_Key), a_Rsa) != 0)
|
||||
{
|
||||
ASSERT(!"Cannot copy PrivKey to PK context");
|
||||
return;
|
||||
}
|
||||
m_IsValid = true;
|
||||
}
|
||||
|
||||
~cPubKey()
|
||||
{
|
||||
if (m_IsValid)
|
||||
{
|
||||
pk_free(&m_Key);
|
||||
}
|
||||
}
|
||||
|
||||
operator pk_context * (void) { return &m_Key; }
|
||||
|
||||
protected:
|
||||
bool m_IsValid;
|
||||
pk_context m_Key;
|
||||
} PkCtx(&m_Rsa);
|
||||
|
||||
unsigned char buf[3000];
|
||||
int res = pk_write_pubkey_der(PkCtx, buf, sizeof(buf));
|
||||
if (res < 0)
|
||||
{
|
||||
return AString();
|
||||
}
|
||||
return AString((const char *)(buf + sizeof(buf) - res), (size_t)res);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cRsaPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
|
||||
{
|
||||
if (a_EncryptedLength < m_Rsa.len)
|
||||
{
|
||||
LOGD("%s: Invalid a_EncryptedLength: got %u, exp at least %u",
|
||||
__FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
|
||||
);
|
||||
ASSERT(!"Invalid a_DecryptedMaxLength!");
|
||||
return -1;
|
||||
}
|
||||
if (a_DecryptedMaxLength < m_Rsa.len)
|
||||
{
|
||||
LOGD("%s: Invalid a_DecryptedMaxLength: got %u, exp at least %u",
|
||||
__FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
|
||||
);
|
||||
ASSERT(!"Invalid a_DecryptedMaxLength!");
|
||||
return -1;
|
||||
}
|
||||
size_t DecryptedLength;
|
||||
int res = rsa_pkcs1_decrypt(
|
||||
&m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), RSA_PRIVATE, &DecryptedLength,
|
||||
a_EncryptedData, a_DecryptedData, a_DecryptedMaxLength
|
||||
);
|
||||
if (res != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return (int)DecryptedLength;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cRsaPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
|
||||
{
|
||||
if (a_EncryptedMaxLength < m_Rsa.len)
|
||||
{
|
||||
LOGD("%s: Invalid a_EncryptedMaxLength: got %u, exp at least %u",
|
||||
__FUNCTION__, (unsigned)a_EncryptedMaxLength, (unsigned)(m_Rsa.len)
|
||||
);
|
||||
ASSERT(!"Invalid a_DecryptedMaxLength!");
|
||||
return -1;
|
||||
}
|
||||
if (a_PlainLength < m_Rsa.len)
|
||||
{
|
||||
LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u",
|
||||
__FUNCTION__, (unsigned)a_PlainLength, (unsigned)(m_Rsa.len)
|
||||
);
|
||||
ASSERT(!"Invalid a_PlainLength!");
|
||||
return -1;
|
||||
}
|
||||
int res = rsa_pkcs1_encrypt(
|
||||
&m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), RSA_PRIVATE,
|
||||
a_PlainLength, a_PlainData, a_EncryptedData
|
||||
);
|
||||
if (res != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return (int)m_Rsa.len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
59
src/PolarSSL++/RsaPrivateKey.h
Normal file
59
src/PolarSSL++/RsaPrivateKey.h
Normal file
@ -0,0 +1,59 @@
|
||||
|
||||
// RsaPrivateKey.h
|
||||
|
||||
// Declares the cRsaPrivateKey class representing a private key for RSA operations.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CtrDrbgContext.h"
|
||||
#include "polarssl/rsa.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Encapsulates an RSA private key used in PKI cryptography */
|
||||
class cRsaPrivateKey
|
||||
{
|
||||
public:
|
||||
/** Creates a new empty object, the key is not assigned */
|
||||
cRsaPrivateKey(void);
|
||||
|
||||
/** Deep-copies the key from a_Other */
|
||||
cRsaPrivateKey(const cRsaPrivateKey & a_Other);
|
||||
|
||||
~cRsaPrivateKey();
|
||||
|
||||
/** Generates a new key within this object, with the specified size in bits.
|
||||
Returns true on success, false on failure. */
|
||||
bool Generate(unsigned a_KeySizeBits = 1024);
|
||||
|
||||
/** Returns the public key part encoded in ASN1 DER encoding */
|
||||
AString GetPubKeyDER(void);
|
||||
|
||||
/** Decrypts the data using RSAES-PKCS#1 algorithm.
|
||||
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||
Returns the number of bytes decrypted, or negative number for error. */
|
||||
int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
|
||||
|
||||
/** Encrypts the data using RSAES-PKCS#1 algorithm.
|
||||
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||
Returns the number of bytes decrypted, or negative number for error. */
|
||||
int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
|
||||
|
||||
protected:
|
||||
/** The PolarSSL key context */
|
||||
rsa_context m_Rsa;
|
||||
|
||||
/** The random generator used for generating the key and encryption / decryption */
|
||||
cCtrDrbgContext m_CtrDrbg;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
138
src/PolarSSL++/Sha1Checksum.cpp
Normal file
138
src/PolarSSL++/Sha1Checksum.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
|
||||
// Sha1Checksum.cpp
|
||||
|
||||
// Declares the cSha1Checksum class representing the SHA-1 checksum calculator
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Sha1Checksum.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
// Self-test the hash formatting for known values:
|
||||
// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48
|
||||
// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1
|
||||
// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6
|
||||
|
||||
static class Test
|
||||
{
|
||||
public:
|
||||
Test(void)
|
||||
{
|
||||
AString DigestNotch, DigestJeb, DigestSimon;
|
||||
Byte Digest[20];
|
||||
cSha1Checksum Checksum;
|
||||
Checksum.Update((const Byte *)"Notch", 5);
|
||||
Checksum.Finalize(Digest);
|
||||
cSha1Checksum::DigestToJava(Digest, DigestNotch);
|
||||
Checksum.Restart();
|
||||
Checksum.Update((const Byte *)"jeb_", 4);
|
||||
Checksum.Finalize(Digest);
|
||||
cSha1Checksum::DigestToJava(Digest, DigestJeb);
|
||||
Checksum.Restart();
|
||||
Checksum.Update((const Byte *)"simon", 5);
|
||||
Checksum.Finalize(Digest);
|
||||
cSha1Checksum::DigestToJava(Digest, DigestSimon);
|
||||
printf("Notch: \"%s\"\n", DigestNotch.c_str());
|
||||
printf("jeb_: \"%s\"\n", DigestJeb.c_str());
|
||||
printf("simon: \"%s\"\n", DigestSimon.c_str());
|
||||
assert(DigestNotch == "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48");
|
||||
assert(DigestJeb == "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1");
|
||||
assert(DigestSimon == "88e16a1019277b15d58faf0541e11910eb756f6");
|
||||
}
|
||||
} test;
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cSha1Checksum:
|
||||
|
||||
cSha1Checksum::cSha1Checksum(void) :
|
||||
m_DoesAcceptInput(true)
|
||||
{
|
||||
sha1_starts(&m_Sha1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSha1Checksum::Update(const Byte * a_Data, size_t a_Length)
|
||||
{
|
||||
ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
|
||||
|
||||
sha1_update(&m_Sha1, a_Data, a_Length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSha1Checksum::Finalize(cSha1Checksum::Checksum & a_Output)
|
||||
{
|
||||
ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
|
||||
|
||||
sha1_finish(&m_Sha1, a_Output);
|
||||
m_DoesAcceptInput = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSha1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out)
|
||||
{
|
||||
Checksum Digest;
|
||||
memcpy(Digest, a_Digest, sizeof(Digest));
|
||||
|
||||
bool IsNegative = (Digest[0] >= 0x80);
|
||||
if (IsNegative)
|
||||
{
|
||||
// Two's complement:
|
||||
bool carry = true; // Add one to the whole number
|
||||
for (int i = 19; i >= 0; i--)
|
||||
{
|
||||
Digest[i] = ~Digest[i];
|
||||
if (carry)
|
||||
{
|
||||
carry = (Digest[i] == 0xff);
|
||||
Digest[i]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
a_Out.clear();
|
||||
a_Out.reserve(40);
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
AppendPrintf(a_Out, "%02x", Digest[i]);
|
||||
}
|
||||
while ((a_Out.length() > 0) && (a_Out[0] == '0'))
|
||||
{
|
||||
a_Out.erase(0, 1);
|
||||
}
|
||||
if (IsNegative)
|
||||
{
|
||||
a_Out.insert(0, "-");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSha1Checksum::Restart(void)
|
||||
{
|
||||
sha1_starts(&m_Sha1);
|
||||
m_DoesAcceptInput = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
52
src/PolarSSL++/Sha1Checksum.h
Normal file
52
src/PolarSSL++/Sha1Checksum.h
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
// Sha1Checksum.h
|
||||
|
||||
// Declares the cSha1Checksum class representing the SHA-1 checksum calculator
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polarssl/sha1.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Calculates a SHA1 checksum for data stream */
|
||||
class cSha1Checksum
|
||||
{
|
||||
public:
|
||||
typedef Byte Checksum[20]; // The type used for storing the checksum
|
||||
|
||||
cSha1Checksum(void);
|
||||
|
||||
/** Adds the specified data to the checksum */
|
||||
void Update(const Byte * a_Data, size_t a_Length);
|
||||
|
||||
/** Calculates and returns the final checksum */
|
||||
void Finalize(Checksum & a_Output);
|
||||
|
||||
/** Returns true if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
|
||||
bool DoesAcceptInput(void) const { return m_DoesAcceptInput; }
|
||||
|
||||
/** Converts a raw 160-bit SHA1 digest into a Java Hex representation
|
||||
According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802
|
||||
*/
|
||||
static void DigestToJava(const Checksum & a_Digest, AString & a_JavaOut);
|
||||
|
||||
/** Clears the current context and start a new checksum calculation */
|
||||
void Restart(void);
|
||||
|
||||
protected:
|
||||
/** True if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
|
||||
bool m_DoesAcceptInput;
|
||||
|
||||
sha1_context m_Sha1;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
243
src/PolarSSL++/SslContext.cpp
Normal file
243
src/PolarSSL++/SslContext.cpp
Normal file
@ -0,0 +1,243 @@
|
||||
|
||||
// SslContext.cpp
|
||||
|
||||
// Implements the cSslContext class that holds everything a single SSL context needs to function
|
||||
|
||||
#include "Globals.h"
|
||||
#include "SslContext.h"
|
||||
#include "EntropyContext.h"
|
||||
#include "CtrDrbgContext.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cSslContext::cSslContext(void) :
|
||||
m_IsValid(false),
|
||||
m_HasHandshaken(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cSslContext::~cSslContext()
|
||||
{
|
||||
if (m_IsValid)
|
||||
{
|
||||
ssl_free(&m_Ssl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cSslContext::Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> & a_CtrDrbg)
|
||||
{
|
||||
// Check double-initialization:
|
||||
if (m_IsValid)
|
||||
{
|
||||
LOGWARNING("SSL: Double initialization is not supported.");
|
||||
return POLARSSL_ERR_SSL_MALLOC_FAILED; // There is no return value well-suited for this, reuse this one.
|
||||
}
|
||||
|
||||
// Set the CtrDrbg context, create a new one if needed:
|
||||
m_CtrDrbg = a_CtrDrbg;
|
||||
if (m_CtrDrbg.get() == NULL)
|
||||
{
|
||||
m_CtrDrbg.reset(new cCtrDrbgContext);
|
||||
m_CtrDrbg->Initialize("MCServer", 8);
|
||||
}
|
||||
|
||||
// Initialize PolarSSL's structures:
|
||||
memset(&m_Ssl, 0, sizeof(m_Ssl));
|
||||
int res = ssl_init(&m_Ssl);
|
||||
if (res != 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
ssl_set_endpoint(&m_Ssl, a_IsClient ? SSL_IS_CLIENT : SSL_IS_SERVER);
|
||||
ssl_set_authmode(&m_Ssl, SSL_VERIFY_OPTIONAL);
|
||||
ssl_set_rng(&m_Ssl, ctr_drbg_random, &m_CtrDrbg->m_CtrDrbg);
|
||||
ssl_set_bio(&m_Ssl, ReceiveEncrypted, this, SendEncrypted, this);
|
||||
|
||||
#ifdef _DEBUG
|
||||
/*
|
||||
// These functions allow us to debug SSL and certificate problems, but produce way too much output,
|
||||
// so they're disabled until someone needs them
|
||||
ssl_set_dbg(&m_Ssl, &SSLDebugMessage, this);
|
||||
ssl_set_verify(&m_Ssl, &SSLVerifyCert, this);
|
||||
*/
|
||||
#endif
|
||||
|
||||
m_IsValid = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSslContext::SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName)
|
||||
{
|
||||
// Store the data in our internal buffers, to avoid losing the pointers later on
|
||||
// PolarSSL will need these after this call returns, and the caller may move / delete the data before that:
|
||||
m_ExpectedPeerName = a_ExpectedPeerName;
|
||||
m_CACerts = a_CACert;
|
||||
|
||||
// Set the trusted CA root cert store:
|
||||
ssl_set_authmode(&m_Ssl, SSL_VERIFY_REQUIRED);
|
||||
ssl_set_ca_chain(&m_Ssl, m_CACerts->GetInternal(), NULL, m_ExpectedPeerName.empty() ? NULL : m_ExpectedPeerName.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cSslContext::WritePlain(const void * a_Data, size_t a_NumBytes)
|
||||
{
|
||||
ASSERT(m_IsValid); // Need to call Initialize() first
|
||||
if (!m_HasHandshaken)
|
||||
{
|
||||
int res = Handshake();
|
||||
if (res != 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return ssl_write(&m_Ssl, (const unsigned char *)a_Data, a_NumBytes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cSslContext::ReadPlain(void * a_Data, size_t a_MaxBytes)
|
||||
{
|
||||
ASSERT(m_IsValid); // Need to call Initialize() first
|
||||
if (!m_HasHandshaken)
|
||||
{
|
||||
int res = Handshake();
|
||||
if (res != 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return ssl_read(&m_Ssl, (unsigned char *)a_Data, a_MaxBytes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cSslContext::Handshake(void)
|
||||
{
|
||||
ASSERT(m_IsValid); // Need to call Initialize() first
|
||||
ASSERT(!m_HasHandshaken); // Must not call twice
|
||||
|
||||
int res = ssl_handshake(&m_Ssl);
|
||||
if (res == 0)
|
||||
{
|
||||
m_HasHandshaken = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cSslContext::NotifyClose(void)
|
||||
{
|
||||
return ssl_close_notify(&m_Ssl);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
void cSslContext::SSLDebugMessage(void * a_UserParam, int a_Level, const char * a_Text)
|
||||
{
|
||||
if (a_Level > 3)
|
||||
{
|
||||
// Don't want the trace messages
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the terminating LF:
|
||||
size_t len = strlen(a_Text) - 1;
|
||||
while ((len > 0) && (a_Text[len] <= 32))
|
||||
{
|
||||
len--;
|
||||
}
|
||||
AString Text(a_Text, len + 1);
|
||||
|
||||
LOGD("SSL (%d): %s", a_Level, Text.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cSslContext::SSLVerifyCert(void * a_This, x509_crt * a_Crt, int a_Depth, int * a_Flags)
|
||||
{
|
||||
char buf[1024];
|
||||
UNUSED(a_This);
|
||||
|
||||
LOG("Verify requested for (Depth %d):", a_Depth);
|
||||
x509_crt_info(buf, sizeof(buf) - 1, "", a_Crt);
|
||||
LOG("%s", buf);
|
||||
|
||||
int Flags = *a_Flags;
|
||||
if ((Flags & BADCERT_EXPIRED) != 0)
|
||||
{
|
||||
LOG(" ! server certificate has expired");
|
||||
}
|
||||
|
||||
if ((Flags & BADCERT_REVOKED) != 0)
|
||||
{
|
||||
LOG(" ! server certificate has been revoked");
|
||||
}
|
||||
|
||||
if ((Flags & BADCERT_CN_MISMATCH) != 0)
|
||||
{
|
||||
LOG(" ! CN mismatch");
|
||||
}
|
||||
|
||||
if ((Flags & BADCERT_NOT_TRUSTED) != 0)
|
||||
{
|
||||
LOG(" ! self-signed or not signed by a trusted CA");
|
||||
}
|
||||
|
||||
if ((Flags & BADCRL_NOT_TRUSTED) != 0)
|
||||
{
|
||||
LOG(" ! CRL not trusted");
|
||||
}
|
||||
|
||||
if ((Flags & BADCRL_EXPIRED) != 0)
|
||||
{
|
||||
LOG(" ! CRL expired");
|
||||
}
|
||||
|
||||
if ((Flags & BADCERT_OTHER) != 0)
|
||||
{
|
||||
LOG(" ! other (unknown) flag");
|
||||
}
|
||||
|
||||
if (Flags == 0)
|
||||
{
|
||||
LOG(" This certificate has no flags");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif // _DEBUG
|
||||
|
||||
|
||||
|
||||
|
137
src/PolarSSL++/SslContext.h
Normal file
137
src/PolarSSL++/SslContext.h
Normal file
@ -0,0 +1,137 @@
|
||||
|
||||
// SslContext.h
|
||||
|
||||
// Declares the cSslContext class that holds everything a single SSL context needs to function
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polarssl/ssl.h"
|
||||
#include "../ByteBuffer.h"
|
||||
#include "X509Cert.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// fwd:
|
||||
class cCtrDrbgContext;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Acts as a generic SSL encryptor / decryptor between the two endpoints. The "owner" of this class is expected
|
||||
to create it, initialize it and then provide the means of reading and writing data through the SSL link.
|
||||
This is an abstract base class, there are descendants that handle the specific aspects of how the SSL peer
|
||||
data comes into the system:
|
||||
- cBufferedSslContext uses a cByteBuffer to read and write the data
|
||||
- cCallbackSslContext uses callbacks to provide the data
|
||||
*/
|
||||
class cSslContext abstract
|
||||
{
|
||||
public:
|
||||
/** Creates a new uninitialized context */
|
||||
cSslContext(void);
|
||||
|
||||
~cSslContext();
|
||||
|
||||
/** Initializes the context for use as a server or client.
|
||||
Returns 0 on success, PolarSSL error on failure. */
|
||||
int Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> & a_CtrDrbg = SharedPtr<cCtrDrbgContext>());
|
||||
|
||||
/** Returns true if the object has been initialized properly. */
|
||||
bool IsValid(void) const { return m_IsValid; }
|
||||
|
||||
/** Sets a cert chain as the trusted cert store for this context.
|
||||
Calling this will switch the context into strict cert verification mode.
|
||||
a_ExpectedPeerName is the CommonName that we expect the SSL peer to have in its cert,
|
||||
if it is different, the verification will fail. An empty string will disable the CN check. */
|
||||
void SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName);
|
||||
|
||||
/** Writes data to be encrypted and sent to the SSL peer. Will perform SSL handshake, if needed.
|
||||
Returns the number of bytes actually written, or PolarSSL error code.
|
||||
If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any
|
||||
cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call
|
||||
this function again with the same parameters. Note that this may repeat a few times before the data is
|
||||
actually written, mainly due to initial handshake. */
|
||||
int WritePlain(const void * a_Data, size_t a_NumBytes);
|
||||
|
||||
/** Reads data decrypted from the SSL stream. Will perform SSL handshake, if needed.
|
||||
Returns the number of bytes actually read, or PolarSSL error code.
|
||||
If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any
|
||||
cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call
|
||||
this function again with the same parameters. Note that this may repeat a few times before the data is
|
||||
actually read, mainly due to initial handshake. */
|
||||
int ReadPlain(void * a_Data, size_t a_MaxBytes);
|
||||
|
||||
/** Performs the SSL handshake.
|
||||
Returns zero on success, PoladSSL error code on failure.
|
||||
If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any
|
||||
cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call
|
||||
this function again. Note that this may repeat a few times before the handshake is completed. */
|
||||
int Handshake(void);
|
||||
|
||||
/** Returns true if the SSL handshake has been completed. */
|
||||
bool HasHandshaken(void) const { return m_HasHandshaken; }
|
||||
|
||||
/** Notifies the SSL peer that the connection is being closed.
|
||||
Returns 0 on success, PolarSSL error code on failure. */
|
||||
int NotifyClose(void);
|
||||
|
||||
protected:
|
||||
/** True if the object has been initialized properly. */
|
||||
bool m_IsValid;
|
||||
|
||||
/** The random generator to use */
|
||||
SharedPtr<cCtrDrbgContext> m_CtrDrbg;
|
||||
|
||||
/** The SSL context that PolarSSL uses. */
|
||||
ssl_context m_Ssl;
|
||||
|
||||
/** True if the SSL handshake has been completed. */
|
||||
bool m_HasHandshaken;
|
||||
|
||||
/** A copy of the trusted CA root cert store that is passed to us in SetCACerts(), so that the pointer
|
||||
stays valid even after the call, when PolarSSL finally uses it. */
|
||||
cX509CertPtr m_CACerts;
|
||||
|
||||
/** Buffer for the expected peer name. We need to buffer it because the caller may free the string they
|
||||
give us before PolarSSL consumes the raw pointer it gets to the CN. */
|
||||
AString m_ExpectedPeerName;
|
||||
|
||||
|
||||
/** The callback used by PolarSSL when it wants to read encrypted data. */
|
||||
static int ReceiveEncrypted(void * a_This, unsigned char * a_Buffer, size_t a_NumBytes)
|
||||
{
|
||||
return ((cSslContext *)a_This)->ReceiveEncrypted(a_Buffer, a_NumBytes);
|
||||
}
|
||||
|
||||
/** The callback used by PolarSSL when it wants to write encrypted data. */
|
||||
static int SendEncrypted(void * a_This, const unsigned char * a_Buffer, size_t a_NumBytes)
|
||||
{
|
||||
return ((cSslContext *)a_This)->SendEncrypted(a_Buffer, a_NumBytes);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
/** The callback used by PolarSSL to output debug messages */
|
||||
static void SSLDebugMessage(void * a_UserParam, int a_Level, const char * a_Text);
|
||||
|
||||
/** The callback used by PolarSSL to log information on the cert chain */
|
||||
static int SSLVerifyCert(void * a_This, x509_crt * a_Crt, int a_Depth, int * a_Flags);
|
||||
#endif // _DEBUG
|
||||
|
||||
/** Called when PolarSSL wants to read encrypted data. */
|
||||
virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) = 0;
|
||||
|
||||
/** Called when PolarSSL wants to write encrypted data. */
|
||||
virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) = 0;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
38
src/PolarSSL++/X509Cert.cpp
Normal file
38
src/PolarSSL++/X509Cert.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
|
||||
// X509Cert.cpp
|
||||
|
||||
// Implements the cX509Cert class representing a wrapper over X509 certs in PolarSSL
|
||||
|
||||
#include "Globals.h"
|
||||
#include "X509Cert.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cX509Cert::cX509Cert(void)
|
||||
{
|
||||
x509_crt_init(&m_Cert);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cX509Cert::~cX509Cert()
|
||||
{
|
||||
x509_crt_free(&m_Cert);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cX509Cert::Parse(const void * a_CertContents, size_t a_Size)
|
||||
{
|
||||
return x509_crt_parse(&m_Cert, (const unsigned char *)a_CertContents, a_Size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
41
src/PolarSSL++/X509Cert.h
Normal file
41
src/PolarSSL++/X509Cert.h
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
// X509Cert.h
|
||||
|
||||
// Declares the cX509Cert class representing a wrapper over X509 certs in PolarSSL
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polarssl/x509_crt.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cX509Cert
|
||||
{
|
||||
friend class cSslContext;
|
||||
|
||||
public:
|
||||
cX509Cert(void);
|
||||
~cX509Cert(void);
|
||||
|
||||
/** Parses the certificate chain data into the context.
|
||||
Returns 0 on succes, or PolarSSL error code on failure. */
|
||||
int Parse(const void * a_CertContents, size_t a_Size);
|
||||
|
||||
protected:
|
||||
x509_crt m_Cert;
|
||||
|
||||
/** Returns the internal cert ptr. Only use in PolarSSL API calls. */
|
||||
x509_crt * GetInternal(void) { return &m_Cert; }
|
||||
} ;
|
||||
|
||||
typedef SharedPtr<cX509Cert> cX509CertPtr;
|
||||
|
||||
|
||||
|
||||
|
@ -10,13 +10,7 @@
|
||||
#include "inifile/iniFile.h"
|
||||
#include "json/json.h"
|
||||
|
||||
#include "polarssl/config.h"
|
||||
#include "polarssl/net.h"
|
||||
#include "polarssl/ssl.h"
|
||||
#include "polarssl/entropy.h"
|
||||
#include "polarssl/ctr_drbg.h"
|
||||
#include "polarssl/error.h"
|
||||
#include "polarssl/certs.h"
|
||||
#include "PolarSSL++/BlockingSslClientSocket.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
@ -148,92 +142,74 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
|
||||
{
|
||||
LOGD("Trying to auth user %s", a_UserName.c_str());
|
||||
|
||||
int ret, server_fd = -1;
|
||||
int ret;
|
||||
unsigned char buf[1024];
|
||||
const char *pers = "cAuthenticator";
|
||||
|
||||
entropy_context entropy;
|
||||
ctr_drbg_context ctr_drbg;
|
||||
ssl_context ssl;
|
||||
x509_crt cacert;
|
||||
|
||||
/* Initialize the RNG and the session data */
|
||||
memset(&ssl, 0, sizeof(ssl_context));
|
||||
x509_crt_init(&cacert);
|
||||
|
||||
entropy_init(&entropy);
|
||||
if ((ret = ctr_drbg_init(&ctr_drbg, entropy_func, &entropy, (const unsigned char *)pers, strlen(pers))) != 0)
|
||||
{
|
||||
LOGWARNING("cAuthenticator: ctr_drbg_init returned %d", ret);
|
||||
|
||||
// Free all resources which have been initialized up to this line
|
||||
x509_crt_free(&cacert);
|
||||
entropy_free(&entropy);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Initialize certificates */
|
||||
// TODO: Grab the sessionserver's root CA and any intermediates and hard-code them here, instead of test_ca_list
|
||||
ret = x509_crt_parse(&cacert, (const unsigned char *)test_ca_list, strlen(test_ca_list));
|
||||
// This is the data of the root certs for Starfield Technologies, the CA that signed sessionserver.mojang.com's cert:
|
||||
// Downloaded from http://certs.starfieldtech.com/repository/
|
||||
static const AString StarfieldCACert(
|
||||
// G2 cert
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx\n"
|
||||
"EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT\n"
|
||||
"HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs\n"
|
||||
"ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw\n"
|
||||
"MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6\n"
|
||||
"b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj\n"
|
||||
"aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp\n"
|
||||
"Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n"
|
||||
"ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg\n"
|
||||
"nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1\n"
|
||||
"HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N\n"
|
||||
"Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN\n"
|
||||
"dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0\n"
|
||||
"HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO\n"
|
||||
"BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G\n"
|
||||
"CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU\n"
|
||||
"sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3\n"
|
||||
"4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg\n"
|
||||
"8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K\n"
|
||||
"pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1\n"
|
||||
"mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\n"
|
||||
"-----END CERTIFICATE-----\n\n"
|
||||
// Original (G1) cert:
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl\n"
|
||||
"MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp\n"
|
||||
"U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw\n"
|
||||
"NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE\n"
|
||||
"ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp\n"
|
||||
"ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3\n"
|
||||
"DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf\n"
|
||||
"8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN\n"
|
||||
"+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0\n"
|
||||
"X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa\n"
|
||||
"K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA\n"
|
||||
"1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G\n"
|
||||
"A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR\n"
|
||||
"zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0\n"
|
||||
"YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD\n"
|
||||
"bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w\n"
|
||||
"DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3\n"
|
||||
"L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D\n"
|
||||
"eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl\n"
|
||||
"xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp\n"
|
||||
"VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY\n"
|
||||
"WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=\n"
|
||||
"-----END CERTIFICATE-----\n"
|
||||
);
|
||||
|
||||
if (ret < 0)
|
||||
// Connect the socket:
|
||||
cBlockingSslClientSocket Socket;
|
||||
Socket.SetTrustedRootCertsFromString(StarfieldCACert, m_Server);
|
||||
if (!Socket.Connect(m_Server, 443))
|
||||
{
|
||||
LOGWARNING("cAuthenticator: x509_crt_parse returned -0x%x", -ret);
|
||||
|
||||
// Free all resources which have been initialized up to this line
|
||||
x509_crt_free(&cacert);
|
||||
entropy_free(&entropy);
|
||||
LOGWARNING("cAuthenticator: Can't connect to %s: %s", m_Server.c_str(), Socket.GetLastErrorText().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Connect */
|
||||
if ((ret = net_connect(&server_fd, m_Server.c_str(), 443)) != 0)
|
||||
{
|
||||
LOGWARNING("cAuthenticator: Can't connect to %s: %d", m_Server.c_str(), ret);
|
||||
|
||||
// Free all resources which have been initialized up to this line
|
||||
x509_crt_free(&cacert);
|
||||
entropy_free(&entropy);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Setup */
|
||||
if ((ret = ssl_init(&ssl)) != 0)
|
||||
{
|
||||
LOGWARNING("cAuthenticator: ssl_init returned %d", ret);
|
||||
|
||||
// Free all resources which have been initialized up to this line
|
||||
x509_crt_free(&cacert);
|
||||
net_close(server_fd);
|
||||
ssl_free(&ssl);
|
||||
entropy_free(&entropy);
|
||||
memset(&ssl, 0, sizeof(ssl));
|
||||
return false;
|
||||
}
|
||||
ssl_set_endpoint(&ssl, SSL_IS_CLIENT);
|
||||
ssl_set_authmode(&ssl, SSL_VERIFY_OPTIONAL);
|
||||
ssl_set_ca_chain(&ssl, &cacert, NULL, "PolarSSL Server 1");
|
||||
ssl_set_rng(&ssl, ctr_drbg_random, &ctr_drbg);
|
||||
ssl_set_bio(&ssl, net_recv, &server_fd, net_send, &server_fd);
|
||||
|
||||
/* Handshake */
|
||||
while ((ret = ssl_handshake(&ssl)) != 0)
|
||||
{
|
||||
if ((ret != POLARSSL_ERR_NET_WANT_READ) && (ret != POLARSSL_ERR_NET_WANT_WRITE))
|
||||
{
|
||||
LOGWARNING("cAuthenticator: ssl_handshake returned -0x%x", -ret);
|
||||
|
||||
// Free all resources which have been initialized up to this line
|
||||
x509_crt_free(&cacert);
|
||||
net_close(server_fd);
|
||||
ssl_free(&ssl);
|
||||
entropy_free(&entropy);
|
||||
memset(&ssl, 0, sizeof(ssl));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the GET request */
|
||||
// Create the GET request:
|
||||
AString ActualAddress = m_Address;
|
||||
ReplaceString(ActualAddress, "%USERNAME%", a_UserName);
|
||||
ReplaceString(ActualAddress, "%SERVERID%", a_ServerId);
|
||||
@ -245,30 +221,23 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
|
||||
Request += "Connection: close\r\n";
|
||||
Request += "\r\n";
|
||||
|
||||
ret = ssl_write(&ssl, (const unsigned char *)Request.c_str(), Request.size());
|
||||
if (ret <= 0)
|
||||
if (!Socket.Send(Request.c_str(), Request.size()))
|
||||
{
|
||||
LOGWARNING("cAuthenticator: ssl_write returned %d", ret);
|
||||
|
||||
// Free all resources which have been initialized up to this line
|
||||
x509_crt_free(&cacert);
|
||||
net_close(server_fd);
|
||||
ssl_free(&ssl);
|
||||
entropy_free(&entropy);
|
||||
memset(&ssl, 0, sizeof(ssl));
|
||||
LOGWARNING("cAuthenticator: Writing SSL data failed: %s", Socket.GetLastErrorText().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read the HTTP response */
|
||||
// Read the HTTP response:
|
||||
std::string Response;
|
||||
for (;;)
|
||||
{
|
||||
memset(buf, 0, sizeof(buf));
|
||||
ret = ssl_read(&ssl, buf, sizeof(buf));
|
||||
ret = Socket.Receive(buf, sizeof(buf));
|
||||
|
||||
if ((ret == POLARSSL_ERR_NET_WANT_READ) || (ret == POLARSSL_ERR_NET_WANT_WRITE))
|
||||
{
|
||||
continue;
|
||||
// This value should never be returned, it is handled internally by cBlockingSslClientSocket
|
||||
LOGWARNING("cAuthenticator: SSL reading failed internally.");
|
||||
return false;
|
||||
}
|
||||
if (ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY)
|
||||
{
|
||||
@ -276,24 +245,18 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
|
||||
}
|
||||
if (ret < 0)
|
||||
{
|
||||
LOGWARNING("cAuthenticator: ssl_read returned %d", ret);
|
||||
break;
|
||||
LOGWARNING("cAuthenticator: SSL reading failed: -0x%x", -ret);
|
||||
return false;
|
||||
}
|
||||
if (ret == 0)
|
||||
{
|
||||
LOGWARNING("cAuthenticator: EOF");
|
||||
break;
|
||||
}
|
||||
|
||||
Response.append((const char *)buf, ret);
|
||||
Response.append((const char *)buf, (size_t)ret);
|
||||
}
|
||||
|
||||
ssl_close_notify(&ssl);
|
||||
x509_crt_free(&cacert);
|
||||
net_close(server_fd);
|
||||
ssl_free(&ssl);
|
||||
entropy_free(&entropy);
|
||||
memset(&ssl, 0, sizeof(ssl));
|
||||
Socket.Disconnect();
|
||||
|
||||
// Check the HTTP status line:
|
||||
AString prefix("HTTP/1.1 200 OK");
|
||||
|
@ -18,19 +18,7 @@
|
||||
#include "../WorldStorage/FastNBT.h"
|
||||
#include "../WorldStorage/EnchantmentSerializer.h"
|
||||
#include "../StringCompression.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#pragma warning(disable:4244)
|
||||
#pragma warning(disable:4231)
|
||||
#pragma warning(disable:4189)
|
||||
#pragma warning(disable:4702)
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
#include "PolarSSL++/Sha1Checksum.h"
|
||||
|
||||
|
||||
|
||||
@ -819,7 +807,7 @@ void cProtocol132::SendEncryptionKeyRequest(void)
|
||||
void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce)
|
||||
{
|
||||
// Decrypt EncNonce using privkey
|
||||
cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
|
||||
cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
|
||||
|
||||
Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
|
||||
int res = rsaDecryptor.Decrypt((const Byte *)a_EncNonce.data(), a_EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce));
|
||||
@ -876,7 +864,7 @@ void cProtocol132::StartEncryption(const Byte * a_Key)
|
||||
m_IsEncrypted = true;
|
||||
|
||||
// Prepare the m_AuthServerID:
|
||||
cSHA1Checksum Checksum;
|
||||
cSha1Checksum Checksum;
|
||||
cServer * Server = cRoot::Get()->GetServer();
|
||||
AString ServerID = Server->GetServerID();
|
||||
Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length());
|
||||
@ -884,7 +872,7 @@ void cProtocol132::StartEncryption(const Byte * a_Key)
|
||||
Checksum.Update((const Byte *)Server->GetPublicKeyDER().data(), Server->GetPublicKeyDER().size());
|
||||
Byte Digest[20];
|
||||
Checksum.Finalize(Digest);
|
||||
cSHA1Checksum::DigestToJava(Digest, m_AuthServerID);
|
||||
cSha1Checksum::DigestToJava(Digest, m_AuthServerID);
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,7 +24,8 @@
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "../Crypto.h"
|
||||
#include "PolarSSL++/AesCfb128Decryptor.h"
|
||||
#include "PolarSSL++/AesCfb128Encryptor.h"
|
||||
|
||||
|
||||
|
||||
@ -79,8 +80,8 @@ public:
|
||||
protected:
|
||||
bool m_IsEncrypted;
|
||||
|
||||
cAESCFBDecryptor m_Decryptor;
|
||||
cAESCFBEncryptor m_Encryptor;
|
||||
cAesCfb128Decryptor m_Decryptor;
|
||||
cAesCfb128Encryptor m_Encryptor;
|
||||
|
||||
AString m_DataToSend;
|
||||
|
||||
|
@ -33,6 +33,7 @@ Implements the 1.7.x protocol classes:
|
||||
#include "../CompositeChat.h"
|
||||
#include "../Entities/ArrowEntity.h"
|
||||
#include "../Entities/FireworkEntity.h"
|
||||
#include "PolarSSL++/Sha1Checksum.h"
|
||||
|
||||
|
||||
|
||||
@ -1690,7 +1691,7 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe
|
||||
}
|
||||
|
||||
// Decrypt EncNonce using privkey
|
||||
cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
|
||||
cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
|
||||
Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
|
||||
int res = rsaDecryptor.Decrypt((const Byte *)EncNonce.data(), EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce));
|
||||
if (res != 4)
|
||||
@ -2293,7 +2294,7 @@ void cProtocol172::StartEncryption(const Byte * a_Key)
|
||||
m_IsEncrypted = true;
|
||||
|
||||
// Prepare the m_AuthServerID:
|
||||
cSHA1Checksum Checksum;
|
||||
cSha1Checksum Checksum;
|
||||
cServer * Server = cRoot::Get()->GetServer();
|
||||
const AString & ServerID = Server->GetServerID();
|
||||
Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length());
|
||||
@ -2301,7 +2302,7 @@ void cProtocol172::StartEncryption(const Byte * a_Key)
|
||||
Checksum.Update((const Byte *)Server->GetPublicKeyDER().data(), Server->GetPublicKeyDER().size());
|
||||
Byte Digest[20];
|
||||
Checksum.Finalize(Digest);
|
||||
cSHA1Checksum::DigestToJava(Digest, m_AuthServerID);
|
||||
cSha1Checksum::DigestToJava(Digest, m_AuthServerID);
|
||||
}
|
||||
|
||||
|
||||
|
@ -30,7 +30,8 @@ Declares the 1.7.x protocol classes:
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "../Crypto.h"
|
||||
#include "PolarSSL++/AesCfb128Decryptor.h"
|
||||
#include "PolarSSL++/AesCfb128Encryptor.h"
|
||||
|
||||
|
||||
|
||||
@ -236,8 +237,8 @@ protected:
|
||||
|
||||
bool m_IsEncrypted;
|
||||
|
||||
cAESCFBDecryptor m_Decryptor;
|
||||
cAESCFBEncryptor m_Encryptor;
|
||||
cAesCfb128Decryptor m_Decryptor;
|
||||
cAesCfb128Decryptor m_Encryptor;
|
||||
|
||||
/** The logfile where the comm is logged, when g_ShouldLogComm is true */
|
||||
cFile m_CommLogFile;
|
||||
|
@ -23,7 +23,7 @@
|
||||
#pragma warning(disable:4702)
|
||||
#endif
|
||||
|
||||
#include "Crypto.h"
|
||||
#include "PolarSSL++/RsaPrivateKey.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
@ -109,7 +109,7 @@ public: // tolua_export
|
||||
/** Returns base64 encoded favicon data (obtained from favicon.png) */
|
||||
const AString & GetFaviconData(void) const { return m_FaviconData; }
|
||||
|
||||
cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
|
||||
cRsaPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
|
||||
const AString & GetPublicKeyDER(void) const { return m_PublicKeyDER; }
|
||||
|
||||
bool ShouldAuthenticate(void) const { return m_ShouldAuthenticate; }
|
||||
@ -182,7 +182,7 @@ private:
|
||||
bool m_bRestarting;
|
||||
|
||||
/** The private key used for the assymetric encryption start in the protocols */
|
||||
cRSAPrivateKey m_PrivateKey;
|
||||
cRsaPrivateKey m_PrivateKey;
|
||||
|
||||
/** Public key for m_PrivateKey, ASN1-DER-encoded */
|
||||
AString m_PublicKeyDER;
|
||||
|
Loading…
Reference in New Issue
Block a user