Why am I getting different results from different skein hash APIs? - c

I've tried a few. Python's pyskein; a javascript skein calculator I found online somewhere; and the skein calculator being used for xkcd's april fools' comic all give the same output for a given input.
But when I download version 1.3 of the reference C source here I get different results. Worst of all, the results I get from the C API perfectly match the "known answer test" examples that come with the source code, so I assume I'm using it right.
My C code:
#include <stdio.h>
#include <stdlib.h>
#include "SHA3api_ref.h"
int main(int argc, const char * argv[])
{
const int BITS = 256; // length of hash in bits
const int LENGTH = 32; // length of data in bits
BitSequence *hashval = calloc(BITS/8, 1);
const BitSequence content[] = {0xC1, 0xEC, 0xFD, 0xFC};
Hash(BITS, content, LENGTH, hashval);
for (int i = 0; i < BITS/8; i++) {
printf("%02X", hashval[i]);
}
return 0;
}
result hex: 2638B1711F1346D08BF02B5D1A575CD924140A608512AF5B8E4475632599A896
Python code for the same hash on the same data:
import skein
print( skein.skein256(bytes([0xC1, 0xEC, 0xFD, 0xFC])).hexdigest() )
result hex: 07e785ce898fa5cfa22e15294481717935923985ea90f67fc65cb5b3cb718190
Note that the C answer is the expected answer according to the KAT_MCT/ShortMsgKAT_256.txt file that comes with the code. But pyskein gives results that everyone else seems to agree are correct. What am I missing?

Related

OpenSSL EVP AES Encryption and Base64 Encoding producing unusable results

So I'm trying to reproduce an encryption and encoding operation in C, that I've managed to make work in C#, JScript, Python and Java. Now, it's mostly just for obfuscating data - not actual encryption - so it's basically for aesthetic purposes only.
First thing's first, the data string that's being encrypted looks like this:
"[3671,3401,736,1081,0,32558], [3692,3401,748,1105,0,32558], [3704,3401,774,1162,0,32558], [3722,3401,774,1162,0,32558], [3733,3401,769,1172,0,32558]"
Biggest first issue for C is that this can vary in length. Each [x,y,z,a,b,c] represents some data point, and the actual string that will be encrypted can have anywhere from one data point, to 100. So I'm sure my memory management might be broken somewhere as well. Second issue is, I don't seem to be getting the correct expected result after encoding. After encrypting, the byte result of the C cipher is the same as the python cipher. But when I encode to base64 in C, it does not get the expected result at all.
#include <X11/Xlib.h>
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <malloc.h>
#include <time.h>
#include <errno.h>
#include <linux/input.h>
#include <fcntl.h>
#include <string.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
#include <openssl/params.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
void PBKDF2_HMAC_SHA_1(const char* pass, int passlen, const unsigned char* salt, int saltlen, int32_t iterations, uint32_t outputBytes, char* hexResult, uint8_t* binResult)
{
unsigned int i;
unsigned char digest[outputBytes];
PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iterations, EVP_sha1(), outputBytes, digest);
for (i = 0; i < sizeof(digest); i++)
{
sprintf(hexResult + (i * 2), "%02x", 255 & digest[i]);
binResult[i] = digest[i];
}
}
int main(void){
char intext[] = "[3671,3401,736,1081,0,32558], [3692,3401,748,1105,0,32558], [3704,3401,774,1162,0,32558], [3722,3401,774,1162,0,32558], [3733,3401,769,1172,0,32558]";
int outlen, final_length;
EVP_CIPHER_CTX *ctx;
ctx = EVP_CIPHER_CTX_new();
size_t i;
char sid[] = "u9SXNMeTkvyBr3n81SJ7Lj216w04gJ99";
char pk[] = "jeIHjod1cZeM1U04cy8z7488AeY1Sl25";
uint32_t outputBytes = 48;
uint32_t iterations = 128;
unsigned char byteresult[2*outputBytes+1];
char hexresult[2*outputBytes+1];
memset(byteresult,0,sizeof(byteresult));
uint8_t binResult[outputBytes+1];
memset(binResult,0,sizeof(binResult));
char *finResult = NULL;
char key[65];
memset(key,0,sizeof(key));
char * keystart = hexresult +32;
char iv[33];
memset(iv,0,sizeof(iv));
PBKDF2_HMAC_SHA_1(sid,strlen(sid),pk,strlen(pk),iterations,outputBytes,hexresult,binResult);
memcpy(key, keystart,64);
memcpy(iv, hexresult,32);
EVP_CipherInit_ex(ctx, EVP_aes_256_cbc(), NULL,(unsigned char *)key, (unsigned char *)iv, 1);
unsigned char *outbuf;
int outbuflen = sizeof(intext) + EVP_MAX_BLOCK_LENGTH - (sizeof(intext) % 16);
outbuf = (unsigned char *)malloc(outbuflen);
EVP_CipherUpdate(ctx, outbuf, &outbuflen,(unsigned char *)intext, strlen(intext));
EVP_CipherFinal_ex(ctx, outbuf + outbuflen, &final_length);
outlen += final_length;
EVP_CIPHER_CTX_free(ctx);
char bytesout[strlen(outbuf) + outbuflen];
int buflen = 0;
for (i=0;i< outbuflen + final_length;i++)
{
buflen += 1;
sprintf(bytesout + (i * 2),"%02x", outbuf[i]);
}
printf("bytesout: %s\n", bytesout);
char outtext[sizeof(bytesout)];
memset(outtext,0, sizeof(outtext));
int outtext_len = sizeof(outtext);
EVP_ENCODE_CTX *ectx = EVP_ENCODE_CTX_new();
EVP_EncodeInit(ectx);
EVP_EncodeBlock(outtext, bytesout, sizeof(bytesout));
EVP_EncodeFinal(ectx, (unsigned char*)outtext, &outtext_len);
EVP_ENCODE_CTX_free(ectx);
printf("b64Encoded String %s \n", outtext);}
Makefile:
gcc simplecipher.c -o simplecipher -lX11 -lncurses -lssl -lcrypto
Result:
bytesout: eafafcde5c00eb6e649d61a09f9b52d13dd8c783d73afcbc03dfb5cea0cd3ab627528ec1b2997105871d570c0b972349943800aacd063093d97f7f39554775aa4256bd26599dde66bb76b925d9f021f6b657d1a91eb08e1900b6ad91f7f65b97e1a7e17b8d959a65d6893af458e26761536b3ffdf470f89f1aac24ca02782fb8a691c25b368549387890dc73143bb213e0ce616264e5b30add3b480c24f5edc6
b64Encoded String ZWFmYWZjZGU1YzAwZWI2ZTY0OWQ2MWEwOWY5YjUyZDEzZGQ4Yzc4M2Q3M2FmY2JjMDNkZmI1Y2VhMGNkM2FiNjI3NTI4ZWMxYjI5OTcxMDU4NzFkNTcwYzBiOTcyMzQ5OTQzODAwYWFjZDA2MzA5M2Q5N2Y3ZjM5NTU0Nzc1YWE0MjU2YmQyNjU5OWRkZTY2YmI3NmI=
When I do a similar script in python:
import base64
from Cryptodome.Cipher import AES
from Cryptodome.Random import get_random_bytes
from Cryptodome.Protocol.KDF import PBKDF2
from Crypto.Util.Padding import pad
import binascii
symmetric_key = "u9SXNMeTkvyBr3n81SJ7Lj216w04gJ99"
salt = "jeIHjod1cZeM1U04cy8z7488AeY1Sl25"
pbbytes = PBKDF2(symmetric_key.encode("utf-8"), salt.encode("utf-8"), 48, 128)
iv = pbbytes[0:16]
key = pbbytes[16:48]
half_iv=iv[0:8]
half_key=key[0:16]
cipher = AES.new(key, AES.MODE_CBC, iv)
cipher = AES.new(binascii.hexlify(bytes(half_key)), AES.MODE_CBC, binascii.hexlify(bytes(half_iv)))
print("test encoding:")
intext = b"[3671,3401,736,1081,0,32558], [3692,3401,748,1105,0,32558], [3704,3401,774,1162,0,32558], [3722,3401,774,1162,0,32558], [3733,3401,769,1172,0,32558]"
print("intext pre padding: ", intext)
paddedtext = pad(intext,16)
print("intext post padding: ", paddedtext)
en_bytes = cipher.encrypt(paddedtext)
print("encrypted bytes: ", binascii.hexlify(bytearray(en_bytes)))
en_data = base64.b64encode(en_bytes)
en_bytes_string = ''.join(map(chr, en_bytes))
print("encoded bytes: ", en_data)
Result:
encrypted bytes: b'eafafcde5c00eb6e649d61a09f9b52d13dd8c783d73afcbc03dfb5cea0cd3ab627528ec1b2997105871d570c0b972349943800aacd063093d97f7f39554775aa4256bd26599dde66bb76b925d9f021f6b657d1a91eb08e1900b6ad91f7f65b97e1a7e17b8d959a65d6893af458e26761536b3ffdf470f89f1aac24ca02782fb8a691c25b368549387890dc73143bb213e0ce616264e5b30add3b480c24f5edc6'
encoded bytes: b'6vr83lwA625knWGgn5tS0T3Yx4PXOvy8A9+1zqDNOrYnUo7BsplxBYcdVwwLlyNJlDgAqs0GMJPZf385VUd1qkJWvSZZnd5mu3a5JdnwIfa2V9GpHrCOGQC2rZH39luX4afhe42VmmXWiTr0WOJnYVNrP/30cPifGqwkygJ4L7imkcJbNoVJOHiQ3HMUO7IT4M5hYmTlswrdO0gMJPXtxg=='
So as you can see, the encoded portion comes out completely differently in the C application. In Jscript, C#, and Java it comes out exactly as in the python script. The encrypted portion, however, is the same between the two. Just encoding seems to break it. Now this could be 100% because I've absolutely butchered something when passing the bytes/char arrays around. I just can't seem to find out where in the chain I've broken down here. Any suggestions?
The C code base64s the wrong buffer. namely bytesout, which is already an ASCII text:
for (i=0;i< outbuflen + final_length;i++)
{
buflen += 1;
sprintf(bytesout + (i * 2),"%02x", outbuf[i]);
}
You need to encode outbuf instead.
PS: the code cries for a serious cleanup.
Alright,
Just wanted to say thanks to everyone who commented, and answered but I did figure it out this morning, basically using
EVP_EncodeBlock(outtext, outbuf, buflen);
Is what solved it. Before I'd pass in either sizeof(outtext) or sizeof(outbuf) and that would only encode what looked like a part of the first data point (likely up to the first ',' or something). But this fixes it. I can now encrypt a string of datapoints regardless of their starting size, and decrypt it in python. I had buflen in there just to debug the amount of bytes that were being written to the bytesout char array, but it seemed to do the trick.
Cheers, everyone!
I was trying to do the same thing, and just finished doing so. I believe your question is misleading. You are not actually encoding a digest in base64. Rather, you are encoding the hexadecimal representation of a digest in base64 (as user58697 already stated in his own response). Also, as specified in Ian Abbott's comment, you're using EVP_ENCODE_CTX wrong.
I believe most people would actually want to encode the digest itself in base64. If you're trying to implement stuff like xmlenc (and I assume most specifications that use these base64 encoded digests), it can be done in the following fashion, using libcrypto~3.0:
void base64_digest(const char* input, int input_length)
{
// Generating a digest
EVP_MD_CTX* context = EVP_MD_CTX_new();
const EVP_MD* md = EVP_sha512();
unsigned char md_value[EVP_MAX_MD_SIZE];
unsigned int md_len;
EVP_DigestInit_ex2(context, md, NULL);
EVP_DigestUpdate(context, input, input_length);
EVP_DigestFinal_ex(context, md_value, &md_len);
// Encoding digest to base64
char output[EVP_MAX_MD_SIZE]; // not sure this is the best size for this buffer,
// but it's not gonna need more than EVP_MAX_MD_SIZE
EVP_EncodeBlock((unsigned char*)output, md_value, md_len);
// cleanup
EVP_MD_CTX_free(context);
printf("Base64-encoded digest: %s\n", output);
}
Incidentally, the result will be much shorter (with padding, 88 characters is the expected length, while I believe you'll get 172 characters by encoding the hex digest instead).
You also don't need to use EVP_ENCODE_CTX, EVP_EncodeInit nor EVP_EncodeFinal, as EVP_EncodeBlock doesn't need any of these.
For C++ developers, I also have an implementation at https://github.com/crails-framework/libcrails-encrypt (check out the MessageDigest class).

Integer data compression for transfer in C without external libraries

I googled ans searched here a bunch without a fitting solution. The title is maybe a bit weird or not fully accurate, but let me explain:
My IoT device collects a bunch of data every second that I can represent as a list of integer. Here is an example of one row of sensor reads (the zeros are not always 0 btw):
230982 0 4294753011 -9 4294198951 -1 4294225518 0 0 0 524789 0 934585 0 4 0 0 0 0
On trigger I want to send the whole table (all rows until then) to my computer. I could just stringify it and concatenate everything, but wonder if there is a more efficient encoding/compression to reduce the byte count, both when storing in RAM/flash and for reduced transfer volume. Ideally this could be achieved with integrated functions, ie no external compression libraries. I am not that strong with encoding/compression, hope you can give me a hint.
Zlib/Zstd libraries are better suited for doing general purpose compression. If I may assume that you don't want to use any third party libraries, here is a hand coded version of some naive compression method, which saves half of the bytes of the input string.
The basic idea is very simple. Your strings will at most have 16 different characters which can be mapped to 4-bits rather than typical 8-bits. SEE THE ASSUMPTIONS BELOW. You can try base16, base64, base128 encodings too, but this is the simplest.
Assumptions:
First you'll convert all your numbers into a string in decimal format.
The string won't contain any other characters than 0,1,2,3,4,5,6,7,8,9,+,-,.,space, and a comma.
============================================================================
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static inline char map(char c)
{
switch(c) {
case ' ' : return ('/' - '*');
case '\0': return 0;
default : return c - '*';
}
return 0;
}
static inline char revmap(char c)
{
switch(c) {
case '\0' : return 0;
case '/' - '*': return ' ';
default : return c + '*';
}
return 0;
}
char *compress(const char *s, int len)
{
int i, j;
char *compr = malloc((len+1)/2 + 1);
j = 0;
for (i = 1; i < len; i += 2)
compr[j++] = map(s[i-1]) << 4 | map(s[i]);
if (i-1 < len)
compr[j++] = map(s[i-1]) << 4;
compr[j] = '\0';
return compr;
}
char *decompress(const char *s, int len)
{
int i, j;
char *decompr = malloc(2*len + 1);
for (i = j = 0; i < len; i++) {
decompr[j++] = revmap((s[i] & 0xf0) >> 4);
decompr[j++] = revmap(s[i] & 0xf);
}
decompr[j] = '\0';
return decompr;
}
int main()
{
const char *input = "230982 0 4294753011 -9 4294198951 -1 4294225518 0 0 0 524789 0 934585 0 4 0 0 0 0 ";
int plen = strlen(input);
printf("plain(len=%d): %s\n", plen, input);
char *compr = compress(input, plen);
int clen = strlen(compr);
char *decompr = decompress(compr, clen);
int dlen = strlen(decompr);
printf("decompressed(len=%d): %s\n", dlen, decompr);
free(compr);
free(decompr);
}
Simplest solution is to simply dump data out in binary form. It may be smaller or bigger than string form depending on your data, but you don't have to do any data processing on device.
If most of your data is small, you can use variable length data encoding for serialization. There are several, but CBOR is fairly simple.
If your data changes only very little, you could send only first row as absolute values, and remaining rows as delta of previous row. This would result in many small numbers, which typically are more efficient in previously mentioned encoding systems.
I wouldn't try to implement any general purpose compression algorithms without any experience and external libraries, unless you absolutely need it. Finding suitable algorithm that compresses your data well enough and with reasonable resource usage can be time consuming.

How to strip "\x" from MAC address (in char*) by a reusable function?

I thought that I can do that easily as I was doing similar with
uint8_t array[6] = {0x00, 0x0d, 0x3f, 0xcd, 0x02, 0x5f}
But, it turns out to be, I am not there yet.
Input structure;
char *MAC_ADDR = "\x00\x22\xC7\xFF\xFF\x27";
I want it to be converted into;
char *MAC_ADDR_NEW = "0022C7FFFF27";
Your inputs are highly appreciated.
I'm not quite sure what reusable function means. That said,
you could do the allocation and conversion with the (non-standard) asprintf function, as follows:
#include <stdio.h>
#include <stdint.h>
int main(void){
char *MAC_ADDR = "\x00\x22\xC7\xFF\xFF\x27";
char *MAC_ADDR_NEW;
asprintf (&MAC_ADDR_NEW, "%02x%02x%02x%02x%02x%02x",
(uint8_t)MAC_ADDR[0], (uint8_t)MAC_ADDR[1], (uint8_t)MAC_ADDR[2],
(uint8_t)MAC_ADDR[3], (uint8_t)MAC_ADDR[4], (uint8_t)MAC_ADDR[5]);
printf("%s\n", MAC_ADDR_NEW);
free(MAC_ADDR_NEW); /* Good software hygiene is to free what you allocate. */
/* You could reuse the same code again here for another conversion. */
return 0;
}
The casts to uint8_t avoid sign extension for 0xFF values to FFFFFFFF, etc. Error checking left as an exercise.
$ cc x.c && ./a.out
0022c7ffff27
For completeness based on valuable inputs from #Jonathan Leffler and #Jens, I drop my proven answer.
Here is the function I've tested and started to use;
#include <stdio.h>
const unsigned char * MAC_HEX_TO_STR(char *MAC_ADDR);
const unsigned char * MAC_HEX_TO_STR(char *MAC_ADDR){
// If static is not used, due to local variable is destroyed out of the function will return gibberish!
static char memory[13];
static char *MAC_ADDR_NEW = memory;
snprintf(memory, sizeof(memory), "%.2X%.2X%.2X%.2X%.2X%.2X", (unsigned char)MAC_ADDR[0], (unsigned char)MAC_ADDR[1], (unsigned char)MAC_ADDR[2], (unsigned char)MAC_ADDR[3], (unsigned char)MAC_ADDR[4], (unsigned char)MAC_ADDR[5]);
//printf(" 1 ==>> %s\n ", MAC_ADDR_NEW); // Debug if you like
//MAC_ADDR_NEW[13] = 0; // I don't know, I tried with or without but no difference observed!
return MAC_ADDR_NEW;
}
int main()
{
char *MAC_ADDR = "\x00\x22\xC7\xFF\xFF\x27";
const unsigned char* RETURNED_MAC = MAC_HEX_TO_STR(MAC_ADDR);
printf(" RETURNED_MAC ==>> %s\n ", RETURNED_MAC );
return 0;
}
You may reach the test from here.

SHA1 checksumming a length-prefixed message in a streaming fashion

Git-SHAs are computed by prefixing "blob $DecimalMessageLength\0" to a message and then SHA1-checksumming the prefixed message.
From the properties of the SHA1 algorithm, is it possible to do this in a streaming fashion, i.e., prepend the prefix after the message body has been hashed?
C example below (link with -lcrypto with libssl-dev installed; it's probably not very useful since this one doesn't even expose the SHA1 algorithm but I was playing...):
#include <openssl/sha.h>
#include <stdio.h>
#include <stdlib.h>
int pr_dgst(unsigned char const Dgst[static SHA_DIGEST_LENGTH])
{
char const digits[]="0123456789abcdef";
char digest_pr[(SHA_DIGEST_LENGTH)*2+1];
for(size_t i=0;i<SHA_DIGEST_LENGTH;i++){
digest_pr[i*2+0]=digits[Dgst[i]/16];
digest_pr[i*2+1]=digits[Dgst[i]%16];
}
digest_pr[(SHA_DIGEST_LENGTH)*2]='\0';
return puts(digest_pr);
}
int main()
{
system("echo gitsha; printf '%s' 'abc' | git hash-object --stdin");
#define STR_STRLEN(A) A, (sizeof(A)/sizeof(*(A))-1) //paste string literal and its length
unsigned char digest[SHA_DIGEST_LENGTH];
SHA_CTX ctx;
SHA1_Init(&ctx); SHA1_Update(&ctx,STR_STRLEN("blob 3\0abc")); SHA1_Final(digest,&ctx);
pr_dgst(digest); //prints the same as the system command
//do this in a streaming fashion??
SHA1_Init(&ctx);
size_t len = 0;
SHA1_Update(&ctx,STR_STRLEN("a")); len++;
SHA1_Update(&ctx,STR_STRLEN("b")); len++;
SHA1_Update(&ctx,STR_STRLEN("c")); len++;
//"prepend" "blob 3\0" now?
SHA1_Final(digest,&ctx);
/*pr_dgst(digest);*/
}
It is only possible to add bytes to the end of the message stream - otherwise the hash function would be cryptographically broken.
One of the upsides of having a prefix for 2 files is that you can store 2 files with a known bare SHA-1 collision into the same repository and they would get different blob IDs!

Generating random values without time.h

I want to generate random numbers repeatedly without using the time.h library. I saw another post regarding use the
srand(getpid());
however that doesn't seem to work for me getpid hasn't been declared. Is this because I'm missing the library for it? If it is I need to work out how to randomly generate numbers without using any other libraries than the ones I currently have.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int minute, hour, day, month, year;
srand(getpid());
minute = rand() % (59 + 1 - 0) + 0;
hour = rand() % (23 + 1 - 0) + 0;
day = rand() % (31 + 1 - 1) + 1;
month = rand() % (12 + 1 - 1) + 1;
year = 2018;
printf("Transferred successfully at %02d:%02d on %02d/%02d/%d\n", hour,
minute, day, month, year);
return 0;
}
NB: I can only use libraries <stdio.h> and <stdlib.h> and <string.h> — strict guidelines for an assignment.
getpid hasn't been declared.
No, because you haven't included the <unistd.h> header where it is declared (and according to your comment, you cannot use it, because you're restricted to using <stdlib.h>, <string.h>, and <stdio.h>).
In that case, I would use something like
#include <stdlib.h>
#include <stdio.h>
static int randomize_helper(FILE *in)
{
unsigned int seed;
if (!in)
return -1;
if (fread(&seed, sizeof seed, 1, in) == 1) {
fclose(in);
srand(seed);
return 0;
}
fclose(in);
return -1;
}
static int randomize(void)
{
if (!randomize_helper(fopen("/dev/urandom", "r")))
return 0;
if (!randomize_helper(fopen("/dev/arandom", "r")))
return 0;
if (!randomize_helper(fopen("/dev/random", "r")))
return 0;
/* Other randomness sources (binary format)? */
/* No randomness sources found. */
return -1;
}
and a simple main() to output some pseudorandom numbers:
int main(void)
{
int i;
if (randomize())
fprintf(stderr, "Warning: Could not find any sources for randomness.\n");
for (i = 0; i < 10; i++)
printf("%d\n", rand());
return EXIT_SUCCESS;
}
The /dev/urandom and /dev/random character devices are available in Linux, FreeBSD, macOS, iOS, Solaris, NetBSD, Tru64 Unix 5.1B, AIX 5.2, HP-UX 11i v2, and /dev/random and /dev/arandom on OpenBSD 5.1 and later.
As usual, it looks like Windows does not provide any such randomness sources: Windows C programs must use proprietary Microsoft interfaces instead.
The randomize_helper() returns nonzero if the input stream is NULL, or if it cannot read an unsigned int from it. If it can read an unsigned int from it, it is used to seed the standard pseudorandom number generator you can access using rand() (which returns an int between 0 and RAND_MAX, inclusive). In all cases, randomize_helper() closes non-NULL streams.
You can add other binary randomness sources to randomize() trivially.
If randomize() returns 0, rand() should return pseudorandom numbers. Otherwise, rand() will return the same default sequence of pseudorandom numbers. (They will still be "random", but the same sequence will occur every time you run the program. If randomize() returns 0, the sequence will be different every time you run the program.)
Most standard C rand() implementations are linear congruental pseudorandom number generators, often with poor choices of parameters, and as a result, are slowish, and not very "random".
For non-cryptographic work, I like to implement one of the Xorshift family of functions, originally by George Marsaglia. They are very, very fast, and reasonably random; they pass most of the statistical randomness tests like the diehard tests.
In OP's case, the xorwow generator could be used. According to current C standards, unsigned int is at least 32 bits, so we can use that as the generator type. Let's see what implementing one to replace the standard srand()/rand() would look like:
#include <stdlib.h>
#include <stdio.h>
/* The Xorwow PRNG state. This must not be initialized to all zeros. */
static unsigned int prng_state[5] = { 1, 2, 3, 4, 5 };
/* The Xorwow is a 32-bit linear-feedback shift generator. */
#define PRNG_MAX 4294967295u
unsigned int prng(void)
{
unsigned int s, t;
t = prng_state[3] & PRNG_MAX;
t ^= t >> 2;
t ^= t << 1;
prng_state[3] = prng_state[2];
prng_state[2] = prng_state[1];
prng_state[1] = prng_state[0];
s = prng_state[0] & PRNG_MAX;
t ^= s;
t ^= (s << 4) & PRNG_MAX;
prng_state[0] = t;
prng_state[4] = (prng_state[4] + 362437) & PRNG_MAX;
return (t + prng_state[4]) & PRNG_MAX;
}
static int prng_randomize_from(FILE *in)
{
size_t have = 0, n;
unsigned int seed[5] = { 0, 0, 0, 0, 0 };
if (!in)
return -1;
while (have < 5) {
n = fread(seed + have, sizeof seed[0], 5 - have, in);
if (n > 0 && ((seed[0] | seed[1] | seed[2] | seed[3] | seed[4]) & PRNG_MAX) != 0) {
have += n;
} else {
fclose(in);
return -1;
}
}
fclose(in);
prng_seed[0] = seed[0] & PRNG_MAX;
prng_seed[1] = seed[1] & PRNG_MAX;
prng_seed[2] = seed[2] & PRNG_MAX;
prng_seed[3] = seed[3] & PRNG_MAX;
prng_seed[4] = seed[4] & PRNG_MAX;
/* Note: We might wish to "churn" the pseudorandom
number generator state, to call prng()
a few hundred or thousand times. For example:
for (n = 0; n < 1000; n++) prng();
This way, even if the seed has clear structure,
for example only some low bits set, we start
with a PRNG state with set and clear bits well
distributed.
*/
return 0;
}
int prng_randomize(void)
{
if (!prng_randomize_from(fopen("/dev/urandom", "r")))
return 0;
if (!prng_randomize_from(fopen("/dev/arandom", "r")))
return 0;
if (!prng_randomize_from(fopen("/dev/random", "r")))
return 0;
/* Other sources? */
/* No randomness sources found. */
return -1;
}
The corresponding main() to above would be
int main(void)
{
int i;
if (prng_randomize())
fprintf(stderr, "Warning: No randomness sources found!\n");
for (i = 0; i < 10; i++)
printf("%u\n", prng());
return EXIT_SUCCESS;
}
Note that PRNG_MAX has a dual purpose. On one hand, it tells the maximum value prng() can return -- which is an unsigned int, not int like rand(). On the other hand, because it must be 232-1 = 4294967295, we also use it to ensure the temporary results when generating the next pseudorandom number in the sequence remain 32-bit. If the uint32_t type, declared in stdint.h or inttypes.h were available, we could use that and drop the masks (& PRNG_MAX).
Note that the prng_randomize_from() function is written so that it still works, even if the randomness source cannot provide all requested bytes at once, and returns a "short count". Whether this occurs in practice is up to debate, but I prefer to be certain. Also note that it does not accept the state if it is all zeros, as that is the one single prohibited initial seed state for the Xorwow PRNG.
You can obviously use both srand()/rand() and prng()/prng_randomize() in the same program. I wrote them so that the Xorwow generator functions all start with prng.
Usually, I do put the PRNG implementation into a header file, so that I can easily test it (to verify it works) by writing a tiny test program; but also so that I can switch the PRNG implementation simply by switching to another header file. (In some cases, I put the PRNG state into a structure, and have the caller provide a pointer to the state, so that any number of PRNGs can be used concurrently, independently of each other.)
however that doesn't seem to work for me getpid hasn't been declared.
That's because you need to include the headers for getpid():
#include <sys/types.h>
#include <unistd.h>
Another option is to use time() to seed (instead of getpid()):
srand((unsigned int)time(NULL));
As other answer pointed, you need to include the unistd.h header. If you don't want to do that then put the declaration of getpid() above main(). Read the manual page of getpid() here http://man7.org/linux/man-pages/man2/getpid.2.html
One approach may be
#include <stdio.h>
#include <stdlib.h>
pid_t getpid(void); /* put the declrataion of getpid(), if don't want to include the header */
int main(void) {
/* .. some code .. */
return 0;
}
Or you can use time() like
srand((unsigned int)time(NULL));

Resources