2015-08-11 11:23:30 +01:00
|
|
|
/*
|
|
|
|
prg.c version 20150811
|
|
|
|
Andreas Hülsing
|
|
|
|
Public domain.
|
|
|
|
*/
|
2015-08-11 11:08:27 +01:00
|
|
|
#include "chacha.h"
|
|
|
|
#include "prg.h"
|
2015-08-12 16:59:29 +01:00
|
|
|
#include <stdio.h>
|
2015-10-28 14:49:46 +00:00
|
|
|
#include <openssl/sha.h>
|
|
|
|
#include <openssl/hmac.h>
|
|
|
|
#include <openssl/evp.h>
|
2015-08-11 11:08:27 +01:00
|
|
|
|
|
|
|
const unsigned char zero_nonce[12] = {0};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generates rlen output bytes using ChaCha20 with a zero nonce and counter = 0
|
|
|
|
*/
|
2015-08-12 14:30:01 +01:00
|
|
|
void prg(unsigned char *r, unsigned long long rlen, const unsigned char *key, unsigned int key_len)
|
2015-08-11 11:08:27 +01:00
|
|
|
{
|
2015-10-28 14:49:46 +00:00
|
|
|
if(key_len == 32){
|
|
|
|
CRYPTO_chacha_20_keystream(r, rlen, key, zero_nonce, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(key_len == 64)
|
|
|
|
{
|
|
|
|
unsigned long long left = rlen;
|
|
|
|
u_int32_t counter = 0;
|
|
|
|
unsigned char *c = (unsigned char*)&counter;
|
|
|
|
unsigned int length;
|
|
|
|
unsigned int i = 0;
|
|
|
|
unsigned char tmp[64];
|
|
|
|
while(left > 0)
|
|
|
|
{
|
|
|
|
HMAC(EVP_sha512(), key, key_len, c , 4, tmp, &length);
|
|
|
|
if(length != 64)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "HMAC outputs %d bytes... That should not happen...",length);
|
|
|
|
}
|
|
|
|
for(i = 0; ((i < length) && (i < left));i++)
|
|
|
|
{
|
|
|
|
r[rlen-left+i] = tmp[i];
|
|
|
|
}
|
|
|
|
left -=length;
|
|
|
|
counter++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fprintf(stderr,"prg.c:: Code only supports 32 byte and 64 byte seeds");
|
|
|
|
}
|
|
|
|
}
|
2015-08-11 11:08:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-10-28 14:49:46 +00:00
|
|
|
* Generates n output bytes using ChaCha20 (n=32) or HMAC-SHA2-512 (n=64).
|
|
|
|
*
|
|
|
|
* For ChaCha, nonce and counter are set depending on the address addr. For HMAC, addr is used as message.
|
2015-08-11 11:08:27 +01:00
|
|
|
*/
|
2015-10-28 14:49:46 +00:00
|
|
|
void prg_with_counter(unsigned char *r, const unsigned char *key, unsigned int n, const unsigned char addr[16])
|
2015-08-11 11:08:27 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
unsigned char nonce[12];
|
2015-10-28 14:49:46 +00:00
|
|
|
if(n == 32){
|
2015-08-12 16:59:29 +01:00
|
|
|
for(i = 0; i < 12; i++)
|
|
|
|
{
|
|
|
|
nonce[i] = addr[i];
|
|
|
|
}
|
|
|
|
uint32_t counter;
|
|
|
|
counter = (((uint32_t)addr[12]) << 24)|(((uint32_t)addr[13]) << 16)|(((uint32_t)addr[14]) << 8)|addr[15];
|
|
|
|
// TODO: Check address handling. Endianess?
|
2015-10-28 14:49:46 +00:00
|
|
|
CRYPTO_chacha_20_keystream(r, n, key, nonce, counter);
|
2015-08-12 16:59:29 +01:00
|
|
|
}
|
|
|
|
else
|
2015-08-11 11:08:27 +01:00
|
|
|
{
|
2015-10-28 14:49:46 +00:00
|
|
|
if(n == 64)
|
2015-08-12 16:59:29 +01:00
|
|
|
{
|
2015-10-28 14:49:46 +00:00
|
|
|
// for(i = 0; i < 12; i++)
|
|
|
|
// {
|
|
|
|
// nonce[i] = addr[i];
|
|
|
|
// }
|
|
|
|
// uint32_t counter;
|
|
|
|
// counter = (((uint32_t)addr[12]) << 24)|(((uint32_t)addr[13]) << 16)|(((uint32_t)addr[14]) << 8)|addr[15];
|
|
|
|
// // TODO: WRONG! Uses only 32 byte of key. However, does not compile with HMAC-SHA512
|
|
|
|
// CRYPTO_chacha_20_keystream(r, rlen, key, nonce, counter);
|
|
|
|
unsigned int length;
|
|
|
|
HMAC(EVP_sha512(), key, n, addr, 16, r, &length);
|
|
|
|
if(length != 64)
|
2015-08-12 16:59:29 +01:00
|
|
|
{
|
2015-10-28 14:49:46 +00:00
|
|
|
fprintf(stderr, "HMAC outputs %d bytes... That should not happen...",length);
|
2015-08-12 16:59:29 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fprintf(stderr,"prg.c:: Code only supports 32 byte and 64 byte seeds");
|
|
|
|
}
|
2015-08-11 11:08:27 +01:00
|
|
|
}
|
|
|
|
}
|