ritter.vg
tech > security > adventures in (in)security > people who shouldn't do crypto episode 2
08 Aug 2009 00:12:23 EST

This article also has a followup article so when you're done reading this, check the followup!

I happened across a lifehacker post about a web tool called crypo.biz (note the misspelling) a tool that is aimed at encrypting short messages like text messages, and boasts Military Grade 1280-bit Encryption Algorithm. That should be enough to set off any crypto nerd's bullshit detector, so I set about figuring out just what the hell is going on here.

In my recon phase, I discovered lots of shady things that are ancillary to their cryptography. I won't go into details, just laundry list them for your perusal and investigation: no readily accessible javascript showing the code, no explanation of algorithms, a bunch of google tracker urchins (6 on a page?), alexa iframes, and a veritable network of shady sites (12345678910 and more than this).

So the first step was to alert() my way to victory (or code). Then I set about hacking the javascript around and reproducing their crypto. That effort is reproduced here, with logging and comparison ability. Note that I've renamed functions and combined functions from their source. For example, they don't call the base64encoding and decoding what it actually is, I just recognized the bit-shifting (google codesearch helped).

So just what the hell are they doing?! Well it took a bit of reading and hacking around, but here's a walkthrough of the process for you:

Encrypt
 1. Your key is base64encoded with a standard charset
    Your plaintext is passed through encodeURIComponent
 2. 
    a. Each letter in the encoded key is sequentially put through a process I will call as "bastardize-encoding"
 
 unsigned long long bastardize-encode(str)
 {
 	scrambledStr = base64encode(str, scrambledCharset)
 	builtHex = "0x";
 	for each (character in scrambledStr)
 	{
 		builtHex .= toHex(character) 
 		//where
 		//	toHex: 'g' -> 67
 		//	.= is the concatonation operator (borrowed from PHP)
 	}
 	//builtHex is now a string like 0x676E3939
 	return hexToNum(builtHex) //where hexToNum interprets the string as a number
 }

   b. unsigned long long largeNumber = 0;
      foreach(character in encodedKey)
         largeNumber += bastardize-encode(character);

   c. This results in a large number only representable in C using unsigned long long
      This is also the reason the website limits you to a 12 character key - any larger and javascript data structures cause undefined behavior.
   
   d. This is your "true key" that is used to "encrypt" the plaintext

 3. ciphertext = "";
    foreach(substring in plainText) 
    //A substring of a length that varies by keysize (keylen / 5 rounded according to mathemtical rules)
    {
 	unsigned long long encodedPlaintext = bastardize-encode(substring);
 	ciphertext .= encodedPlaintext + largeNumber;
    }
 
 
Decrypt
 1. Your key is put through the same base64encode, and bastardize-encode to result in largeNumber.
 2. halfwayThere = ""
    foreach (number in ciphertext)
    {
 	halfwayThere .= number- largeNumber
    }
 3. I now have a string, halfway there, that looks like this:
    35254B39 567A5A39 6A643039 68364B39 55707339 68643039 677A5139 6D387339 35733939
    The spaces illustrate the breaks between the numbers
 4. This resultant string is treated as a string of characters represented as integers in hex. 
    e.g. 35 is 0x35 or '5', 25 is 0x25 or '%', 4B is 0x4B or 'K'
    The entire character string representation of the above is:
    5%K9VzZ9jd09h6K9Ups9hd09gzQ9m8s95s99
 5. This value is base64decoded using the scrambled charset to obtain:
    testing%20encrypt
 6. Which is then passed through decodeURIComponent

So you can see that there is no actual "crypto" here. It's a glorified Vigenere Cipher, with some base64 and bastardized encoding. There's no notion of "bits" in this cryptography and even if you want to argue about the entropy in your password, it comes nowhere near 100 bits, let alone 1280. This crypto is as close to Military Grade crypto as my 1987 Cadillac is to a Military Grade tank.

As part of the learning experience, I also duplicated the code in C, which is available to you as well. I used it mostly as an exercise to brush up on my C and learn how to use valgrind (which is awesome). The code is not refactored, and is pretty ugly. It compiles with warnings about unsigned long long - which is necessary for the "largeNumber" bit from above.

So I've come this far in doing the ugly work to make the code understandable and able to be worked with - can you build a cracker? I'll post links here, just e-mail me.

This article also has a followup article so when you're done reading this, check the followup!

Comments
Add a comment...
required
required, hidden, gravatared

required, markdown enabled (help)
you type:you see:
*italics*italics
**bold**bold
[stolen from reddit!](http://reddit.com)stolen from reddit!
* item 1
* item 2
* item 3
  • item 1
  • item 2
  • item 3
> quoted text
quoted text
Lines starting with four spaces
are treated like code:

    if 1 * 2 < 3:
        print "hello, world!"
Lines starting with four spaces
are treated like code:
if 1 * 2 < 3:
    print "hello, world!"