Simple batch Cryptography: howto crypt / decrypt ROT13:

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: Simple batch Cryptography: howto crypt / decrypt ROT13:

#16 Post by jeb » 08 Aug 2010 14:50

aGerman wrote:As you can see I escaped the brackets too, but no success.
Any ideas?

Yes. It is the ampersand, it is active because the escape for second quote isn't working.
(I suppose it is not neccessary to escape the brackets)

So the command is splitting
set "newstring=^" & ("

set "newstring=^"
(" - this one fails
It can be solve the same way like the next ...

jeb wrote:I believe there is no simple, clean solution.

@myself: The solution is clean and simple :)

Using mixed EnabledDelayedExpansion and DisabledDelayedExpansion

Code: Select all

:: process file
setlocal DisableDelayedExpansion
for /f "tokens=1* delims=:" %%a in ('findstr /n . "example.txt"') do (
  set "string=%%b"
  call :procLine
)

pause
goto :eof

:: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:procLine
setlocal EnableDelayedExpansion
set "newstring="

set "countstring=!string:"=^"!"

set "countstring=!countstring:^=^^!"
set "countstring=!countstring:<=^<!"
set "countstring=!countstring:>=^>!"
set "countstring=!countstring:|=^|!"
set "countstring=!countstring:&=^&!"
setlocal DisableDelayedExpansion
echo endecho=%countstring%
endlocal
goto :eof

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Simple batch Cryptography: howto crypt / decrypt ROT13:

#17 Post by aGerman » 08 Aug 2010 15:03

jeb wrote:Yes. It is the ampersand, it is active because the escape for second quote isn't working.
(I suppose it is not neccessary to escape the brackets)

Yes, I saw this too. I've no idea how I could solve it :cry:

jeb wrote:Using mixed EnabledDelayedExpansion and DisabledDelayedExpansion

I have tried to avoid that. I wasn't sure about exclamation marks into the string.

Regards
aGerman

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Simple batch Cryptography: howto crypt / decrypt ROT13:

#18 Post by aGerman » 09 Aug 2010 00:19

jeb

Thanks for pointing EnableDelayedExpansion, this was the key.
I had some problems to work whith and to figure out what and how I have to escape. Finaly lines beginning with a colon didn't work. But now we have a real chance it could work for each character and each combination.

Code: Select all

@echo off &setlocal
:: *** capitals and smalls space separated
set "capitals=A B C D E F G H I L K L M N O P Q R S T U V W X Y Z"
set "smalls=a b c d e f g h i j k l m n o p q r s t u v w x y z"

:: *** iterate over %capitals% to create new variables
::      1st format: %C_A%=0, %C_B%=1, ... %C_Z%=25
::      2nd format: %C_0%=A, %C_2%=B, ... %C_25%=Z
set /a n=0
for %%a in (%capitals%) do (
  call set "C_%%a=%%n%%"
  call set "C_%%n%%=%%a"
  set /a n+=1
)

:: *** the same procedure with smalls: %S_a%=0 etc. and %S_0%=a etc.
set /a n=0
for %%a in (%smalls%) do (
  call set "S_%%a=%%n%%"
  call set "S_%%n%%=%%a"
  set /a n+=1
)

:: *** process file line by line and find string length -1
set /a n=0
for /f "tokens=* delims=0123456789" %%a in ('findstr /n "^" "example.txt"') do (
  set "string=%%a"
  >%temp%\len.tmp (call more +%%n%% "example.txt"|findstr /n "^"|findstr /b /c:"1:")
  for %%i in (%temp%\len.tmp) do set /a len=%%~zi-5
  del %temp%\len.tmp
  call :procLine
  set /a n+=1
)

pause
goto :eof

:: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:procLine
set "newstring="
setlocal EnableDelayedExpansion

:: *** output before ROT13
set "string=!string:~1!"
echo\before: !string!

:: *** iterate over the string to get character by character
for /l %%i in (0,1,%len%) do (
  set "char=!string:~%%i,1!"
  call :procChar
)
endlocal &set "newstring=%newstring%"

:: *** output after ROT13
echo\after:  %newstring%
echo\
goto :eof
endlocal

:: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:procChar
:: *** escape special characters
set "char=!char:^=^^!"
set "char=!char:&=^&!"
set "char=!char:<=^<!"
set "char=!char:>=^>!"
set "char=!char:|=^|!"

:: *** look for caps
echo\!char!|findstr "%capitals%">nul &&(
  REM *** find the number of the capital
  set "num=!C_%char%!"
  REM *** add 13
  set /a num+=13
  REM *** modulo 26 (calculate the remainder of the division by 26)
  set /a num=num%%26
  REM *** find the new character using the calculated remainder
  call set "char=%%C_!num!%%"
)

:: *** look for small letters and do the same like for caps
echo\!char!|findstr "%smalls%">nul &&(
  call set "num=!S_%char%!"
  set /a num+=13
  set /a num=num%%26
  call set "char=%%S_!num!%%"
)

:: *** append the character to the new string
set "newstring=!newstring!!char!"

goto :eof


example.txt

Code: Select all

UEME_RUNPATH:C:\Program Files\myProggy\
&()[]{}^=;!'+,`~-_><|*?%$/.@"#0123
"&()[]{}^=;!'+,`~-_><|*?%$/.@"#0123
12>345^6"78^9a>b

  >%temp%\len.tmp (call more +%%n%% "example.txt"|findstr /n "^"|findstr /b /c:"1:")

:procChar
:: *** escape special characters
set "char=!char:^=^^!"
set "char=!char:&=^&!"
set "char=!char:<=^<!"
set "char=!char:>=^>!"
set "char=!char:|=^|!"

:: *** look for small letters and do the same like for caps
echo\!char!|findstr "%smalls%">nul &&(
  call set "num=!S_%char%!"
  set /a num+=13
  set /a num=num%%26
  call set "char=%%S_!num!%%"
)

Thanks jeb, again I learned a lot.

@ByteAnlyser
Sorry for the long response, but sometimes such things are bugging me :wink: .

Regards
aGerman

ByteAnalyser
Posts: 17
Joined: 16 Jul 2010 20:05

Re: Simple batch Cryptography: howto crypt / decrypt ROT13:

#19 Post by ByteAnalyser » 09 Aug 2010 08:24

aGerman wrote:Thanks jeb, again I learned a lot.

@ByteAnlyser
Sorry for the long response, but sometimes such things are bugging me :wink: .

o_0 what can I say... You are both amazing and in my Guru-Respect-List, really. I appreciate a lot your job and all responses in other threads...

@jeb
Great!!!

@aGerman
Never worry about long responses, the important thing is always what comes in the end. And I'm really glad you learned something new w/ my problem :)

Best and Sincerely Regards
ByteAnalyser

orange_batch
Expert
Posts: 442
Joined: 01 Aug 2010 17:13
Location: Canadian Pacific
Contact:

Re: Simple batch Cryptography: howto crypt / decrypt ROT13:

#20 Post by orange_batch » 15 Aug 2010 17:47

Ok I don't know what you guys have done exactly, I'm not going to read it all, but this is my solution. This will be my first encryptor, I wrote this based on a concatenator I wrote yesterday for extracting in order, all numbers within a string (with some other features but it's irrelevant).

If this is just for file path strings, you will have no problems. Otherwise,

Caveats (these are typical to DOS):

1. In a variable, ! needs to be escaped ^!, % needs to be escaped %%.
-If you enter a variable with /p, or text file with for etc, they will be escaped automatically of course.

2. " will cause a failure if they happen to expose a special character to the interpreter, outside of a string context.
-In this case, special characters are escaped as follows: ^^^^ , ^^^! , ^^^& , %%
-Always fails: < > | (redirection characters)

Notes:
-This could easily be turned into a function/subroutine but I was lazy, it's just in-order as it is.
-I was also lazy and predominantly used ! instead of % for variable expansion.

Code: Select all

@echo off&setlocal enabledelayedexpansion

set "input=UEME_RUNPATH:C:\Program Files\myProggy\"

:: Set character conversion maps.
set "upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ"
set "upmap=NOPQRSTUVWXYZABCDEFGHIJKLM"
set "lomap=nopqrstuvwxyzabcdefghijklm"

:: Sets temp string that is nibbled at. Prepares exclamation marks.
set "step=%input:!=^!%"

:: Checks character by character. First checks if letter, then checks case.
:: If not a letter, appends current character.
:rotloop
if defined step (
    set "isletter=false"
    for /l %%x in (0,1,25) do (
        if /i "!step:~0,1!"=="!upper:~%%x,1!" (
            if "!step:~0,1!"=="!upper:~%%x,1!" (
                set "out=!out!!upmap:~%%x,1!"
            ) else (
                set "out=!out!!lomap:~%%x,1!"
            )
            set "isletter=true"
        )
    )
    if "!isletter!"=="false" (
        set "out=!out!!step:~0,1!"
    )
    set "step=!step:~1!"
    goto rotloop
)

echo:
echo:  Your input string:  "!input!"
echo:
echo:  Your output string: "!out!"
echo:
echo:  Match test string:  "HRZR_EHACNGU:P:\Cebtenz Svyrf\zlCebttl\"
echo:
pause


Is this what you guys were working towards? Please let me know.

I'm starting to think using ! instead of % predominantly is far more advantageous though situational.

FYI: This could also be modified to be a more formidable encryptor by using one set of compare maps, including spaces and punctuation, then randomizing all the characters on the conversion side.

orange_batch
Expert
Posts: 442
Joined: 01 Aug 2010 17:13
Location: Canadian Pacific
Contact:

Re: Simple batch Cryptography: howto crypt / decrypt ROT13:

#21 Post by orange_batch » 16 Aug 2010 01:50

As a follow-up, here is a more robust encryptor that I mentioned in the previous post. The same caveats apply, except under caveat 1, ^ also needs to be escaped ^^ in a variable (but again, not from user input/text file). Clearly it has something to do with the different process below.

A new caveat however, is when a string contains both ! and ^. The ^ is lost, and the encryption shifts (ie corrupts). Due to ! being way more common, I would recommend removing ^ from the maps.

To decrypt, simply switch the maps. You can re-encrypt something any number of times and decrypt it back the same number of times. This could actually become a decent encryptor if repeat encryption is combined with a custom shiftable conversion map, thus generating a key of sorts. Still, with a lot of work a human could read it by resolving each character manually since we're just swapping characters back and forth. This could further be solved by scrambling the results in a pattern.

Code: Select all

@echo off&setlocal enabledelayedexpansion

set /p "input=  Encrypt string:      "

:: Set character conversion maps.
set "chmap1=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 `~^!@#$%%^^&*()-_=+[{]}\;:',./?"
set "chmap2=Yu5?[D#1pyBa6iK`: k70nAW2.VPt%%d*+_MLcR)3qsS;F/,]ThIJCm've^!E=fZ4N-wb@O&$}\g{^^X(z~lj8HGo9rQxU"

:: Vertical unescaped character-to-character reference.
:: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 `~!@#$%^&*()-_=+[{]}\;:',./?"
:: Yu5?[D#1pyBa6iK`: k70nAW2.VPt%d*+_MLcR)3qsS;F/,]ThIJCm've!E=fZ4N-wb@O&$}\g{^X(z~lj8HGo9rQxU"

:: Sets temp string that is nibbled at. Prepares exclamation marks.
set "step=%input:!=^!%"

:: Checks character by character. 90 is 1 less than characters in character map (0-indexed).
:encryptloop
if defined step (
    for /l %%x in (0,1,90) do (
        if "!step:~0,1!"=="!chmap1:~%%x,1!" (
            set "out=!out!!chmap2:~%%x,1!"
        )
    )
    set "step=!step:~1!"
    goto encryptloop
)
echo:
echo:  Your input string:  "!input!"
echo:
echo:  Your output string: "!out!"
echo:
pause
echo:!out!>encryptstring.txt
notepad encryptstring.txt
del encryptstring.txt


Here is the script I wrote to generate a repeatedly re-randomized encryption map and prepare ! ^ and % so you can simply paste it into the encryptor:

Code: Select all

@echo off&setlocal enabledelayedexpansion

:: String to randomize.
set "input=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 `~^!@#$%%^^&*()-_=+[{]}\;:',./?"

:: Number of times to randomize result.
set repeat=10

:: Randomizer. 91 is the number of characters (unescaped) in input string.
for /l %%x in (1,1,%repeat%) do (
set out=
for /l %%y in (91,-1,1) do (
    set /a randpos=!random!%%%%y
    set /a randafter=!randpos!+1
    call set "out=%%out%%%%input:~!randpos!,1%%"
    call set "input=%%input:~0,!randpos!%%%%input:~!randafter!%%"
)
set "input=!out!"
echo:  Out: "!out!"
echo:
)
:: Prepare output for encryptor.
set "out=!out:^=^^^^!"
set "out=%out:!=^^^!%"
set "out=!out:%%=%%%%!"
echo:  Out: "!out!"
echo:
pause
echo:!out!>randomstring.txt
notepad randomstring.txt
del randomstring.txt


For the record, I know next to jack squat about encryption, I just had these ideas.

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Simple batch Cryptography: howto crypt / decrypt ROT13:

#22 Post by aGerman » 16 Aug 2010 12:11

Try your codes with the lines I posted above (example.txt).

Regards
aGerman

orange_batch
Expert
Posts: 442
Joined: 01 Aug 2010 17:13
Location: Canadian Pacific
Contact:

Re: Simple batch Cryptography: howto crypt / decrypt ROT13:

#23 Post by orange_batch » 16 Aug 2010 21:28

It works but the caveats apply. Upon closer examination, I think a function miiight be able to interpret when " occurs and escape the necessary characters, resolving this DOS problem... unless the problem defeats the solution as well, lol. It would also have to compensate ^ based on presence of !... I need to do tests.

Green = characters within string.
Blue = characters outside string (interpreted).
Red = characters causing effect (quotes, etc).

&()[]{}^=;!'+,`~-_><|*?%$/.@"#0123
Caret ^ is lost due to presence of !, unless escaped ^^.

"&()[]{}^=;!'+,`~-_><|*?%$/.@"#0123
Fails due to special characters being interpreted.

12>345^6"78^9a>b
Caret ^ is lost and > causes string to break (redirect to file "b"), unless escaped ^^ and ^>.

>%temp%\len.tmp (call more +%%n%% "example.txt"|findstr /n "^"|findstr /b /c:"1:")
Caret ^ is lost if not escaped ^^.


Ok, I did tests to determine which characters cause failures and how.

Code: Select all

Outside string:

^ to ^^
& to ^&
| to ^|
< to ^<
> to ^>
! to ^!

If text contains ! anywhere,

Within string: ^ needs to be ^^

Not in string: ^ needs to be ^^^^

" determines string or interpreted.


Now I will try to create a contextual escape function. I believe this will need to be done as a subroutine and not the nibble method, since the nibble method exposes the remainder of the string on each pass.

orange_batch
Expert
Posts: 442
Joined: 01 Aug 2010 17:13
Location: Canadian Pacific
Contact:

Re: Simple batch Cryptography: howto crypt / decrypt ROT13:

#24 Post by orange_batch » 17 Aug 2010 00:00

Damn... I wrote this code, not cleaned up yet, and upon testing I forgot, it's not possible to compare quotes is it? I can't test further if I can't lol. This is what I meant about DOS limitation... Edit: Maybe I can use string substitution to replace quotes with a rarely if ever used ANSI character, that way I can compare it then revert it. I need to sleep now though.

This is how to create a clean variable catalog of a text file at least, and an example of DOS "while" and sub-"while" loops...

Updated:

Code: Select all

setlocal enabledelayedexpansion

for /f "delims=] tokens=1*" %%x in ('type text.txt^|find /v /n ""') do (
set /a lines+=1
set "line!lines!=%%y"
)

set quote="
:nextline
set /a currentline+=1
if %currentline% GTR %lines% goto end
if not defined line%currentline% goto nextline
set currentletter=-1
set stringmode=1
set exclaim=0

:: Check if line contains exclamation mark. The former fails with certain characters.
::echo:"line!currentline!"|find /v "!">nul || set exclaim=1

:exclaimfind
set /a currentletter+=1
set "workingletter=!line%currentline%:~%currentletter%,1!"
if "!workingletter!"=="" goto exclaimbreak
if "!workingletter!"=="!quote!" goto exclaimfind
if "%workingletter%"=="!" (set exclaim=1&goto exclaimbreak) else goto exclaimfind
:exclaimbreak
set currentletter=-1

:nextletter
set /a currentletter+=1
set "workingletter=!line%currentline%:~%currentletter%,1!"
if "!workingletter!"=="" goto nextline

:: If letter is a quotation mark, toggle stringmode.
if "!workingletter!"=="!quote!" (
if %stringmode%==1 (set stringmode=0) else set stringmode=1
set "line%currentline%escaped=!line%currentline%escaped!!workingletter!" & goto nextletter
)

:: Process characters if not in stringmode. Process carets if in exclamation mode. Gotos cut down on CPU load.

if %stringmode%==1 (

if "!workingletter!"=="^" (
if %exclaim%==1 set "line%currentline%escaped=!line%currentline%escaped!^^" & goto nextletter
)
set "line%currentline%escaped=!line%currentline%escaped!!workingletter!" & goto nextletter

) else (

if "%workingletter%"=="!" set "line%currentline%escaped=!line%currentline%escaped!^^^!" & goto nextletter
if "!workingletter!"=="&" set "line%currentline%escaped=!line%currentline%escaped!^^&" & goto nextletter
if "!workingletter!"=="<" set "line%currentline%escaped=!line%currentline%escaped!^^<" & goto nextletter
if "!workingletter!"==">" set "line%currentline%escaped=!line%currentline%escaped!^^>" & goto nextletter
if "!workingletter!"=="|" set "line%currentline%escaped=!line%currentline%escaped!^^|" & goto nextletter
if "!workingletter!"=="^" (
if %exclaim%==0 (
set "line%currentline%escaped=!line%currentline%escaped!^^^^" & goto nextletter
) else (
set "line%currentline%escaped=!line%currentline%escaped!^^^^^^^^" & goto nextletter
)
)
set "line%currentline%escaped=!line%currentline%escaped!!workingletter!" & goto nextletter

)

:end
set line
exit /b
Last edited by orange_batch on 18 Aug 2010 04:11, edited 1 time in total.

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Simple batch Cryptography: howto crypt / decrypt ROT13:

#25 Post by aGerman » 17 Aug 2010 11:26

:lol: Good exercise for batch coding, isn't it?

Compare quotes is possible. Have a look at my latest code... I used FINDSTR. This is some slower but works. I did never replace quotes with a different character. This is not "clean" enough for my own demands :wink:

Regards
aGerman

orange_batch
Expert
Posts: 442
Joined: 01 Aug 2010 17:13
Location: Canadian Pacific
Contact:

Re: Simple batch Cryptography: howto crypt / decrypt ROT13:

#26 Post by orange_batch » 17 Aug 2010 15:12

It's funny, I think of solutions during my sleep. I thought of that one too... I'll see what I can do.

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: Simple batch Cryptography: howto crypt / decrypt ROT13:

#27 Post by jeb » 17 Aug 2010 16:01

In my opinion, the only way to process the lines of a file, is to disable the DelayedExpansion, because with EnableDelayedExpansion you lose the exlamation marks.

That's because the interpreer phase of !var! is after the phase of %%X.
But then you have to Enable the DelayedExpansion, because the only way of replace and escape characters is possible with the exlamation marks syntax, because it is the last interpreter phase, so the rest of the string will be unchanged, with %var% syntax you got many problems.
(The interpreter phase of doubling the ^^ is "after" the !var! phase, but only the rest of the line is interpreted, not the content of !var! itself)
Calling a subroutine to replace the charactes is only possible, if you use a "global" variable, but not with use a parameter, like call :myReplace %%X, because then the "call" will start many interpreter phases for the content of %%X.

So the code could be:

Code: Select all

for /f "delims=" %%X in (example.txt) DO (
   setlocal DisableDelayedExpansion
   set var=%%X
   setlocal EnableDelayedExpansion
   set "var=!var:^=^^!"
   set "var=!var:"=^^^"!"
   rem escape > < & and so on here


aGerman wrote:Compare quotes is possible. Have a look at my latest code... I used FINDSTR

Hmm, I can't see the problem at all :)

You can compare quotes if you use !var!, the quotes are not interpreted anymore at this phase.

Code: Select all

@echo off
setlocal DisableDelayedExpansion
set quote1=^"
set quote2=^"^"
for /f "delims=" %%X in (example.txt) DO (
   setlocal DisableDelayedExpansion
   set var=%%X
    setlocal EnableDelayedExpansion
   echo The line is "!var!"
   if [!quote1!]==[!var!] (
     echo found a single quote
     )
   if [!quote2!]==[!var!] (
     echo found two quotes
     )
)


hope it helps
jeb

orange_batch
Expert
Posts: 442
Joined: 01 Aug 2010 17:13
Location: Canadian Pacific
Contact:

Re: Simple batch Cryptography: howto crypt / decrypt ROT13:

#28 Post by orange_batch » 17 Aug 2010 23:53

Cool, I got my script working, to a degree. However, the problems continue to compound eachother. I'm not sure if I care to work more on this...

Honestly, I think DOS just isn't a reliable text processor if your file contains special characters.

So, I might leave it at that or see if I can't do more, but I have my own project to get back to! :)

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Simple batch Cryptography: howto crypt / decrypt ROT13:

#29 Post by dbenham » 25 Apr 2011 19:27

:D I've managed to implement an efficient "bullet proof" ROT13 cipher routine using techniques developed in this thread: http://www.dostips.com/forum/viewtopic.php?f=3&t=1733.

Initially I created a modified version of :hex2str that shifted the hex numbers corresponding to English alpha characters before converting to the character. Encoding a string required a call to :str2hex followed by a call to the modified :hex2str. But I decided to improve performance by doing the complete process in one pass.

I've created the function :rot13 to encrypt/decrypt a string within a variable, and :rot13F to encrypt/decrypt the contents of a text file. The new functions are available in CharLib.bat found here: http://sites.google.com/site/dbenhamfiles/ (The file needs to be renamed after download). I would post the code here but some characters are corrupted when I paste the code here.

Function :rot13F is able to encode or decode a 26K file in around 30 seconds on my Vista machine at work.

It should be relatively easy to develop any number of ciphers using the techniques in CharLib.bat. Another possibility is development of a function to compute a checksum for a string and/or a file.

Dave Benham

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Simple batch Cryptography: howto crypt / decrypt ROT13:

#30 Post by dbenham » 26 Apr 2011 12:07

I optimized the functions from my prior post to be fully self contained (no dependencies) and to use a more efficient transformation map. An additional benefit is I can now post the code here without corruption.

Function :rot13F is now able to process a 26kb file in 9 seconds. Not bad for musty old DOS! :D
(Yes I know any number of "real" programming languages could do the same in the blink of an eye :wink: )

The functions should support the complete extended ASCII character set, except for the following:
0x00 <NUL>
0x0A <LF>
0x0D <CR>

I believe :rot13F may choke if the input file contains 0x1A <Ctrl-Z> .

Support for <LF> and <CR> could be added to :rot13, but I didn't think it was worth it.

Here is :rot13 to encrypt/decrypt a string within a variable:

Code: Select all

:rot13   StrVar [RtnVar]           -- Applies the ROT13 cipher to a string
::
::  Applies the simple "rotate alphabet 13 places" cipher to the string
::  contained within variable StrVar.
::
::  Sets RtnVar=result
::  or displays result if RtnVar not specified
::
  setlocal
  set "NotDelayedFlag=!"
  setlocal enableDelayedExpansion
  set upper=#AAN#BBO#CCP#DDQ#EER#FFS#GGT#HHU#IIV#JJW#KKX#LLY#MMZ#NNA#OOB#PPC#QQD#RRE#SSF#TTG#UUH#VVI#WWJ#XXK#YYL#ZZM#
  set lower=#aan#bbo#ccp#ddq#eer#ffs#ggt#hhu#iiv#jjw#kkx#lly#mmz#nna#oob#ppc#qqd#rre#ssf#ttg#uuh#vvi#wwj#xxk#yyl#zzm#
  set "str=A!%~1!"
  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"
  )
  set /a len-=1
  set rtn=
  for /l %%n in (0,1,!len!) do (
    set "c=!%~1:~%%n,1!"
    if "!c!" geq "a" if "!c!" leq "Z" (
      for /f "delims=" %%c in ("!c!") do (
        set "test=!upper:*#%%c=!"
        if "!test:~0,1!"=="!c!" (
          set c=!test:~1,1!
        ) else (
          set "test=!lower:*#%%c=!"
          if "!test:~0,1!"=="!c!" set c=!test:~1,1!
        )
      )
    )
    set "rtn=!rtn!!c!"
  )
  if "%~2"=="" (
    echo:!rtn!
    exit /b
  )
  :: The remainder is "Jeb magic" used to transfer the rtn value across the function endlocal barrier
  if defined rtn (
    set "rtn=!rtn:%%=%%~A!"
    set "rtn=!rtn:"=%%~B!"
    if not defined NotDelayedFlag set "rtn=!rtn:^=^^^^!"
  )
  if defined rtn if not defined NotDelayedFlag set "rtn=%rtn:!=^^^!%" !
  set "replace=%% """"
  for /f "tokens=1,2" %%A in ("!replace!") do (
    endlocal
    endlocal
    set "%~2=%rtn%" !
  )
exit /b

The function can be called while delayed expansion is enabled or disabled!


Here is :rot13F to encrypt/decrypt contents of a file:

Code: Select all

:rot13F  InFile [OutFile]          -- Applies the ROT13 cipher to a file
::
::  Applies the simple "rotate alphabet 13 places" cipher to the contents
::  of file InFile.
::
::  Writes the results to file OutFile
::  or displays the results if OutFile is not specified
::
::  OutFile should not contain ^ or ! in the name.
::
::  Warning - OutFile must not be the same as InFile. The file will be
::            deleted if InFile and OutFile are the same.
::
  setlocal disableDelayedExpansion
  set "outFile="
  if not "%~2"=="" (
    set outFile=^>^>"%~2"
    if exist "%~2" del "%~2"
  )
  set upper=#AAN#BBO#CCP#DDQ#EER#FFS#GGT#HHU#IIV#JJW#KKX#LLY#MMZ#NNA#OOB#PPC#QQD#RRE#SSF#TTG#UUH#VVI#WWJ#XXK#YYL#ZZM#
  set lower=#aan#bbo#ccp#ddq#eer#ffs#ggt#hhu#iiv#jjw#kkx#lly#mmz#nna#oob#ppc#qqd#rre#ssf#ttg#uuh#vvi#wwj#xxk#yyl#zzm#
  for /f "skip=2 tokens=1,* delims=[]" %%a in ('find /v /n "" %1') do (
    set "ln=%%b"
    setlocal enableDelayedExpansion
    set "str=A!ln!"
    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"
    )
    set /a len-=1
    set rtn=
    for /l %%n in (0,1,!len!) do (
      set "c=!ln:~%%n,1!"
      if "!c!" geq "a" if "!c!" leq "Z" (
        for /f "delims=" %%c in ("!c!") do (
          set "test=!upper:*#%%c=!"
          if "!test:~0,1!"=="!c!" (
            set c=!test:~1,1!
          ) else (
            set "test=!lower:*#%%c=!"
            if "!test:~0,1!"=="!c!" set c=!test:~1,1!
          )
        )
      )
      set "rtn=!rtn!!c!"
    )
    echo:!rtn!%outFile%
    endlocal
  )
exit /b

:rot13F is actually smaller than :rot13 because it doesn't need to transport the result to a variable across an endlocal barrier.

Dave Benham

Post Reply