Random (One Time) Pad Generator
Algorithm creator(s)
n/a
PB author(s)
Steve Hutchesson
Description
Create a One Time Pad (OTP). Implemented in PB's inline assembler.
Note
Ported from the MASM version to PB. Included is John Walker's public domain random testing application ENT to test the quality of the results.
Source
https://forum.powerbasic.com/forum/user-to-user-discussions/programming/755535-otp-one-time-pad-comments?p=755547#post755547
See also
Source Code
Download source code file randompad.bas (Right-click -> "Save as ...")
' ��������������������������������������������������������������������������������������������������
MACRO FUNCTION malloc(bcnt) = GlobalAlloc(%GMEM_FIXED or %GMEM_ZEROINIT,bcnt)
MACRO FUNCTION mfree(hMem) = GlobalFree(hMem)
' ��������������������������������������������������������������������������������������������������
FUNCTION random_pad$(ByVal psiz as DWORD)
' ---------------------------------------------
' shift from 4 gig range to 4 gig ^ 4 gig range
' ---------------------------------------------
LOCAL pad1 as DWORD
LOCAL pad2 as DWORD
rpad1$ = get_pad$(psiz) ' get the 1st pad
pad1 = StrPtr(rpad1$)
' -------------------------------------------------
' This combined delay ensures that the two pads use
' very different seeds that are not predictable.
' -------------------------------------------------
! cpuid ; serialising instruction
! pause ; spinlock delay instruction
SleepEx 20,0 ' yield at least 1 timeslice
! cpuid ; serialising instruction
! pause ; spinlock delay instruction
' ------------------------------------
rpad2$ = get_pad$(psiz) ' get the second pad
pad2 = StrPtr(rpad2$)
' -------------------------
' XOR the two pads together
' -------------------------
! mov esi, pad1
! mov edi, pad2
! mov ebx, psiz
! xor ecx, ecx
lbl1:
! movzx eax, BYTE PTR [esi+ecx]
! movzx edx, BYTE PTR [edi+ecx]
! xor al, dl
! mov [esi+ecx], al ; write result back to 1st pad
! add ecx, 1
! sub ebx, 1
! jnz lbl1
' -------------------------
FUNCTION = rpad1$
End FUNCTION
' ��������������������������������������������������������������������������������������������������
FUNCTION get_pad$(ByVal psiz as DWORD)
LOCAL mptr as DWORD ' memory pointer
LOCAL ppad as DWORD ' basic string pointer
mptr = create_random_pad(psiz) ' mptr is the address of the random pad
pad$ = space$(psiz) ' create a basic string
ppad = StrPtr(pad$) ' get its address
copymem(mptr,ppad,psiz) ' copy the allocated memory to the basic string
mfree(mptr) ' release memory
FUNCTION = pad$
End FUNCTION
' ��������������������������������������������������������������������������������������������������
FUNCTION create_random_pad(ByVal bcnt as DWORD) as DWORD
#REGISTER NONE
LOCAL range as DWORD
LOCAL pmem as DWORD
LOCAL xtra as DWORD
LOCAL rseed as DWORD
LOCAL icnt as DWORD
LOCAL lcnt as DWORD
PREFIX "!"
mov eax, bcnt
add eax, eax ; double the original count
mov lcnt, eax ; store result in lcnt
mov range, 255 ; byte range
END PREFIX
pmem = malloc(lcnt)
PREFIX "!"
call get_random_seed ; get an initial seed
mov rseed, eax
xor ebx, ebx ; set the loop lcnter
mov edi, pmem ; put the buffer address into EDI
; ------------------
; NaN's nrandom algo
; ------------------
lpstart:
mov eax, rseed
test eax, &H80000000
jz lbl1
add eax, &H7FFFFFFF
lbl1:
xor edx, edx
mov ecx, 127773
div ecx
mov ecx, eax
mov eax, 16807
mul edx
mov edx, ecx
mov ecx, eax
mov eax, 2836
mul edx
sub ecx, eax
xor edx, edx
mov eax, ecx
mov rseed, ecx
div range
mov [edi], dl ; write BYTE result to buffer
add edi, 1
add rseed, 1
add icnt, 1
add ebx, 1
cmp ebx, lcnt
jl lpstart
; --------------------------------------------------------------------------------------------------
END PREFIX
xtra = malloc(bcnt) ' allocate a buffer for the pad size
PREFIX "!"
mov esi, pmem ; loaded random buffer
mov edi, xtra
mov ebx, bcnt
sub esi, 1
mov edx, ebx
neg edx
cploop:
add esi, 1
movzx eax, BYTE PTR [esi]
movzx ecx, BYTE PTR [esi+ebx]
xor eax, ecx
mov [edi], al
add edi, 1
add edx, 1
jnz cploop
END PREFIX
mfree(pmem)
FUNCTION = xtra
End FUNCTION
' ��������������������������������������������������������������������������������������������������
FUNCTION get_random_seed() as DWORD
' ------------------------------------------------------------
' get 2 random seeds from 2 spaced calls and XOR them together
' ------------------------------------------------------------
#REGISTER NONE
LOCAL seed1 as DWORD
LOCAL seed2 as DWORD
seed1 = create_random_seed()
! cpuid ; serialising instruction
! pause ; spinlock delay instruction
SleepEx 20,0 ' yield at least 1 timeslice
! cpuid ; serialising instruction
! pause ; spinlock delay instruction
seed2 = create_random_seed()
! mov eax, seed1
! mov ecx, seed2
! xor eax, ecx
! mov FUNCTION, eax
End FUNCTION
' ��������������������������������������������������������������������������������������������������
FUNCTION create_random_seed() as DWORD
' The STRING technique converts the output to a string, reverses the string
' then read up to 10 characters from the left side of the string which
' is then converted back to a DWORD value.
' the string is reversed to get the most rapidly changing numbers that
' are normally on the right side of the converted number.
' get DWORD output from both RDTSC and GetTickCount(), bit rotate both
' values by the WORD value taken from the two leading bytes (range 0-99),
' 1 left, the other right then XOR the results together for the output.
#REGISTER NONE
LOCAL seed as DWORD
LOCAL shft as DWORD
LOCAL rdts as DWORD
LOCAL tcnt as DWORD
LOCAL see2 as DWORD
LOCAL tcn$
! rdtsc
! mov rdts, eax ' use the low DWORD from RDTSC
tcn$ = strreverse$(format$(rdts))
shft = val(left$(tcn$,2)) ' get shift range 0-99
seed = val(left$(tcn$,10)) ' read up to 10 characters from the string
tcnt = val(left$(strreverse$(format$(GetTickCount)),10))
! mov ecx, shft
! ror tcnt, cl ; rotate tcnt right by shft
! mov ecx, shft
! rol seed, cl ; rotate seed left by shft
! mov eax, seed
! mov ecx, tcnt
! xor eax, ecx
! mov seed, eax
FUNCTION = seed
End FUNCTION
' ��������������������������������������������������������������������������������������������������
FUNCTION copymem(ByVal src as DWORD,ByVal dst as DWORD,ByVal ln as DWORD) as DWORD
PREFIX "!"
cld
mov esi, src
mov edi, dst
mov ecx, ln
shr ecx, 2
rep movsd
mov ecx, ln
and ecx, 3
rep movsb
END PREFIX
End FUNCTION
' ��������������������������������������������������������������������������������������������������
FUNCTION exist(fname$) as DWORD
FUNCTION = Len( Dir$(fname$, 17) ) > 0
END FUNCTION
' ��������������������������������������������������������������������������������������������������
FUNCTION app_path() as STRING
#REGISTER NONE
LOCAL sln as DWORD
LOCAL pst as DWORD
buf$ = nul$(260)
pst = StrPtr(buf$)
sln = GetModuleFileName(ByVal %NULL,ByVal pst,260)
PREFIX "! "
mov esi, pst ; load the buffer address
add esi, sln ; add length to locate at end of result string
mov edi, esi ; store esi in edi
; -----------------------
; backscan to get 1st "\"
; -----------------------
lbl1:
sub esi, 1
movzx eax, BYTE PTR [esi] ; zero extend byte
cmp eax, "\" ; test for "\"
jne lbl1 ; loop back if not
sub edi, esi
sub sln, edi
add sln, 1
END PREFIX
FUNCTION = left$(buf$,sln)
End FUNCTION
' ��������������������������������������������������������������������������������������������������