how to display password in asterisk

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Posts: 91
Joined: 02 Oct 2012 17:21

Re: how to display password in asterisk

#16 Post by carlsomo » 10 Jul 2013 00:13

Here is an example of asking for a user name and password and encrypting the results into a file that can
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 @
::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 for inspiration,  Carl

@echo off&setlocal DisableDelayedExpansion
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
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
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

::***||      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
  SetLocal DisableDelayedExpansion
  For /F %%# In ('"Prompt;$H&For %%# in (1) Do Rem"') Do Set "BS=%%#"
  SetLocal EnableDelayedExpansion
  if "%~1"=="" EndLocal&EndLocal&exit/b
  if /i "/n" equ "%~1" (
  ) 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

:: 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
  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"

  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
     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 (
           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_

: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
  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 (
      set "%~1=%var%" !
      @echo off
  )&exit /b 0
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
  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%%

:CharLib.bat Routines from dbenham - thanks
call :%*

: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
  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"=="" (
    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 (
      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
    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"
    IF "%~2" NEQ "" SET /a %~2=%len%

:_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.
  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 (
    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.
  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 (
    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%
    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
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%

Post Reply