Rot13 and Rot5 implementation using Windows Batch


Rot13 and Rot5 are two ASCII rotation scheme that are made for alphabetic and digits respectively. The Rot13, namely, rotates the letter by 13 places, ‘A’ to ‘N’, ‘B’ to ‘M’ and so on. The Rot5, rotates the digits: ‘0’ to ‘5’, ‘1’ to ‘6’ and so on.

Why 13 and 5? because there are 26 alphetical letters and 10 digits, rotation half way gives the following two important characteristics.

t = R13(R13(t)) and t = R5(R5(t))

The Rot13 and Rot5 can be combined to encypt a given text string e.g. using this can easily protect the resource string in executable files from modification. The delphi implementation is shown below.

// Rot13+Rot5
function Rot13(const s: string): string;
const
  rot13a: array ['A'..'Z'] of Char = 'NOPQRSTUVWXYZABCDEFGHIJKLM';
  rot13b: array ['a'..'z'] of Char = 'nopqrstuvwxyzabcdefghijklm';
  rot5: array ['0'..'9'] of Char = '5678901234';
var
  i: integer;
begin
  Result := s;
  for i := 1 to Length(s) do
  begin
    if (s[i] in ['A'..'Z']) then
    begin
      Result[i] := rot13a[s[i]];
    end
    else
    if (s[i] in ['a'..'z']) then
    begin
      Result[i] := rot13b[s[i]];
    end
    else
    if (s[i] in ['0'..'9']) then
    begin
      Result[i] := rot5[s[i]];  // rot5
    end;
  end;
end;

Two lookup tables are made and this yields a straightforward implementation. Without tables, the rotation can also be computed simply using ord that returns the ASCII of a given character.

IF J >= 65 AND J <= 90 THEN
	J = ((J - 52) MOD 26) + 65
ELSEIF J >= 97 AND J <= 122 THEN
	J = ((J - 84) MOD 26) + 97
END IF

Rot13 + Rot5 is often called Rot18. There is an important variant that obfuscates the text over a large ASCII table. The Rot47 rotates 47, for example, ‘A’ mapped to ‘p’ and ‘a’ mapped to ‘2’. 

The Pascal version of Rot47 can be implemented in the following simple function.

function Rot47(const s: string): string;
var
  i, j: integer;
begin
  Result := s;
  for i := 1 to Length(s) do
  begin
    j := Ord(s[i]);
    if (j in [33..126]) then
    begin
      Result[i] := Chr(33 + ((j + 14) mod 94));
    end;
  end;
end;

Both can be implemented easily using ‘tr’ command at Linux SHELL.

$ # Map upper case A-Z to N-ZA-M and lower case a-z to n-za-m
$ echo "The Quick Brown Fox Jumps Over The Lazy Dog" | tr 'A-Za-z' 'N-ZA-Mn-za-m'
Gur Dhvpx Oebja Sbk Whzcf Bire Gur Ynml Qbt
$ tr 'A-Za-z' 'N-ZA-Mn-za-m' <<<"The Quick Brown Fox Jumps Over The Lazy Dog"
Gur Dhvpx Oebja Sbk Whzcf Bire Gur Ynml Qbt
$ echo "The Quick Brown Fox Jumps Over The Lazy Dog" | tr '\!-~' 'P-~\!-O'
%96 "F:4< qC@H? u@I yF>AD ~G6C %96 {2KJ s@8
$ tr '\!-~' 'P-~\!-O' <<<"The Quick Brown Fox Jumps Over The Lazy Dog"
%96 "F:4< qC@H? u@I yF>AD ~G6C %96 {2KJ s@8

It is obvious that Rot47 gives a better obfuscation than Rot18 because Rot47 applies to a larger look-up table.

With windows batch programming, a Rot18 implementation becomes interesting, because there is no inherent support of chr and ord functions that converts ASCII to character and vice versa. However, since there are only 26 + 26 + 10 = 62 possible cases, this can be solved by 62 if-s.

The batch script processes the given command line parameters using %*, and at the begining, the length of the text is computed. It rotates each character one by one using for /l loop. The multiple if-s translate the text to its rotated ones.

@echo off
:: rot13.bat
:: [email protected]
:: https://helloacm.com
:: 16-Sept-2012

setlocal enableextensions enabledelayedexpansion 
if [%1] neq [] goto start

echo Rot13 ^& Rot5
echo Usage: %0 text

goto :end

:start
	set _len=0
	set _str=%*

	:: Get the length of the sentence
	set _subs=%_str%

:loop
	if not defined _subs goto :result

	::remove the first char
	set _subs=%_subs:~1%
	set /a _len+=1
	goto loop	

:result
	set /a _len-=1
	(set s=)
	for /l %%g in (0,1,%_len%) do (
		call :build %%g
	)

	echo %s%

	goto :end

:build
	:: get the next character
	call set _digit=%%_str:~%1,1%%%
	:: rot13 ^& rot5
	if "!_digit!"=="a" (
		(set s=!s!n)
	) else if "!_digit!"=="b" (
		(set s=!s!o)
	) else if "!_digit!"=="c" (
		(set s=!s!p)
	) else if "!_digit!"=="d" (
		(set s=!s!q)
	) else if "!_digit!"=="e" (
		(set s=!s!r)
	) else if "!_digit!"=="f" (
		(set s=!s!s)
	) else if "!_digit!"=="g" (
		(set s=!s!t)
	) else if "!_digit!"=="h" (
		(set s=!s!u)
	) else if "!_digit!"=="i" (
		(set s=!s!v)
	) else if "!_digit!"=="j" (
		(set s=!s!w)
	) else if "!_digit!"=="k" (
		(set s=!s!x)
	) else if "!_digit!"=="l" (
		(set s=!s!y)
	) else if "!_digit!"=="m" (
		(set s=!s!z)
	) else if "!_digit!"=="n" (
		(set s=!s!a)
	) else if "!_digit!"=="o" (
		(set s=!s!b)
	) else if "!_digit!"=="p" (
		(set s=!s!c)
	) else if "!_digit!"=="q" (
		(set s=!s!d)
	) else if "!_digit!"=="r" (
		(set s=!s!e)
	) else if "!_digit!"=="s" (
		(set s=!s!f)
	) else if "!_digit!"=="t" (
		(set s=!s!g)
	) else if "!_digit!"=="u" (
		(set s=!s!h)
	) else if "!_digit!"=="v" (
		(set s=!s!i)
	) else if "!_digit!"=="w" (
		(set s=!s!j)
	) else if "!_digit!"=="x" (
		(set s=!s!k)
	) else if "!_digit!"=="y" (
		(set s=!s!l)
	) else if "!_digit!"=="z" (
		(set s=!s!m)
	) else if "!_digit!"=="A" (
		(set s=!s!N)
	) else if "!_digit!"=="B" (
		(set s=!s!O)
	) else if "!_digit!"=="C" (
		(set s=!s!P)
	) else if "!_digit!"=="D" (
		(set s=!s!Q)
	) else if "!_digit!"=="E" (
		(set s=!s!R)
	) else if "!_digit!"=="F" (
		(set s=!s!S)
	) else if "!_digit!"=="G" (
		(set s=!s!T)
	) else if "!_digit!"=="H" (
		(set s=!s!U)
	) else if "!_digit!"=="I" (
		(set s=!s!V)
	) else if "!_digit!"=="J" (
		(set s=!s!W)
	) else if "!_digit!"=="K" (
		(set s=!s!X)
	) else if "!_digit!"=="L" (
		(set s=!s!U)
	) else if "!_digit!"=="M" (
		(set s=!s!Z)
	) else if "!_digit!"=="N" (
		(set s=!s!A)
	) else if "!_digit!"=="O" (
		(set s=!s!B)
	) else if "!_digit!"=="P" (
		(set s=!s!C)
	) else if "!_digit!"=="Q" (
		(set s=!s!D)
	) else if "!_digit!"=="R" (
		(set s=!s!E)
	) else if "!_digit!"=="S" (
		(set s=!s!F)
	) else if "!_digit!"=="T" (
		(set s=!s!G)
	) else if "!_digit!"=="U" (
		(set s=!s!H)
	) else if "!_digit!"=="V" (
		(set s=!s!I)
	) else if "!_digit!"=="W" (
		(set s=!s!J)
	) else if "!_digit!"=="X" (
		(set s=!s!K)
	) else if "!_digit!"=="Y" (
		(set s=!s!L)
	) else if "!_digit!"=="Z" (
		(set s=!s!M)
	) else if "!_digit!"=="0" (
		(set s=!s!5)
	) else if "!_digit!"=="1" (
		(set s=!s!6)
	) else if "!_digit!"=="2" (
		(set s=!s!7)
	) else if "!_digit!"=="3" (
		(set s=!s!8)
	) else if "!_digit!"=="4" (
		(set s=!s!9)
	) else if "!_digit!"=="5" (
		(set s=!s!0)
	) else if "!_digit!"=="6" (
		(set s=!s!1)
	) else if "!_digit!"=="7" (
		(set s=!s!2)
	) else if "!_digit!"=="8" (
		(set s=!s!3)
	) else if "!_digit!"=="9" (
		(set s=!s!4)
	) else (
		(set s=!s!!_digit!)
	) 
:end
endlocal

The source can be found at [github]. It is also noted that this batch script does not support pipeline command yet [improvements here]. For example, if you want something like ‘rot13.bat text | print.bat’, it will complain ‘The process tried to write to a nonexistent pipe’.

The shortest implementation found [here] in C, using 64-bytes only.

1
main(a){while(a=~getchar())putchar(~a-1/(~(a|32)/13*2-11)*13);}
main(a){while(a=~getchar())putchar(~a-1/(~(a|32)/13*2-11)*13);}

This does not use look-up tables but only mathematic integer computation based on ASCII.

rot Rot13 and Rot5 implementation using Windows Batch algorithms batch script beginner code code library delphi encryption implementation programming languages string tools / utilities windows windows command shell windows scripting host

–EOF (The Ultimate Computing & Technology Blog) —

GD Star Rating
loading...
1384 words
Last Post: Another Batch Utility: Reverse the Given Text
Next Post: Enable Pipelines in Windows Batch Programming

The Permanent URL is: Rot13 and Rot5 implementation using Windows Batch

Leave a Reply