--- /dev/null
+# CryptoFoleo
+A library with some basic cryptography for C and Haskell.
+
+ uint8_t* chacha20(uint8_t[32], uint8_t[12], uint32_t, uint64_t);
+
+Generate a pseudorandom number mask from ChaCha20 cipher. The first parameter is the key, the second is the nonce, the third is the starting block number, and the last is the number of bytes you want to generate. If you are using this in conjunction with Poly1305, then you MUST use a starting block greater than zero.
+
+ uint8_t* poly1305(uint8_t*, uint8_t*, uint8_t*, uint32_t);
+
+Generate a Poly1305 hash where the first two parameters are 16-byte starting states (r, s), the third is a pointer to the data to hash, and the last is the length of that data. A Poly1305 hash is always 16 bytes.
+
+ uint8_t* chacha20_poly1305(uint8_t[32], uint8_t[12], uint8_t*, uint64_t);
+
+Generates a Poly1305 message authentication code. The first two parameters are again the key and the nonce for the ChaCha20 cipher, the second is the pointer to the message to be authenticated and the last is the length of the message. This code is again 16 bytes.
+
+ uint8_t* dhke(uint8_t*, uint8_t*);
+
+Performs a Diffie-Hellman key exchange using the 4096-bit prime ID#16 located in RFC#3526. The two parameters are "private" and "public" where "private" refers to the initial randomly generated numbers and "public" refers to the computed numbers that are shared across the network. If the function is called with both options as NULL, then it will return a randomly generated "private" value that is 512 bytes in size. If that private value is then passed into the first parameter with the public parameter, the second parameter, left as NULL, then it will return the 512 public bytes that are meant to be shared over the network. If the private value is passed into the first parameter and the public value received other the network is passed into the second parameter, it will then compute the 512 byte shared secret. This one function can therefore handle the entire key exchange process.
+
+ uint8_t* dhke_prf(uint32_t, uint8_t*, uint32_t, uint8_t*, uint32_t, uint8_t*, uint32_t);
+
+Because the key is 4096 bits long which may either be too much or too little
+depending on your purposes, this library also offers as a way to convert the
+output of the key exchange into any arbitrary number of bytes appropriate
+for your purposes. This is just an implemetation of the PRF() function described in RFC#5246 using SHA-256.
+
+The first parameter specifies how many bytes you wish to return. If you are using a ChaCha20 cipher, this will be 32 as you will need 32-bytes for the ChaCha20 key, and thus the 512-byte shared secret will be converted into a 32-byte value. The rest of the parameters are pointers to some data followed by the number of bytes representing the size of that data. These three options are, in order, the secret, the label, and seed. The secret is the Diffie-Hellman shared secret derived at the end of the Diffie-Hellman key exchange process. The label and the seed require further explanation.
+
+The label should specify the kind of operation being done. It is common to not use the Diffie-Hellman output directly but instead
+transform it into another shared secret by first passing it into the PRF.
+Since the PRF is effectively a pseudorandom number generator, if both sides
+start with the same seed, they will still derive the same secret. In this
+case, the label is specified as "master secret" without a null terminator.
+
+This master secret is then used to derive further session keys to be used
+later in the communication, and at that point PRF() is called again with
+a different label "key expansion" again without the null terminator. Using
+different labels for different operations makes sure you get a different
+set of pseudorandom numbers per operation which both parties should agree
+upon.
+
+The seed helps increase the unpredictability of the PRF function by
+introducing additional random numbers into the starting point of the PRF()
+function. Since both parties need to produce the same numbers, this seed
+will have to be shared publicly, typically as part of the same handshake
+where they exchange their Diffie-Hellman numbers.
+
+
+ uint8_t* prigen(uint16_t);
+
+Generates a random prime number. The parameter is the byte-width of the prime number. For example, if you want to generate random 1024-bit RSA keys, then you can call this twice passing in the number 128.
+
+ rsakey_t rsa_public(uint8_t*, uint16_t, uint8_t*, uint16_t, uint8_t*, uint16_t);
+
+This takes three parameters: p, q, and e, and from them calculates the RSA public key. The reason there are six parameters is because after each key buffer is another parameter specifying the size of that buffer in bytes.
+
+ rsakey_t rsa_private(uint8_t*, uint16_t, uint8_t*, uint16_t, uint8_t*, uint16_t);
+
+Same as above except it calculates the RSA private key.
+
+ rsakey_t rsa_import(uint8_t*, uint16_t, uint8_t*, uint16_t);
+
+Imports an RSA key from a buffer. This expects you to either pass in d and n, or e and n, depending on whether or not it is a private or public key.
+
+ uint8_t* rsa_export(rsakey_t, uint8_t, uint16_t*);
+
+Export an RSA key. The second parameter specifies which key you want to export. For public keys, valid options are the byte 'e' or the byte 'n'. For private keys, valid options are the byte 'd' or the byte 'n'. The last parameter will contain the size of the key in bytes, and the function returns a pointer to that key.
+
+ void rsa_free(rsakey_t);
+
+Free the memory associated with an RSA key.
+
+ uint8_t* rsa_encrypt(rsakey_t, uint8_t, uint8_t*, uint16_t);
+
+Encrypts some data using an RSA key. This only encrypts a single block which is why the last parameter, which specifies the size of the data you wish to encrypt, is only a 16-bit integer. If you want to encrypt many blocks of data, you will need to break your data up into blocks manually and call this for each block. The third parameter points to the buffer of data you want to encrypt.
+
+The second parameter is the type of padding to be used during encryption. Current supported options are RSA_ENCRYPTION which applies PKCS#1 v1.5 encryption padding, RSA_SIGNATURE which applies PKCS#1 v1.5 signature padding, and RSA_OAEP which applies optimal asymmetric encryption padding with SHA-256. You can also pass RSA_NONE into it for no padding at all.
+
+ uint8_t* rsa_decrypt(rsakey_t, uint8_t, uint8_t*, uint16_t*);
+
+This will both decrypt and "de-pad" RSA ciphertext blocks. Since the size of the message could be smaller than the maximum size that could fit into the block, it also will return the message size after decryption as the last parameter. Like with encryption, you can also specify the padding type. If the padding types do not match up from what was encrypted, it will fail to decrypt, returning a NULL value.
+
+ uint8_t* sha256(uint8_t*, uint32_t);
+
+Computes a SHA-256 hash with the two parameters being a pointer to the data and the size of the data to be hashed.
--- /dev/null
+#include <stdint.h>
+#include <gmp.h>
+
+uint8_t* chacha20(uint8_t[32], uint8_t[12], uint32_t, uint64_t);
+uint8_t* chacha20_poly1305(uint8_t[32], uint8_t[12], uint8_t*, uint64_t);
+uint8_t* dhke(uint8_t*, uint8_t*);
+uint8_t* dhke_prf(uint32_t, uint8_t*, uint32_t, uint8_t*, uint32_t, uint8_t*, uint32_t);
+uint8_t* poly1305(uint8_t*, uint8_t*, uint8_t*, uint64_t);
+uint8_t* prigen(uint16_t);
+#define RSA_NONE 99
+#define RSA_ENCRYPTION 1
+#define RSA_SIGNATURE 2
+#define RSA_OAEP 3
+#define RSA_PSS 4
+typedef struct
+{
+ mpz_t n, k;
+ uint16_t bitWidth;
+} rsakey_t;
+rsakey_t rsa_public(uint8_t*, uint16_t, uint8_t*, uint16_t, uint8_t*, uint16_t);
+rsakey_t rsa_private(uint8_t*, uint16_t, uint8_t*, uint16_t, uint8_t*, uint16_t);
+rsakey_t rsa_import(uint8_t*, uint16_t, uint8_t*, uint16_t);
+uint8_t* rsa_export(rsakey_t, uint8_t, uint16_t*);
+void rsa_free(rsakey_t);
+uint8_t* rsa_encrypt(rsakey_t, uint8_t, uint8_t*, uint16_t);
+uint8_t* rsa_decrypt(rsakey_t, uint8_t, uint8_t*, uint16_t*);
+uint8_t* sha256(uint8_t*, uint32_t);
--- /dev/null
+gcc -shared -fPIC src/all.c -o bin/libCryptoFoleo.so -lgmp -DDEVICE='"/dev/random"'
+cp src/headers.h bin/CryptoFoleo.h
--- /dev/null
+#include "headers.h"
+#include "chacha20.c"
+#include "dhke.c"
+#include "poly1305.c"
+#include "prigen.c"
+#include "rsa.c"
+#include "sha256.c"
\ No newline at end of file
--- /dev/null
+#ifndef __CHACHA20__
+#define __CHACHA20__
+#include <stdio.h>
+#include <stdint.h>
+#include "poly1305.c"
+
+static uint32_t chacha20_lr(uint32_t a, uint8_t b)
+{
+ return (a << b) | (a >> (32 - b));
+}
+
+static void chacha20_QR(uint32_t *cc, uint8_t a, uint8_t b, uint8_t c, uint8_t d)
+{
+ cc[a] += cc[b]; cc[d] ^= cc[a]; cc[d] = chacha20_lr(cc[d], 16);
+ cc[c] += cc[d]; cc[b] ^= cc[c]; cc[b] = chacha20_lr(cc[b], 12);
+ cc[a] += cc[b]; cc[d] ^= cc[a]; cc[d] = chacha20_lr(cc[d], 8);
+ cc[c] += cc[d]; cc[b] ^= cc[c]; cc[b] = chacha20_lr(cc[b], 7);
+}
+
+static void chacha20_DR(uint32_t *cc)
+{
+ chacha20_QR(cc, 0, 4, 8, 12);
+ chacha20_QR(cc, 1, 5, 9, 13);
+ chacha20_QR(cc, 2, 6, 10, 14);
+ chacha20_QR(cc, 3, 7, 11, 15);
+ chacha20_QR(cc, 0, 5, 10, 15);
+ chacha20_QR(cc, 1, 6, 11, 12);
+ chacha20_QR(cc, 2, 7, 8, 13);
+ chacha20_QR(cc, 3, 4, 9, 14);
+}
+
+static void chacha20_CB(uint32_t *cc)
+{
+ uint8_t i;
+ uint32_t x[16];
+ for (i = 0; i < 16; i++)
+ {
+ x[i] = cc[i];
+ }
+ for (i = 0; i < 10; i++)
+ {
+ chacha20_DR(cc);
+ }
+ for (i = 0; i < 16; i++)
+ {
+ cc[i] += x[i];
+ }
+}
+
+static void chacha20_S(uint32_t *cc, uint8_t *cs)
+{
+ for (uint8_t i = 0; i < 16; i++)
+ {
+ cs[4 * i] = (cc[i] & 0xFF);
+ cs[4 * i + 1] = ((cc[i] >> 8) & 0xFF);
+ cs[4 * i + 2] = ((cc[i] >> 16) & 0xFF);
+ cs[4 * i + 3] = ((cc[i] >> 24) & 0xFF);
+ }
+}
+
+static void chacha20_block(uint8_t key[32], uint8_t nonce[12], uint32_t block, uint8_t out[64])
+{
+ uint32_t cc[] =
+ {
+ 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574,
+
+ key[0] | (key[1] << 8) | (key[2] << 16) | (key[3] << 24),
+ key[4] | (key[5] << 8) | (key[6] << 16) | (key[7] << 24),
+ key[8] | (key[9] << 8) | (key[10] << 16) | (key[11] << 24),
+ key[12] | (key[13] << 8) | (key[14] << 16) | (key[15] << 24),
+
+ key[16] | (key[17] << 8) | (key[18] << 16) | (key[19] << 24),
+ key[20] | (key[21] << 8) | (key[22] << 16) | (key[23] << 24),
+ key[24] | (key[25] << 8) | (key[26] << 16) | (key[27] << 24),
+ key[28] | (key[29] << 8) | (key[30] << 16) | (key[31] << 24),
+
+ block,
+
+ nonce[0] | (nonce[1] << 8) | (nonce[2] << 16) | (nonce[3] << 24),
+ nonce[4] | (nonce[5] << 8) | (nonce[6] << 16) | (nonce[7] << 24),
+ nonce[8] | (nonce[9] << 8) | (nonce[10] << 16) | (nonce[11] << 24)
+ };
+
+ chacha20_CB(cc);
+ chacha20_S(cc, out);
+}
+
+/*Don't use block #0 if you are using this in conjunction with poly1305*/
+uint8_t* chacha20(uint8_t key[32], uint8_t nonce[12], uint32_t block, uint64_t count)
+{
+ if (count > (274877906944 - block * 64)) return NULL;
+ uint8_t* ret = malloc(0);
+ uint8_t ccblock[64];
+ uint64_t size = 0;
+ while (count > 64)
+ {
+ ret = realloc(ret, size + 64);
+ chacha20_block(key, nonce, block++, ccblock);
+ for (uint8_t i = 0; i < 64; i++) ret[size + i] = ccblock[i];
+ size += 64;
+ count -= 64;
+ }
+ if (count > 0)
+ {
+ ret = realloc(ret, size + count);
+ chacha20_block(key, nonce, block, ccblock);
+ for (uint8_t i = 0; i < count; i++) ret[size + i] = ccblock[i];
+ }
+ return ret;
+}
+
+//Calculates poly1305 for ciphertext encrypted with chacha20
+uint8_t* chacha20_poly1305(uint8_t key[32], uint8_t nonce[12], uint8_t* cipherText, uint64_t lengthInBytes)
+{
+ uint8_t* keydata = chacha20(key, nonce, 0, 32);
+ uint8_t r[16];
+ uint8_t s[16];
+ for (uint8_t i = 0; i < 16; i++)
+ {
+ r[i] = keydata[i];
+ s[i] = keydata[i + 16];
+ }
+ free(keydata);
+ return poly1305(r, s, cipherText, lengthInBytes);
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef __DHKE__
+#define __DHKE__
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <gmp.h>
+#include "sha256.c"
+
+/*
+dhke(private, public)
+
+Here, "private" refers to random numbers intended to be used in the key exchange
+while "public" refers to the public information shared in the communication.
+If both are NULL, then it will generate random private numbers and return those
+as a buffer. If you then pass those into the function again as the private
+parameter and leave public as NULL, it will generate the public value meant to
+be shared. If you pass in your private value as the private parameter and the
+public value you acquired from the other person as the public parameter, it will
+return the shared secret.
+
+dhke_prf(desiredBytes, secret, secretS, label, labelS, seed, seedS)
+
+Because the key is 4096 bits long which may either be too much or too little
+depending on your purposes, this library also offers as a way to convert the
+output of the key exchange into any arbitrary number of bytes appropriate
+for your purposes.
+
+The "desired bytes" is the amount of bytes you want and the "secret" should
+be the 4096 byte shared secret arrived at after the key exchange. Note that
+the parameters that end with a capital S are just the length of bytes of
+the buffer pointed to by the previous parameter.
+
+The label should specify the kind of operation being done.
+
+It is common to not use the Diffie-Hellman output directly but instead
+transform it into another shared secret by first passing it into the PRF.
+Since the PRF is effectively a pseudorandom number generator, if both sides
+start with the same seed, they will still derive the same secret. In this
+case, the label is specified as "master secret" without a null terminator.
+
+This master secret is then used to derive further session keys to be used
+later in the communication, and at that point PRF() is called again with
+a different level "key expansion" again without the null terminator. Using
+different labels for different operations makes sure you get a different
+set of pseudorandom numbers per operations which both parties should agree
+upon.
+
+The seed helps increase the unpredictability of the PRF function by
+introducing additional random numbers into the starting point of the PRF()
+function. Since both parties need to produce the same numbers, this seed
+will have to be shared publicly, typically as part of the same handshake
+where they exchange their Diffie-Hellman numbers.
+
+The PRF() function utilizes the SHA-256 hash, but in theory could be
+modified to support any hash. However, SHA-256 is a pretty common industry
+standard, so for simplification reasons, the PRF() here does not require
+a hash as an input but just chooses SHA-256 with appropriate parameters
+automagically.
+*/
+
+
+/*
+ key exchange here is fixed to using a group from RFC#3526
+*/
+static uint8_t RFC3526ID16[] =
+{
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+ 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+ 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+ 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+ 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+ 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+ 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+ 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+ 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+ 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+ 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
+ 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
+ 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+ 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
+ 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
+ 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+ 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
+ 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
+ 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
+ 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
+ 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
+ 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
+ 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
+ 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
+ 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
+ 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
+ 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
+ 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
+ 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
+ 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
+ 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
+ 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
+ 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
+ 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
+ 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
+ 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
+ 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
+ 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
+ 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
+ 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
+ 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
+ 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
+ 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
+ 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
+ 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
+ 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
+ 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
+ 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
+ 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
+ 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
+ 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
+ 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
+ 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
+ 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
+ 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
+ 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
+ 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
+ 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+static void dhke_store(mpz_t n, uint8_t* b, uint32_t s)
+{
+ for (uint32_t i = 0; i < s; i++)
+ {
+ b[s - (i + 1)] = mpz_get_ui(n);
+ mpz_div_ui(n, n, 256);
+ }
+}
+
+static void dhke_load(mpz_t n, uint8_t* b, uint32_t s)
+{
+ mpz_set_ui(n, 0);
+ for (uint32_t i = 0; i < s; i++)
+ {
+ mpz_mul_ui(n, n, 256);
+ mpz_add_ui(n, n, b[i]);
+ }
+}
+
+/*
+ pass in NULL for both to get a new private value
+ pass in the private value with a null for public
+ to return the public value to be shared
+ pass in the private value and the public
+ received to compute the final key
+*/
+uint8_t* dhke(uint8_t* private, uint8_t* public)
+{
+ mpz_t n, g, p;
+ mpz_init(n);
+ mpz_init(g);
+ mpz_init(p);
+ mpz_set_ui(g, 2);
+ dhke_load(p, RFC3526ID16, 512);
+ uint8_t* out = malloc(512);
+
+ if (private == NULL && public == NULL)
+ {
+ FILE* f = fopen(DEVICE, "r");
+ fread(out, 1, 512, f);
+ fclose(f);
+ out[0] = out[0] & 0b01111111;
+ }
+ else if (private != NULL && public == NULL)
+ {
+ dhke_load(n, private, 512);
+ mpz_powm(n, g, n, p);
+ dhke_store(n, out, 512);
+ }
+ else
+ {
+ mpz_t m;
+ mpz_init(m);
+ dhke_load(m, private, 512);
+ dhke_load(n, public, 512);
+ mpz_powm(n, n, m, p);
+ dhke_store(n, out, 512);
+ mpz_clear(m);
+ }
+
+ mpz_clear(n);
+ mpz_clear(g);
+ mpz_clear(p);
+ return out;
+}
+
+//HMAC(K, m) = H((K' xor opad) || H((K' xor ipad) || m))
+static uint8_t* dhke_hmac
+(
+ uint8_t* (hash_func)(uint8_t*, uint32_t),
+ uint32_t Hs, //hash size
+ uint32_t Bs, //block size
+ uint8_t* K,
+ uint32_t Ks, //K size
+ uint8_t* M,
+ uint32_t Ms //M size
+)
+{
+ uint8_t* tmp1;
+ uint8_t* Kp; //K prime
+
+ if (Ks <= Bs)
+ {
+ Kp = malloc(Bs);
+ for (uint32_t i = 0; i < Bs; i++)
+ {
+ Kp[i] = i < Ks ? K[i] : 0;
+ }
+ }
+ else
+ {
+ tmp1 = hash_func(K, Ks);
+ Kp = malloc(Bs);
+ for (uint32_t i = 0; i < Bs; i++)
+ {
+ Kp[i] = i < Hs ? tmp1[i] : 0;
+ }
+ free(tmp1);
+ }
+
+ //opad and ipad
+ uint8_t opad[Bs];
+ uint8_t ipad[Bs];
+ for (uint32_t i = 0; i < Bs; i++)
+ {
+ opad[i] = 0x5C;
+ ipad[i] = 0x36;
+ }
+ tmp1 = malloc(Bs + Ms);
+ for (uint32_t i = 0; i < Bs + Ms; i++)
+ {
+ tmp1[i] = i < Bs ? Kp[i] ^ ipad[i] : M[i - Bs];
+ }
+ uint8_t* tmp2 = hash_func(tmp1, Bs + Ms);
+ free(tmp1);
+
+ tmp1 = malloc(Bs + Hs);
+ for (uint32_t i = 0; i < Bs + Hs; i++)
+ {
+ tmp1[i] = i < Bs ? Kp[i] ^ opad[i] : tmp2[i - Bs];
+ }
+ free(tmp2);
+ free(Kp);
+
+ tmp2 = hash_func(tmp1, Bs + Hs);
+ free(tmp1);
+ return tmp2;
+
+}
+
+//A(0) = seed
+//A(i) = HMAC_hash(secret, A(i-1))
+static uint8_t* dhke_hmac_A
+(
+ uint8_t iter, //iteration
+ uint8_t* (hash_func)(uint8_t*, uint32_t),
+ uint32_t Hs, //hash size
+ uint32_t Bs, //block size
+ uint8_t* secret,
+ uint32_t secretS, //secret size
+ uint8_t* seed,
+ uint32_t seedS, //seed size
+ uint32_t* returnSize
+)
+{
+ uint8_t* out;
+ if (iter == 0)
+ {
+ out = malloc(seedS);
+ for (uint32_t i = 0; i < seedS; i++)
+ {
+ out[i] = seed[i];
+ }
+ *returnSize = seedS;
+ return out;
+ }
+ uint32_t retSize;
+ uint8_t* tmp = dhke_hmac_A(iter - 1, hash_func, Hs, Bs, secret, secretS, seed, seedS, &retSize);
+ out = dhke_hmac(hash_func, Hs, Bs, secret, secretS, tmp, retSize);
+ free(tmp);
+ *returnSize = Hs;
+ return out;
+}
+
+//PRF(secret, label, seed) = P_<hash>(secret, label + seed)
+// = HMAC_hash(secret, A(i) + seed)
+//We are using sha256, but this is coded in such a way
+// that we could extend it to other algorithms in the
+// future.
+uint8_t* dhke_prf
+(
+ uint32_t desiredBytes,
+ uint8_t* secret,
+ uint32_t secretS,
+ uint8_t* label,
+ uint32_t labelS,
+ uint8_t* seed,
+ uint32_t seedS
+)
+{
+ uint32_t Hs = 32;
+ uint32_t Bs = 64;
+ uint32_t iter = 1;
+ uint8_t* keystream = malloc(0);
+ uint8_t* labelSeed = malloc(labelS + seedS);
+
+ for (uint32_t i = 0; i < labelS + seedS; i++)
+ labelSeed[i] = i < labelS ? label[i] : seed[i - labelS];
+
+ while (desiredBytes != 0)
+ {
+ uint32_t tmp1S;
+ uint8_t* tmp1 = dhke_hmac_A(iter, sha256, Hs, Bs, secret, secretS, labelSeed, labelS + seedS, &tmp1S);
+ tmp1 = realloc(tmp1, tmp1S + labelS + seedS);
+ for (uint32_t i = 0; i < labelS + seedS; i++)
+ tmp1[i + tmp1S] = labelSeed[i];
+ uint8_t* tmp2 = dhke_hmac(sha256, Hs, Bs, secret, secretS, tmp1, tmp1S + labelS + seedS);
+ free(tmp1);
+ if (desiredBytes >= Bs)
+ {
+ keystream = realloc(keystream, iter * Bs);
+ for (uint32_t i = 0; i < Bs; i++)
+ keystream[i + (iter - 1) * Bs] = tmp2[i];
+ desiredBytes -= Bs;
+ }
+ else
+ {
+ keystream = realloc(keystream, (iter - 1) * Bs + desiredBytes);
+ for (uint32_t i = 0; i < desiredBytes; i++)
+ keystream[i + (iter - 1) * Bs] = tmp2[i];
+ desiredBytes = 0;
+ }
+ free(tmp2);
+ iter++;
+ }
+ free(labelSeed);
+ return keystream;
+}
+#endif
--- /dev/null
+#include <stdint.h>
+#include <gmp.h>
+
+uint8_t* chacha20(uint8_t[32], uint8_t[12], uint32_t, uint64_t);
+uint8_t* chacha20_poly1305(uint8_t[32], uint8_t[12], uint8_t*, uint64_t);
+uint8_t* dhke(uint8_t*, uint8_t*);
+uint8_t* dhke_prf(uint32_t, uint8_t*, uint32_t, uint8_t*, uint32_t, uint8_t*, uint32_t);
+uint8_t* poly1305(uint8_t*, uint8_t*, uint8_t*, uint64_t);
+uint8_t* prigen(uint16_t);
+#define RSA_NONE 99
+#define RSA_ENCRYPTION 1
+#define RSA_SIGNATURE 2
+#define RSA_OAEP 3
+#define RSA_PSS 4
+typedef struct
+{
+ mpz_t n, k;
+ uint16_t bitWidth;
+} rsakey_t;
+rsakey_t rsa_public(uint8_t*, uint16_t, uint8_t*, uint16_t, uint8_t*, uint16_t);
+rsakey_t rsa_private(uint8_t*, uint16_t, uint8_t*, uint16_t, uint8_t*, uint16_t);
+rsakey_t rsa_import(uint8_t*, uint16_t, uint8_t*, uint16_t);
+uint8_t* rsa_export(rsakey_t, uint8_t, uint16_t*);
+void rsa_free(rsakey_t);
+uint8_t* rsa_encrypt(rsakey_t, uint8_t, uint8_t*, uint16_t);
+uint8_t* rsa_decrypt(rsakey_t, uint8_t, uint8_t*, uint16_t*);
+uint8_t* sha256(uint8_t*, uint32_t);
--- /dev/null
+#ifndef __POLY1305__
+#define __POLY1305__
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <gmp.h>
+
+static void poly1305_clamp(uint8_t* r)
+{
+ r[3] &= 15;
+ r[7] &= 15;
+ r[11] &= 15;
+ r[15] &= 15;
+ r[4] &= 252;
+ r[8] &= 252;
+ r[12] &= 252;
+}
+
+static void poly1305_b2n_le(mpz_t n, uint8_t *b, uint8_t s, uint8_t init)
+{
+ mpz_set_ui(n, init);
+ for (int8_t i = s - 1; i >= 0; i--)
+ {
+ mpz_mul_ui(n, n, 256);
+ mpz_add_ui(n, n, b[i]);
+ }
+}
+
+static void poly1305_dump(char *p, mpz_t n)
+{
+ char *nh = mpz_get_str(NULL, 16, n);
+ printf("%s = %s\n", p, nh);
+ free(nh);
+}
+
+//bS and bR are read little-endian and 16-bytes
+//return value must be freed
+uint8_t* poly1305(uint8_t* bR, uint8_t* bS, uint8_t* bM, uint64_t bMs)
+{
+ uint8_t bP[] =
+ {
+ 0xfb, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0x03
+ };
+
+ poly1305_clamp(bR);
+
+ mpz_t P, r, s, Acc, b;
+ mpz_init(P);
+ mpz_init(b);
+ mpz_init(r);
+ mpz_init(s);
+ mpz_init(Acc);
+ mpz_set_ui(Acc, 0);
+ poly1305_b2n_le(P, bP, 17, 0);
+ poly1305_b2n_le(s, bS, 16, 0);
+ poly1305_b2n_le(r, bR, 16, 0);
+
+ for (uint64_t i = 0;; i++)
+ {
+ uint64_t bytesLeft = bMs - (i * 16);
+ poly1305_b2n_le(b, bM + i * 16, bytesLeft < 16 ? bytesLeft : 16, 1);
+ mpz_add(Acc, Acc, b);
+ mpz_mul(Acc, Acc, r);
+ mpz_mod(Acc, Acc, P);
+ if (bytesLeft < 16) break;
+ }
+ mpz_add(Acc, Acc, s);
+
+ uint8_t *ret = malloc(16);
+ for (uint8_t i = 0; i < 16; i++)
+ {
+ ret[i] = mpz_get_ui(Acc);
+ mpz_div_ui(Acc, Acc, 256);
+ }
+ mpz_clear(P);
+ mpz_clear(b);
+ mpz_clear(r);
+ mpz_clear(s);
+ mpz_clear(Acc);
+ return ret;
+}
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef __PRIGEN__
+#define __PRIGEN__
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <gmp.h>
+
+static void PRIGEN_GetRandom(mpz_t n, uint16_t bytes, FILE *f)
+{
+ mpz_set_ui(n, 0);
+ for (uint16_t i = 0; i < bytes; i++)
+ {
+ mpz_mul_2exp(n, n, 8);
+ uint8_t c = fgetc(f);
+ if (i == 0) c |= 0b10000000;
+ if (i == bytes - 1) c |= 1;
+ mpz_add_ui(n, n, c);
+ }
+}
+
+static void PRIGEN_ComputeDS(mpz_t n, mpz_t d, uint16_t *s)
+{
+ mpz_t t;
+ mpz_init(t);
+ mpz_set(d, n);
+ mpz_sub_ui(d, d, 1);
+ *s = 0;
+ for (;;)
+ {
+ mpz_mod_ui(t, d, 2);
+ if (mpz_sgn(t) != 0) break;
+ mpz_div_ui(d, d, 2);
+ *s = (*s) + 1;
+ }
+ mpz_clear(t);
+}
+
+static uint8_t PRIGEN_PrimeTestOnce(mpz_t n, mpz_t d, uint16_t s, uint16_t witness)
+{
+ mpz_t x, m, a, two;
+ uint8_t ret = 0;
+ mpz_init(x);
+ mpz_init(m);
+ mpz_init(a);
+ mpz_init(two);
+ mpz_set_ui(two, 2);
+ mpz_sub_ui(m, n, 1);
+ mpz_set_ui(a, witness);
+
+ for (uint16_t i = 0; i < s; i++)
+ {
+ if (i == 0)
+ {
+ mpz_powm(x, a, d, n);
+ if (mpz_cmp_ui(x, 1) == 0 || mpz_cmp(x, m) == 0)
+ {
+ ret = 1;
+ break;
+ }
+ }
+ else
+ {
+ mpz_powm(x, x, two, n);
+ if (mpz_cmp(x, m) == 0)
+ {
+ ret = 1;
+ break;
+ }
+ if (mpz_cmp_ui(x, 1) == 0)
+ {
+ ret = 0;
+ break;
+ }
+ }
+ }
+
+ mpz_clear(x);
+ mpz_clear(m);
+ mpz_clear(a);
+ mpz_clear(two);
+ return ret;
+}
+
+static uint8_t PRIGEN_PrimeTest(mpz_t n)
+{
+ mpz_t d;
+ mpz_init(d);
+ uint16_t s = 0;
+ PRIGEN_ComputeDS(n, d, &s);
+
+ for (uint8_t a = 2; a < 12; a++)
+ {
+ if (!PRIGEN_PrimeTestOnce(n, d, s, a))
+ {
+ mpz_clear(d);
+ return 0;
+ }
+ }
+
+ mpz_clear(d);
+ return 1;
+}
+
+static void PRIGEN_GeneratePrime(mpz_t n, int bytes)
+{
+ FILE *f = fopen(DEVICE, "r");
+ do
+ {
+ PRIGEN_GetRandom(n, bytes, f);
+ } while (!PRIGEN_PrimeTest(n));
+ fclose(f);
+}
+
+/* Generate prime of X bytes */
+uint8_t* prigen(uint16_t bytes)
+{
+ uint8_t* buffer = malloc(bytes);
+ FILE *f = fopen(DEVICE, "r");
+ mpz_t n, t;
+ mpz_init(n);
+ do
+ {
+ PRIGEN_GetRandom(n, bytes, f);
+ } while (!PRIGEN_PrimeTest(n));
+ mpz_export(buffer, NULL, 1, 1, 0, 0, n);
+ mpz_clear(n);
+ fclose(f);
+ return buffer;
+}
+#endif
--- /dev/null
+#ifndef __RSA__
+#define __RSA__
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <gmp.h>
+#include "sha256.c"
+#include "prigen.c"
+/*typedef struct
+{
+ mpz_t n, k;
+ uint16_t bitWidth;
+} rsakey_t;*/
+
+
+static void rsa_store(mpz_t n, uint8_t* b, uint32_t s)
+{
+ for (uint32_t i = 0; i < s; i++)
+ {
+ b[s - (i + 1)] = mpz_get_ui(n);
+ mpz_div_ui(n, n, 256);
+ }
+}
+
+static void rsa_load(mpz_t n, uint8_t* b, uint32_t s)
+{
+ mpz_set_ui(n, 0);
+ for (uint32_t i = 0; i < s; i++)
+ {
+ mpz_mul_ui(n, n, 256);
+ mpz_add_ui(n, n, b[i]);
+ }
+}
+
+//Keys and their sizes in terms of BYTES
+rsakey_t rsa_public(uint8_t* p, uint16_t pS, uint8_t* q, uint16_t qS, uint8_t* e, uint16_t eS)
+{
+ mpz_t np, nq, ne;
+ mpz_init(np);
+ mpz_init(nq);
+ mpz_init(ne);
+ mpz_set_ui(np, 0);
+ mpz_set_ui(nq, 0);
+ mpz_set_ui(ne, 0);
+
+ rsa_load(np, p, pS);
+ rsa_load(nq, q, qS);
+ rsa_load(ne, q, qS);
+
+ rsakey_t ret;
+ ret.bitWidth = (pS + qS) * 8;
+ mpz_init(ret.n);
+ mpz_init(ret.k);
+ mpz_mul(ret.n, np, nq);
+ mpz_set(ret.k, ne);
+
+ mpz_clear(np);
+ mpz_clear(nq);
+ mpz_clear(ne);
+ return ret;
+}
+
+rsakey_t rsa_private(uint8_t* p, uint16_t pS, uint8_t* q, uint16_t qS, uint8_t* e, uint16_t eS)
+{
+ mpz_t np, nq, ne;
+ mpz_init(np);
+ mpz_init(nq);
+ mpz_init(ne);
+ mpz_set_ui(np, 0);
+ mpz_set_ui(nq, 0);
+ mpz_set_ui(ne, 0);
+
+ rsa_load(np, p, pS);
+ rsa_load(nq, q, qS);
+ rsa_load(ne, q, qS);
+
+ rsakey_t ret;
+ ret.bitWidth = (pS + qS) * 8;
+ mpz_init(ret.n);
+ mpz_init(ret.k);
+ mpz_mul(ret.n, np, nq);
+ mpz_set(ret.k, ne);
+
+ mpz_sub_ui(np, np, 1);
+ mpz_sub_ui(nq, nq, 1);
+ mpz_mul(np, np, nq);
+ mpz_invert(ret.k, ret.k, np);
+
+ mpz_clear(np);
+ mpz_clear(nq);
+ mpz_clear(ne);
+ return ret;
+}
+
+uint8_t* rsa_export(rsakey_t key, uint8_t whichone, uint16_t* newsize)
+{
+ uint8_t* ret = malloc(key.bitWidth / 8);
+ switch (whichone)
+ {
+ case 'd':
+ case 'D':
+ case 'e':
+ case 'E':
+ rsa_store(key.k, ret, key.bitWidth / 8);
+ *newsize = key.bitWidth / 8;
+ return ret;
+ case 'n':
+ case 'N':
+ rsa_store(key.n, ret, key.bitWidth / 8);
+ *newsize = key.bitWidth / 8;
+ return ret;
+ }
+ *newsize = 0;
+ free(ret);
+ return NULL;
+}
+
+rsakey_t rsa_import(uint8_t* bufferK, uint16_t byteSizeK, uint8_t* bufferN, uint16_t byteSizeN)
+{
+ rsakey_t ret;
+ ret.bitWidth = byteSizeN * 8;
+ mpz_init(ret.k);
+ mpz_init(ret.n);
+ mpz_set_ui(ret.k, 0);
+ mpz_set_ui(ret.n, 0);
+
+ rsa_load(ret.k, bufferK, byteSizeK);
+ rsa_load(ret.n, bufferN, byteSizeN);
+
+ return ret;
+}
+
+void rsa_free(rsakey_t key)
+{
+ key.bitWidth = -1;
+ mpz_clear(key.n);
+ mpz_clear(key.k);
+}
+
+//convert to PKCS#1 v1.5 encryption block
+// note this is considered insecure and OAEP should be used instead
+// OAEP is handled by a separate library in this framework
+static uint8_t* RSA_Pad(uint16_t size, uint8_t* buffer, uint16_t bufferSizeInBytes)
+{
+ size /= 8;
+ if (bufferSizeInBytes - 11 > size)
+ {
+ return NULL;
+ }
+ uint8_t* block = malloc(size);
+ uint16_t i = 0;
+ block[i++] = 0x00;
+ block[i++] = 0x02;
+
+ uint16_t psLen = size - (3 + bufferSizeInBytes);
+ uint8_t* ps = malloc(psLen);
+ FILE* f = fopen(DEVICE, "r");
+ fread(ps, 1, psLen, f);
+
+ for (uint16_t j = 0; j < psLen; j++)
+ {
+ while (ps[j] == 0x00)
+ {
+ ps[j] = fgetc(f);
+ }
+ block[i++] = ps[j];
+ }
+ free(ps);
+
+ block[i++] = 0x00;
+ fclose(f);
+
+ for (uint16_t j = 0; j < bufferSizeInBytes; j++)
+ {
+ block[i++] = buffer[j];
+ }
+ return block;
+}
+
+//Removes the PKCS#1 v1.5 padding scheme
+static uint8_t* RSA_DePad(uint16_t size, uint8_t* block, uint16_t* bufferSizeInBytes)
+{
+ uint16_t i = 2;
+ if (block[0] != 0x00 || (block[1] != 0x01 && block[1] != 0x02))
+ {
+ *bufferSizeInBytes = -1;
+ return NULL;
+ }
+ while (block[i++] != 0)
+ {
+ if (i == size / 8)
+ {
+ *bufferSizeInBytes = -1;
+ return NULL;
+ }
+ }
+ if (i < 11)
+ {
+ *bufferSizeInBytes = -1;
+ return NULL;
+ }
+
+ *bufferSizeInBytes = (size / 8) - i;
+ uint8_t* buffer = malloc(*bufferSizeInBytes);
+ for (uint16_t j = 0; i < (size / 8); i++)
+ {
+ buffer[j++] = block[i];
+ }
+ return buffer;
+}
+
+//convert to PKCS#1 v1.5 signature block
+// note this is NOT considered insecure but PSS is often used instead
+// PSS is handled by a separate library in this framework
+static uint8_t* RSA_PadSig(uint16_t size, uint8_t* buffer, uint16_t bufferSizeInBytes)
+{
+ size /= 8;
+ if (bufferSizeInBytes - 11 > size)
+ {
+ return NULL;
+ }
+ uint8_t* block = malloc(size);
+ uint16_t i = 0;
+ block[i++] = 0x00;
+ block[i++] = 0x01;
+
+ uint16_t psLen = size - (3 + bufferSizeInBytes);
+ for (uint16_t j = 0; j < psLen; j++)
+ {
+ block[i++] = 0xFF;
+ }
+
+ block[i++] = 0x00;
+
+ for (uint16_t j = 0; j < bufferSizeInBytes; j++)
+ {
+ block[i++] = buffer[j];
+ }
+ return block;
+}
+
+static uint8_t* RSA_Apply(rsakey_t key, uint8_t* block)
+{
+ uint8_t* newblock = malloc(key.bitWidth / 8);
+ mpz_t n;
+ mpz_init(n);
+ mpz_set_ui(n, 0);
+
+ rsa_load(n, block, key.bitWidth / 8);
+ mpz_powm(n, n, key.k, key.n);
+ rsa_store(n, newblock, key.bitWidth / 8);
+
+ mpz_clear(n);
+ return newblock;
+}
+
+static uint8_t* RSA_MGF1(uint8_t* (hashfunc)(uint8_t*, uint32_t), uint32_t hashsize, uint8_t* seed, uint32_t seedsize, uint32_t totalsize)
+{
+ uint8_t* premask = malloc(seedsize + sizeof(uint32_t));
+ for (uint32_t i = 0; i < seedsize; i++) premask[i] = seed[i];
+
+ uint8_t* mask = malloc(0);
+ for (uint32_t counter = 0; counter * hashsize < totalsize; counter++)
+ {
+ premask[seedsize + 0] = counter >> 24;
+ premask[seedsize + 1] = counter >> 16;
+ premask[seedsize + 2] = counter >> 8;
+ premask[seedsize + 3] = counter;
+
+ uint8_t* postmask = hashfunc(premask, seedsize + sizeof(uint32_t));
+ mask = realloc(mask, (counter + 1) * hashsize);
+ for (uint32_t i = 0; i < hashsize; i++)
+ {
+ mask[counter * hashsize + i] = postmask[i];
+ }
+ free(postmask);
+ }
+ free(premask);
+ return mask;
+}
+
+/*this uses sha-256*/
+static uint8_t* RSA_PadOAEP(uint16_t size, uint8_t* buffer, uint16_t mLen)
+{
+ uint32_t kLen = size / 8; //length of RSA modulus
+ uint32_t hLen = 32; //length of hash output
+ uint32_t mmLen = kLen - 2 * hLen - 2; //maximum message length
+ uint32_t psLen = kLen - mLen - 2 * hLen - 2; //padding string length
+ uint32_t dbLen = hLen + psLen + 1 + mLen; //datablock length
+ if (mLen > mmLen)
+ {
+ return NULL;
+ }
+
+ //Build Seed
+ uint8_t Seed[hLen];
+ FILE* f = fopen(DEVICE, "r");
+ fread(Seed, 1, hLen, f);
+ fclose(f);
+
+ //Build DB
+ uint8_t* HashL = sha256(NULL, 0);
+ uint8_t DB[dbLen];
+ uint32_t pos = 0;
+ for (uint32_t i = 0; i < hLen; i++) DB[pos++] = HashL[i];
+ free(HashL);
+ for (uint32_t i = 0; i < psLen; i++) DB[pos++] = 0x00;
+ DB[pos++] = 0x01;
+ for (uint32_t i = 0; i < mLen; i++) DB[pos++] = buffer[i];
+
+ //Mask DB
+ uint8_t* DBMask = RSA_MGF1(sha256, hLen, Seed, hLen, dbLen);
+ for (uint32_t i = 0; i < dbLen; i++) DB[i] ^= DBMask[i];
+ free(DBMask);
+
+ //Mask Seed
+ uint8_t* SeedMask = RSA_MGF1(sha256, hLen, DB, dbLen, hLen);
+ for (uint32_t i = 0; i < hLen; i++) Seed[i] ^= SeedMask[i];
+ free(SeedMask);
+
+ //Finalize
+ uint8_t* out = malloc(1 + hLen + dbLen);
+ pos = 0;
+ out[pos++] = 0x00;
+ for (uint32_t i = 0; i < hLen; i++) out[pos++] = Seed[i];
+ for (uint32_t i = 0; i < dbLen; i++) out[pos++] = DB[i];
+ return out;
+}
+
+//Removes the OAEP padding scheme
+static uint8_t* RSA_DeOAEP(uint16_t size, uint8_t* block, uint16_t* bufferSizeInBytes)
+{
+ if (block[0] != 0x00) return NULL;
+ uint32_t kLen = size / 8; //length of RSA modulus
+ uint32_t hLen = 32; //length of hash output
+ uint32_t dbLen = kLen - hLen - 1; //datablock length
+
+ //Grab the masks
+ uint8_t MaskedSeed[hLen];
+ for (uint32_t i = 0; i < hLen; i++) MaskedSeed[i] = block[i + 1];
+ uint8_t MaskedDB[dbLen];
+ for (uint32_t i = 0; i < dbLen; i++) MaskedDB[i] = block[i + 1 + hLen];
+
+ //Recover the original Seed
+ uint8_t* Seed = RSA_MGF1(sha256, hLen, MaskedDB, dbLen, hLen);
+ for (uint32_t i = 0; i < hLen; i++) Seed[i] ^= MaskedSeed[i];
+
+ //Recover the original DB
+ uint8_t* SeedMask = RSA_MGF1(sha256, hLen, Seed, hLen, dbLen);
+ for (uint32_t i = 0; i < dbLen; i++) MaskedDB[i] ^= SeedMask[i];
+ free(Seed);
+ free(SeedMask);
+
+ //Verify the padding
+ uint32_t pos = hLen;
+ while (MaskedDB[pos] == 0)
+ if ((++pos) == dbLen - 1) return NULL;
+ if (MaskedDB[pos] != 0x01) return NULL;
+ pos++;
+
+ //Extract the data
+ uint32_t outlen = dbLen - pos;
+ uint8_t* out = malloc(outlen);
+ for (uint32_t i = 0; i < outlen; i++)
+ {
+ out[i] = MaskedDB[pos++];
+ }
+
+ *bufferSizeInBytes = outlen;
+ return out;
+}
+
+uint8_t* rsa_encrypt(rsakey_t key, uint8_t padding, uint8_t* buffer, uint16_t bufferSize)
+{
+ uint8_t* block;
+ uint8_t* eblock;
+ if (padding == RSA_ENCRYPTION)
+ {
+ block = RSA_Pad(key.bitWidth, buffer, bufferSize);
+ eblock = RSA_Apply(key, block);
+ free(block);
+ }
+ else if (padding == RSA_SIGNATURE)
+ {
+ block = RSA_PadSig(key.bitWidth, buffer, bufferSize);
+ eblock = RSA_Apply(key, block);
+ free(block);
+ }
+ else if (padding == RSA_OAEP)
+ {
+ block = RSA_PadOAEP(key.bitWidth, buffer, bufferSize);
+ eblock = RSA_Apply(key, block);
+ free(block);
+ }
+ else
+ {
+ eblock = RSA_Apply(key, buffer);
+ }
+ return eblock;
+}
+
+uint8_t* rsa_decrypt(rsakey_t key, uint8_t padding, uint8_t* eblock, uint16_t* bufferSize)
+{
+ uint8_t* block;
+ uint8_t* buffer;
+ if (padding == RSA_ENCRYPTION || padding == RSA_SIGNATURE)
+ {
+ block = RSA_Apply(key, eblock);
+ buffer = RSA_DePad(key.bitWidth, block, bufferSize);
+ free(block);
+ }
+ else if (padding == RSA_OAEP)
+ {
+ block = RSA_Apply(key, eblock);
+ buffer = RSA_DeOAEP(key.bitWidth, block, bufferSize);
+ free(block);
+ }
+ else
+ {
+ buffer = RSA_Apply(key, eblock);
+ }
+ return buffer;
+}
+#endif
--- /dev/null
+#ifndef __SHA256__
+#define __SHA256__
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+static uint32_t sha256_rr(uint32_t a, uint32_t b)
+{
+ return (a >> b) | (a << (32 - b));
+}
+
+static uint32_t sha256_init[] =
+{
+ 0x6a09e667,
+ 0xbb67ae85,
+ 0x3c6ef372,
+ 0xa54ff53a,
+ 0x510e527f,
+ 0x9b05688c,
+ 0x1f83d9ab,
+ 0x5be0cd19
+};
+
+static uint32_t sha256_h[] =
+{
+ 0x6a09e667,
+ 0xbb67ae85,
+ 0x3c6ef372,
+ 0xa54ff53a,
+ 0x510e527f,
+ 0x9b05688c,
+ 0x1f83d9ab,
+ 0x5be0cd19
+};
+
+static uint32_t sha256_k[] =
+{
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+static void sha256_process_block(uint32_t *p)
+{
+
+ uint8_t i;
+ uint32_t w[64];
+ for (i = 0; i < 64; i++) w[i] = 0;
+ for (i = 0; i < 16; i++) w[i] = p[i];
+
+ uint32_t A, B, C, D, E, F, G, H;
+ uint32_t s0, s1, t1, t2, ch, maj;
+ for (i = 16; i < 64; i++)
+ {
+ s0 = sha256_rr(w[i - 15], 7) ^ sha256_rr(w[i - 15], 18) ^ (w[i - 15] >> 3);
+ s1 = sha256_rr(w[i - 2], 17) ^ sha256_rr(w[i - 2], 19) ^ (w[i - 2] >> 10);
+ w[i] = w[i - 16] + s0 + w[i - 7] + s1;
+ }
+
+ i = 0;
+
+ A = sha256_h[0];
+ B = sha256_h[1];
+ C = sha256_h[2];
+ D = sha256_h[3];
+ E = sha256_h[4];
+ F = sha256_h[5];
+ G = sha256_h[6];
+ H = sha256_h[7];
+
+ for (i = 0; i < 64; i++)
+ {
+ s1 = sha256_rr(E, 6) ^ sha256_rr(E, 11) ^ sha256_rr(E, 25);
+ ch = (E & F) ^ ((~E) & G);
+ t1 = H + s1 + ch + sha256_k[i] + w[i];
+ s0 = sha256_rr(A, 2) ^ sha256_rr(A, 13) ^ sha256_rr(A, 22);
+ maj = (A & B) ^ (A & C) ^ (B & C);
+ t2 = s0 + maj;
+
+ H = G;
+ G = F;
+ F = E;
+ E = D + t1;
+ D = C;
+ C = B;
+ B = A;
+ A = t1 + t2;
+ }
+
+ sha256_h[0] += A;
+ sha256_h[1] += B;
+ sha256_h[2] += C;
+ sha256_h[3] += D;
+ sha256_h[4] += E;
+ sha256_h[5] += F;
+ sha256_h[6] += G;
+ sha256_h[7] += H;
+
+}
+
+static uint32_t* sha256_pad(uint8_t* msg, uint32_t size, uint32_t* newsize)
+{
+ uint64_t osize = size * 8;
+ uint8_t *msg_padded = malloc(size);
+ for (uint64_t i = 0; i < size; i++)
+ {
+ msg_padded[i] = msg[i];
+ }
+ if (size % 64 != 0 || size == 0)
+ {
+ msg_padded = realloc(msg_padded, size + 1);
+ msg_padded[size] = 0x80;
+ size++;
+
+ while ((size + 8) % 64 != 0)
+ {
+ msg_padded = realloc(msg_padded, size + 1);
+ msg_padded[size] = 0;
+ size++;
+ }
+
+ msg_padded = realloc(msg_padded, size + 8);
+ msg_padded[size + 0] = (osize >> 56) & 0xFF;
+ msg_padded[size + 1] = (osize >> 48) & 0xFF;
+ msg_padded[size + 2] = (osize >> 40) & 0xFF;
+ msg_padded[size + 3] = (osize >> 32) & 0xFF;
+ msg_padded[size + 4] = (osize >> 24) & 0xFF;
+ msg_padded[size + 5] = (osize >> 16) & 0xFF;
+ msg_padded[size + 6] = (osize >> 8) & 0xFF;
+ msg_padded[size + 7] = (osize >> 0) & 0xFF;
+ size += 8;
+ }
+
+ uint32_t* output = malloc((size / 4) * sizeof(uint32_t));
+ for (uint64_t i = 0; i < size / 4; i++)
+ {
+ output[i] = msg_padded[i * 4] << 24;
+ output[i] |= msg_padded[i * 4 + 1] << 16;
+ output[i] |= msg_padded[i * 4 + 2] << 8;
+ output[i] |= msg_padded[i * 4 + 3];
+ }
+ free(msg_padded);
+ *newsize = size / 4;
+ return output;
+}
+
+uint8_t* sha256(uint8_t* msg, uint32_t size)
+{
+ //set initial state
+ for (uint8_t i = 0; i < sizeof(sha256_h) / sizeof(uint32_t); i++)
+ {
+ sha256_h[i] = sha256_init[i];
+ }
+
+ //pad the message
+ uint32_t newsize;
+ uint32_t* padded = sha256_pad(msg, size, &newsize);
+
+ //run the algorithm
+ for (uint32_t i = 0; i < newsize / 16; i++)
+ {
+ sha256_process_block(padded + (i * 16));
+ }
+
+ //done
+ free(padded);
+
+ //breakout
+ uint8_t* out = malloc(sizeof(sha256_h) * sizeof(uint32_t));
+ for (uint32_t i = 0; i < sizeof(sha256_h); i++)
+ {
+ out[i * sizeof(uint32_t) + 0] = sha256_h[i] >> 24;
+ out[i * sizeof(uint32_t) + 1] = sha256_h[i] >> 16;
+ out[i * sizeof(uint32_t) + 2] = sha256_h[i] >> 8;
+ out[i * sizeof(uint32_t) + 3] = sha256_h[i];
+ }
+ return out;
+}
+#endif