Home
The home page for RotNN
Project Page
Contains more information, support, feedback, you name it.
README
Usage, examples, stuff.
Download
SourceForge
Feedback
Email me your thoughts.
[I have to apologize right off the bat here: I cannot write documentation for the life of me.]
  • You can run a test of rotNN.py by starting it from the command line.
    $ python rotNN.py
    This will fire up a whole slew of test cases demonstrating the different functions available from rotNN.py. These cases probably are the best source of information about this library. But, what the heck, here goes...

RotNN.py is a library that allows you to do a 'rotation' of ascii characters of any number that you want, provided it is less than or equal to the total number of available characters (26 for rotation, 94 for srotation and wrotation).

The usual use for something like this is known as rot13 (which is the default number for .rotation). Rot13 is an old way of obfuscating text so that it is both unreadable and easily unscrambled at the same time. You would want something like this in a USENET post that gives away a movie ending, for instance. By rot13-ing the text, you can keep it away from those who would rather not know and at the same time make it accessible to those would enjoy having things spoiled for them.

A quick demonstration...

You know, at the ending of the movie where Colonel Halpablatt is revealed to be both the Dark Undertaker, the Detective and Betty Sue's father at the same time?! Boy, was I surprised! And to think, by seeing this preview showing, I know all this stuff before it hits the general public!

Post this to a movie newsgroup and risk getting your house firebombed. However, if you would post something like this...

For my thoughts on the ending of ROCKY XXV, rot13 the following:
Lbh xabj, ng gur raqvat bs gur zbivr jurer Pbybary Unycnoyngg vf erirnyrq gb or obgu gur Qnex Haqregnxre, gur Qrgrpgvir naq Orggl Fhr'f sngure ng gur fnzr gvzr?! Obl, jnf V fhecevfrq! Naq gb guvax, ol frrvat guvf cerivrj fubjvat, V xabj nyy guvf fghss orsber vg uvgf gur trareny choyvp!

No one could say that you ruined it prematurely for them.

Now, rot13 may be the standard .rotation, but you can also do rotations by any amount that you want. Let's look at the usage...

rotnn.rotate (string [, option_number])
rotnn.unrotate (string [, optional_number])
rotnn.srotate (string [, optional_number])
rotnn.sunrotate (string [, optional_number])
rotnn.wrotate (string [, optional_number])
rotnn.wunrotate (string [, optional_number])

The optional number is the NN in rotNN. By default it's 13 for rotate and srotate and 47 for wrotate.

Why 47, you ask? Rot13 had a special property whereby you could decrypt a rot13-ed message by re-rot13-ing it. It's the same deal with wrotate. (But not with srotate! You always have to .sunrotate those!) A wrotate47 of a wrotate47-ed message will return you the same message. Love that symmetry.

The (s|w)unrotate functions are there for when you rotate by something other than the symmetrical numbers (13 and 47). I suppose one could do the math and figure out the next number that you would have to rotate by to return to the original text, but it's much easier to do an unrotate by the SAME number that you rotated with. A "rotnn.srotate(string, 42)" will be undone by a "rotnn.sunrotate(string, 42)".

And let me guess: "Why srotate and wrotate?". Rot13 originally only works upon A-Z and a-z. It leave punctuation, spacing and whatnot alone. Fine for some things, not fine for others. Srotate works upon the entire printable character set (at least for UNIX -- Use one of the others, YMMV), including punctuation and spaces. It leaves carriage returns and other unprintables alone. Wrotate does the same with a minor exception: it doesn't rotate spaces. What does this mean? Well, for one, if you have a file that contains quite a few spaces as delimiters (or other such stuff - Python source files, for another), srotating it is either messy or really obvious as to it's intent (or both). Wrotate works like a charm in this instance.

See the following examples for s and wrotate usage.

Rotnn.srotating (by 30) the LICENSE file gives us this...

t$12(.->PLOJ>d$!14 18>OWWW
a./81(&'3>FaG>OWWOJ>OWWW>d1$$>q.%36 1$>d.4-# 3(.-J>g-"L
SW>r$,/+$>n+ "$J>q4(3$>QQNJ>`.23.-J>k_>>NPOOOKOQNU>>sq_
c5$18.-$>(2>/$1,(33$#>3.>"./8> -#>#(231(!43$>5$1! 3(,>"./($2
.%>3'(2>+("$-2$>#."4,$-3J>!43>"' -&(-&>(3>(2>-.3> ++.6$#L

yr'(2>(2>3'$>%(123>1$+$ 2$#>5$12(.->.%>3'$>j$22$1>enjL>>g3> +2.>".4-32
> 2>3'$>24""$22.1>.%>3'$>els>j(!1 18>n4!+(">j("$-2$J>5$12(.->PJ>'$-"$
>3'$>5$12(.->-4,!$1>PLOL{

...and so on and so forth. Kewl, eh? Watch what wrotate does to the same file...

t%23)/. PLOJ d%"25!29 OWWW
a/092)'(4 FaG OWWOJ OWWW d2%% q/&47!2% d/5.$!4)/.J g.#L
SW r%-0,% n,!#%J q5)4% QQNJ `/34/.J k_  NPOOOKOQNU  sq_
c6%29/.% )3 0%2-)44%$ 4/ #/09 !.$ $)342)"54% 6%2"!4)- #/0)%3
/& 4()3 ,)#%.3% $/#5-%.4J "54 #(!.').' )4 )3 ./4 !,,/7%$L

yr()3 )3 4(% &)234 2%,%!3%$ 6%23)/. /& 4(% j%33%2 enjL  g4 !,3/ #/5.43
 !3 4(% 35##%33/2 /& 4(% els j)"2!29 n5",)# j)#%.3%J 6%23)/. PJ (%.#%
 4(% 6%23)/. .5-"%2 PLOL{

It's a little hard to see (Way to go Adam -- give 'em a cruddy example...), but wrotate retains the original spacing of the file - possibly a big clue to someone trying to guess what you did to it.

However, watch what happens when we srotate the rotnn source...

AAAAAAAAAAAAAAAAAAAAAAAA%*#4!.+56O#22'0&AI%*4I14&!%*#4ALA#/1706JJ
AAAAAAAAAAAAAAAA'.+(AIIZRN#/1706JA]^A14&!%*#4A]^AZQJ[
AAAAAAAAAAAAAAAAAAAAAAAA%*#4!.+56O#22'0&AI%*4IWVALAI#/1706ANAIZRANA14&!%*#4JJJJ
AAAAAAAAAAAAAAAA'.+(AIIRSTN#/1706JA]^A14&!%*#4A]^ARSSJ[
AAAAAAAAAAAAAAAAAAAAAAAA%*#4!.+56O#22'0&AI%*4IZXALAI#/1706ANAIRSTANA14&!%*#4JJJJ
AAAAAAAAAAAAAAAA'.5'[
AAAAAAAAAAAAAAAAAAAAAAAA%*#4!.+56O#22'0&AI%*4I14&!%*#4JJ

Ewww, look at those A's! Wouldn't take long for someone to figure out what's going on here. Let's wrotate it instead...

                        &+$5"/,67O$33(1' I&+5I25'"&+$5 L $02817JJ
                (/,) IIZRN$02817J ]^ 25'"&+$5 ]^ ZQJ[
                        &+$5"/,67O$33(1' I&+5IWV L I$02817 N IZR N 25'"&+$5JJJJ
                (/,) IIRSTN$02817J ]^ 25'"&+$5 ]^ RSSJ[
                        &+$5"/,67O$33(1' I&+5IZX L I$02817 N IRST N 25'"&+$5JJJJ
                (/6([
                        &+$5"/,67O$33(1' I&+5I25'"&+$5JJ

Ahh, much better. Without the A's giving away your rotation value, it's suddenly much harder to decrypt.

And a final caveat: (s|w)rotation isn't really that tough of encryption. If the NSA is coming after you, you'd be a fool to use something like this. It does, however, serve as an excellent obfuscation agent. For instance, I wrote a proxy pass-around that would let you access blocked sites from a trusted site. The URLs looked soemthing like this:

http://www.foo.com/cgi/sa?fuzzybunnies.com:8080

It would take one glance at a log file to have the administrator figure out what the filter couldn't. However, after wrotating the address, the logs would be filled with something like...

http://www.foo.com/cgi/sa?)8==<%811,(6O&20[YQYQ

Lotsa luck figuring that one out by looking at it, Mr. Administrator!

I hope you enjoy this code.


rotnn.py - A character rotation library
Copyright (C) 2000 - Adam Gurno

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA