Simple RSA public key encryption library for C/C++.
Catcrypt can do these:
- Generating RSA keypairs
- Exporting RSA keys as HEX representations
- Importing RSA keys from HEX
- Encrypting data
- Decrypting data
- Signing data
- Exporting signatures into string
- Importing signatures from string
- Verifying data by signature
Jump to the Example if you wanna be quick.
Caution
Please read this: This RSA library seems to be safe but THERE IS NO ANY GUARANTEE! The prime number generation seems to be safe enough and impossible (I'M NOT SURE and THERE IS NO ANY GUARANTEE) to break. Using this library or not is %100 in your responsibility.
I wrote this library for only signing & verifying purpose for my game server and just wanted to share it as open source by extracting from my game server with some other things like my string and reference counting and referencing implementations.
Warning
The library uses 2048 bit keys by default. It has a weird "addition loop" thing for random prime number generation and I'm not sure if it is better or worse for entropy. (I'll visualize it and see if it is or not.) It uses 65537 for public key exponent. This RSA implementation is not compatible with any other RSA implementation. It uses my own format for encrypted data.
#include "rsa.h"
You can just build and link rsa.o
and use rsa.h
. Don't forget to use -O3
flag for compilation.
Using make
will build catcrypt and examples:
cd /path/to/catcrypt
make
cd /path/to/your/app
gcc -o app.exe app.c \
/path/to/catcrypt/rsa.o -I /path/to/catcrypt \
./catcrypt/thirdparty/gmp-6.3.0/.libs/libgmp.a -I ./catcrypt/thirdparty/gmp-6.3.0
You need to link GNU MP Big Number library too like this ^^.
Here you can see everything:
#define CATCRYPT_RSA_PUB_EXPONENT 65537
#define CATCRYPT_RSA_PRIME_BITS 2048
#define CATCRYPT_RSA_PRIME_REPS 50
#define CATCRYPT_RSA_BLOCK_SIZE 128
#define CATCRYPT_MPZ_ENDIAN 1
#define CATCRYPT_MPZ_ORDER 1
typedef uint8_t catcrypt_rsa_random_seed_adds_t;
#define CATCRYPT_RSA_RANDOM_SEED_ADDS_MASK 20 // 1 to 2 ^ ((sizeof(catcrypt_rsa_random_seed_adds_t) * 8) - 1)
typedef struct catcrypt_rsa_keypair catcrypt_rsa_keypair_t;
typedef struct catcrypt_rsa_key catcrypt_rsa_key_t;
typedef struct catcrypt_rsa_encrypted catcrypt_rsa_encrypted_t;
struct catcrypt_rsa_key {
REF_COUNTEDIFY();
mpz_t e;
mpz_t n;
};
struct catcrypt_rsa_keypair {
REF_COUNTEDIFY();
catcrypt_rsa_key_t* pubkey;
catcrypt_rsa_key_t* privkey;
};
struct catcrypt_rsa_encrypted {
REF_COUNTEDIFY();
catcrypt_string_t* data;
catcrypt_rsa_key_t* key;
};
uint32_t catcrypt_rsa_hash_h32(char* str);
uint32_t catcrypt_rsa_hash_h32__n(char* data, ssize_t length);
bool catcrypt_rsa_random_seed(unsigned char* seed, size_t size);
void catcrypt_rsa_random_prime(mpz_t num);
catcrypt_rsa_key_t* catcrypt_rsa_key_new();
void catcrypt_rsa_key_free(catcrypt_rsa_key_t* key);
catcrypt_rsa_keypair_t* catcrypt_rsa_keypair_new();
void catcrypt_rsa_keypair_free(catcrypt_rsa_keypair_t* keypair);
catcrypt_rsa_encrypted_t* catcrypt_rsa_encrypted_new();
void catcrypt_rsa_encrypted_set_key(catcrypt_rsa_encrypted_t* encrypted, catcrypt_rsa_key_t* key);
void catcrypt_rsa_encrypted_set_data(catcrypt_rsa_encrypted_t* encrypted, catcrypt_string_t* data);
void catcrypt_rsa_encrypted_free(catcrypt_rsa_encrypted_t* encrypted);
catcrypt_rsa_encrypted_t* catcrypt_rsa_encrypt(catcrypt_string_t* data, catcrypt_rsa_key_t* pubkey);
catcrypt_string_t* catcrypt_rsa_decrypt(catcrypt_rsa_encrypted_t* encrypted, catcrypt_rsa_key_t* privkey);
catcrypt_string_t* catcrypt_rsa_key_to_bin(catcrypt_rsa_key_t* key);
catcrypt_rsa_key_t* catcrypt_rsa_key_from_bin(catcrypt_string_t* hex);
catcrypt_string_t* catcrypt_rsa_key_to_hex(catcrypt_rsa_key_t* key);
catcrypt_rsa_key_t* catcrypt_rsa_key_from_hex(catcrypt_string_t* hex);
catcrypt_string_t* catcrypt_rsa_sign(catcrypt_string_t* data, catcrypt_rsa_key_t* privkey);
bool catcrypt_rsa_verify(catcrypt_string_t* data, catcrypt_string_t* signature, catcrypt_rsa_key_t* pubkey);
catcrypt_string_t* catcrypt_rsa_signature_to_hex(catcrypt_string_t* signature_bin);
catcrypt_string_t* catcrypt_rsa_signature_from_hex(catcrypt_string_t* signature_hex);
It is easy to understand I think. Please look at the example usage. (./examples/test
)
Actually, I wrote this library for one of my projects and extracted it to make it an independent open source library.
It has my strings and reference counting and reference system that you can easily understand how it works in the following example.
You can see string things here:
/**
* ! Free by ref counting
*/
typedef struct catcrypt_string {
char* value;
unsigned int size;
unsigned int length;
unsigned int is_alloc_str;
catcrypt_ref_counted_t ref_counted;
} catcrypt_string_t;
catcrypt_string_t* catcrypt_string_new();
catcrypt_string_t* catcrypt_string_new__n(int length);
catcrypt_string_t catcrypt_string_from_cstr__copy(char* cstr, ssize_t length);
catcrypt_string_t* catcrypt_string_new_from_cstr__copy(char* cstr, ssize_t length);
catcrypt_string_t* catcrypt_string_new_from_binary__copy(char* data, ssize_t length);
catcrypt_string_t catcrypt_string_from_cstr(char* cstr, ssize_t length);
catcrypt_string_t catcrypt_string_from_binary(char* data, ssize_t length);
catcrypt_string_t* catcrypt_string_new_from_cstr(char* cstr, ssize_t length);
void catcrypt_string_free(catcrypt_string_t* string);
void catcrypt_string_set_value(catcrypt_string_t* string, char* value);
void catcrypt_string_set_value__n(catcrypt_string_t* string, char* value, size_t length);
void catcrypt_string_append__cstr__n(catcrypt_string_t* string, char* value, ssize_t length);
bool catcrypt_string_compare(catcrypt_string_t* string, catcrypt_string_t* other);
My reference counting has reference counted type (catcrypt_ref_counted_t*
) which this library only uses but also it has a reference system too.
typedef void (*catcrypt_ref_free_f_t)(void*);
#define CATCRYPT_REF_COUNTED_INIT(obj, free_f) \
catcrypt_ref_counted_init(&(obj->ref_counted), (catcrypt_ref_free_f_t) free_f);
#define CATCRYPT_REF_COUNTED_USE(obj) \
catcrypt_util_verbose("Referencing: %s\n", #obj); \
\
catcrypt_ref_counted_use(&(obj->ref_counted));
#define CATCRYPT_REF_COUNTED_LEAVE(obj) \
catcrypt_util_verbose("Dereferencing: %s\n", #obj); \
\
if (obj != NULL) { \
catcrypt_ref_counted_leave((void **) (&(obj)), &(obj->ref_counted)); \
}
#define REF_COUNTEDIFY() \
catcrypt_ref_counted_t ref_counted;
#define CATCRYPT_REF_BY(name) name##_ref
#define CATCRYPT_REF(type, name) \
type name; \
catcrypt_ref_t* CATCRYPT_REF_BY(name);
#define CATCRYPT_REF_NEW(path, expr) \
path = expr; \
CATCRYPT_REF_BY(path) = catcrypt_ref_new((void *) path, &(path->ref_counted));
#define CATCRYPT_REF_ASSIGN(var, val) \
catcrypt_ref_assign(&(CATCRYPT_REF_BY(var)), &(CATCRYPT_REF_BY(val))); \
var = val;
#define CATCRYPT_REF_SET(ref, obj) \
ref = obj; \
catcrypt_ref_set(CATCRYPT_REF_BY(ref), (void *) (ref));
#define CATCRYPT_REF_USE(name) catcrypt_ref_use(CATCRYPT_REF_BY(name));
#define CATCRYPT_REF_LEAVE(name) catcrypt_ref_leave(&(CATCRYPT_REF_BY(name)));
#define CATCRYPT_REF_ARG(type, name) type name, catcrypt_ref_t* name##_ref
#define CATCRYPT_REF_PASS(name) catcrypt_ref_new((void *) name, &(name->ref_counted));
typedef struct catcrypt_ref_counted catcrypt_ref_counted_t;
typedef struct catcrypt_ref catcrypt_ref_t;
struct catcrypt_ref_counted {
int count;
catcrypt_ref_free_f_t free_f;
};
struct catcrypt_ref {
int count;
void* obj;
catcrypt_ref_counted_t* ref_counted;
};
void catcrypt_ref_counted_init(catcrypt_ref_counted_t* ref_counted, catcrypt_ref_free_f_t free_f);
void catcrypt_ref_counted_use(catcrypt_ref_counted_t* ref_counted);
void catcrypt_ref_counted_leave(void** obj_vp, catcrypt_ref_counted_t* ref_counted);
catcrypt_ref_t* catcrypt_ref_new(void* obj, catcrypt_ref_counted_t* ref_counted);
void catcrypt_ref_free(catcrypt_ref_t* ref);
void catcrypt_ref_use(catcrypt_ref_t* ref);
void catcrypt_ref_leave(catcrypt_ref_t** ref);
void catcrypt_ref_assign(catcrypt_ref_t** dst, catcrypt_ref_t** src);
void catcrypt_ref_set(catcrypt_ref_t* ref, void* obj);
#include <stdio.h>
#include "../../include/rsa.h"
int main() {
char* data_to_encrypt = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed no sumo stet, est ei quodsi feugait liberavisse, in pro quot facete definitiones. Vivendum intellegat et qui, ei denique consequuntur vix. Offendit eleifend moderatius ex vix, quem odio mazim et qui, purto expetendis cotidieque quo cu, veri persius vituperata ei nec. Partiendo adversarium no mea. Offendit eleifend moderatius ex vix, quem odio mazim et qui, purto expetendis cotidieque quo cu, veri persius vituperata ei nec. Qui gloriatur scribentur et, id velit verear mel, cum no porro debet. Sit fugit nostrum et. Offendit eleifend moderatius ex vix, quem odio mazim et qui, purto expetendis cotidieque quo cu, veri persius vituperata ei nec. Pro ea animal dolores. Scripta periculis ei eam, te pro movet reformidans. Soluta facilisi instructior eam in, ferri oratio ancillae te ius. Vivendum intellegat et qui, ei denique consequuntur vix.";
printf("Generating key pair...\n");
catcrypt_string_t* data_to_encrypt_str = catcrypt_string_new_from_cstr(data_to_encrypt, strlen(data_to_encrypt)); CATCRYPT_REF_COUNTED_USE(data_to_encrypt_str);
catcrypt_rsa_keypair_t* keypair = catcrypt_rsa_keypair_new(); CATCRYPT_REF_COUNTED_USE(keypair);
catcrypt_string_t* pubkey_hex = catcrypt_rsa_key_to_hex(keypair->pubkey); CATCRYPT_REF_COUNTED_USE(pubkey_hex);
catcrypt_string_t* privkey_hex = catcrypt_rsa_key_to_hex(keypair->privkey); CATCRYPT_REF_COUNTED_USE(privkey_hex);
catcrypt_rsa_key_t* pubkey_from_hex = catcrypt_rsa_key_from_hex(pubkey_hex); CATCRYPT_REF_COUNTED_USE(pubkey_from_hex);
catcrypt_rsa_key_t* privkey_from_hex = catcrypt_rsa_key_from_hex(privkey_hex); CATCRYPT_REF_COUNTED_USE(privkey_from_hex);
catcrypt_string_t* pubkey_from_hex_to_hex = catcrypt_rsa_key_to_hex(pubkey_from_hex); CATCRYPT_REF_COUNTED_USE(pubkey_from_hex_to_hex);
catcrypt_string_t* privkey_from_hex_to_hex = catcrypt_rsa_key_to_hex(privkey_from_hex); CATCRYPT_REF_COUNTED_USE(privkey_from_hex_to_hex);
catcrypt_rsa_encrypted_t* encrypted = catcrypt_rsa_encrypt(data_to_encrypt_str, pubkey_from_hex); CATCRYPT_REF_COUNTED_USE(encrypted);
catcrypt_string_t* decrypted = catcrypt_rsa_decrypt(encrypted, privkey_from_hex); CATCRYPT_REF_COUNTED_USE(decrypted);
printf("Decrypted: %s\n", decrypted->value);
catcrypt_string_t* signature = catcrypt_rsa_sign(data_to_encrypt_str, keypair->privkey); CATCRYPT_REF_COUNTED_USE(signature);
catcrypt_string_t* signature_hex = catcrypt_rsa_signature_to_hex(signature); CATCRYPT_REF_COUNTED_USE(signature_hex);
printf("Signature: %s\n", signature_hex->value);
catcrypt_string_t* signature_from_hex = catcrypt_rsa_signature_from_hex(signature_hex); CATCRYPT_REF_COUNTED_USE(signature_from_hex);
bool verified = catcrypt_rsa_verify(data_to_encrypt_str, signature_from_hex, keypair->pubkey);
printf("Public Key: %s\n", pubkey_hex->value);
printf("Private Key: %s\n", privkey_hex->value);
printf("Public Key From Hex: %s\n", pubkey_from_hex_to_hex->value);
printf("Private Key From Hex: %s\n", privkey_from_hex_to_hex->value);
printf("Verified: %d\n", verified);
CATCRYPT_REF_COUNTED_LEAVE(data_to_encrypt_str);
CATCRYPT_REF_COUNTED_LEAVE(keypair);
CATCRYPT_REF_COUNTED_LEAVE(pubkey_hex);
CATCRYPT_REF_COUNTED_LEAVE(privkey_hex);
CATCRYPT_REF_COUNTED_LEAVE(pubkey_from_hex);
CATCRYPT_REF_COUNTED_LEAVE(privkey_from_hex);
CATCRYPT_REF_COUNTED_LEAVE(pubkey_from_hex_to_hex);
CATCRYPT_REF_COUNTED_LEAVE(privkey_from_hex_to_hex);
CATCRYPT_REF_COUNTED_LEAVE(encrypted);
CATCRYPT_REF_COUNTED_LEAVE(decrypted);
CATCRYPT_REF_COUNTED_LEAVE(signature);
CATCRYPT_REF_COUNTED_LEAVE(signature_hex);
CATCRYPT_REF_COUNTED_LEAVE(signature_from_hex);
return 0;
}
Idk.. I had made it for another project libhash in a coffee break before. According to my tests, it seems pretty oki and safe.
Here my dumb hash32 algorithm:
uint32_t catcrypt_rsa_hash_h32__n(char* data, ssize_t length) {
uint32_t hash = 0;
int remaining = 4;
int prev = 0;
for (int i=0; (length == -1) ? (i < length): (data[i] != '\0'); i++) {
remaining--;
int c = data[i] & 0b01111111;
uint8_t mask = ((c % 255) << (((((prev % 2) != 0) ? prev: 1) * i * c) % 7));
*(((unsigned char *)(&hash)) + ((i * c + prev) % 3)) = ((prev % 2) == 0)
? mask | prev
: mask & prev;
prev = (i * c) % 7;
}
for (int i=remaining; i > 0; i--) {
*(((unsigned char *)(&hash)) + ((4 - i) % 4)) = data[i % ((4 - i) % (4 - remaining))];
}
return hash;
}
CATCRYPT_RSA_PUB_EXPONENT
: The public exponent used in RSA encryption.CATCRYPT_RSA_PRIME_BITS
: The number of bits in the prime numbers used for RSA encryption.CATCRYPT_RSA_PRIME_REPS
: The number of repetitions for the Miller-Rabin primality test.CATCRYPT_RSA_BLOCK_SIZE
: The block size for RSA encryption.
catcrypt_rsa_key
: Represents an RSA key.catcrypt_rsa_keypair
: Represents a pair of RSA keys (public and private).catcrypt_rsa_encrypted
: Represents encrypted data.
Hashes a string.
Hashes a data of given length.
Seeds the random number generator.
Generates a random prime number.
Creates a new RSA key.
Frees an RSA key.
Creates a new RSA key pair.
Frees an RSA key pair.
Creates a new encrypted data object.
Sets the key for an encrypted data object.
Sets the data for an encrypted data object.
Frees an encrypted data object.
Encrypts data.
catcrypt_string_t* catcrypt_rsa_decrypt(catcrypt_rsa_encrypted_t* encrypted, catcrypt_rsa_key_t* privkey)
Decrypts data.
Converts an RSA key to binary.
Converts binary data to an RSA key.
Converts an RSA key to hexadecimal.
Converts hexadecimal data to an RSA key.
Signs data.
bool catcrypt_rsa_verify(catcrypt_string_t* data, catcrypt_string_t* signature, catcrypt_rsa_key_t* pubkey)
Verifies a signature.
Converts a signature to hexadecimal.
Converts hexadecimal data to a signature.
Currency | Address |
---|---|
BTC | bc1qhvlc762kwuzeawedl9a8z0duhs8449nwwc35e2 |
ETH | 0x1D99B2a2D85C34d478dD8519792e82B18f861974 |
USDT | 0x1D99B2a2D85C34d478dD8519792e82B18f861974 |
USDC | 0x1D99B2a2D85C34d478dD8519792e82B18f861974 |
XMR | 426nQLFDwpZS64vy6DYdKaHwog3GofyPHFpxvmF6qSQuNg5XJCehv5zPpfh4ff9n5WWfTdKN1Jr29E1XSRuLkjQVJREF7jb |
Copyright (C) 2023, Oğuzhan Eroğlu [email protected] (https://oguzhaneroglu.com/)
This work is licensed under the terms of the MIT license.
For a copy, see https://opensource.org/licenses/MIT.