[Written on September 18th 2002 - Updated May 6th 2003]

(very easily) Breaking a (extremely weak) steganography software:

JpegX


Steganography strength (is it easy to see there is hidden data?): Low
Cryptography strength (is it easy to recover the hidden data?): Low


Or: is something that simple can *really* be called steganography?



[Update:The author of this software was notified. He thanked me for my small analysis and wrote a more secure version 2, which he would like me to have a look at. Cheers to him! He understood that my goal is constructive criticism, a modest effort in order to raise the global level of security softwares, not just poking fun at people. Now visit his interesting site].


While I was having a look at other steganography software around the internet, I found another weak one, once again listed in most of the steganography tools pages: JpegX version 1.00.6.

The author states on his page: "JPegX is completely FREEWARE and hopefully will become a new standard in security!". Well, I don't think so. I have nothing against him, I know it's always fun to code something new (and I like the fact that his program is small), but I would prefer if he had explained how this program worked, so we don't have to reverse it to know that the security level is close to zero.

1. The data is added at the end of jpg files with a nice signature. Very easy to detect.

2. The "encryption" is an alphabet substitution of characters. Very easy to break. Because it works on one byte, whatever the password you choose, you have just 256 possibilities to test.

Basically:

If no password is used, the byte value of the first ASCII character from the "secret message" is added with 187, that is "BB" in hexa. If there's a carry it's added too. Then the second one is added with 188, than 189, etc... That's it. To decrypt, do the inverse processus.

If a password is used, the program seems to sum the ASCII values of the password, then use this value as a substitution key for the first letter, than "key+1" to the second character, etc... That's the "encryption" process. Then it does the same substitution explained in part 1. That's it. The password is not saved, so you have to check the 256 substitution possibilities. You can reduce this number by eliminating certain non-printable ASCII characters.

A quick example:

Let's hide the text "Tuesday at 12 !!" with the password "gloup2=". Here's what JpegX is going to do:



Text        T   u   e   s   d   a   y   .   a   t   .   1   2   .   !   !
ASCII       54  75  65  73  64  61  79  20  61  74  20  31  32  20  21  21

+BB         BB  BB  BB  BB  BB  BB  BB  BB  BB  BB  BB  BB  BB  BB  BB  BB
+Increm      0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
+Carry       1   1   1   1   1   1   1   0   1   1   0   0   0   0   0   0

Result      10  32  23  32  24  22  3B  e2  25  39  E5  F7  F9  E8  EA  EB



This is the final stored scrambled text if we don't use a password. Now let's see what happens with the password. First, let's add all the ASCII values of the password:

"gloup2=" is in ASCII: 67 6C 6F 75 70 32 3D

If we add them all (plus 2 carries, and then plus 1), we obtain the value 99 in hexa. This is the key. Let's now add it to each byte of the scrambled text, plus carry if necessary, plus 0, 1, 2, 3, etc...



Scrambled   10  32  23  32  24  22  3B  e2  25  39  E5  F7  F9  E8  EA  EB

+Key        99  99  99  99  99  99  99  99  99  99  99  99  99  99  99  99
+Increm      0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
+Carry       0   0   0   0   0   0   0   1   0   0   1   1   1   1   1   1

Result      A9  CC  BE  CE  C1  C0  DA  83  C6  DB  89  9C  9F  8F  92  94


Now let's compare these results with what's inside real images transformed with the above example by JpegX, under an hexadecimal editor. The original image is here (5.139 bytes).

First, the one without password (5.245 bytes):


1190     D2 46 97 A7 36 4B 11 FE E5 88 F5 5C DF F2 5F FF     End of the JPG file
11A0     D9 5B 3B 31 53 00 57 61 72 6E 69 6E 67 21 20 4D     JpegX signature
11B0     6F 64 69 66 69 63 61 74 69 6F 6E 20 6F 66 20 74
11C0     68 69 73 20 66 69 6C 65 20 77 69 6C 6C 20 72 65     JpegX warning text
11D0     73 75 6C 74 20 69 6E 20 69 74 20 6E 6F 20 6C 6F
11E0     6E 67 65 72 20 77 6F 72 6B 69 6E 67 2E 20 4A 50
11F0     65 67 58 20 31 2E 30 2E 36 10 00 10 32 23 32 24     Size of hidden text
1200     22 3B E2 25 39 E5 F7 F9 E8 EA EB                    Hidden text


Second, the image with the password (5.245 bytes):


1190     D2 46 97 A7 36 4B 11 FE E5 88 F5 5C DF F2 5F FF     End of the JPG file
11A0     D9 5B 3B 31 53 00 57 61 72 6E 69 6E 67 21 20 4D     JpegX signature
11B0     6F 64 69 66 69 63 61 74 69 6F 6E 20 6F 66 20 74
11C0     68 69 73 20 66 69 6C 65 20 77 69 6C 6C 20 72 65     JpegX warning text
11D0     73 75 6C 74 20 69 6E 20 69 74 20 6E 6F 20 6C 6F
11E0     6E 67 65 72 20 77 6F 72 6B 69 6E 67 2E 20 4A 50
11F0     65 67 58 20 31 2E 30 2E 36 10 00 A9 CC BE CE C1     Size of hidden text
1200     C0 DA 83 C6 DB 89 9C 9F 8F 92 94                    Hidden text


It looks like we have a perfect match.

To automatize the process, I've coded a small utility to deal with JpegX [Now version 0.2]. Note that it won't display the good text if you used in it ASCII characters values smaller than 32 (with the exception of line breaks) or higher than 126 (accents, etc...). It was just to keep the result window small. You can remove my ASCII filter and recompile if you want, the source is here too.

Once again: if a security software does not explain how it works precisely, don't trust it for serious purposes.

Have a nice day!


     Guillermito, September 18th 2002






[Back]