Seuraavassa rutiinit rdrand ja rdseed toiminnolla haettavan satunnaisuuden käyttämiseen. Ensimmäiset rutiinit ovat molemmilla yhteisiä: rdrand:ia ja rdseed:iä ei ole otettu oletuksena käyttöön. Cpuid():llä haetaan prosessorin valmistajaa (vendor) ja tietoa siitä onko käytössä olevassa prosessorissa toteutettuna jompikumpi satunnaisbittigeneraattori. Myös is_cpu_vendor():ia käytetään prosessorin toimittajan nimeämiseen.
#define aFORT_USE_RDRAND 2
#define aFORT_USE_RDSEED 2
#if defined FORT_USE_RDRAND || \
defined FORT_USE_RDSEED
// see: https://software.intel.com/content/www/us/en/develop/articles/intel-digital-random-number-generator-drng-software-implementation-guide.html
void _cpuid(unsigned int leaf, unsigned int subleaf,
unsigned int *a, unsigned int *b, unsigned int *c, unsigned int *d)
{
asm volatile("cpuid"
: "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
: "a" (leaf), "c" (subleaf) );
}
int _is_cpu_vendor(unsigned char *cpuvendor)
{
int ok=0;
unsigned int a, b, c, d;
_cpuid(0, 0, &a, &b, &c, &d);
if(memcmp((char *)(&b), cpuvendor,4)==0 &&
memcmp((char *)(&d), cpuvendor+4,4)==0 &&
memcmp((char *)(&c), cpuvendor+8,4)==0)
ok=1;
return(ok);
}
#endif
Seuraavassa kuvassa rdrand-toiminnon käyttämiseen tarvittavat rutiinit: has_rdrand tarkistaa onko käytettävässä prosessorissa rdrand-toiminto. rdrand_long() palauttaa long pituisen satunnaisbittijonon. rdrand_bytes() käyttää edellisiä ja palauttaa varsinaisen bittijonon.
#ifdef FORT_USE_RDRAND
int _has_rdrand()
{
int ok=0;
unsigned int a, b, c, d;
_cpuid(1, 0, &a, &b, &c, &d);
if((c & 0x40000000) == 0x40000000) {
ok=1;
}
return(ok);
}
int _rdrand_long(unsigned long *therand)
{
unsigned char ret;
asm volatile("rdrand %0; setc %1"
: "=r" (*therand), "=qm" (ret) );
return(int) ret;
}
int rdrand_bytes(int buflen, unsigned char *buf)
{
int n, ret = 0;
unsigned long l;
if(_is_cpu_vendor("GenuineIntel") && _has_rdrand()) {
fprintf(stdout,"Intel rdrand");
ret=1;
} else if(_is_cpu_vendor("AuthenticAMD") && _has_rdrand()) {
fprintf(stdout,"AMD rdrand");
ret=1;
}
if(ret) {
while(buflen > 0) {
if((ret = _rdrand_long(&l)) == 0) // 1 ok, 0 fail
break;
fprintf(stdout," %016lx",l);
n = (buflen < sizeof(l) ? buflen : sizeof(l));
memcpy(buf, (unsigned char *)&l, n);
buf+=n;
buflen-=n;
}
}
return(ret);
}
#endif
Seuraavana vuorossa rdseed toiminnon käyttämiseen tarvittavat toiminnot: tässä on samaan tapaan rdrand:in kanssa kolme toimintoa. has_rdseed() tarkistaa onko käytetyssä prosessorissa ko toimintoa. rdseed_long() muodostaa yhden long:in pituisen satunnaisbittijonon. rdseed_bytes() muodostaa asiakkaan antamaan puskuriin halutun pituisen jonon satunnaisbittejä.
#ifdef FORT_USE_RDSEED
int _has_rdseed()
{
int ok=0;
unsigned int a, b, c, d;
_cpuid(7, 0, &a, &b, &c, &d);
if((b & 0x40000) == 0x40000) {
ok=1;
}
return(ok);
}
int _rdseed_long(unsigned long *therand)
{
unsigned char ret;
asm volatile("rdseed %0; setc %1"
: "=r" (*therand), "=qm" (ret) );
return(int) ret;
}
int rdseed_bytes(int buflen, unsigned char *buf)
{
int n, ret = 0;
unsigned long l;
if(_is_cpu_vendor("GenuineIntel") && _has_rdseed()) {
fprintf(stdout,"Intel rdseed");
ret=1;
} else if(_is_cpu_vendor("AuthenticAMD") && _has_rdseed()) {
fprintf(stdout,"AMD rdseed");
ret=1;
}
if(ret) {
while(buflen > 0) {
if((ret = _rdseed_long(&l)) == 0) // 1 ok, 0 fail
break;
fprintf(stdout," %016lx",l);
n = (buflen < sizeof(l) ? buflen : sizeof(l));
memcpy(buf, (unsigned char *)&l, n);
buf+=n;
buflen-=n;
}
}
return(ret);
}
#endif
Seuraavissa fort-init:in kappaleissa kutsutaan edellisiä rutiineja ja päivitetään fort:in avainnusta.
unsigned char hash[HashLen];
HashCtx hashctx;
unsigned char temp[64];
#ifdef FORT_USE_RDRAND
memset(temp,0,sizeof(temp));
if(rdrand_bytes(sizeof(temp),temp)) {
HashInit(&hashctx);
HashUpdate(&hashctx, (unsigned char *) &cvar,
sizeof(cvar));
HashUpdate(&hashctx, temp, sizeof(temp));
HashFinal(hash, &hashctx);
fprintf(stdout,", sha256: ");
for(int c = 0;c < HashLen; c++) {
fprintf(stdout,"%02x", hash[c]);
}
fprintf(stdout,"\n");
fflush(stdout);
fort_reseed(sizeof(hash), hash);
inccvar();
}
#endif
#ifdef FORT_USE_RDSEED
memset(temp,0,sizeof(temp));
if(rdseed_bytes(sizeof(temp),temp)) {
HashInit(&hashctx);
HashUpdate(&hashctx, (unsigned char *) &cvar,
sizeof(cvar));
HashUpdate(&hashctx, temp, sizeof(temp));
HashFinal(hash, &hashctx);
fprintf(stdout,", sha256: ");
for(int c = 0;c < HashLen; c++) {
fprintf(stdout,"%02x", hash[c]);
}
fprintf(stdout,"\n");
fflush(stdout);
fort_reseed(sizeof(hash), hash);
inccvar();
}
#endif