Tässä postissa käyn läpi tertun ns istuntoavaimen muodostamisen. Istuntoavaimen luomiseen tarvitaan satunnaisbittigeneraattori ja joku sisäinen malli, jonka mukaan istuntoavain muodostetaan satunnaisbittigeneraattorin antamista biteistä. Ensin yksinkertainen satunnaisbittigeneraattori ressu:
Tässä käytetään vain yhtä lähdettä, ressua. Varmuuden vuoksi kannattaa lisätä ainakin toinen lähde.
#include <sys/time.h>
unsigned char dba_clockbyte() /* JariK 2013-2020 */
{
struct timeval tv;
gettimeofday(&tv,NULL);
return(tv.tv_usec & 0xff);
}
void dba_ressu_genbytes(int size, unsigned char *buffer) /* JariK 12/2020 */
{
int c, d, e, f, byte, prevbyte, bits;
f=0;
bits=0;
for(c=0; c<8 || c%8!=0 || c<16 || c<48 ||
bits<8*size; c++) {
for(d=0; d<size; d++) {
e = buffer[d];
e = ((e&0x80)>>7) | ((e&0x7f)<<1);
byte = dba_clockbyte();
buffer[d] = e^byte;
if(prevbyte != byte) {
bits++;
prevbyte = byte;
}
}
for(d=0; d<size; d++) {
f = (f+buffer[d])%size;
e = buffer[d];
buffer[d] = buffer[f];
buffer[f] = e;
}
}
}
Ja sitten rutiinit, joilla satunnaismerkkejä saa merkki kerrallaan:
#define DBA_RESSUCNT 128
#define DBA_RESSU_CLEAR 2
unsigned char dba_ressu_bytes[DBA_RESSUCNT];
int dba_ressu_byte = 999999;
int dba_ressu_cnt = DBA_RESSUCNT;
int dba_ressu_genbyte()
{
if(dba_ressu_byte>=dba_ressu_cnt) {
#ifdef DBA_RESSU_CLEAR
memset(dba_ressu_bytes,0,dba_ressu_cnt);
#else
if(dba_ressu_byte==999999)
memset(dba_ressu_bytes,0,dba_ressu_cnt);
#endif
dba_ressu_genbytes(dba_ressu_cnt,dba_ressu_bytes);
dba_ressu_byte=0;
}
return(dba_ressu_bytes[dba_ressu_byte++]);
}
int dba_ressu_genbyte_limit(int limit)
{
int c;
while((c = dba_ressu_genbyte())>=
(256/limit)*limit);
/* while((c = fort_random_data_byte())>
(256/limit)*limit); little bug */
return(c % limit);
}
void dba_ressu_random_clear()
{
memset(dba_ressu_bytes,0,dba_ressu_cnt);
dba_ressu_byte=999998;
}
Seuraava rutiini arpoo istuntoavaimen merkki kerrallaan:
// 0123456789
// abcdefghij
// klmnopqrst
// uvwxyzABCD
// EFGHIJKLMN
// OPQRSTUVWX
// YZ
void dba_gensessionid(int size, unsigned char *buffer)
{
int len,byte,first;
unsigned char chars[] =
"0123456789" \
"abcdefghijklmnopqrstuvwxyz" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
unsigned char *n;
dba_ressu_random_clear();
n=buffer;
len=0;
first=1;
while(++len<size) {
if(first)
byte=dba_ressu_genbyte_limit(sizeof(chars)-11)+10;
else
byte=dba_ressu_genbyte_limit(sizeof(chars)-1);
*n++=chars[byte];
first=0;
}
*n='\0';
dba_ressu_random_clear();
}
Session id talletetaan kookieksi tulostamalla kookierivi html otsakkeeseen:
#define DBS_RENEW_SESSION_HOURS 24
void dba_renew_cookie()
{
dbs_html_buf_printf(HTML_HEADER_BUFFER,"Set-Cookie: sessionid=%s; Max-Age=%d\r\n",
htmlsessionid, 3600*DBS_RENEW_SESSION_HOURS);
}
Vielä pieni pääohjelma: tässä avaimen pituus on 32 merkkiä, viimeinen merkki on ‘\0’.
void main()
{
char buffer[33];
dba_gensessionid(sizeof(buffer),buffer);
fprintf(stdout,"%s\n",buffer);
}