#include "CryptoOpenSSL.h" namespace { struct BIOFreeAll { void operator()(BIO *p) { BIO_free_all(p); } }; } // namespace CryptoOpenSSL::CryptoOpenSSL() { // OpenSSL init ENGINE_load_builtin_engines(); ENGINE_register_all_complete(); this->publicKey = std::vector(DH_KEY_SIZE); this->privateKey = generateVectorWithRandomData(DH_KEY_SIZE); } CryptoOpenSSL::~CryptoOpenSSL() { if (this->dhContext != nullptr) { DH_free(this->dhContext); } } std::vector CryptoOpenSSL::base64Decode(const std::string& data) { // base64 in openssl is an absolute mess lmao std::unique_ptr b64(BIO_new(BIO_f_base64())); BIO_set_flags(b64.get(), BIO_FLAGS_BASE64_NO_NL); BIO *source = BIO_new_mem_buf(data.c_str(), -1); // read-only source BIO_push(b64.get(), source); const int maxlen = data.size() / 4 * 3 + 1; std::vector decoded(maxlen); const int len = BIO_read(b64.get(), decoded.data(), maxlen); decoded.resize(len); return decoded; } std::string CryptoOpenSSL::base64Encode(const std::vector& data) { // base64 in openssl is an absolute mess lmao x 2 std::unique_ptr b64(BIO_new(BIO_f_base64())); // No newline mode, put all the data into sink BIO_set_flags(b64.get(), BIO_FLAGS_BASE64_NO_NL); BIO *sink = BIO_new(BIO_s_mem()); BIO_push(b64.get(), sink); BIO_write(b64.get(), data.data(), data.size()); BIO_flush(b64.get()); const char *encoded; const long len = BIO_get_mem_data(sink, &encoded); return std::string(encoded, len); } // Sha1 void CryptoOpenSSL::sha1Init() { SHA1_Init(&sha1Context); } void CryptoOpenSSL::sha1Update(const std::string& s) { sha1Update(std::vector(s.begin(), s.end())); } void CryptoOpenSSL::sha1Update(const std::vector& vec) { SHA1_Update(&sha1Context, vec.data(), vec.size()); } std::vector CryptoOpenSSL::sha1FinalBytes() { std::vector digest(20); // 20 is 160 bits SHA1_Final(digest.data(), &sha1Context); return digest; } std::string CryptoOpenSSL::sha1Final() { auto digest = sha1FinalBytes(); return std::string(digest.begin(), digest.end()); } // HMAC SHA1 std::vector CryptoOpenSSL::sha1HMAC(const std::vector& inputKey, const std::vector& message) { std::vector digest(20); // 20 is 160 bits auto hmacContext = HMAC_CTX_new(); HMAC_Init_ex(hmacContext, inputKey.data(), inputKey.size(), EVP_sha1(), NULL); HMAC_Update(hmacContext, message.data(), message.size()); unsigned int resLen = 0; HMAC_Final(hmacContext, digest.data(), &resLen); HMAC_CTX_free(hmacContext); return digest; } // AES CTR void CryptoOpenSSL::aesCTRXcrypt(const std::vector& key, std::vector& iv, std::vector &data) { // Prepare AES_KEY auto cryptoKey = AES_KEY(); AES_set_encrypt_key(key.data(), 128, &cryptoKey); // Needed for openssl internal cache unsigned char ecountBuf[16] = {0}; unsigned int offsetInBlock = 0; CRYPTO_ctr128_encrypt( data.data(), data.data(), data.size(), &cryptoKey, iv.data(), ecountBuf, &offsetInBlock, block128_f(AES_encrypt)); } void CryptoOpenSSL::aesECBdecrypt(const std::vector& key, std::vector& data) { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); EVP_CIPHER_CTX_init(ctx); int len = 0; EVP_DecryptInit_ex(ctx, EVP_aes_192_ecb(), NULL, key.data(), NULL); EVP_DecryptUpdate(ctx, data.data(), &len, data.data(), data.size()); EVP_DecryptFinal_ex(ctx, data.data() + len, &len); EVP_CIPHER_CTX_free(ctx); } // PBKDF2 std::vector CryptoOpenSSL::pbkdf2HmacSha1(const std::vector& password, const std::vector& salt, int iterations, int digestSize) { std::vector digest(digestSize); // Generate PKDF2 digest PKCS5_PBKDF2_HMAC_SHA1((const char *)password.data(), password.size(), (const unsigned char *)salt.data(), salt.size(), iterations, digestSize, digest.data()); return digest; } void CryptoOpenSSL::dhInit() { // Free old context if (this->dhContext != nullptr) { DH_free(this->dhContext); } this->dhContext = DH_new(); // Set prime and the generator DH_set0_pqg(this->dhContext, BN_bin2bn(DHPrime, DH_KEY_SIZE, NULL), NULL, BN_bin2bn(DHGenerator, 1, NULL)); // Generate public and private keys and copy them to vectors DH_generate_key(this->dhContext); BN_bn2bin(DH_get0_pub_key(dhContext), this->publicKey.data()); } std::vector CryptoOpenSSL::dhCalculateShared(const std::vector& remoteKey) { auto sharedKey = std::vector(DH_KEY_SIZE); // Convert remote key to bignum and compute shared key auto pubKey = BN_bin2bn(&remoteKey[0], DH_KEY_SIZE, NULL); DH_compute_key(sharedKey.data(), pubKey, this->dhContext); BN_free(pubKey); return sharedKey; } // Random stuff std::vector CryptoOpenSSL::generateVectorWithRandomData(size_t length) { std::vector randomVec(length); if(RAND_bytes(randomVec.data(), length) == 0) { } return randomVec; }