retrieve the password based on user name. The routine can accept all characters entered from the
keyboard but the only editing available is a backspace... No home, end, insert, del, etc. It gets way more
complicated to do intra-line editing but I do have a routine for that as well if anyone is remotely interested.
The stipulation is that if you wish to allow poison characters as input you must call the routine with delayed
expansion disabled or directly from the command line to get the desired result. This routine is just an
example compiled from the work of others on Dostips and StackOverflow, etc, and I gladly accept any
comments or corrections to the methods employed and borrowed from these websites after months of trying
to learn difficult and 'crazy' concepts from the learned posters. This routine takes the user name and converts
it (lower case) to a Hex filename.log with a Base64 encryption algorithm that is freeware and mostly used to
encrypt emails to put the password into a file mixed with the username and spacer chars as a 'key'. If the
parent routine can be compiled into an executable that cannot be easily decompiled then it could be very
hard to break. This routine is a rather simple example. One could add complexities such as storing the hex
conversion filename in reverse character order or using another algorithm beyond the popular Base64.
Enough said, check this out:
Code: Select all
::Encrypt.bat Asks for User name and masked password and encrypts / decrypts
::using Base64.exe algorithm available as freeware from Faith Kodak @ www.f2ko.de
::The filename is just the Username translated to Hex to create the file name.log
::Another extension such as .dll could be used and the user files could be hidden and/or
::password protected as another layer of protection by an administrator
::User name is also used as a 'key' added to the password with separators to complicate things
::prior to the Base 64 algorithm being applied. I think this routine is also "poison char' friendly
::If the main routine could be encrypted from prying eyes as a truly compiled exe file
::then I think this algorithm would be hard to break. This is just my first try at a proof
::of concept. By the way I thank all who contribute to Dostips.com for inspiration, Carl
@echo off&setlocal DisableDelayedExpansion
:StartMain
echo(Set up New User Name ^(Case insensitive^) and Password ^(Case sensitive^):
call :getvar key="Enter your User Name: " len
if %len% equ 0 goto :EndMain
call :AssignVar key1 = key
call :tolower key1
call :charlib.bat str2Hex key1 keyHex
If exist "%keyHex%.log" echo(User Name already exisits, try again&pause&goto :StartMain
rem.>"%keyHex%.txt"
If not exist "%keyHex%.txt" echo(Cannot write to file on this drive&pause&goto :EndMain
call :getvar pwd="Enter your password: " len /m
if %len% equ 0 goto :EndMain
::Create temp file using Hex name, containing password and user name combined with arbitrary separator
set "sep=°"
> "%keyHex%.txt" call :eco pwd sep key sep
base64 -e "%keyHex%.txt" "%keyHex%.log" &del "%keyHex%.txt%"
::For demonstration
echo(
call :eco /n "User '" key "' was combined with Password '" pwd "'and encrypted" /n
echo(&echo(The encrypted file is '%keyHex%.log' with contents:&echo(
type "%keyHex%.log"
echo(&echo(&echo(Now set keys ^(User name^) and pwd and filename to nul:
echo(echo on&@echo on
set key=&set key1=&set pwd=&set "keyHex="
@echo off&echo(
::Now get User Name to retrieve the User's log file and password
call :Getvar key1="Enter your User Name to retrieve your password: " len
if %len% equ 0 goto :EndMain
call :eco "Now we can retrieve your password file based on user name '" key1 "':" /n
call :tolower key1
call :charlib.bat str2Hex key1 keyHex
if not exist "%keyHex%.log" echo(FATAL ERROR: Log file deleted or User name not found&pause&goto :EndMain
setlocal disabledelayedexpansion
for /f "usebackq tokens=1* delims=°" %%a in (`type "%keyHex%.log"^|base64 -d -s`) do (
set "key=%%b"
set "pwd=%%a"
)
call :Assignvar key = key "~0,-3"
call :Assignvar pwd = pwd "~0,-2"
echo(&echo(Retrieved data from file: %keyHex%.log
call :eco "Your retrieved username=" key /n
call :eco "Your retrieved password=" pwd /n
endlocal
:EndMain
EndLocal&exit/b
::*********************************::
::***|| SUBROUTINES ||***::
::*********************************::
:Eco "Here is a char: " char " and a string: " EnvarString /n "This is line two."
::
:: Echo's strings mixed with environment variables with or without CR/LF or embed CR/LF inside
:: Environment variables must be passed by name (not reference) and may contain poison chars
:: Quoted strings are echo'd as is and may have leading or trailing spaces do not quote Env vars
:: To place a newline (CF/LF) use '/n' unquoted
:::
::: Dependencies - None Author: Carl with ideas borrowed from Dostips.com
:::
SetLocal DisableDelayedExpansion
For /F %%# In ('"Prompt;$H&For %%# in (1) Do Rem"') Do Set "BS=%%#"
SetLocal EnableDelayedExpansion
:Start_Eco
if "%~1"=="" EndLocal&EndLocal&exit/b
if /i "/n" equ "%~1" (
echo(
) else if not defined %1 (
set "string=.%BS%%~1"
for /f delims^=^ eol^= %%# in ("!string!") do EndLocal& set/p="%%#" <nul
SetLocal EnableDelayedExpansion
) else ( <nul set/p=".%BS%!%~1!")
shift&goto :Start_Eco
:End_Eco
:GetVar
:: SYNTAX: GetVar ^<EnVar^> [="User Prompt: "] [length] [/m]
::
:: Assigns User input to the Environment variable passed as 1st argument
:: Allows unbalance quotes and 'poison' characters mixed with quotes
:: The only editing key available to the User is 'backspace'
:: The user string entered is set in the Environment variable, 'Envar'
:: If no arguments are passed the routine quits, stand alone version displays this help
:: The fisrt argument is mandatory, the rest are optional
:: To display a variable with Poison chars and quotes use: Eco.bat
:: To mask input with '*'s place /m at the very end of the argument list
:: This routine has flaws if called from a Delayed Expansion environment
::
:: Example:
::
:: GetVar.bat Pa$$word="Enter your 'Poison Password' string: " len /m
:: Eco.bat "Your Poison Password is: '" Pa$$word "' with length: " len
:::
::: Dependencies - None Author: Carl with ideas borrowed from Dostips.com
:::
if "%~1"=="" goto :EndGetVar
SetLocal DisableDelayedExpansion
set "NotDelayedFlag=!"
set "Masked="
echo(%*|find " /m">nul
if %errorlevel% equ 0 set "Masked=*"
For /F %%# In ('"Prompt;$H&For %%# in (1) Do Rem"') Do Set "BS=%%#"
Set "Line="
if /i "%~2" neq "/m" <Nul set/p=".%BS% %BS%%~2"
:Char_Loop_
Set "Key="
For /F "delims=" %%# In (
'Xcopy /L /W "%~f0" "%~f0" 2^>Nul'
) Do If Not Defined Key Set "Key=%%#"
Set "Key=%Key:~-1%"
rem If "!" equ "%Key%" set "Key=%Key:!=^!%"
SetLocal EnableDelayedExpansion
If Not Defined Key ( Rem Enter pressed
echo(
If not Defined Line EndLocal&EndLocal&(
If Defined %~1 Set "%~1="
If Defined %~3 Set/a "%~3=0
)&exit/b 0
For /F delims^=^ eol^= %%# In ("!Line!") Do (
EndLocal&EndLocal&(
If not "%~3"=="" Set/a "%~3=%length%"
If Not "%~1"=="" (Set "%~1=%%#")
exit/b %length%
)
)
)
If %BS%==^%Key% (
Set "Key="
If Defined Line set/a length-=1& Set "Line=!Line:~0,-1!"& Set /P "=%BS% %BS%" <Nul
) Else (
If defined Masked (Set "Display=*") Else (Set "Display=!Key:~-1!")
set/a length+=1& Set /p=".%BS%!Display!" <Nul
)
If Not Defined Line (
EndLocal& Set/a length=1& Set "Line=%Key%"
) Else For /F delims^=^ eol^= %%# In ("!Line!") Do (
EndLocal& Set/a length=%length%& Set "Line=%%#%Key%"
)
Goto :Char_Loop_
:EndGetVar
exit/b
:AssignVar RtrnVar = String Variable operations, Designed to handle 'Poison' characters
::
::AssignVar RtrnVar = String + String2 ;Concatenate 2 strings
:: or RtrnVar = String ;Assign string with 'Poison' chars
:: or RtrnVar = String "a.=b;" ;RtrnVar=%String:a.=b;%
:: or RtrnVar = String "~3,-5" ;RtrnVar=%String:~3,-5%
:::
::: Dependencies - None Author: Carl with ideas borrowed from jeb and Dostips.com
:::
SetLocal
set "NotDelayedFlag=!"
if "%~2"=="" goto :EndAssignVar
if not defined %~2 goto :EndAssignVar
SetLocal EnableDelayedExpansion
set "var=!%~2!!%~4!"
if "" neq "%~3" if "+" neq "%~3" (set "var=!var:%~3!")
rem set "var=!var:%%=%%~A!"
set "var=!var:"=%%~B!"
if not defined NotDelayedFlag set "var=!var:^=^^^^!"
if not defined NotDelayedFlag set "var=%var:!=^^^!%" !
set "replace=%% """ ."
for /F "tokens=1,2,3" %%A in ("!replace!") DO (
EndLocal
EndLocal
set "%~1=%var%" !
@echo off
)&exit /b 0
:End_AssignVar
EndLocal&exit/b -1
:toLower str -- converts uppercase character to lowercase
:: -- str [in,out] - valref of string variable to be converted
:$created 20060101 :$changed 20080219 :$categories StringManipulation
:$source http://www.dostips.com
if not defined %~1 EXIT /b
for %%a in ("A=a" "B=b" "C=c" "D=d" "E=e" "F=f" "G=g" "H=h" "I=i"
"J=j" "K=k" "L=l" "M=m" "N=n" "O=o" "P=p" "Q=q" "R=r"
"S=s" "T=t" "U=u" "V=v" "W=w" "X=x" "Y=y" "Z=z" "Ä=ä"
"Ö=ö" "Ü=ü") do (
call set %~1=%%%~1:%%~a%%
)
EXIT /b
:CharLib.bat Routines from dbenham - thanks
call :%*
exit/b
:str2hex StrVar [RtnVar] -- Convert a string to hex digits
::
:: Converts the string contained within variable StrVar into a string of
:: ASCII codes, with each code represented as a pair of hexadecimal digits.
:: The length of the result will always be exactly twice the length of the
:: original string.
::
:: Sets RtnVar=result
:: or displays result if RtnVar not specified
:::
::: Dependencies - :_toAsciiMap, :_getLF, :_getCR, :StrLen
:::
setlocal enableDelayedExpansion
set "str=!%~1!"
call :_toAsciiMap map
call :StrLen str len
set /a len-=1
set rtn=
set err=0
for /l %%n in (0,1,%len%) do (
set "c=!str:~%%n,1!"
set "hex="
if "!c!"==";" set hex=3B
if "!c!"=="=" set hex=3D
if "!c!"=="^!" set hex=21
if not defined hex for /f "delims=" %%c in ("!c!") do (
set "test=!map:*#%%c=!"
if not "%%c"=="!test:~0,1!" set "test=!test:*#%%c=!"
if "%%c"=="!test:~0,1!" set "hex=!test:~1,2!"
)
if not defined hex (
if not defined ASCII_10 call :_getLF
if "!c!"=="!ASCII_10!" set hex=0A
)
if not defined hex (
if not defined ASCII_13 call :_getCR
if "!c!"=="!ASCII_13!" set hex=0D
)
:: if not defined yet then must be 1A since all other viable characters are accounted for!
if not defined hex set hex=1A
set rtn=!rtn!!hex!
)
( endlocal
if "%~2" neq "" (set %~2=%rtn%) else echo:%rtn%
)
exit /b 0
:hex2str [Options] HexVar [RtnVar] -- Convert hex digits to a string
::
:: Converts a string of hexadecimal digits contained within variable HexVar
:: into a string, where each pair of hex digits in the input represents the
:: ASCII code of a character in the result.
::
:: sets RtnVar=result
:: or displays the result if RtnVar is not specified
::
:: If any of the problematic characters below appear in the hex string
:: at least once then the indicated value is added to the errorlevel,
:: and the character may also be represented by a replacement string.
:: The absence of a Default Replacement indicates the character will be
:: represented as itself by default. The Default Replacement may be over-
:: ridden by one of the case insensitive options, where the str following
:: the option represents the replacement string. If there is no string after
:: the option then the character will be stripped from the output.
::
:: Default
:: Option Hex Character errorlevel Replacement
:: ------ --- --------------- ---------- -----------
:: /Nstr 00 null 1 <NUL>
:: /Lstr 0A line feed 2
:: /Cstr 0D carriage return 4
:: /Estr invalid-hex-digit 8 <ERR>
::
:: If the final output contains a carriage return or line feed, then the
:: rtnVar variable should only be accessed via delayed substitution.
::
:: If the hex string contains 1A then the function will briefly create a
:: temporary file to generate the correct SUB character. The location of
:: the file is specified by the %TEMP% or %TMP% variable, or the current
:: directory if neither variable is defined.
::
:: Aborts with an error message to stderr and errorlevel 16 if the hex string
:: length is not divisible by 2.
:::
::: Dependencies - :_fromAsciiMap, :_getLF, :_getCR, :_getSUB, :StrLen, :Unique
:::
setlocal
set "NotDelayedFlag=!"
setlocal enableDelayedExpansion
call :_fromAsciiMap map
set "nulStr=<NUL>"
set "errStr=<ERR>"
set lfStr=
set crStr=
set subStr=
set lfSkip=
set crSkip=
set shiftCnt=0
set skip=
for %%a in (%*) do (
if not defined skip (
set "arg=%%~a"
if not "!arg:~0,1!"=="/" (
set skip=true
) else (
set "opt=!arg:~1,1!"
set "str=!arg:~2!"
if /i "!opt!"=="N" set "nulStr=!str!"
if /i "!opt!"=="L" set "lfStr=!str!" & set "lfSkip=true"
if /i "!opt!"=="C" set "crStr=!str!" & set "crSkip=true"
if /i "!opt!"=="E" set "errStr=!str!"
set /a shiftCnt+=1
)
)
)
for /l %%n in (1,1,%shiftCnt%) do shift /1
call :StrLen %~1 len
set /a mod=len%%2
if %mod%==1 1>&2 echo ERROR: Hex string length not a multiple of 2& exit /b 16
set rtn=
set /a len-=1
set err=0
for /l %%n in (0,2,%len%) do (
set "d="
2>nul set /a d=0x!%~1:~%%n,2!
if not defined d (
set "c=!errStr!"
set /a "err|=8"
) else if !d!==0 (
set "c=!nulStr!"
set /a "err|=1"
) else if !d!==10 (
if not defined lfStr if not defined lfSkip (if not defined ASCII_10 call :_getLF)& set lfStr=!ASCII_10!
set "c=!lfStr!"
set /a "err|=2"
) else if !d!==13 (
if not defined crStr if not defined crSkip (if not defined ASCII_13 call :_getCR)& set crStr=!ASCII_13!
set "c=!crStr!"
set /a "err|=4"
) else if !d!==26 (
if not defined subStr (if not defined ASCII_26 call :_getSUB)& set subStr=!ASCII_26!
set "c=!subStr!"
) else for %%d in (!d!) do set c=^!map:~%%d,1!
set "rtn=!rtn!!c!"
)
if "%~2"=="" (
echo:!rtn!
exit /b %err%
)
if defined rtn (
set "rtn=!rtn:%%=%%~3!"
set "rtn=!rtn:"=%%~4!"
if defined ASCII_13 for %%a in ("!ASCII_13!") do set "rtn=!rtn:%%~a=%%~5!"
if defined ASCII_10 for %%a in ("!ASCII_10!") do set "rtn=!rtn:%%~a=%%~6!"
if not defined NotDelayedFlag set "rtn=!rtn:^=^^^^!"
)
if defined rtn if not defined NotDelayedFlag set "rtn=%rtn:!=^^^!%" !
set "replace=%% """ !ASCII_13!!ASCII_13!"
for %%6 in ("!ASCII_10!") do (
for /F "tokens=1,2,3" %%3 in ("!replace!") DO (
endlocal
endlocal
set "%~2=%rtn%" !
exit /b %err%
)
)
exit /b
:_getLF -- Sets ASCII_10 to a line feed (0x0A) character
if not defined ASCII_10 set ASCII_10=^
:: The above 2 blank lines MUST be preserved!
exit /b
:_getCR -- Sets ASCII_13 to a carriage return (0x0D) character
if not defined ASCII_13 for /f %%a in ('copy /Z "%~dpf0" nul') do set "ASCII_13=%%a"
exit /b
:StrLen string len -- returns the length of a string
:: -- string [in] - variable name containing the string being measured for length
:: -- len [out] - variable to be used to return the string length
:: Many thanks to 'sowgtsoi', but also 'jeb' and 'amel27' dostips forum users helped making this short and efficient
:$created 20081122 :$changed 20101116 :$categories StringOperation
:$source http://www.dostips.com
( SETLOCAL ENABLEDELAYEDEXPANSION
set "str=A!%~1!"&rem keep the A up front to ensure we get the length and not the upper bound
rem it also avoids trouble in case of empty string
set "len=0"
for /L %%A in (12,-1,0) do (
set /a "len|=1<<%%A"
for %%B in (!len!) do if "!str:~%%B,1!"=="" set /a "len&=~1<<%%A"
)
)
( ENDLOCAL & REM RETURN VALUES
IF "%~2" NEQ "" SET /a %~2=%len%
)
EXIT /b
:_toAsciiMap rtnVar -- Creates a map useful for converting a char to ASCII
::
:: Sets variable rtnVar to a string useful for converting characters into
:: their numeric ASCII code values using hexadecimal notation. The following
:: characters are not represented: 0x00, 0x0A, 0x0D, 0x1A. The following
:: characters are represented but are difficult to extract: 0x21, 0x3B, 0x3D.
::
setlocal
set "NotDelayedFlag=!"
setlocal DisableDelayedExpansion
set rtn=xxx#01#02#03#04#05#06#07#08# 09#0B#0C#0E#0F#10#11#12#13#14#15#16#17#18#19#1B#1C#1D#1E#1F# 20#!!21#%%~B%%~B22###23#$$24#%%~A%%~A25#^&^&26#''27#^(^(28#^)^)29#**2A#++2B#,,2C#--2D#..2E#//2F#0030#1131#2232#3333#4434#5535#6636#7737#8838#9939#::3A#;;3B#^<^<3C#==3D#^>^>3E#??3F#@@40#AA41#BB42#CC43#DD44#EE45#FF46#GG47#HH48#II49#JJ4A#KK4B#LL4C#MM4D#NN4E#OO4F#PP50#QQ51#RR52#SS53#TT54#UU55#VV56#WW57#XX58#YY59#ZZ5A#[[5B#\\5C#]]5D#^^^^5E#__5F#``60#aa61#bb62#cc63#dd64#ee65#ff66#gg67#hh68#ii69#jj6A#kk6B#ll6C#mm6D#nn6E#oo6F#pp70#qq71#rr72#ss73#tt74#uu75#vv76#ww77#xx78#yy79#zz7A#{{7B#^|^|7C#}}7D#~~7E#7F#€€80#81#‚‚82#ƒƒ83#„„84#……85#††86#‡‡87#ˆˆ88#‰‰89#ŠŠ8A#‹‹8B#ŒŒ8C#8D#ŽŽ8E#8F#90#‘‘91#’’92#““93#””94#••95#––96#——97#˜˜98#™™99#šš9A#››9B#œœ9C#9D#žž9E#ŸŸ9F# A0#¡¡A1#¢¢A2#££A3#¤¤A4#¥¥A5#¦¦A6#§§A7#¨¨A8#©©A9#ªªAA#««AB#¬¬AC#AD#®®AE#¯¯AF#°°B0#±±B1#²²B2#³³B3#´´B4#µµB5#¶¶B6#··B7#¸¸B8#¹¹B9#ººBA#»»BB#¼¼BC#½½BD#¾¾BE#¿¿BF#ÀÀC0#ÁÁC1#ÂÂC2#ÃÃC3#ÄÄC4#ÅÅC5#ÆÆC6#ÇÇC7#ÈÈC8#ÉÉC9#ÊÊCA#ËËCB#ÌÌCC#ÍÍCD#ÎÎCE#ÏÏCF#ÐÐD0#ÑÑD1#ÒÒD2#ÓÓD3#ÔÔD4#ÕÕD5#ÖÖD6#××D7#ØØD8#ÙÙD9#ÚÚDA#ÛÛDB#ÜÜDC#ÝÝDD#ÞÞDE#ßßDF#ààE0#ááE1#ââE2#ããE3#ääE4#ååE5#ææE6#ççE7#èèE8#ééE9#êêEA#ëëEB#ììEC#ííED#îîEE#ïïEF#ððF0#ññF1#òòF2#óóF3#ôôF4#õõF5#ööF6#÷÷F7#øøF8#ùùF9#úúFA#ûûFB#üüFC#ýýFD#þþFE#ÿÿFF#
setlocal EnableDelayedExpansion
if not defined NotDelayedFlag set "rtn=!rtn:^=^^^^!"
if not defined NotDelayedFlag set "rtn=%rtn:!=^^^!%" !
set "replace=%% """"
for /F "tokens=1,2" %%A in ("!replace!") DO (
endlocal&endlocal&endlocal
set "%~1=%rtn%" !
exit /b 0
)
exit /b
:_fromAsciiMap rtnVar -- Creates a map useful for converting ASCII to a char
::
:: Sets variable rtnVar to a 256 character string containing the complete
:: extended ASCII character set except a space has been substituted for each
:: of the following problematic characters: 0x00, 0x0A, 0x0D, 0x1A.
:: The string is particularly well suited to convert a numeric ASCII code
:: into the corresponding character.
::
setlocal
set "NotDelayedFlag=!"
setlocal DisableDelayedExpansion
set rtn= !%%~B#$%%~A^&'^(^)*+,-./0123456789:;^<=^>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^^_`abcdefghijklmnopqrstuvwxyz{^|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
setlocal EnableDelayedExpansion
if not defined NotDelayedFlag set "rtn=!rtn:^=^^^^!"
if not defined NotDelayedFlag set "rtn=%rtn:!=^^^!%" !
set "replace=%% """"
for /F "tokens=1,2" %%A in ("!replace!") DO (
endlocal&endlocal&endlocal
set "%~1=%rtn%" !
exit /b 0
)
exit /b
:_getCR -- Sets ASCII_13 to a carriage return (0x0D) character
if not defined ASCII_13 for /f %%a in ('copy /Z "%~dpf0" nul') do set "ASCII_13=%%a"
exit /b
:_getSUB -- sets ASCII_26 to the ASCII code 26 (0x1A) character
::
:: Briefly creates a temporary file with a unique name that should prevent
:: collisions in a shared environment.
:::
::: Dependencies - :Unique
:::
if defined ASCII_26 exit /b
setlocal disableDelayedExpansion
call :Unique file
if defined temp (set filePath=%temp%) else if defined tmp (set filePath=%tmp%) else set filePath=.
set file="%filePath%\_getSUB_%file%_%random%.tmp"
copy /a nul+nul %file% > nul
for /f "usebackq" %%a in (%file%) do set "SUB=%%a"
del %file%
(endlocal
set ASCII_26=%SUB%
)
exit /b
:Unique ret -- returns a unique string based on a date-time-stamp, YYYYMMDDhhmmsscc
:: -- ret [out,opt] - unique string
:$created 20060101 :$changed 20080219 :$categories StringOperation,DateAndTime
:$source http://www.dostips.com
SETLOCAL
for /f "skip=1 tokens=2-4 delims=(-)" %%a in ('"echo.|date"') do (
for /f "tokens=1-3 delims=/.- " %%A in ("%date:* =%") do (
set %%a=%%A&set %%b=%%B&set %%c=%%C))
set /a "yy=10000%yy% %%10000,mm=100%mm% %% 100,dd=100%dd% %% 100"
for /f "tokens=1-4 delims=:. " %%A in ("%time: =0%") do @set UNIQUE=%yy%%mm%%dd%%%A%%B%%C%%D
ENDLOCAL & IF "%~1" NEQ "" (SET %~1=%UNIQUE%) ELSE echo.%UNIQUE%
EXIT /b