init
This commit is contained in:
parent
1ade51f4ef
commit
f3743942ee
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
__pycache__
|
||||||
|
*.pem
|
||||||
|
example
|
19
Makefile
Normal file
19
Makefile
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
CXX = g++
|
||||||
|
CXXFLAGS = -std=c++17 -I/usr/local/include/botan-2/ -lbotan-2
|
||||||
|
RUN = ./
|
||||||
|
LD_LIBRARY_PATH = /usr/local/lib
|
||||||
|
|
||||||
|
.PHONY: all clean build run
|
||||||
|
|
||||||
|
all: build run
|
||||||
|
|
||||||
|
build: example.cpp
|
||||||
|
$(CXX) example.cpp $(CXXFLAGS) -o example
|
||||||
|
run:
|
||||||
|
$(RUN)example
|
||||||
|
|
||||||
|
run_python:
|
||||||
|
LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) python example.py
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.pem
|
152
crypto_lib.cpp
Normal file
152
crypto_lib.cpp
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
#include <botan/auto_rng.h>
|
||||||
|
#include <botan/rsa.h>
|
||||||
|
#include <botan/pkcs8.h>
|
||||||
|
#include <botan/x509_key.h>
|
||||||
|
#include <botan/pubkey.h>
|
||||||
|
#include <botan/data_src.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace CryptoLib {
|
||||||
|
std::pair<std::unique_ptr<Botan::Private_Key>, std::unique_ptr<Botan::Public_Key>>
|
||||||
|
generate_keys(int key_size = 2048);
|
||||||
|
|
||||||
|
std::pair<std::unique_ptr<Botan::Private_Key>, std::unique_ptr<Botan::Public_Key>>
|
||||||
|
generate_keys(int key_size) {
|
||||||
|
Botan::AutoSeeded_RNG rng;
|
||||||
|
std::unique_ptr<Botan::RSA_PrivateKey> private_key(new Botan::RSA_PrivateKey(rng, key_size));
|
||||||
|
std::unique_ptr<Botan::RSA_PublicKey> public_key(new Botan::RSA_PublicKey(*private_key));
|
||||||
|
|
||||||
|
return std::make_pair(std::move(private_key), std::move(public_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> encrypt(const Botan::Public_Key& public_key, const std::string& data) {
|
||||||
|
std::vector<uint8_t> data_vector(data.begin(), data.end());
|
||||||
|
Botan::AutoSeeded_RNG rng;
|
||||||
|
Botan::PK_Encryptor_EME encryptor(public_key, rng, "OAEP(SHA-256)");
|
||||||
|
return encryptor.encrypt(data_vector, rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string decrypt(const Botan::Private_Key& private_key, const std::vector<uint8_t>& encrypted_data) {
|
||||||
|
std::vector<uint8_t> encrypted_vector(encrypted_data.begin(), encrypted_data.end());
|
||||||
|
Botan::AutoSeeded_RNG rng;
|
||||||
|
Botan::PK_Decryptor_EME decryptor(private_key, rng, "OAEP(SHA-256)");
|
||||||
|
auto result = decryptor.decrypt(encrypted_vector);
|
||||||
|
return std::string(result.begin(), result.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string public_key_to_string(const Botan::Public_Key& public_key) {
|
||||||
|
return Botan::X509::PEM_encode(public_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Botan::Public_Key> public_key_from_string(const std::string& key_string) {
|
||||||
|
Botan::DataSource_Memory ds(key_string);
|
||||||
|
return std::unique_ptr<Botan::Public_Key>(Botan::X509::load_key(ds));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string private_key_to_string(const Botan::Private_Key& private_key) {
|
||||||
|
return Botan::PKCS8::PEM_encode(private_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Botan::Private_Key> private_key_from_string(const std::string& key_string) {
|
||||||
|
Botan::DataSource_Memory ds(key_string);
|
||||||
|
return std::unique_ptr<Botan::Private_Key>(Botan::PKCS8::load_key(ds));
|
||||||
|
}
|
||||||
|
|
||||||
|
void save_private_key(const Botan::Private_Key& private_key, const std::string& filename) {
|
||||||
|
std::ofstream file(filename);
|
||||||
|
if (file.is_open()) {
|
||||||
|
file << Botan::PKCS8::PEM_encode(private_key);
|
||||||
|
file.close();
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Cannot open file for writing: " + filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void save_public_key(const Botan::Public_Key& public_key, const std::string& filename) {
|
||||||
|
std::ofstream file(filename);
|
||||||
|
if (file.is_open()) {
|
||||||
|
file << Botan::X509::PEM_encode(public_key);
|
||||||
|
file.close();
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Cannot open file for writing: " + filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Botan::Private_Key> load_private_key(const std::string& filename) {
|
||||||
|
std::ifstream file(filename);
|
||||||
|
if (file.is_open()) {
|
||||||
|
std::string content((std::istreambuf_iterator<char>(file)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
file.close();
|
||||||
|
Botan::DataSource_Memory ds(content);
|
||||||
|
return std::unique_ptr<Botan::Private_Key>(Botan::PKCS8::load_key(ds));
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Cannot open file for reading: " + filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Botan::Public_Key> load_public_key(const std::string& filename) {
|
||||||
|
std::ifstream file(filename);
|
||||||
|
if (file.is_open()) {
|
||||||
|
std::string content((std::istreambuf_iterator<char>(file)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
file.close();
|
||||||
|
Botan::DataSource_Memory ds(content);
|
||||||
|
return std::unique_ptr<Botan::Public_Key>(Botan::X509::load_key(ds));
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Cannot open file for reading: " + filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string bytes_to_base64(const std::vector<unsigned char>& data) {
|
||||||
|
static const char* const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
std::string result;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
while (i < data.size()) {
|
||||||
|
uint32_t octet_a = i < data.size() ? data[i++] : 0;
|
||||||
|
uint32_t octet_b = i < data.size() ? data[i++] : 0;
|
||||||
|
uint32_t octet_c = i < data.size() ? data[i++] : 0;
|
||||||
|
|
||||||
|
uint32_t triple = (octet_a << 16) + (octet_b << 8) + octet_c;
|
||||||
|
|
||||||
|
result += chars[(triple >> 18) & 63];
|
||||||
|
result += chars[(triple >> 12) & 63];
|
||||||
|
result += chars[(triple >> 6) & 63];
|
||||||
|
result += chars[triple & 63];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add padding
|
||||||
|
switch (data.size() % 3) {
|
||||||
|
case 1:
|
||||||
|
result[result.size() - 2] = '=';
|
||||||
|
result[result.size() - 1] = '=';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
result[result.size() - 1] = '=';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> base64_to_bytes(const std::string& input) {
|
||||||
|
static const std::string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
std::vector<unsigned char> result;
|
||||||
|
|
||||||
|
int val = 0, valb = -8;
|
||||||
|
for (unsigned char c : input) {
|
||||||
|
if (c == '=') break;
|
||||||
|
if (chars.find(c) == std::string::npos) continue;
|
||||||
|
|
||||||
|
val = (val << 6) + chars.find(c);
|
||||||
|
valb += 6;
|
||||||
|
if (valb >= 0) {
|
||||||
|
result.push_back((val >> valb) & 0xFF);
|
||||||
|
valb -= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
86
crypto_lib.py
Normal file
86
crypto_lib.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import botan2 as botan
|
||||||
|
import base64
|
||||||
|
|
||||||
|
class CryptoLib:
|
||||||
|
@staticmethod
|
||||||
|
def generate_keys(key_size=2048):
|
||||||
|
"""Generate RSA key pair"""
|
||||||
|
rng = botan.RandomNumberGenerator()
|
||||||
|
private_key = botan.PrivateKey.create("RSA", str(key_size), rng)
|
||||||
|
public_key = private_key.get_public_key()
|
||||||
|
return private_key, public_key
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def encrypt(public_key, data):
|
||||||
|
"""Encrypt data with public key"""
|
||||||
|
if isinstance(data, str):
|
||||||
|
data = data.encode('utf-8')
|
||||||
|
rng = botan.RandomNumberGenerator()
|
||||||
|
encryptor = botan.PKEncrypt(public_key, "OAEP(SHA-256)")
|
||||||
|
return encryptor.encrypt(data, rng)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def decrypt(private_key, encrypted_data):
|
||||||
|
"""Decrypt data with private key"""
|
||||||
|
decryptor = botan.PKDecrypt(private_key, "OAEP(SHA-256)")
|
||||||
|
return decryptor.decrypt(encrypted_data)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def public_key_to_string(public_key):
|
||||||
|
"""Convert public key to PEM string"""
|
||||||
|
return public_key.to_pem().encode('utf-8')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def public_key_from_string(key_string):
|
||||||
|
"""Load public key from PEM string"""
|
||||||
|
if isinstance(key_string, str):
|
||||||
|
key_string = key_string.encode('utf-8')
|
||||||
|
return botan.PublicKey.load(key_string)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def private_key_to_string(private_key):
|
||||||
|
"""Convert private key to PEM string"""
|
||||||
|
return private_key.to_pem().decode('utf-8')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def private_key_from_string(key_string):
|
||||||
|
"""Load private key from PEM string"""
|
||||||
|
if isinstance(key_string, str):
|
||||||
|
key_string = key_string.encode('utf-8')
|
||||||
|
return botan.PrivateKey.load(key_string)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def save_private_key(private_key, filename):
|
||||||
|
"""Save private key to file"""
|
||||||
|
with open(filename, 'w') as f:
|
||||||
|
# f.write(private_key.to_pem().encode('utf-8'))
|
||||||
|
f.write(private_key.to_pem())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def save_public_key(public_key, filename):
|
||||||
|
"""Save public key to file"""
|
||||||
|
with open(filename, 'w') as f:
|
||||||
|
# f.write(public_key.to_pem().decode('utf-8'))
|
||||||
|
f.write(public_key.to_pem())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def load_private_key(filename):
|
||||||
|
"""Load private key from file"""
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
pem_data = f.read()
|
||||||
|
return botan.PrivateKey.load(pem_data.encode('utf-8'))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def load_public_key(filename):
|
||||||
|
"""Load public key from file"""
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
pem_data = f.read()
|
||||||
|
return botan.PublicKey.load(pem_data.encode('utf-8'))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def bytes_to_base64(public_key: bytes) -> str:
|
||||||
|
return base64.b64encode(public_key).decode('utf-8')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def base64_to_bytes(key_string: str) -> bytes:
|
||||||
|
return base64.b64decode(key_string.encode('utf-8'))
|
75
example.cpp
Normal file
75
example.cpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#include "crypto_lib.cpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
try {
|
||||||
|
std::cout << "=== Asymmetric Cryptography Example ===" << std::endl;
|
||||||
|
std::string generate_new_keys;
|
||||||
|
std::cout << "Generate new keys? (y/n): ";
|
||||||
|
std::cin >> generate_new_keys;
|
||||||
|
|
||||||
|
std::string message;
|
||||||
|
std::vector<uint8_t> encrypted;
|
||||||
|
|
||||||
|
if (generate_new_keys == "y") {
|
||||||
|
// 1. Generate keys
|
||||||
|
std::cout << "1. Generating key pair...\n\n";
|
||||||
|
auto keys = CryptoLib::generate_keys(2048);
|
||||||
|
auto& private_key = keys.first;
|
||||||
|
auto& public_key = keys.second;
|
||||||
|
|
||||||
|
// 2. Save keys to files
|
||||||
|
std::cout << "2. Saving keys to files...\n\n";
|
||||||
|
CryptoLib::save_private_key(*private_key, "private_key.pem");
|
||||||
|
CryptoLib::save_public_key(*public_key, "public_key.pem");
|
||||||
|
|
||||||
|
message = "Hello, this is a secret message!";
|
||||||
|
} else {
|
||||||
|
std::cout << "Enter message to decrypt (if exists): ";
|
||||||
|
std::cin.ignore();
|
||||||
|
std::getline(std::cin, message);
|
||||||
|
|
||||||
|
if (!message.empty()) {
|
||||||
|
encrypted = CryptoLib::base64_to_bytes(message);
|
||||||
|
} else {
|
||||||
|
message = "Hello, this is a secret message!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Load keys from files
|
||||||
|
std::cout << "3. Loading keys from files...\n\n";
|
||||||
|
auto loaded_private_key = CryptoLib::load_private_key("private_key.pem");
|
||||||
|
auto loaded_public_key = CryptoLib::load_public_key("public_key.pem");
|
||||||
|
|
||||||
|
// 4. Convert public key to string and back
|
||||||
|
std::cout << "4. Loaded keys:\n";
|
||||||
|
std::string private_key_str = CryptoLib::private_key_to_string(*loaded_private_key);
|
||||||
|
std::string public_key_str = CryptoLib::public_key_to_string(*loaded_public_key);
|
||||||
|
std::cout << "Private key string as: " << private_key_str.substr(0, 50) << "...\n";
|
||||||
|
std::cout << "Public key string as: " << public_key_str.substr(0, 50) << "...\n\n";
|
||||||
|
|
||||||
|
std::cout << "5. Convert public key from string...\n\n";
|
||||||
|
auto restored_public_key = CryptoLib::public_key_from_string(public_key_str);
|
||||||
|
|
||||||
|
if (encrypted.empty()) {
|
||||||
|
// 6. Encrypt data
|
||||||
|
std::cout << "6. Testing ecnryption..." << std::endl;
|
||||||
|
std::cout << "Original message: " << message << std::endl;
|
||||||
|
encrypted = CryptoLib::encrypt(*loaded_public_key, message);
|
||||||
|
std::cout << "Encrypted (base64): " << CryptoLib::bytes_to_base64(encrypted) << std::endl;
|
||||||
|
std::cout << "Encrypted data size: " << encrypted.size() << " bytes\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Decrypt data
|
||||||
|
std::string decrypted_message = CryptoLib::decrypt(*loaded_private_key, encrypted);
|
||||||
|
std::cout << "7. Decrypted message: " << decrypted_message << "\n";
|
||||||
|
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << "Error: " << e.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
47
example.py
Normal file
47
example.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
from crypto_lib import *
|
||||||
|
|
||||||
|
# Example usage
|
||||||
|
if __name__ == "__main__":
|
||||||
|
generate_new_keys = input('Generate new keys? (y/n): ')
|
||||||
|
if generate_new_keys == 'y':
|
||||||
|
# 1. Generate keys
|
||||||
|
print("1. Generating key pair...\n")
|
||||||
|
private_key, public_key = CryptoLib.generate_keys(2048)
|
||||||
|
|
||||||
|
# 2. Save keys to files
|
||||||
|
print("2. Saving keys to files...\n")
|
||||||
|
CryptoLib.save_private_key(private_key, "private_key.pem")
|
||||||
|
CryptoLib.save_public_key(public_key, "public_key.pem")
|
||||||
|
|
||||||
|
encrypted = ''
|
||||||
|
else:
|
||||||
|
encrypted = CryptoLib.base64_to_bytes(input('Enter message (if exist): '))
|
||||||
|
|
||||||
|
# 6. Load keys from files
|
||||||
|
print("3. Loading keys from files...\n")
|
||||||
|
loaded_private_key = CryptoLib.load_private_key("private_key.pem")
|
||||||
|
loaded_public_key = CryptoLib.load_public_key("public_key.pem")
|
||||||
|
|
||||||
|
# 3. Convert public key to string and back
|
||||||
|
print("4. Loaded keys:.")
|
||||||
|
private_key_str = CryptoLib.public_key_to_string(loaded_private_key)
|
||||||
|
public_key_str = CryptoLib.public_key_to_string(loaded_public_key)
|
||||||
|
print(f'Private key as string: {private_key_str[:50]}...')
|
||||||
|
print(f'Public key as string: {public_key_str[:50]}...\n')
|
||||||
|
|
||||||
|
print(f'5. Convert public key from string...\n')
|
||||||
|
restored_public_key = CryptoLib.public_key_from_string(public_key_str)
|
||||||
|
|
||||||
|
if not encrypted:
|
||||||
|
# 6. Encrypt data
|
||||||
|
print("6. Encrypting data...")
|
||||||
|
message = "Hello, this is a secret message from Python!"
|
||||||
|
print(f'Original message: {message}')
|
||||||
|
encrypted = CryptoLib.encrypt(loaded_public_key, message)
|
||||||
|
print(f'Encrypted (base64): {CryptoLib.bytes_to_base64(encrypted)}')
|
||||||
|
print(f"Encrypted data size: {len(encrypted)} bytes\n")
|
||||||
|
|
||||||
|
# 7. Decrypt data
|
||||||
|
decrypted_data = CryptoLib.decrypt(loaded_private_key, encrypted)
|
||||||
|
decrypted_message = decrypted_data.decode('utf-8')
|
||||||
|
print(f"7. Decrypted message: {decrypted_message}")
|
Loading…
Reference in New Issue
Block a user