[Windows] Passwords and Prompts
Posted: Tue Nov 27, 2012 3:40 am
Had to make some password stuff and used this GUI to test the routines.
The timed InputRequester was tricky due to my typos and having to debug WITHOUT netmaestro's Messaging tool
If only I saw that earlier...
EDIT: added an error check to the encrypt/decrypt functions.
The timed InputRequester was tricky due to my typos and having to debug WITHOUT netmaestro's Messaging tool

If only I saw that earlier...

Code: Select all
; COMPILER OPTIONS:
; [x] Use Compiler: PureBasic 5.00 (x86)
; [ ] Use Icon:
; [ ] Enable inline ASM support
; [±] Create unicode executable
; [ ] Create threadsafe executable
; [ ] Enable OnError lines support
; [ ] Enable XP skin support
; [ ] Request Administrator mode for Windows Vista
; [ ] Request User mode for Windows Vista (no virtualization)
; Library Subsystem:
; Executable Format: Windows ;|Console|Shared DLL
; CPU: All ;|Dynamic|w/MMX|w/3DNOW|w/SSE|w/SSE2
; File Format: UTF-8
EnableExplicit
#SP$ = Chr(32)
#SPC = 32 ; " " ;#SP = 32 ; " " #SP fails???
Procedure.s SF_Encrypt_AESB64(s$, Key$, nKeyBits.i=256, *AESinit.Integer=0)
; REV: 121124, skywalk
; modified from Blue(Guy LeBleu), 111127
; Ascii or Unicode
; WARNING: AESEncoding can add Nulls to result, so cannot view with PeekS()
; Must convert AESresult to Base64$ for simple viewing.
; Also, if a result is stored in Ascii it cannot be decrypted with Unicode.
; Keep encryption data in same format!
; *AESinitvector accepts 16 bytes.
Protected.i n = StringByteLength(s$) + SizeOf(Character) ; include null terminator
If nKeyBits >= 256
nKeyBits = 256
ElseIf nKeyBits >= 192
nKeyBits = 192
Else
nKeyBits = 128
EndIf
If n < nKeyBits / 8
n = nKeyBits / 8 ; minimum size required by AES encoding
EndIf
Protected.i *AES = AllocateMemory(n) ; buffer for binary encrypted result
If *AES
Key$ = LSet(Key$, nKeyBits/8, #SP$) ; Force Key$ to correct size.
If *AESinit
AESEncoder(@s$, *AES, n, @Key$, nKeyBits, *AESinit, #PB_Cipher_CBC)
Else
AESEncoder(@s$, *AES, n, @Key$, nKeyBits, 0, #PB_Cipher_ECB)
EndIf
; convert AES$ to Base64 Ascii string
Protected.i n64 = n * 1.5 ; coding space for Base64 = 150%
If n64 < 64
n64 = 64 ; minimum required
EndIf
s$ = Space(n64) ; Reusing s$ variable = B64$
Base64Encoder(*AES, n, @s$, n64)
FreeMemory(*AES)
Else
s$ = #NULL$
EndIf
ProcedureReturn s$
EndProcedure
Procedure.s SF_Decrypt_AESB64(AESB64$, Key$, nKeyBits.i=256, *AESinit.Integer=0)
; REV: 121124, skywalk
; modified from Blue(Guy LeBleu), 111127
; Ascii or Unicode
; To rebuild AES encrypted block from a B64 string,
; you must know exact size of original AES encrypted buffer.
; WARNING: AESEncoding can add Nulls to result, so cannot view with PeekS()
; Must convert AESresult to Base64$ for simple viewing.
; Also, if a result is stored in Ascii it cannot be decrypted with Unicode.
; Keep encryption data in same format!
; *AESinitvector accepts 16 bytes.
Protected.i nAESB64 = StringByteLength(AESB64$)
Protected.i *AES = AllocateMemory(nAESB64)
If *AES
If nKeyBits >= 256
nKeyBits = 256
ElseIf nKeyBits >= 192
nKeyBits = 192
Else
nKeyBits = 128
EndIf
Base64Decoder(@AESB64$, nAESB64, *AES, nAESB64)
; Decrypt AES buffer to recover original expression
; Calculate nBytes in AES cipher from nBytes in Base64 string
; since each block of 4 base64 bytes represents 3 encrypted AES bytes,
; except for last one, which may end with padding characters.
; count number of padding bytes and subtract from final count.
; nAESbytes = lenB64String / 4 * 3 - n_fill_bytes
Protected.i *B64 = @AESB64$
Protected.i nAES = StringByteLength(AESB64$)
*B64 + nAES ; move pointer to last byte of string
nAES / 4 * 3 ; 3 AES bytes for each 4 Base64 bytes
If PeekB(*B64 - 2) = #SPC
nAES - 2
ElseIf PeekB(*B64 - 1) = #SPC
nAES - 1
EndIf
AESB64$ = Space(nAES) ; Reusing AESB64$ variable = s$
Key$ = LSet(Key$, nKeyBits/8, #SP$) ; Force Key$ to correct size.
If *AESinit
AESDecoder(*AES, @AESB64$, nAES, @Key$, nKeyBits, *AESinit, #PB_Cipher_CBC)
Else
AESDecoder(*AES, @AESB64$, nAES, @Key$, nKeyBits, 0, #PB_Cipher_ECB)
EndIf
FreeMemory(*AES)
Else
AESB64$ = #NULL$
EndIf
ProcedureReturn AESB64$
EndProcedure
#gui_TimerPSWDCHAR = 5555 ; Arbitrary number
#gui_TimerPSWDTMO = 10000 ; Timeout(ms), Change to ~15000 after debugging
Procedure gui_InputRequesterPSWD_CB(hW.i, Msg.i, idEvent.i, Time.i)
; REV: 121126, skywalk
Protected.s wT$ = Space(#MAX_PATH)
GetWindowText_(hW, @wT$, #MAX_PATH)
Protected.i hW_IRQ = FindWindow_("InputRequester", wT$)
If idEvent = #gui_TimerPSWDCHAR
Protected.i hW_Edit = FindWindowEx_(hW_IRQ, 0, "Edit", #NULL$)
;SendMessage_(hW_Edit, #WM_SETTEXT, 0, "You did not enter a password before timing out!")
SendMessage_(hW_Edit, #EM_SETPASSWORDCHAR, '*', 0)
SendMessage_(hW_Edit, #EM_SETSEL, 0, -1)
KillTimer_(hW, idEvent)
; Set new Timer w/Password prompt limit = #gui_TimerPSWDTMO msec
SetTimer_(hW, #gui_TimerPSWDTMO, #gui_TimerPSWDTMO, @gui_InputRequesterPSWD_CB())
ElseIf idEvent = #gui_TimerPSWDTMO
Protected.i hW_BTN = FindWindowEx_(hW_IRQ, 0, "Button", "OK") ; Must explicitly search for "OK"!
; FindWindowEx_(hW_IRQ, 0, "Button", #NULL$) ; Using Null$ or "" Fails! :(
; Choose your method to proceed once timeout occurs.
; Sendkeys [ESCAPE] = CANCEL
;keybd_event_(#VK_ESCAPE,0,0,0)
;keybd_event_(#VK_ESCAPE,0,#KEYEVENTF_KEYUP,0)
; Sendkeys [ENTER] = Full or partial capture of Password entered so far...
;keybd_event_(#VK_RETURN,0,0,0)
;keybd_event_(#VK_RETURN,0,#KEYEVENTF_KEYUP,0)
; SendClick [BM_CLICK] = Full or partial capture of Password entered so far...
SendMessage_(hW_BTN, #BM_CLICK, 0, 0)
KillTimer_(hW, idEvent)
EndIf
EndProcedure
Procedure.s gui_InputRequesterPSWD(wID, Prompt$="Enter Password", Def$=#NULL$)
; REV: 121126, skywalk
SetTimer_(WindowID(wID), #gui_TimerPSWDCHAR, 10, @gui_InputRequesterPSWD_CB())
ProcedureReturn InputRequester(GetWindowTitle(wID), Prompt$, Def$)
EndProcedure
#AESkey = 2
#AESinit = 4
#pwdYOU = 6
#pwdEncrypt = 8
#pwdDecrypt = 10
#pwdREAL = 12
If OpenWindow(0,0,0,400,400,"Password Prompt...",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
Define.s pwd$, key$ = "MYSUPERSECRETKEY", AESinit$ = "MYSUPERSECRETINITVECTOR"
Define.s pwdEncrypt$
Define.s pwdDecrypt$
Define.s pwdREAL$ = "PB5"
Define.i ht = 20, wd = 380, y = 10
ButtonGadget(0, wd/1.5+10, 10+(ht+y)*4, 100, 25, "Password Prompt")
TextGadget (1, 75,10+(ht+y)*0,wd,ht," -- AES KEY (length depends on nKeyBits) -- ")
StringGadget(#AESkey, 5,5+(ht+y)*1,wd,ht,key$)
TextGadget (3, 75,10+(ht+y)*2,wd,ht," -- AES InitVector (only 16 bytes used) -- ")
StringGadget(#AESinit, 5,5+(ht+y)*3,wd,ht,AESinit$)
TextGadget (5, 75,10+(ht+y)*4,wd,ht," -- Password You Entered -- ")
StringGadget(#pwdYOU, 5,5+(ht+y)*5,wd/1.5,ht,"")
TextGadget (7, 75,10+(ht+y)*6,wd,ht," -- AES256+BASE64 Encrypted Password -- ")
StringGadget(#pwdEncrypt, 5,5+(ht+y)*7,wd,ht,"")
TextGadget (9, 75,10+(ht+y)*8,wd,ht," -- AES256+BASE64 Encrypted Password -> Unencrypted -- ")
StringGadget(#pwdDecrypt,5,5+(ht+y)*9,wd/1.5,ht,"")
TextGadget (11, 75,10+(ht+y)*11,wd,ht," -- Password To Match -- ")
StringGadget(#pwdREAL,5,5+(ht+y)*12,wd/1.5,ht,pwdREAL$)
SetGadgetColor(#AESkey, #PB_Gadget_BackColor, #Yellow)
SetGadgetColor(#AESinit, #PB_Gadget_BackColor, #Yellow)
SetGadgetColor(#pwdYOU, #PB_Gadget_BackColor, #Yellow)
Define.i evWW
Repeat
evWW = WaitWindowEvent()
Select evWW
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Gadget
If EventGadget() = 0
pwd$ = gui_InputRequesterPSWD(0, "Enter Password: " + Str(#gui_TimerPSWDTMO/1000) + " second time limit!", "You did not enter a password before timing out!")
key$ = GetGadgetText(#AESkey)
AESinit$ = GetGadgetText(#AESinit)
SetGadgetText(#pwdYOU, pwd$)
pwdEncrypt$ = SF_Encrypt_AESB64(pwd$, key$, 256, @AESinit$)
SetGadgetText(#pwdEncrypt, pwdEncrypt$)
pwdDecrypt$ = SF_Decrypt_AESB64(pwdEncrypt$, key$, 256, @AESinit$)
SetGadgetText(#pwdDecrypt, pwdDecrypt$)
pwdREAL$ = GetGadgetText(#pwdREAL)
If pwdREAL$ = pwdDecrypt$
SetGadgetColor(#pwdDecrypt, #PB_Gadget_BackColor, #Green)
SetGadgetColor(#pwdREAL, #PB_Gadget_BackColor, #Green)
Else
SetGadgetColor(#pwdDecrypt, #PB_Gadget_BackColor, RGB(241, 77, 77))
SetGadgetColor(#pwdREAL, #PB_Gadget_BackColor, RGB(241, 77, 77))
EndIf
EndIf
EndSelect
ForEver
EndIf