267 lines
8.6 KiB
C++
267 lines
8.6 KiB
C++
#pragma once
|
|
#include <openssl/err.h>
|
|
#include <openssl/bio.h>
|
|
#include <openssl/rsa.h>
|
|
#include <openssl/pem.h>
|
|
|
|
#include <string>
|
|
|
|
#ifdef _DEBUG
|
|
#pragma comment(lib, "libcryptoMTd.lib")
|
|
#else
|
|
#pragma comment(lib, "libcryptoMT.lib")
|
|
#endif
|
|
#pragma comment(lib, "WS2_32.lib") // some symbol are used in OpenSSL static lib
|
|
#pragma comment(lib, "Crypt32.lib") // some symbol are used in OpenSSL static lib
|
|
|
|
class RSACipher {
|
|
private:
|
|
RSA * _RsaObj;
|
|
|
|
RSACipher() : _RsaObj(nullptr) {}
|
|
RSACipher(RSA* lpRsa) : _RsaObj(lpRsa) {}
|
|
|
|
RSACipher(const RSACipher&) = delete;
|
|
RSACipher(RSACipher&&) = delete;
|
|
RSACipher& operator=(const RSACipher&) = delete;
|
|
RSACipher& operator=(RSACipher&&) = delete;
|
|
|
|
public:
|
|
|
|
enum class KeyType {
|
|
PrivateKey,
|
|
PublicKey
|
|
};
|
|
|
|
enum class KeyFormat {
|
|
NotSpecified,
|
|
PEM,
|
|
PKCS1
|
|
};
|
|
|
|
~RSACipher() {
|
|
if (_RsaObj)
|
|
RSA_free(_RsaObj);
|
|
_RsaObj = nullptr;
|
|
}
|
|
|
|
static RSACipher* Create() {
|
|
RSACipher* aCipher = new RSACipher(RSA_new());
|
|
if (aCipher->_RsaObj == nullptr) {
|
|
delete aCipher;
|
|
aCipher = nullptr;
|
|
}
|
|
return aCipher;
|
|
}
|
|
|
|
bool GenerateKey(int bits, unsigned long long e = RSA_F4) {
|
|
bool bSuccess = false;
|
|
BIGNUM* bn_e = nullptr;
|
|
|
|
bn_e = BN_new();
|
|
if (bn_e == nullptr)
|
|
goto ON_RSACipher_GenerateKey0_ERROR;
|
|
|
|
if (!BN_set_word(bn_e, e))
|
|
goto ON_RSACipher_GenerateKey0_ERROR;
|
|
|
|
if (!RSA_generate_key_ex(_RsaObj, bits, bn_e, nullptr))
|
|
goto ON_RSACipher_GenerateKey0_ERROR;
|
|
|
|
bSuccess = true;
|
|
|
|
ON_RSACipher_GenerateKey0_ERROR:
|
|
if (bn_e)
|
|
BN_free(bn_e);
|
|
return bSuccess;
|
|
}
|
|
|
|
template<KeyType _Type, KeyFormat _Format = KeyFormat::NotSpecified>
|
|
bool ExportKeyToFile(const std::string& filename) {
|
|
static_assert(
|
|
_Type == KeyType::PrivateKey || (_Format == KeyFormat::PEM || _Format == KeyFormat::PKCS1),
|
|
"Not supported format."
|
|
);
|
|
|
|
bool bSuccess = false;
|
|
BIO* bio_file = nullptr;
|
|
|
|
bio_file = BIO_new_file(filename.c_str(), "w");
|
|
if (bio_file == nullptr)
|
|
goto ON_RSACipher_ExportKeyToFile_0_ERROR;
|
|
|
|
if (_Type == KeyType::PrivateKey) {
|
|
bSuccess = PEM_write_bio_RSAPrivateKey(bio_file, _RsaObj, nullptr, nullptr, 0, nullptr, nullptr) ? true : false;
|
|
} else {
|
|
if (_Format == KeyFormat::PEM)
|
|
bSuccess = PEM_write_bio_RSA_PUBKEY(bio_file, _RsaObj) ? true : false;
|
|
else if (_Format == KeyFormat::PKCS1)
|
|
bSuccess = PEM_write_bio_RSAPublicKey(bio_file, _RsaObj) ? true : false;
|
|
}
|
|
|
|
ON_RSACipher_ExportKeyToFile_0_ERROR:
|
|
return bSuccess;
|
|
}
|
|
|
|
template<KeyType _Type, KeyFormat _Format = KeyFormat::NotSpecified>
|
|
std::string ExportKeyString() {
|
|
static_assert(
|
|
_Type == KeyType::PrivateKey || (_Format == KeyFormat::PEM || _Format == KeyFormat::PKCS1),
|
|
"Not supported format."
|
|
);
|
|
|
|
std::string KeyString;
|
|
BIO* bio_mem = nullptr;
|
|
int len = 0;
|
|
const char* lpdata = nullptr;
|
|
|
|
bio_mem = BIO_new(BIO_s_mem());
|
|
if (bio_mem == nullptr)
|
|
goto ON_RSACipher_ExportKeyString_0_ERROR;
|
|
|
|
if (_Type == KeyType::PrivateKey) {
|
|
if (!PEM_write_bio_RSAPrivateKey(bio_mem, _RsaObj, nullptr, nullptr, 0, nullptr, nullptr))
|
|
goto ON_RSACipher_ExportKeyString_0_ERROR;
|
|
} else {
|
|
if (_Format == KeyFormat::PEM) {
|
|
if (!PEM_write_bio_RSA_PUBKEY(bio_mem, _RsaObj))
|
|
goto ON_RSACipher_ExportKeyString_0_ERROR;
|
|
} else if (_Format == KeyFormat::PKCS1) {
|
|
if (!PEM_write_bio_RSAPublicKey(bio_mem, _RsaObj))
|
|
goto ON_RSACipher_ExportKeyString_0_ERROR;
|
|
}
|
|
}
|
|
|
|
len = BIO_get_mem_data(bio_mem, &lpdata);
|
|
|
|
KeyString.resize(len);
|
|
memcpy(KeyString.data(), lpdata, len);
|
|
|
|
ON_RSACipher_ExportKeyString_0_ERROR:
|
|
if (bio_mem)
|
|
BIO_free_all(bio_mem);
|
|
return KeyString;
|
|
}
|
|
|
|
template<KeyType _Type, KeyFormat _Format = KeyFormat::NotSpecified>
|
|
bool ImportKeyFromFile(const std::string& filename) {
|
|
static_assert(
|
|
_Type == KeyType::PrivateKey || (_Format == KeyFormat::PEM || _Format == KeyFormat::PKCS1),
|
|
"Not supported format."
|
|
);
|
|
|
|
bool bSuccess = false;
|
|
BIO* bio_file = nullptr;
|
|
RSA* _newRsaObj = nullptr;
|
|
|
|
bio_file = BIO_new_file(filename.c_str(), "r");
|
|
if (bio_file == nullptr)
|
|
goto ON_RSACipher_ImportKeyFromFile_0_ERROR;
|
|
|
|
if (_Type == KeyType::PrivateKey) {
|
|
_newRsaObj = PEM_read_bio_RSAPrivateKey(bio_file, nullptr, nullptr, nullptr);
|
|
} else {
|
|
if (_Format == KeyFormat::PEM)
|
|
_newRsaObj = PEM_read_bio_RSA_PUBKEY(bio_file, nullptr, nullptr, nullptr);
|
|
else if (_Format == KeyFormat::PKCS1)
|
|
_newRsaObj = PEM_read_bio_RSAPublicKey(bio_file, nullptr, nullptr, nullptr);
|
|
}
|
|
|
|
if (_newRsaObj) {
|
|
RSA_free(_RsaObj);
|
|
_RsaObj = _newRsaObj;
|
|
bSuccess = true;
|
|
}
|
|
|
|
ON_RSACipher_ImportKeyFromFile_0_ERROR:
|
|
if (bio_file)
|
|
BIO_free_all(bio_file);
|
|
return bSuccess;
|
|
}
|
|
|
|
template<KeyType _Type, KeyFormat _Format = KeyFormat::NotSpecified>
|
|
bool ImportKeyString(const std::string& KeyString) {
|
|
static_assert(
|
|
_Type == KeyType::PrivateKey || (_Format == KeyFormat::PEM || _Format == KeyFormat::PKCS1),
|
|
"Not supported format."
|
|
);
|
|
|
|
bool bSuccess = false;
|
|
BIO* bio_mem = nullptr;
|
|
RSA* _newRsaObj = nullptr;
|
|
|
|
bio_mem = BIO_new(BIO_s_mem());
|
|
if (bio_mem == nullptr)
|
|
goto ON_RSACipher_ImportKeyString_0_ERROR;
|
|
|
|
BIO_puts(bio_mem, KeyString.c_str());
|
|
|
|
if (_Type == KeyType::PrivateKey) {
|
|
_newRsaObj = PEM_read_bio_RSAPrivateKey(bio_mem, nullptr, nullptr, nullptr);
|
|
} else {
|
|
if (_Format == KeyFormat::PEM)
|
|
_newRsaObj = PEM_read_bio_RSA_PUBKEY(bio_mem, nullptr, nullptr, nullptr);
|
|
else if (_Format == KeyFormat::PKCS1)
|
|
_newRsaObj = PEM_read_bio_RSAPublicKey(bio_mem, nullptr, nullptr, nullptr);
|
|
}
|
|
|
|
if (_newRsaObj) {
|
|
RSA_free(_RsaObj);
|
|
_RsaObj = _newRsaObj;
|
|
bSuccess = true;
|
|
}
|
|
|
|
ON_RSACipher_ImportKeyString_0_ERROR:
|
|
if (bio_mem)
|
|
BIO_free_all(bio_mem);
|
|
return bSuccess;
|
|
}
|
|
|
|
template<KeyType _Type = KeyType::PublicKey>
|
|
int Encrypt(const void* from, int len, void* to, int padding) {
|
|
int write_bytes = 0;
|
|
|
|
if (_Type == KeyType::PrivateKey) {
|
|
write_bytes = RSA_private_encrypt(len,
|
|
reinterpret_cast<const unsigned char*>(from),
|
|
reinterpret_cast<unsigned char*>(to),
|
|
_RsaObj,
|
|
padding);
|
|
} else {
|
|
write_bytes = RSA_public_encrypt(len,
|
|
reinterpret_cast<const unsigned char*>(from),
|
|
reinterpret_cast<unsigned char*>(to),
|
|
_RsaObj,
|
|
padding);
|
|
}
|
|
|
|
if (write_bytes == -1)
|
|
write_bytes = 0;
|
|
return write_bytes;
|
|
}
|
|
|
|
template<KeyType _Type = KeyType::PrivateKey>
|
|
int Decrypt(const void* from, int len, void* to, int padding) {
|
|
int write_bytes = 0;
|
|
|
|
if (_Type == KeyType::PrivateKey) {
|
|
write_bytes = RSA_private_decrypt(len,
|
|
reinterpret_cast<const unsigned char*>(from),
|
|
reinterpret_cast<unsigned char*>(to),
|
|
_RsaObj,
|
|
padding);
|
|
} else {
|
|
write_bytes = RSA_public_decrypt(len,
|
|
reinterpret_cast<const unsigned char*>(from),
|
|
reinterpret_cast<unsigned char*>(to),
|
|
_RsaObj,
|
|
padding);
|
|
}
|
|
|
|
if (write_bytes == -1)
|
|
write_bytes = 0;
|
|
return write_bytes;
|
|
}
|
|
|
|
};
|