------------------------------------------------------------------------- WARNING These implimentations of crypto functions are NOT SECURE and SHOULD NOT be used in any serious implimentations of anything whatsoever. This code has been written solely as a learning experience for the writer. One day far in the future it might come closer to being secure, but that day is not today. As it stands, there are more vulnerabilities than I can count or even understand. Seriously, don't use this. ------------------------------------------------------------------------- DESCRIPTION This is RSAES, a C++ interface for encryption over RSA and AES-N. In its current state, this project IS NOT SECURE and should not be used in production. It is a learning experience on the author's part, and only might be secure in the distant future. The intent is for applications which need very simple encryption in a very small footprint. This library is meant to be portable above all else, with two options of use: using a pre-compiled version of GMP linked through lgmp, or through a version of mini-gmp when <gmp.h> is not available, which is contained herein. AES-N is a fork of the AES algorithm which has been designed to work with any key size that is a power of two above 128. For values of 128, 256, and 512, the algorithm is the same as the reference AES algorithm. Larger key sizes follow the most obvious pattern in the algorithm, and are implimented accordingly. I've personally tested key sizes up to about 1 Gigabyte with success. ------------------------------------------------------------------------- MAKEFILE INSTRUCTIONS To begin using RSAES, one must first run `make init` in the RSAES directory. This will construct RSAES.hpp from RSAES.hpp.proto, which can be included in desired applications. `make init` has a few options, which are described as follows: make init Assumes the behavior of make init lib=yes make init lib=yes Assumes GMP is installed on the target system. RSAES.hpp will include <gmp.h> and should compiled with the -lgmp flag. If GMP is not installed on the target system, use the next option make init lib=no Assumes GMP is not installed on the target system. Instead of linking to libgmp, RSAES.hpp will include "mini-gmp/mini-gmp.c" and will include the functions and struct definitions needed for RSAES to work properly. The advantage here is more portability at the cost of performance, as mini-gmp uses a pure C implimentation of GMP. This is slower as it does not have assemby optimizations, but should be fully cross-platform. In both cases, simply `#include "RSAES.hpp"` in your project, with proper directory structure, and everything should work smoothly. Furthermore, the makefile has a few more abilities, all accessable only after a `make init`. They are as follows: make test Compiles tests_and_examples.cpp using RSAES.hpp and runs a test suite. `make test` assumes g++ to comple, however a specific compiler can be used through specifying the CXX flag. As follows is an example: make test CXX=clang++ This would compile tests_and_examples.cpp with clang and run a.out. Additionally, CXXFLAGS is recognized and can be passed to the makefile in order to specify optimizations or special circumstances. Example is as follows: make test CXXFLAGS="-O2 -Wall -Werror" make debug Same as make test, but runs the resulting executable under valgrind to check for errors. make time Same as make test, but runs the resulting executable with the `time` command make clean Remove all generated files, likely editor files, and executables generated by other make options. Should leave the entire repository the same as it was when first cloned ------------------------------------------------------------------------- TOP LEVEL INTERFACE The top level interface is held in the `RSAES` namespace in the class `EncryptionManager`. ----------EncryptionManager CONSTRUCTORS EncryptionManager(unsigned int RSAbits) Creates an empty EncryptionManager and initilizes public and private RSA keys (the size of which is passed as RSAbits). This should be the first constructor used when starting 2-way communicatoin. At this point, the getPublicKey() method is now available. EncryptionManager(std::string key, size_t AESbits) Creates an EncryptionManager using an RSA public key. This public key should come from the getPublicKey() method from the first constructor. AESbits is the size of bits in AES-N. See description for clarification on AES-N. At this point, the getKeyResponse() method is now available. EncryptionManager(std::string key) Creates an EncryptionManager with only an RSA public key. Identical in purpose to the above constructor, but chooses the largest AES-N keysize that can fit within the RSA key. Gives less control, but ensures the most secure possible algorithm given the size of the RSA key. At this point, the getKeyResponse() method is now available. EncryptionManager() Creates an empty EncryptionManager for the express reason of unpacking a string into it. See the pack() and unpack() methods ~EncryptionManager() The deconstructor is available at any time and should be mentioned here. When deconstructed, this object overwrites all its members with random bits before freeing them, just in case a malacoius program would get a hold of the malloc'd memory. Additionally, memory management has been taken care of so that even if an EncryptionManager goes out of scope before being fully initilized, memory management is still safe and secure. ----------EncryptionManager METHODS std::string getPublicKey() Available immediatly after using the first constructor. This method returns the RSA public key, as packed in base64. Once transfered, the result should be passed to the second constructor. std::string getKeyResponse() Available immediatly after using the second constructor. This method returns the internal AES-N key, encrypted with the RSA key, and packed in base64. Once transfered, the result should be passed to the following method on the first object. At this point, the encrypt() and decrypt() methods are available. void registerPass(std::string KeyResponse) Available immediatly after calling getPublicKey() on an object instantiated by the first constructor. This method decrypts and stores the shared AES-N key. At this point, the encrypt() and decrypt() methods are available. std::string encrypt(std::string input) Available immediatly after calling getKeyResponse() or registerPass() on an object. This method takes a string of any length and returns the string as encrypted by AES-N, using the internal AES-N key, and packed as base64. std::string decrypt(std::string input) Available immediatly after calling getKeyResponse() or registerPass() on an object. This method takes a string returned from the encrypt() method and returns the decrypted string using the internal AES-N key. std::string pack() Return a base64 encoded string containing a small snippet of the AES key. This string can be saved to disk for future sessions when RAM is cleared void unpack(std::string input) Takes a string previously returned from pack(), used to initilize an EncryptionManager constructed from the default EncryptionManager() constructor. After running unpack, both encrypt and decrypt are available. void destroy() Free all allocated memory associated with the object. Very similar to the deconstructor, but doesn't re-seed the random objects. ------------------------------------------------------------------------- LOW LEVEL INTERFACES The low level interfaces are held in the RSAES namespace, under one of the following sub-namespaces: RSA, AES, or UTIL. The low level interface is not meant to be used directly and thus is not as clean as the top level interface. However, in the usecases of debugging or highly- optimized implimentations where the top level interface offers more than needed, use of the low level interfaces are encouraged. ----------UTIL The UTILity namespace houses the general utility functions and objects used all over in the library. They are as follows: -->OBJECTS Global objects are as such so that they only needs to be initilized once, saving on memory usage and improving speed. std::random_device rd; An std::random_device used for better randomization than rand(). std::mt19937 mt(rd()); The Mersenne Twister algorithm, as initilized by our random device. Used for extracting random numbers from the distribution objects. std::uniform_int_distribution<unsigned short> dist_char(0, 255); Used for creating padding at the end of messages. std::uniform_int_distribution<unsigned short> dist_char_1(1, 255); Used for creating an AES key. This is different because bugs. std::uniform_int_distribution<unsigned long long int> dist_short(0, std::numeric_limits<unsigned short>::max()); Used for clearing vectors, as it's much faster to use shorts when possible. std::uniform_int_distribution<unsigned long> dist_r(0, std::numeric_limits<unsigned long>::max()); Used for generic randomness and seeding the GMP random structs. const char base64_chars[64]; Used as a lookup table for base64 en/decoding. -->FUNCTIONS inline char find_as_base64(char tofind) Used to reverse the lookup base64_chars lookup table during decodng. std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len) Used to base64 encode some bytes. It doesn't take a string because that's how I found it on the internet. std::string base64_decode(std::string const& encoded_string) Used to decode a base64 string. The return value is a string whos bytes are not all valid ascii. ----------RSA The RSA namespace houses everything needed to run and manage the RSA side of RSAES. It contains various functions and a single class (RSAmanager). -->FUNCTIONS std::string packKey(std::pair<mpz_t,mpz_t> key) Packs the public `key` and returns valid ascii. void unpackKey(std::pair<mpz_t,mpz_t> **rop, std::string key) Unpacks the public `key` into `rop`. std::string encrypt(std::string input, std::pair<mpz_t,mpz_t> *key) The full RSA encryption algorithm. Encrypts `input` using the public `key`. -->RSAmanager The RSAmanager is a mid-level interface for dealing with RSA encryption. >Members std::pair<mpz_t,mpz_t> public_key; Public member which stores the public key. mpz_t private_key; Private member which stores the private key. gmp_randstate_t r; The source of randomness for the object. >Constructor RSAmanager(unsigned int bits) Takes bits as an argument. Typically 1024, 2048, 4096, or higher. Creates the public and private key. >Destructor ~RSAmanager() Fills all used ram with random bits before clearing memory, just in case. >Methods inline std::string decrypt(std::string msg) Full RSA decryption algorithm. Decrypts `msg` using the private key. All private methods are simply used to help decrypt and instantiate. ----------AES The AES namespace houses everything needed to run and manage the AES side of RSAES. Although it is a part of RSAES, it can stand alone as just an AES implimentation. It contains many functions, varibles and a single class (AESkey). Only the important ones are shown. -->FUNCTIONS std::vector<unsigned char> expand_key(std::vector<unsigned char> in) Takes an N-bit key, where N is restricted to 128, 256, or any power of two thereafter. Returns an expanded key. This is the KeyExpansion step in the reference AES algorithm. unsigned char small_encrypt(unsigned char *in, AESkey &expanded_key) Fully encrypts a 4x4 bytetable. This is the entire reference AES algorithm. unsigned char small_decrypt(unsigned char *in, AESkey &expanded_key) Fully decrypts a 4x4 bytetable. This is the reference AES decryption algorithm. std::string big_encrypt(std::string input, AESkey &expanded_key) Takes a whole string, padds it, encrypts each table, then wraps it up in base64 and returns a passable, encrypted string. std::string big_decrypt(std::string input, AESkey &expanded_key) Takes a whole string, decodes it from base64, decrypts it, un-padds it and returns the clean string. -->AESkey The AES key class is simply a wrapper for an expanded key with methods to step over the key and produce round keys. >Members size_t base; The base size of the key in bytes. If you're using AES-256, this value would be 32. std::vector<unsigned char> expanded_key; Holds the value of the expanded key. >Constructors AESkey(std::vector<unsigned char> in) Creates an expanded key from a given unexpanded key (in the case) of a hashed password. AESkey(size_t _base) Creates an expanded key at random, given only by the size of key desired. >Destructor ~AESkey() Randomizes all ram before releasing just in case. >Methods std::array<unsigned char, 16> getRoundKey(bool B = false) Gets the next round key and automatically advances forward or backwards. inline void advanceRound() Readys the next round key. inline void setStart() Gets the key ready for front-to-back navigation (encryption). inline void setEnd() Gets the key ready for back-to-fromt navigation (decryption). inline std::string pack() Returns a base64 encoded, shortened version of the internal key used for saving to disk.