Freebasic "Simple Password generator example" porting to BCX

Started by djsb, August 10, 2024, 03:56:02 AM

Previous topic - Next topic

djsb

How would I port this Freebasic "Simple Password Generator" code example (using WinFBE 3.1.0) over to BCX?

' FreeBASIC, password generator example

#lang "fblite"
Option Explicit
Const PasswordLength = 18
Const NumberOfPasswords = 24
Dim As String CharacterSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 'Alphanumeric
''Dim As String CharacterSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+[]{}|;:,.<>?/"
Dim As String SpecialCharacters1 = "{}()[]<>"
Dim As String SpecialCharacters2 = "'!%^&*_+-=:;@'~#|\/,.?"
CharacterSet += SpecialCharacters2 ' Build to what you want

Randomize , 5 '' Cryptographic

Sub Shuffle(a As String)
    #define range(f,l) Int(Rnd*((l+1)-(f))+(f))
    Dim As Ubyte L = Len(a)
    For i As Ubyte = 0 To L-2
        Swap a[i], a[range(i+1, L-1)]
    Next i
End Sub

Print "Character set length:"; Len(CharacterSet)
Print "Password length:"; PasswordLength
Print "Entropy:"; PasswordLength * Log(Len(CharacterSet)) / Log(2); " (NIST >= 112)"
Print
Print NumberOfPasswords; " Passwords"
Print

For i As Ulong = 1 To NumberOfPasswords
    Do ' Until at least one number is in the generated password.
        Shuffle(CharacterSet)
    Loop Until InStr(Left(CharacterSet, PasswordLength), Any "0123456789") <> 0
    Print Left(CharacterSet, PasswordLength)
Next

Sleep


I'm also wondering if it would port over to QBASIC on my Pocket 386? I could then use it as a portable air gapped password generator. Thanks.

MrBcx

David,

This was a little tricky to convert but this compiles with Lcc-Win32, Pelles, Mingw, and MSVC and seems to run as expected.


' Freebasic Simple_Password_Generator by Löwenherz
' Ported to BCX BASIC by MrBcx with help from ChatGPT
'**********************************************************************
' The following text added by MrBcx found by googling NIST entropy 112
'**********************************************************************
' Look-up secrets having at least 112 bits of entropy SHALL be hashed
' with an approved one-way function as described in Sec. 5.1. 1.2.
' Look-up secrets with fewer than 112 bits of entropy SHALL be salted
' and hashed using a suitable password hashing scheme, also described
' in Sec.Dec 8, 2023
'
' NIST Special Publication 800-63B
' National Institute of Standards and Technology (.gov)
'**********************************************************************

CONST PasswordLength = 18
CONST NumberOfPasswords = 24

DIM AS STRING CharacterSet  ' Alphanumeric
DIM AS STRING SpecialCharacters1
DIM AS STRING SpecialCharacters2

CharacterSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"  ' Alphanumeric
SpecialCharacters1 = "{}()[]<>"
SpecialCharacters2 = "'!%^&*_+-=:;@'~#|\/,.?"

CharacterSet = CharacterSet + SpecialCharacters2  ' Build to what you want

RANDOMIZE (5)  ' Cryptographic

SUB Shuffle(a AS STRING)
    MACRO range(f, l) = INT(RND * ((l + 1) - (f)) + (f))
    DIM AS LONG L = LEN(a)
    FOR LONG i = 0 TO L - 2
        DIM AS LONG j = range(i + 1, L - 1)
        ' Manual swap implementation for characters
        DIM AS STRING temp
        temp = MID$(a, i + 1, 1)
        MID$(a, i + 1, 1) = MID$(a, j + 1, 1)
        MID$(a, j + 1, 1) = temp
    NEXT
END SUB

PRINT "Character set length:"; LEN(CharacterSet)
PRINT "Password length:"; PasswordLength
PRINT "Entropy:"; CAST(INT, PasswordLength * LOG(LEN(CharacterSet)) / LOG(2)); " (NIST >= 112)"
PRINT
PRINT NumberOfPasswords; " Passwords"
PRINT

DIM AS ULONG i
FOR i = 1 TO NumberOfPasswords
    DO  ' Until at least one number is in the generated password.
        Shuffle(CharacterSet)
    LOOP UNTIL INSTRANY (LEFT$(CharacterSet, PasswordLength), "0123456789") <> 0
    PRINT LEFT$(CharacterSet, PasswordLength)
NEXT

PAUSE


FUNCTION INSTRANY (Main$ AS STRING, Words$ AS STRING) AS LONG
    ' Returns TRUE if any character in Words$ is found in Main$
    DIM AS LONG Found
    FOR LONG i = 1 TO LEN(Words$)
        Found = INSTR(Main$, MID$(Words$, i, 1))
        IF Found THEN FUNCTION = Found
    NEXT
    FUNCTION = 0
END FUNCTION



Sample run:


Character set length: 84
Password length: 18
Entropy: 115 (NIST >= 112)

24 Passwords

b;H!=/dWe?w@QZpyP6
Nuc2Semrv'dWXB+|K:
FJ#89;M@dn3,Dlurbo
B93Juw:\+dae-GjW#2
rcV-8t!j_|2C;Hh=wf
?nY.k\HPb@h56R-T3e
BpS!/5?0r4ogu|d^ZH
i.%w1Q85NtThSP/md&
azjU1kFY+=V.IHQ#Le
8ezCvi='3WX7GSq\0O
J,gAQcM?uxIL@-sXy5
CMl5Tzp|j/f-FW6c8V
@kpvY9NH&q;IU1go3Q
Wp9ZvqyQ;AjRgf%|#N
mq,YxX'C5Ik2y%?EP&
pvz;e4sTqXUx=-!?Vo
@Mef%,tP-80U7Y6'kp
s7/a%5S\_?VihuMCpN
t\JCac!+K9r4'SD5UQ
0'~tXwOam'8znZb^FW
RN&|vHj5!.u#xs9nJ-
Xb/;yAnRFh^OKfQ3_x
7hY\l8bJ#/op&Tmc;E
c.7LJ'jrWiUI4D,5K&

Press any key to continue . . .

djsb


MrBcx

Quote from: djsb on August 10, 2024, 09:17:11 AM
Fantastic. Thank you. I shall study it in depth.

David.

I've added the following comment to my post above for anyone curious about what:
  Entropy: 115 (NIST >= 112)  means in the output of the app.

'**********************************************************************
' The following text added by MrBcx found by googling NIST entropy 112
'**********************************************************************
' Look-up secrets having at least 112 bits of entropy SHALL be hashed
' with an approved one-way function as described in Sec. 5.1. 1.2.
' Look-up secrets with fewer than 112 bits of entropy SHALL be salted
' and hashed using a suitable password hashing scheme, also described
' in Sec.Dec 8, 2023
'
' NIST Special Publication 800-63B
' National Institute of Standards and Technology (.gov)
'**********************************************************************

MrBcx

BCX's built-in SWAP command could not be used for swapping individual bytes within the
same string, in the code I posted earlier, so an alternative (manual) approach was used
in that code instead. 

Thinking there may be times in the future when I'll need such a thing again, I've re-packaged
that byte swapping code into a generic SUB Byte_Swap.  If anyone is interested, you
can replace SUB Shuffle in my original post with the two SUBS provided below.



SUB Shuffle(a AS STRING)
    MACRO range(f, l) = INT(RND * ((l + 1) - (f)) + (f))
    DIM AS LONG L = LEN(a)
    FOR LONG i = 0 TO L-2
      Byte_Swap(ADDRESSOF(a[i]), ADDRESSOF(a[CAST(INT, range(i+1, L-1))]))
    NEXT
END SUB


SUB Byte_Swap (str1 AS STRING, str2 AS STRING)
    '***********************************************************
    ' Calling convention:
    ' Byte_Swap( ADDRESSOF(Str1[Index]), ADDRESSOF(Str2[Index]))
    ' For swapping individual chars within strings which BCX's
    ' built-in SWAP command cannot accomplish at this time.
    '***********************************************************
    DIM temp AS STRING
    temp[0] = str1[0]
    str1[0] = str2[0]
    str2[0] = temp[0]
END SUB