/*
   CyberRax Programming (C) 2000 - 2001
   TITLE:   NOISE.H--
   DESCRIPTION:   Some procedures to access services of NOISE.SYS, a device
                  driver for generating random numbers
   LAST MODIFIED:   1 Dec 2001
   PROCEDURES DEFINED IN THIS FILE:
       : byte NOISE_CHECK()
       : void NOISE_STATUS()
       : void NOISE_GET_ENTROPY()
       : byte NOISE_ADD_TIMER_SAMPLE()
       : word NOISE_ADD_16BIT_SAMPLE(number)
       : word NOISE_READ_URANDOM(number_of_bytes,buffer_segment,buffer_offset)
       : word NOISE_READ_RANDOM(number_of_bytes,buffer_segment,buffer_offset)
       : word NOISE_GET_FLAGS()
       : word NOISE_SET_FLAGS(flags)
       : word NOISE_OPEN_RANDOM(mode)
       : word NOISE_OPEN_URANDOM(mode)
       : word NOISE_READ_CONTROL_RECORD(handle_for_\DEV\RANDOM$,buffer)
       : word NOISE_PATCH_CODE(buffer,start_of_code,end_of_code)

   NOTE:   These procedures (except NOISE_OPEN_xx(), NOISE_PATCH_CODE() and
           NOISE_READ_CONTROL_RECORD()) use the private API of NOISE.SYS and
           have been tested only with version 0.6.3 beta (but should work with
           0.5.3+)
*/

? include "FILE.H--"


// Errorcodes returned by NOISE.SYS
? define NOT_SUPPORTED 0
? define POOL_IS_EMPTY 0xFB
? define QUALITY_IS_LOW 0xFC
? define TOO_MANY_USERS 0xFD
? define FUNC_DISABLED 0xFE
? define SUCCESSFUL 0xFF


// Define procedure
word NOISE_ADD_16BIT_SAMPLE (DX);
word NOISE_READ_URANDOM (CX, AX, DI);
word NOISE_READ_RANDOM (CX, AX, DI);
word NOISE_SET_FLAGS (BX);
word NOISE_OPEN_RANDOM (AL);
word NOISE_OPEN_URANDOM (AL);
word NOISE_READ_CONTROL_RECORD (BX, DX);
word NOISE_PATCH_CODE (SI, CX, DI);


struct NoiseIORecord
   {
   word ControlSize;
   dword IdTag;
   word Version;
   byte Interrupt;
   byte Function;
   };



: byte NOISE_CHECK ()   // ver. 1.01, no need for offset specifing anymore
/* Checks if NOISE.SYS is installed
   Size: 51 bytes
*/
{
$CALL LABEL1
$DB "WlkngOwlNoiseSYS"
LABEL1:
$POP SI
AX = 0x6E00;
$INT 0x32
IF (AL == 0xFF)
   {
   $PUSH ES
   $PUSH CX
   ES = DX;
   CX = 8;
   $CLD
   $REP $CMPSW
   $POP CX
   $POP ES
   $JZ LABEL2
   AX = 0;
   }
LABEL2:
}
/* Returns: AL = 0xFF if NoiseSYS is installed
               CX = version (like 0x0123 = ver. 1.2.3)
            AL = 0 if not
            DI, SI destroyed
*/



: void NOISE_STATUS ()
/* Returns the status of NOISE
   Size: 5 bytes
*/
{
AX = 0x6E10;
$INT 0x32
}
/* Returns: CARRYFLAG set on error, AL = error code
            CARRYFLAG clear if success
               AL = status
                    0xFF if successful
               BH = number of processes using API
               CX = number of random bytes in waiting
               DX = maximum possible bytes waiting (if CX = DX then the pool
                    is full)
*/



: byte NOISE_GET_ENTROPY ()
/* Gets the estimated number of fresh random bits
   Size: 5 bytes
*/
{
AX = 0x6E11;
$INT 0x32
}
/* Returns: CARRYFLAG set on error, AL = error code
            CARRYFLAG clear if successful
               EBX = estimated bit count
               CL = FRAGBITS (number of fractional bits)
               EDX = low 32 bits of total number of samples added
   The estimated number of fresh bits can be calculated like this:
   (EBX >> FRAGBITS) + ((EAX & ((1 << FRAGBITS) - 1) / (1 << FRAGBITS))
*/



: void NOISE_ADD_TIMER_SAMPLE ()
/* 'Advises' NOISE to add the current time value to random number mixing
   This call is ment for programs which use/monitor processes/devices that
      NOISE doesn't (CD-ROM or some application specific ('program has
      finished' or 'computing completed') for example)
   Size: 5 bytes
*/
{
AX = 0x6E12;
$INT 0x32
}
/* Returns: CARRYFLAG set on error, AL = error code
            CARRYFLAG clear if successful, CX = number of random bytes waiting
*/



: word NOISE_ADD_16BIT_SAMPLE ()
/* Lets NOISE include the given 16 bit number (1 word) to number mixing
   Size: 8 bytes
*/
{
AX = 0x6E13;
$INT 0x32
}
/* Returns: CARRYFLAG set on error, AL = error code
            CARRYFLAG clear if successful, CX = number of random bytes waiting
*/



: void NOISE_GET_FLAGS ()
/* Returns a word which indicates current settings
   Size: 5 bytes
*/
{
AX = 0x6E14;
$INT 0x32
}
/* Returns: BX = flags
            CX = mask of settable flags in BX
   Bitfield of flags: 0   MicroSlot Windows is active
                      1-5 reserved
                      6   clock drift sampling
                      7   video retrace drift sampling
                      8   network access sampling
                      9   CD-ROM access sampling
                      10  DOS spinner
                      11  DOS interrupt (21h) sampling
                      12  mouse movement/button sampling
                      13  disk sampling (int 13h)
                      14  keystroke timing
                      15  reserved
*/



: word NOISE_SET_FLAGS ()
/* Sets the flags
   NOTE: the flags word should be ANDed with CX returned by NOISE_GET_FLAGS()
         to mask off those bits which can't be set
   Size: 8 bytes
*/
{
AX = 0x6E15;
$INT 0x32
}
/* Returns: BX = new flags
*/



: word NOISE_READ_URANDOM ()
/* Fills the buffer with random bytes
   Size: 16 bytes
*/
{
ES = AX;
AX = 0x6E16;
$INT 0x32
}
/* Returns: CARRYFLAG set on error, AL = error code
            CARRYFLAG clear if successful, CX = number of random bytes waiting
*/



: word NOISE_READ_RANDOM ()
/* Fills the buffer with random bytes
   The difference between URANDOM and RANDOM reads is, that RANDOM returns
     only fresh random bytes (less then you asked if there weren't so many)
     while URANDOM returns as much as you asked (constantly mixing the bytes
     if the number of fresh bytes is smaller than you wanted). URANDOM is
     theoretically less suitable for high security applications.
   Size: 16 bytes
*/
{
ES = AX;
AX = 0x6E17;
$INT 0x32
}
/* Returns: CARRYFLAG set on error, AL = error code
            CARRYFLAG clear if successful, CX = number of random bytes waiting
*/



: word NOISE_OPEN_RANDOM ()   // ver 1.01, possibility to set mode
/* Opens device \DEV\RANDOM$ or \DEV\RANDOM in binary mode for reading/writing
     random data with FREAD()/FWRITE() or IOCTL calls
   Input: AL = mode (READ, WRITE, READWRITE)
   Size: 73 - 75 bytes
*/
{
$CALL NOR_LOOP

$DB '\\','D','E','V','\\','R','A','N','D','O','M','$',0

NOR_LOOP:
CX = 2;
$POP SI
loop(CX)
    {
    IF (FOPEN(, , ,SI) <> 0)
       GOTO NOR_FOUND;
    DSBYTE[SI + 11] = 0;
    }
GOTO NOR_END;

NOR_FOUND:
?ifdef codesize
   BX >< AX;
?else
   BX = AX;
?endif

AX = 0x4400;
$INT 0x21

IF (CARRYFLAG)
   {
   BX = 0;
   GOTO SET_AX;
   }

AX = 0x4401;
DL |= 0b100000;
DH = 0;
$INT 0x21
IF (CARRYFLAG)
   BX = 0;

SET_AX:
?ifdef codesize
   AX >< BX;
?else
   AX = BX;
?endif

NOR_END:
}
/* Returns: AX = file handle for RANDOM$ if it's present
            AX = 0 if Noise not installed or some error accoured
*/



: word NOISE_OPEN_URANDOM ()   // ver. 1.01, possibility to set mode
/* Opens device \DEV\URANDOM$ or \DEV\URANDOM in binary mode for
     reading/writing random data with FREAD()/FWRITE() (URANDOM$ doesn't
     support IOCTL reads/writes)
   Input: AL = mode (READ, WRITE, READWRITE)
   Size: 74 - 76 bytes
*/
{
$CALL NOU_LOOP

$DB '\\','D','E','V','\\','U','R','A','N','D','O','M','$',0

NOU_LOOP:
CX = 2;
$POP SI
loop(CX)
    {
    IF (FOPEN(, , ,SI) <> 0)
       GOTO NOU_FOUND;
    DSBYTE[SI + 12] = 0;
    }
GOTO NOU_END;

NOU_FOUND:
?ifdef codesize
   BX >< AX;
?else
   BX = AX;
?endif

AX = 0x4400;
$INT 0x21

IF (CARRYFLAG)
   {
   BX = 0;
   GOTO SET_AX;
   }

AX = 0x4401;
DL |= 0b100000;
DH = 0;
$INT 0x21
IF (CARRYFLAG)
   BX = 0;

SET_AX:
?ifdef codesize
   AX >< BX;
?else
   AX = BX;
?endif

NOU_END:
}
/* Returns: AX = file handle for URANDOM$ if it's present
            AX = 0 if Noise not installed or some error accoured
*/



: word NOISE_READ_CONTROL_RECORD ()
/* Reads NoiseSYS's IO Control Record
   Input: BX = handle for \DEV\RANDOM($) (\DEV\URANDOM ain't supported)
          DS:DX = 10 byte buffer
   Size: 12 bytes
*/
{
? DOSrequired 0x0200

AX = 0x4402;
CX = 10;
$INT 0x21
IF (NOTCARRYFLAG)
   AX = 0;
}
/* Returns: NOTCARRYFLAG if successful
               AX = 0
               buffer filled (NoiseIOControl structure):
                  word ControlSize = size of whole record (the procedure reads
                                     only first 10 bytes)
                  dword IdTag      = 6E6F697Ah ('noiz')
                  word Version     = version of Noise
                  byte Interrupt   = interrupt used for API (usually 32h)
                  byte Function    = multiplexnumber (which should be givem
                                     in AH) for API (usually 6Eh)
            CARRYFLAG set on error
               AX = DOS errorcode
*/



: word NOISE_PATCH_CODE ()
/* Patches calls to Noise API to use a different interrupt/multiplexnumber
   NOTES: NOISE_READ_CONTROL_RECORD() *MUST* be used before to fill the buffer
          to be able to define the start and end of code to patch you should
             use the API calls as macros
          all 6Eh CDh 32h sequences are patched in the area, even if they
             are used inside textstrings
   Input: CX = start of code
          DS:SI = buffer which is filled by NOISE_READ_CONTROL_RECORD()
          DI = end of code
   Size = 32 bytes
*/
{
SI += 8;
$LODSB
BH = AL;
$LODSB
BL = AL;
SI = CX;
do {
   $LODSB
   IF (AL == 0x6E)
      {
      $LODSW
      IF (AX == 0x32CD)
         {
         DSBYTE[SI - 3] = BL;
         DSBYTE[SI - 1] = BH;
         }
      }
   } while (DI >= SI);
}
/* Returns: all 6Eh CDh 32h byte sequences in area end_of_code-start_of_code
               patched
            AX, BX, CX, SI, DI destroyed
*/


/* end of NOISE.H-- */
