Writing a CSPRNG in C: Entropy over External Tools
System.init()
With just a few lines of C, we can generate high-entropy, international-standard passwords. Yet, most users still prefer relying on external websites—essentially outsourcing their security to third-party nodes.
Why trust an external server's PRNG when you can compile your own generator and read directly from /dev/urandom?
Example Output
MTικ+Yilл月黄-ЙdΛ宇&洪日tπυ+玄-и0Щ来^]pe}χмsδι盈сidM)8@зΧ&В=isrΡΛπSJiΑΝg ρηh5%%O-Φ!-τΧ5Ы2μю昃地Ь盈*宿ΡδΨМiυzσf8Ι
Source_Code
This implementation uses setlocale for wide-character support and pulls raw bytes from the kernel's entropy pool.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <wchar.h>
#include <locale.h>
const wchar_t latin[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
const wchar_t cyrillic[] = L"бвгдёжзийклмнпрстуфхцчшщъыьэюяБВГДЕЁЖЗИЙКЛМНПРСТУФХЦЧШЩЪЫЬЭЮЯ";
const wchar_t greek[] = L"αβγδεζηθικλμνξοπρστυφχψωΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ";
const wchar_t chinese[] = L" dignified天地玄黄宇宙洪荒日月盈昃辰宿列张寒来暑往秋收冬藏";
const wchar_t symbols[] = L"!@#$%^&*()_+-=[]{}|";
const wchar_t* alphabets[] = {latin, cyrillic, greek, chinese, symbols};
const int counts[] = {62, 66, 48, 30, 19};
int main(int argc, char *argv[]) {
setlocale(LC_ALL, "");
if (argc < 2) {
printf("Usage: %s <length>\n", argv[0]);
return 1;
}
int length = atoi(argv[1]);
int fd = open("/dev/urandom", O_RDONLY);
if (fd == -1) {
perror("Error opening /dev/urandom");
return 1;
}
wprintf(L"Your international password: ");
for (int i = 0; i < length; i++) {
unsigned char r_base[2];
read(fd, r_base, 2);
int alpha_idx = r_base[0] % 5;
int char_idx = r_base[1] % counts[alpha_idx];
wprintf(L"%lc", alphabets[alpha_idx][char_idx]);
}
wprintf(L"\n");
close(fd);
return 0;
}
Compilation_Log
To build this on a Unix-like system (GNU/Linux, Guix, BSD):
gcc passgen.c -o passgen ./passgen 64
—