/*****************************************************************************/ /* RandSeed.c Small utility designed to populate a file with 2048 bytes of PRNG seed data. The seed should be high entropy. This utility generates it by reading selected system SPI performance data and using this along with binary time (~312 bytes of base data on a single CPU machine, up to ~480 bytes on a four CPU system), used to fill the buffer with non-deterministic bytes which are then XORed with one another. This buffer of 2048 bytes is then written to a file with a default name of RANDSEED.DAT (can be specified on the command-line). BUILD DETAILS ------------- See BUILD_RANDSEED.COM procedure. COPYRIGHT --------- Copyright (C) 2002-2021 Mark G.Daniel Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. VERSION HISTORY (update SOFTWAREVN as well) --------------- 23-DEC-2003 MGD v1.0.1, minor conditional mods to support IA64 08-OCT-2002 MGD v1.0.0, initial development */ /*****************************************************************************/ #define SOFTWAREVN "1.0.1" #define SOFTWARENM "RANDSEED" #ifdef __ALPHA char SoftwareID [] = SOFTWARENM " AXP-" SOFTWAREVN; #endif #ifdef __ia64 char SoftwareID [] = SOFTWARENM " IA64-" SOFTWAREVN; #endif #ifdef __VAX # error VAX no longer implemented #endif #ifdef __x86_64 char SoftwareID [] = SOFTWARENM " X86-" SOFTWAREVN; #endif /* standard C header files */ #include #include #include #include #include #include #include #include #include /* VMS-related header files */ #include #include #include #include #include /* values from GETSPIDEF.H */ #define GETSPI$_MODES 4096 #define MSCP_ALL_TOTAL 13 #define GETSPI$_MSCP_ALL 4235 #define GETSPI_ITEM_TOTAL 29 #define GETSPI$_PROCS 4122 #define GETSPI$_PROC 4123 #define GETSPI$_FRLIST 4124 #define GETSPI$_MOLIST 4125 #define GETSPI$_FAULTS 4126 #define GETSPI$_PREADS 4127 #define GETSPI$_PWRITES 4128 #define GETSPI$_PWRITEIO 4129 #define GETSPI$_PREADIO 4130 #define GETSPI$_DIRIO 4150 #define GETSPI$_BUFIO 4151 #define GETSPI$_FCPCALLS 4155 #define GETSPI$_FCPREAD 4156 #define GETSPI$_FCPWRITE 4157 #define GETSPI$_FCPCACHE 4158 #define GETSPI$_FCPCPU 4159 #define GETSPI$_FCPHIT 4160 #define GETSPI$_FCPSPLIT 4161 #define GETSPI$_FCPFAULT 4162 #define GETSPI$_ENQNEW 4163 #define GETSPI$_ENQCVT 4164 #define GETSPI$_DEQ 4165 #define GETSPI$_BLKAST 4166 #define GETSPI$_ENQWAIT 4167 #define GETSPI$_ENQNOTQD 4168 #define GETSPI$_DLCKSRCH 4169 #define GETSPI$_DLCKFND 4170 #define GETSPI$_NUMLOCKS 4171 #define GETSPI$_NUMRES 4172 #define MODES_TOTAL 8 #define MODE_INTERRUPT 0 #define MODE_MULTI_PROC 1 #define MODE_KERNEL 2 #define MODE_EXECUTIVE 3 #define MODE_SUPERVISOR 4 #define MODE_USER 5 #define MODE_COMPATIBILITY 6 #define MODE_NULL 7 #ifndef __VAX # pragma nomember_alignment #endif #define boolean int #define true 1 #define false 0 #define VMSok(x) ((x) & STS$M_SUCCESS) #define VMSnok(x) !(((x) & STS$M_SUCCESS)) char Utility [] = "RANDSEED"; boolean Debug; char RandBuffer [2048], RandElbowRoom [32]; /* function prototypes */ void GenerateRandomData (); int exe$getspi (__unknown_params); boolean strsame (char*, char*, int); /*****************************************************************************/ /* */ int main ( int argc, char *argv[] ) { int cnt, fd, status; char *FileNamePtr; /*********/ /* begin */ /*********/ if (getenv ("RANDSEED$DBUG")) Debug = true; FileNamePtr = NULL; for (cnt = 1; cnt < argc; cnt++) { if (strsame (argv[cnt], "/DBUG", -1)) Debug = true; else FileNamePtr = argv[cnt]; } if (!FileNamePtr) FileNamePtr = "RANDSEED.DAT"; GenerateRandomData (); if (Debug) fprintf (stdout, "|%s|\n", FileNamePtr); fd = open (FileNamePtr, O_WRONLY | O_CREAT, "ctx=bin"); if (fd < 0) exit (vaxc$errno); write (fd, RandBuffer, sizeof(RandBuffer)); close (fd); } /*****************************************************************************/ /* Collect System Performance Information. Uses recently undocument system call EXE$GETSPI(). The code in this function is largely derived from a VMS system performance DECwindows utility named SPI. */ void GenerateRandomData () { static unsigned long MscpAll [MSCP_ALL_TOTAL], GetSpiItem [GETSPI_ITEM_TOTAL]; #ifndef __VAX # pragma nomember_alignment # pragma member_alignment __save #endif /* structure for a single CPU's mode ticks */ static struct SingleCPU { unsigned char CPUid; unsigned long Count[MODES_TOTAL]; }; /* a structure all CPU's mode ticks for a system with up to 32 CPUs */ static struct { unsigned long NumberOfCPUs; struct SingleCPU CPU[32]; } ModeTicks; /* initialize structure for SPI items */ static struct { short BufferLength; short ItemCode; void *BufferPtr; void *LengthPtr; } ItemList[] = { { sizeof(ModeTicks), GETSPI$_MODES, &ModeTicks, 0 }, { sizeof(MscpAll), GETSPI$_MSCP_ALL, &MscpAll, 0 }, { sizeof(unsigned long), GETSPI$_FRLIST, &GetSpiItem[0], 0 }, { sizeof(unsigned long), GETSPI$_MOLIST, &GetSpiItem[1], 0 }, { sizeof(unsigned long), GETSPI$_FAULTS, &GetSpiItem[2], 0 }, { sizeof(unsigned long), GETSPI$_PREADS, &GetSpiItem[3], 0 }, { sizeof(unsigned long), GETSPI$_PWRITES, &GetSpiItem[4], 0 }, { sizeof(unsigned long), GETSPI$_PWRITEIO, &GetSpiItem[5], 0 }, { sizeof(unsigned long), GETSPI$_PREADIO, &GetSpiItem[6], 0 }, { sizeof(unsigned long), GETSPI$_DIRIO, &GetSpiItem[7], 0 }, { sizeof(unsigned long), GETSPI$_BUFIO, &GetSpiItem[8], 0 }, { sizeof(unsigned long), GETSPI$_FCPCALLS, &GetSpiItem[9], 0 }, { sizeof(unsigned long), GETSPI$_FCPREAD, &GetSpiItem[10], 0 }, { sizeof(unsigned long), GETSPI$_FCPWRITE, &GetSpiItem[11], 0 }, { sizeof(unsigned long), GETSPI$_FCPCACHE, &GetSpiItem[12], 0 }, { sizeof(unsigned long), GETSPI$_FCPCPU, &GetSpiItem[13], 0 }, { sizeof(unsigned long), GETSPI$_FCPHIT, &GetSpiItem[14], 0 }, { sizeof(unsigned long), GETSPI$_FCPSPLIT, &GetSpiItem[15], 0 }, { sizeof(unsigned long), GETSPI$_FCPFAULT, &GetSpiItem[16], 0 }, { sizeof(unsigned long), GETSPI$_ENQNEW, &GetSpiItem[17], 0 }, { sizeof(unsigned long), GETSPI$_ENQCVT, &GetSpiItem[18], 0 }, { sizeof(unsigned long), GETSPI$_DEQ, &GetSpiItem[19], 0 }, { sizeof(unsigned long), GETSPI$_BLKAST, &GetSpiItem[20], 0 }, { sizeof(unsigned long), GETSPI$_ENQWAIT, &GetSpiItem[21], 0 }, { sizeof(unsigned long), GETSPI$_ENQNOTQD, &GetSpiItem[22], 0 }, { sizeof(unsigned long), GETSPI$_DLCKSRCH, &GetSpiItem[23], 0 }, { sizeof(unsigned long), GETSPI$_DLCKFND, &GetSpiItem[24], 0 }, { sizeof(unsigned long), GETSPI$_NUMLOCKS, &GetSpiItem[25], 0 }, { sizeof(unsigned long), GETSPI$_NUMRES, &GetSpiItem[26], 0 }, {0,0,0,0} }; #ifndef __VAX # pragma member_alignment __restore #endif int idx, cidx, midx, status; unsigned long BinTime [2]; char *cptr, *rptr, *sptr, *zptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GenerateRandomData()\n"); sys$gettim (&BinTime); /* collect System Performance Information */ status = exe$getspi (0, 0, 0, &ItemList, 0, 0, 0); if (Debug) fprintf (stdout, "exe$getspi() %%X%08.08X\n", status); if (VMSnok (status)) exit (status); /* populate random seed buffer */ zptr = (sptr = RandBuffer) + sizeof(RandBuffer); *(unsigned long*)sptr = BinTime[0]; sptr += 4; /* mode counters for all CPUs */ for (cidx = 0; cidx < ModeTicks.NumberOfCPUs; cidx++) { for (midx = MODE_INTERRUPT; midx <= MODE_NULL; midx++) { if (sptr < zptr) { *(unsigned short*)sptr = (short)BinTime[0]; sptr += 2; *(unsigned long*)sptr = ModeTicks.CPU[cidx].Count[midx]; sptr += 4; *sptr++ = (char)BinTime[0]; } } } /* MSCP counters */ for (idx = 0; idx < MSCP_ALL_TOTAL; idx++) { if (sptr < zptr) { *sptr++ = (char)BinTime[0]; *(unsigned long*)sptr = MscpAll[idx]; sptr += 4; *(unsigned short*)sptr = (short)BinTime[1]; sptr += 2; } } /* miscellaneous item counters */ for (idx = 0; idx < GETSPI_ITEM_TOTAL; idx++) { if (sptr < zptr) { *sptr++ = (char)BinTime[1]; *(unsigned long*)sptr = GetSpiItem[idx]; sptr += 4; *(unsigned short*)sptr = (short)BinTime[0]; sptr += 2; } } if (Debug) fprintf (stdout, "%d bytes\n", sptr - RandBuffer); /* progressively use every third byte to further fill the buffer */ rptr = RandBuffer; while (rptr < zptr && sptr < zptr) { cptr = rptr++; while (cptr < sptr && sptr < zptr) { *sptr++ = *cptr++; cptr += 3; } } /* XOR the buffer */ cptr = RandBuffer; sptr = RandBuffer+3; while (sptr < zptr) { *(unsigned long*)sptr = *(unsigned long*)sptr ^ *(unsigned long*)cptr; cptr += 3; sptr += 3; } sptr = RandBuffer + sizeof(RandBuffer) - strlen(SoftwareID); strcpy (sptr, SoftwareID); } /****************************************************************************/ /* Does a case-insensitive, character-by-character string compare and returns true if two strings are the same, or false if not. If a maximum number of characters are specified only those will be compared, if the entire strings should be compared then specify the number of characters as 0. */ boolean strsame ( char *sptr1, char *sptr2, int count ) { /*********/ /* begin */ /*********/ while (*sptr1 && *sptr2) { if (toupper (*sptr1++) != toupper (*sptr2++)) return (false); if (count) if (!--count) return (true); } if (*sptr1 || *sptr2) return (false); else return (true); } /****************************************************************************/