zsteg 0.0.0 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +2 -7
 - data/Gemfile.lock +2 -4
 - data/README.md +72 -1
 - data/README.md.tpl +23 -0
 - data/Rakefile +5 -3
 - data/TODO +5 -2
 - data/VERSION +1 -1
 - data/bin/zsteg-mask +7 -0
 - data/lib/zsteg/checker/wbstego.rb +69 -14
 - data/lib/zsteg/checker.rb +137 -34
 - data/lib/zsteg/cli.rb +92 -35
 - data/lib/zsteg/extractor/byte_extractor.rb +36 -21
 - data/lib/zsteg/extractor/color_extractor.rb +68 -34
 - data/lib/zsteg/extractor.rb +36 -1
 - data/lib/zsteg/file_cmd.rb +64 -1
 - data/lib/zsteg/mask_cli.rb +268 -0
 - data/lib/zsteg/masker.rb +52 -0
 - data/lib/zsteg/result.rb +27 -32
 - data/lib/zsteg.rb +2 -0
 - data/samples/hackquest/crypt.bmp +0 -0
 - data/samples/hackquest/square.bmp +0 -0
 - data/samples/wbstego/wbsteg_blowfish_pass_1.bmp +0 -0
 - data/samples/wbstego/wbsteg_cast128_pass_1.bmp +0 -0
 - data/samples/wbstego/wbsteg_enc_pass_pass.bmp +0 -0
 - data/samples/wbstego/wbsteg_enc_pass_pass_even.bmp +0 -0
 - data/samples/wbstego/wbsteg_mix_pass_1.bmp +0 -0
 - data/samples/wbstego/wbsteg_mix_pass_1_even.bmp +0 -0
 - data/samples/wbstego/wbsteg_mix_pass_foobar.bmp +0 -0
 - data/samples/wbstego/wbsteg_mix_pass_pass.bmp +0 -0
 - data/samples/wbstego/wbsteg_mixenc_pass_pass_even.bmp +0 -0
 - data/samples/{wbsteg_noenc.bmp → wbstego/wbsteg_noenc.bmp} +0 -0
 - data/samples/wbstego/wbsteg_noenc.png +0 -0
 - data/samples/wbstego/wbsteg_noenc_.bmp +0 -0
 - data/samples/{wbsteg_noenc_17.bmp → wbstego/wbsteg_noenc_17.bmp} +0 -0
 - data/samples/wbstego/wbsteg_noenc__.bmp +0 -0
 - data/samples/{wbsteg_noenc_even.bmp → wbstego/wbsteg_noenc_even.bmp} +0 -0
 - data/samples/wbstego/wbsteg_noenc_even2.bmp +0 -0
 - data/samples/{wbsteg_noenc_even_17.bmp → wbstego/wbsteg_noenc_even_17.bmp} +0 -0
 - data/samples/wbstego/wbsteg_noenc_even_17_.bmp +0 -0
 - data/samples/wbstego/wbsteg_noenc_ext_ABC.bmp +0 -0
 - data/samples/wbstego/wbsteg_rijndael_pass_1.bmp +0 -0
 - data/samples/wbstego/wbsteg_rijndael_pass_pass.bmp +0 -0
 - data/samples/wbstego/wbsteg_rijndael_pass_pass_even.bmp +0 -0
 - data/samples/wbstego/wbsteg_twofish_pass_1.bmp +0 -0
 - data/samples/wechall/5ZMGcCLxpcpsru03.g00000010.png +0 -0
 - data/samples/wechall/5ZMGcCLxpcpsru03.png +0 -0
 - data/samples/wechall/stegano1.bmp +0 -0
 - data/spec/checker_spec.rb +47 -0
 - data/spec/easybmp_spec.rb +9 -0
 - data/spec/hackquest_spec.rb +18 -0
 - data/spec/mask_spec.rb +14 -0
 - data/spec/polictf2012_spec.rb +48 -0
 - data/spec/prime_spec.rb +9 -0
 - data/spec/r3g2b3_spec.rb +9 -0
 - data/spec/spec_helper.rb +21 -4
 - data/spec/wbstego_spec.rb +21 -3
 - data/spec/wechall_spec.rb +26 -0
 - data/tmp/.keep +0 -0
 - data/zsteg.gemspec +121 -0
 - metadata +47 -43
 - data/samples/06_enc.png +0 -0
 - data/samples/Code.png +0 -0
 - data/samples/README +0 -4
 - data/samples/camouflage-password.png +0 -0
 - data/samples/camouflage.png +0 -0
 - data/samples/cats.png +0 -0
 - data/samples/flower.png +0 -0
 - data/samples/flower_rgb1.png +0 -0
 - data/samples/flower_rgb2.png +0 -0
 - data/samples/flower_rgb3.png +0 -0
 - data/samples/flower_rgb4.png +0 -0
 - data/samples/flower_rgb5.png +0 -0
 - data/samples/flower_rgb6.png +0 -0
 - data/samples/montenach-enc.png +0 -0
 - data/samples/ndh2k12_sp113.bmp.7z +0 -0
 - data/samples/openstego_q2.png +0 -0
 - data/samples/openstego_send.png +0 -0
 - data/samples/stg300.png +0 -0
 
    
        data/Gemfile
    CHANGED
    
    | 
         @@ -1,13 +1,8 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            source "http://rubygems.org"
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
            #   gem "activesupport", ">= 2.3.5"
         
     | 
| 
       5 
     | 
    
         
            -
            gem 'zpng', ">= 0.2.1"
         
     | 
| 
       6 
     | 
    
         
            -
            gem "awesome_print"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            gem 'zpng', ">= 0.2.2"
         
     | 
| 
       7 
4 
     | 
    
         
             
            gem "iostruct"
         
     | 
| 
       8 
5 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            # Add dependencies to develop your gem here.
         
     | 
| 
       10 
     | 
    
         
            -
            # Include everything needed to run rake, tests, features, etc.
         
     | 
| 
       11 
6 
     | 
    
         
             
            group :development do
         
     | 
| 
       12 
7 
     | 
    
         
             
              gem "rspec",   ">= 2.8.0"
         
     | 
| 
       13 
8 
     | 
    
         
             
              gem "bundler", ">= 1.0.0"
         
     | 
    
        data/Gemfile.lock
    CHANGED
    
    | 
         @@ -1,7 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            GEM
         
     | 
| 
       2 
2 
     | 
    
         
             
              remote: http://rubygems.org/
         
     | 
| 
       3 
3 
     | 
    
         
             
              specs:
         
     | 
| 
       4 
     | 
    
         
            -
                awesome_print (1.1.0)
         
     | 
| 
       5 
4 
     | 
    
         
             
                diff-lcs (1.1.3)
         
     | 
| 
       6 
5 
     | 
    
         
             
                git (1.2.5)
         
     | 
| 
       7 
6 
     | 
    
         
             
                iostruct (0.0.1)
         
     | 
| 
         @@ -23,16 +22,15 @@ GEM 
     | 
|
| 
       23 
22 
     | 
    
         
             
                rspec-expectations (2.12.1)
         
     | 
| 
       24 
23 
     | 
    
         
             
                  diff-lcs (~> 1.1.3)
         
     | 
| 
       25 
24 
     | 
    
         
             
                rspec-mocks (2.12.1)
         
     | 
| 
       26 
     | 
    
         
            -
                zpng (0.2. 
     | 
| 
      
 25 
     | 
    
         
            +
                zpng (0.2.2)
         
     | 
| 
       27 
26 
     | 
    
         
             
                  rainbow
         
     | 
| 
       28 
27 
     | 
    
         | 
| 
       29 
28 
     | 
    
         
             
            PLATFORMS
         
     | 
| 
       30 
29 
     | 
    
         
             
              ruby
         
     | 
| 
       31 
30 
     | 
    
         | 
| 
       32 
31 
     | 
    
         
             
            DEPENDENCIES
         
     | 
| 
       33 
     | 
    
         
            -
              awesome_print
         
     | 
| 
       34 
32 
     | 
    
         
             
              bundler (>= 1.0.0)
         
     | 
| 
       35 
33 
     | 
    
         
             
              iostruct
         
     | 
| 
       36 
34 
     | 
    
         
             
              jeweler (~> 1.8.4)
         
     | 
| 
       37 
35 
     | 
    
         
             
              rspec (>= 2.8.0)
         
     | 
| 
       38 
     | 
    
         
            -
              zpng (>= 0.2. 
     | 
| 
      
 36 
     | 
    
         
            +
              zpng (>= 0.2.2)
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -18,6 +18,7 @@ Detects: 
     | 
|
| 
       18 
18 
     | 
    
         
             
             * zlib-compressed data
         
     | 
| 
       19 
19 
     | 
    
         
             
             * [OpenStego](http://openstego.sourceforge.net/)
         
     | 
| 
       20 
20 
     | 
    
         
             
             * [Camouflage 1.2.1](http://camouflage.unfiction.com/)
         
     | 
| 
      
 21 
     | 
    
         
            +
             * [LSB with The Eratosthenes set](http://wiki.cedricbonhomme.org/security:steganography)
         
     | 
| 
       21 
22 
     | 
    
         | 
| 
       22 
23 
     | 
    
         | 
| 
       23 
24 
     | 
    
         
             
            Usage
         
     | 
| 
         @@ -25,7 +26,7 @@ Usage 
     | 
|
| 
       25 
26 
     | 
    
         | 
| 
       26 
27 
     | 
    
         
             
                # zsteg -h
         
     | 
| 
       27 
28 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
                Usage: zsteg [options] filename.png
         
     | 
| 
      
 29 
     | 
    
         
            +
                Usage: zsteg [options] filename.png [param_string]
         
     | 
| 
       29 
30 
     | 
    
         | 
| 
       30 
31 
     | 
    
         
             
                    -c, --channels X                 channels (R/G/B/A) or any combination, comma separated
         
     | 
| 
       31 
32 
     | 
    
         
             
                                                     valid values: r,g,b,a,rg,rgb,bgr,rgba,...
         
     | 
| 
         @@ -33,13 +34,83 @@ Usage 
     | 
|
| 
       33 
34 
     | 
    
         
             
                    -b, --bits N                     number of bits (1..8), single value or '1,3,5' or '1-8'
         
     | 
| 
       34 
35 
     | 
    
         
             
                        --lsb                        least significant BIT comes first
         
     | 
| 
       35 
36 
     | 
    
         
             
                        --msb                        most significant BIT comes first
         
     | 
| 
      
 37 
     | 
    
         
            +
                    -P, --prime                      analyze/extract only prime bytes/pixels
         
     | 
| 
      
 38 
     | 
    
         
            +
                    -a, --all                        try all known methods
         
     | 
| 
       36 
39 
     | 
    
         
             
                    -o, --order X                    pixel iteration order (default: 'auto')
         
     | 
| 
       37 
40 
     | 
    
         
             
                                                     valid values: ALL,xy,yx,XY,YX,xY,Xy,bY,...
         
     | 
| 
       38 
41 
     | 
    
         
             
                    -E, --extract NAME               extract specified payload, NAME is like '1b,rgb,lsb'
         
     | 
| 
       39 
42 
     | 
    
         | 
| 
       40 
43 
     | 
    
         
             
                    -v, --verbose                    Run verbosely (can be used multiple times)
         
     | 
| 
       41 
44 
     | 
    
         
             
                    -q, --quiet                      Silent any warnings (can be used multiple times)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    -C, --[no-]color                 Force (or disable) color output (default: auto)
         
     | 
| 
      
 46 
     | 
    
         
            +
                
         
     | 
| 
      
 47 
     | 
    
         
            +
                PARAMS SHORTCUT
         
     | 
| 
      
 48 
     | 
    
         
            +
                	zsteg fname.png 2b,b,lsb,xy  ==>  --bits 2 --channel b --lsb --order xy
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            Examples
         
     | 
| 
      
 51 
     | 
    
         
            +
            --------
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            ### Simple LSB
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                # zsteg flower_rgb3.png
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                3b,rgb,lsb,xy       .. text: "SuperSecretMessage"
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            ### Multi-result file
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                # zsteg cats.png
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                meta F              .. ["Z" repeated 14999985 times]
         
     | 
| 
      
 64 
     | 
    
         
            +
                meta C              .. text: "Fourth and last cat is Luke"
         
     | 
| 
      
 65 
     | 
    
         
            +
                meta A              .. [same as "meta F"]
         
     | 
| 
      
 66 
     | 
    
         
            +
                meta date:create    .. text: "2012-03-15T23:32:46+07:00"
         
     | 
| 
      
 67 
     | 
    
         
            +
                meta date:modify    .. text: "2012-03-15T23:32:14+07:00"
         
     | 
| 
      
 68 
     | 
    
         
            +
                1b,r,lsb,xy         .. text: "Second cat is Marussia"
         
     | 
| 
      
 69 
     | 
    
         
            +
                1b,g,lsb,xy         .. text: "Good, but look a bit deeper..."
         
     | 
| 
      
 70 
     | 
    
         
            +
                1b,bgr,lsb,xy       .. text: "MF_WIhf>"
         
     | 
| 
      
 71 
     | 
    
         
            +
                2b,g,lsb,xy         .. text: "VHello, third kitten is Bessy"
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            ### wbStego even distributed
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                # zsteg wbstego/wbsteg_noenc_even.bmp 1b,lsb,bY -v
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                1b,lsb,bY           .. <wbStego size=22, data="xtSuperSecretMessage\n", even=true, mix=true, controlbyte="t">
         
     | 
| 
      
 78 
     | 
    
         
            +
                    00000000: 51 00 00 16 00 00 74 0d  b5 78 1e a1 39 74 e8 38  |Q.....t..x..9t.8|
         
     | 
| 
      
 79 
     | 
    
         
            +
                    00000010: 53 c6 56 94 75 d1 a5 70  84 c8 27 65 fe 08 72 35  |S.V.u..p..'e..r5|
         
     | 
| 
      
 80 
     | 
    
         
            +
                    00000020: 1f 3e 53 5d a7 65 8b 6e  3b 63 6b 1d bf 72 ee 27  |.>S].e.n;ck..r.'|
         
     | 
| 
      
 81 
     | 
    
         
            +
                    00000030: 65 8d ee 82 74 da 8d 4d  b3 8a 06 65 7e f8 73 9c  |e...t..M...e~.s.|
         
     | 
| 
      
 82 
     | 
    
         
            +
                    00000040: 36 0c 73 aa bd 61 67 29  37 67 5f 0b 06 65 1f a4  |6.s..ag)7g_..e..|
         
     | 
| 
      
 83 
     | 
    
         
            +
                    00000050: 0a a1 f8 35                                       |...5            |
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            ### wbStego encrypted
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                # zsteg wbstego/wbsteg_blowfish_pass_1.bmp 1b,lsb,bY -v
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                1b,lsb,bY           .. <wbStego size=26, data="\rC\xF5\xBF#\xFF[6\e\xB3"..., even=false, hdr="\x01", enc="Blowfish">
         
     | 
| 
      
 90 
     | 
    
         
            +
                    00000000: 1a 00 00 00 ff 01 01 0d  43 f5 bf 23 ff 5b 36 1b  |........C..#.[6.|
         
     | 
| 
      
 91 
     | 
    
         
            +
                    00000010: b3 17 42 4a 3f ba eb c7  ee 9c d7 7a 2b           |..BJ?......z+   |
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
            ### zlib
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                # zsteg ndh2k12_sp113.bmp -b 1 -o yx -v
         
     | 
| 
       42 
96 
     | 
    
         | 
| 
      
 97 
     | 
    
         
            +
                1b,rgb,lsb,yx       .. zlib: data="%PDF-1.4\n%\xC3\xA4\xC3\xBC\xC3\xB6\xC3\x9F\n2 0 obj\n<</Length 3 0 R/Filter/FlateDecode>>\nstream\nx\x9C\x8DT\xC9n\xDB@\f\xBD\xCFW\xF0\x1C \x13\x92\xB3\x03\x86\x80\xC8K\xD1\xDE\\\b\xE8\xA1\xE8)K\x8B\xA2n\x91\\\xF2\xFB!5Zl\xD5v\v\x01\xD4\x90C\xBE\xF7\x86\x1A\n-\xC1\x9By\x01\x94'\x94`=d\xCF\xF0\xFA\x04_n\xE0\xF7\x10Gx\xFDn\xDA\xCE\xB0\x8F6\x80s$Y\xDD#\xDC\xED\b\x1CC\xF7\xBCBBF\x87^\xDE\xA1\xE9~\x9Amg\xF6\x8BZ\xCAYj", offset=4
         
     | 
| 
      
 98 
     | 
    
         
            +
                    00000000: 00 02 eb 9b 78 9c d4 b9  65 54 24 cc 92 36 58 b8  |....x...eT$..6X.|
         
     | 
| 
      
 99 
     | 
    
         
            +
                    00000010: d3 68 e3 ee ee 4e e3 ee  ee 0e 85 bb 3b dd 68 23  |.h...N......;.h#|
         
     | 
| 
      
 100 
     | 
    
         
            +
                    00000020: 8d bb bb bb 3b 8d bb bb  3b 34 ee 6e 1f ef 7b ef  |....;...;4.n..{.|
         
     | 
| 
      
 101 
     | 
    
         
            +
                    00000030: 9d 3b b3 e7 cc 9e d9 3d  df 9e dd cd 8a 1f 99 19  |.;.....=........|
         
     | 
| 
      
 102 
     | 
    
         
            +
                    00000040: 99 55 11 99 4f 58 25 99  82 88 18 1d 13 3d 2b 2c  |.U..OX%......=+,|
         
     | 
| 
      
 103 
     | 
    
         
            +
                    00000050: 59 6f 7e 6f 7b 6f 63 6f  16 2c 33 21 23 a1 9d 91  |Yo~o{oco.,3!#...|
         
     | 
| 
      
 104 
     | 
    
         
            +
                    00000060: 25 2c 2f 2f 83 0c d0 d6  cc d9 9c 90 e5 73 46 89  |%,//.........sF.|
         
     | 
| 
      
 105 
     | 
    
         
            +
                    00000070: 41 cc c2 da 19 e8 c8 20  66 6d e8 0c 14 01 1a db  |A...... fm......|
         
     | 
| 
      
 106 
     | 
    
         
            +
                    00000080: 99 00 f9 f8 60 9d 9c 1d  81 86 36 b0 ee e9 bf 54  |....`.....6....T|
         
     | 
| 
      
 107 
     | 
    
         
            +
                    00000090: 86 6d 57 05 e0 3b 26 d5  2f 71 09 51 63 eb c0 82  |.mW..;&./q.Qc...|
         
     | 
| 
      
 108 
     | 
    
         
            +
                    000000a0: bf 0f 49 4f 6f e8 40 ff  c9 f9 43 25 1d 9e 6b 1b  |..IOo.@...C%..k.|
         
     | 
| 
      
 109 
     | 
    
         
            +
                    000000b0: a3 73 fd 42 c4 a6 65 3d  ef 0a 07 32 17 2d dc f9  |.s.B..e=...2.-..|
         
     | 
| 
      
 110 
     | 
    
         
            +
                    000000c0: 10 8c 0d 4b d7 9d e6 01  12 4f 11 6f f0 cd 64 f2  |...K.....O.o..d.|
         
     | 
| 
      
 111 
     | 
    
         
            +
                    000000d0: f2 19 5c df 76 eb 01 49  dc fd cd 76 65 a2 3a 8a  |..\.v..I...ve.:.|
         
     | 
| 
      
 112 
     | 
    
         
            +
                    000000e0: fd bb 13 a9 e6 3a c9 da  19 34 ae f0 43 bb 90 90  |.....:...4..C...|
         
     | 
| 
      
 113 
     | 
    
         
            +
                    000000f0: 58 88 de 46 ce 91 6f aa  8d d9 7d b8 d6 88 a6 65  |X..F..o...}....e|
         
     | 
| 
       43 
114 
     | 
    
         | 
| 
       44 
115 
     | 
    
         
             
            License
         
     | 
| 
       45 
116 
     | 
    
         
             
            -------
         
     | 
    
        data/README.md.tpl
    CHANGED
    
    | 
         @@ -18,6 +18,7 @@ Detects: 
     | 
|
| 
       18 
18 
     | 
    
         
             
             * zlib-compressed data
         
     | 
| 
       19 
19 
     | 
    
         
             
             * [OpenStego](http://openstego.sourceforge.net/)
         
     | 
| 
       20 
20 
     | 
    
         
             
             * [Camouflage 1.2.1](http://camouflage.unfiction.com/)
         
     | 
| 
      
 21 
     | 
    
         
            +
             * [LSB with The Eratosthenes set](http://wiki.cedricbonhomme.org/security:steganography)
         
     | 
| 
       21 
22 
     | 
    
         | 
| 
       22 
23 
     | 
    
         | 
| 
       23 
24 
     | 
    
         
             
            Usage
         
     | 
| 
         @@ -25,6 +26,28 @@ Usage 
     | 
|
| 
       25 
26 
     | 
    
         | 
| 
       26 
27 
     | 
    
         
             
            % zsteg -h
         
     | 
| 
       27 
28 
     | 
    
         | 
| 
      
 29 
     | 
    
         
            +
            Examples
         
     | 
| 
      
 30 
     | 
    
         
            +
            --------
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            ### Simple LSB
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            % zsteg flower_rgb3.png
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            ### Multi-result file
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            % zsteg cats.png
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            ### wbStego even distributed
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            % zsteg wbstego/wbsteg_noenc_even.bmp 1b,lsb,bY -v
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            ### wbStego encrypted
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            % zsteg wbstego/wbsteg_blowfish_pass_1.bmp 1b,lsb,bY -v
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            ### zlib
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            % zsteg ndh2k12_sp113.bmp -b 1 -o yx -v
         
     | 
| 
       28 
51 
     | 
    
         | 
| 
       29 
52 
     | 
    
         
             
            License
         
     | 
| 
       30 
53 
     | 
    
         
             
            -------
         
     | 
    
        data/Rakefile
    CHANGED
    
    | 
         @@ -23,7 +23,8 @@ Jeweler::Tasks.new do |gem| 
     | 
|
| 
       23 
23 
     | 
    
         
             
              gem.authors = ["Andrey \"Zed\" Zaikin"]
         
     | 
| 
       24 
24 
     | 
    
         
             
              #gem.executables = %w'zsteg'
         
     | 
| 
       25 
25 
     | 
    
         
             
              gem.files.include "lib/**/*.rb"
         
     | 
| 
       26 
     | 
    
         
            -
              gem.files.include "bin 
     | 
| 
      
 26 
     | 
    
         
            +
              gem.files.include "bin/*"
         
     | 
| 
      
 27 
     | 
    
         
            +
              gem.files.exclude "samples/*"
         
     | 
| 
       27 
28 
     | 
    
         
             
              # dependencies defined in Gemfile
         
     | 
| 
       28 
29 
     | 
    
         
             
            end
         
     | 
| 
       29 
30 
     | 
    
         
             
            Jeweler::RubygemsDotOrgTasks.new
         
     | 
| 
         @@ -53,9 +54,10 @@ task :readme do 
     | 
|
| 
       53 
54 
     | 
    
         
             
                puts "[.] #{cmd} ..."
         
     | 
| 
       54 
55 
     | 
    
         
             
                r = "    # #{cmd}\n\n"
         
     | 
| 
       55 
56 
     | 
    
         
             
                cmd.sub! /^zsteg/,"../bin/zsteg"
         
     | 
| 
       56 
     | 
    
         
            -
                lines = `#{cmd}`.sub(/\A\n+/m,''). 
     | 
| 
      
 57 
     | 
    
         
            +
                lines = `#{cmd}`.sub(/\A\n+/m,'').split("\n")
         
     | 
| 
      
 58 
     | 
    
         
            +
                lines.map!{ |l| l.split("\r").last } # emulate CR's
         
     | 
| 
       57 
59 
     | 
    
         
             
                lines = lines[0,25] + ['...'] if lines.size > 50
         
     | 
| 
       58 
     | 
    
         
            -
                r << lines.map{|x| "    #{x}"}.join("\n")
         
     | 
| 
      
 60 
     | 
    
         
            +
                r << lines.map{|x| "    #{x}"}.join("\n").rstrip
         
     | 
| 
       59 
61 
     | 
    
         
             
                r << "\n"
         
     | 
| 
       60 
62 
     | 
    
         
             
              end
         
     | 
| 
       61 
63 
     | 
    
         
             
              Dir.chdir 'samples'
         
     | 
    
        data/TODO
    CHANGED
    
    | 
         @@ -1,9 +1,12 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            [ ] make 'extract' cmd stream its data directly to stdout
         
     | 
| 
       2 
2 
     | 
    
         
             
            [ ] gzip
         
     | 
| 
       3 
     | 
    
         
            -
            [ 
     | 
| 
      
 3 
     | 
    
         
            +
            [ ] wbStego: 4bpp/8bpp BMP
         
     | 
| 
       4 
4 
     | 
    
         
             
            [ ] openstego
         
     | 
| 
       5 
5 
     | 
    
         
             
            [ ] tmp/steg*/*.bmp
         
     | 
| 
       6 
6 
     | 
    
         
             
            [ ] 4bpp/8bpp BMP
         
     | 
| 
      
 7 
     | 
    
         
            +
            [ ] http://search.cpan.org/~nwclark/Acme-Steganography-Image-Png-0.06/Png.pm
         
     | 
| 
      
 8 
     | 
    
         
            +
            [ ] http://registry.gimp.org/node/25988 - GIMP stego plugin
         
     | 
| 
      
 9 
     | 
    
         
            +
            [ ] zsteg-mask: normalize all to white
         
     | 
| 
       7 
10 
     | 
    
         | 
| 
       8 
11 
     | 
    
         
             
            [+] auto pixel order for BMP
         
     | 
| 
       9 
12 
     | 
    
         
             
            [+] BMP
         
     | 
| 
         @@ -11,4 +14,4 @@ 
     | 
|
| 
       11 
14 
     | 
    
         | 
| 
       12 
15 
     | 
    
         
             
            [ ] detect AES from http://punkroy.drque.net/PNG_Steganography/Steganography5.php
         
     | 
| 
       13 
16 
     | 
    
         
             
            [?] http://tobyinkster.co.uk/article/steg-encode/
         
     | 
| 
       14 
     | 
    
         
            -
            [ 
     | 
| 
      
 17 
     | 
    
         
            +
            [+] Sieve of Eratosthenes: http://wiki.cedricbonhomme.org/security:steganography
         
     | 
    
        data/VERSION
    CHANGED
    
    | 
         @@ -1 +1 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            0.0. 
     | 
| 
      
 1 
     | 
    
         
            +
            0.0.1
         
     | 
    
        data/bin/zsteg-mask
    ADDED
    
    
| 
         @@ -2,17 +2,60 @@ module ZSteg 
     | 
|
| 
       2 
2 
     | 
    
         
             
              class Checker
         
     | 
| 
       3 
3 
     | 
    
         
             
                module WBStego
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
                   
     | 
| 
      
 5 
     | 
    
         
            +
                  ENCRYPTIONS = [
         
     | 
| 
      
 6 
     | 
    
         
            +
                    nil,         # 0
         
     | 
| 
      
 7 
     | 
    
         
            +
                    "Blowfish",  # 1
         
     | 
| 
      
 8 
     | 
    
         
            +
                    "Twofish",   # 2
         
     | 
| 
      
 9 
     | 
    
         
            +
                    "CAST128",   # 3
         
     | 
| 
      
 10 
     | 
    
         
            +
                    "Rijndael",  # 4
         
     | 
| 
      
 11 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  class Result < IOStruct.new "a3a3a*", :size, :ext, :data, :even, :hdr, :enc, :mix, :controlbyte
         
     | 
| 
      
 14 
     | 
    
         
            +
                    attr_accessor :color
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
       6 
16 
     | 
    
         
             
                    def initialize *args
         
     | 
| 
       7 
17 
     | 
    
         
             
                      super
         
     | 
| 
       8 
18 
     | 
    
         
             
                      if self.size.is_a?(String)
         
     | 
| 
       9 
19 
     | 
    
         
             
                        self.size = (self.size[0,3] + "\x00").unpack('V')[0]
         
     | 
| 
       10 
20 
     | 
    
         
             
                      end
         
     | 
| 
       11 
     | 
    
         
            -
                      self.even  
     | 
| 
      
 21 
     | 
    
         
            +
                      self.even ||= false
         
     | 
| 
      
 22 
     | 
    
         
            +
                      #self.encrypted ||= false
         
     | 
| 
      
 23 
     | 
    
         
            +
                      if ext[0,2] == "\x00\xff"
         
     | 
| 
      
 24 
     | 
    
         
            +
                        # wbStego 4.x header
         
     | 
| 
      
 25 
     | 
    
         
            +
                        self.hdr  = data[0,ext[2].ord] # 3rd ext byte is hdr len
         
     | 
| 
      
 26 
     | 
    
         
            +
                        self.data = data[hdr.size..-1]
         
     | 
| 
      
 27 
     | 
    
         
            +
                        self.ext  = nil                # encrypted files have no ext
         
     | 
| 
      
 28 
     | 
    
         
            +
                        self.enc  = ENCRYPTIONS[hdr[0].ord] || "unknown ##{hdr[0].ord}"
         
     | 
| 
      
 29 
     | 
    
         
            +
                      elsif (cb=ext[0].ord) & 0xc0 != 0
         
     | 
| 
      
 30 
     | 
    
         
            +
                        # wbStego 2.x/3.x controlbyte
         
     | 
| 
      
 31 
     | 
    
         
            +
                        self.controlbyte = ext[0]
         
     | 
| 
      
 32 
     | 
    
         
            +
                        self.data = ext[1..-1] + data
         
     | 
| 
      
 33 
     | 
    
         
            +
                        self.ext  = nil                # have ext but its encrypted/mixed with data
         
     | 
| 
      
 34 
     | 
    
         
            +
                        self.mix  = true if cb & 0x40 != 0
         
     | 
| 
      
 35 
     | 
    
         
            +
                        self.enc  = "wbStego 2.x/3.x" if cb & 0x80 != 0
         
     | 
| 
      
 36 
     | 
    
         
            +
                      end
         
     | 
| 
       12 
37 
     | 
    
         
             
                    end
         
     | 
| 
       13 
38 
     | 
    
         | 
| 
       14 
39 
     | 
    
         
             
                    def to_s
         
     | 
| 
       15 
     | 
    
         
            -
                       
     | 
| 
      
 40 
     | 
    
         
            +
                      s = inspect.
         
     | 
| 
      
 41 
     | 
    
         
            +
                          sub("#<struct #{self.class.to_s}", "<wbStego").
         
     | 
| 
      
 42 
     | 
    
         
            +
                          gsub(/, \w+=nil/,'')
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                      color = @color
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                      if ext && !valid_ext?
         
     | 
| 
      
 47 
     | 
    
         
            +
                        s.sub!(data.inspect, data[0,10].inspect+"...") if data && data.size>13
         
     | 
| 
      
 48 
     | 
    
         
            +
                        color ||= :gray
         
     | 
| 
      
 49 
     | 
    
         
            +
                      else
         
     | 
| 
      
 50 
     | 
    
         
            +
                        s.sub!(data.inspect, data[0,10].inspect+"...") if data && data.size>13 && enc
         
     | 
| 
      
 51 
     | 
    
         
            +
                        color ||= :bright_red
         
     | 
| 
      
 52 
     | 
    
         
            +
                      end
         
     | 
| 
      
 53 
     | 
    
         
            +
                      s.send(color)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                    # XXX require that file extension be 7-bit ASCII
         
     | 
| 
      
 57 
     | 
    
         
            +
                    def valid_ext?
         
     | 
| 
      
 58 
     | 
    
         
            +
                      ext =~ /\A[\x20-\x7e]+\Z/ && !ext['*'] && !ext['?']
         
     | 
| 
       16 
59 
     | 
    
         
             
                    end
         
     | 
| 
       17 
60 
     | 
    
         
             
                  end
         
     | 
| 
       18 
61 
     | 
    
         | 
| 
         @@ -49,8 +92,15 @@ module ZSteg 
     | 
|
| 
       49 
92 
     | 
    
         
             
                    def check data, params = {}
         
     | 
| 
       50 
93 
     | 
    
         
             
                      return if data.size < 4
         
     | 
| 
       51 
94 
     | 
    
         
             
                      return if params[:bit_order] != :lsb
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                      force_color = nil
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
       52 
98 
     | 
    
         
             
                      if params[:image].format == :bmp
         
     | 
| 
       53 
99 
     | 
    
         
             
                        return if params[:order] !~ /b/i
         
     | 
| 
      
 100 
     | 
    
         
            +
                      else
         
     | 
| 
      
 101 
     | 
    
         
            +
                        # PNG
         
     | 
| 
      
 102 
     | 
    
         
            +
                        return if Array(params[:channels]).join != 'bgr'
         
     | 
| 
      
 103 
     | 
    
         
            +
                        force_color = :gray if params[:order] != 'xY'
         
     | 
| 
       54 
104 
     | 
    
         
             
                      end
         
     | 
| 
       55 
105 
     | 
    
         | 
| 
       56 
106 
     | 
    
         
             
                      size1 = (data[0,3] + "\x00").unpack('V')[0]
         
     | 
| 
         @@ -61,9 +111,16 @@ module ZSteg 
     | 
|
| 
       61 
111 
     | 
    
         
             
                          params[:max_hidden_size]
         
     | 
| 
       62 
112 
     | 
    
         
             
                        end
         
     | 
| 
       63 
113 
     | 
    
         
             
                      return if size1 == 0 || size1 > avail_size
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                      # check if too many zeroes, prevent false positive
         
     | 
| 
      
 116 
     | 
    
         
            +
                      nzeroes = data[3..-1].count("\x00")
         
     | 
| 
      
 117 
     | 
    
         
            +
                      return if nzeroes > 10 && data.size-3-nzeroes < 4
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                      result = nil
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
       64 
121 
     | 
    
         
             
                      size2 = (data[3,3] + "\x00").unpack('V')[0]
         
     | 
| 
       65 
122 
     | 
    
         
             
            #          p [size1, size2, avail_size]
         
     | 
| 
       66 
     | 
    
         
            -
                      if size2 < avail_size
         
     | 
| 
      
 123 
     | 
    
         
            +
                      if size2 < avail_size && size2 > 0
         
     | 
| 
       67 
124 
     | 
    
         
             
                        spacing = 1.0*avail_size/(size2+5) - 1
         
     | 
| 
       68 
125 
     | 
    
         
             
            #            puts "[d] spacing=#{spacing}"
         
     | 
| 
       69 
126 
     | 
    
         
             
                        if spacing > 0
         
     | 
| 
         @@ -77,21 +134,19 @@ module ZSteg 
     | 
|
| 
       77 
134 
     | 
    
         
             
                              error -= 1
         
     | 
| 
       78 
135 
     | 
    
         
             
                            end
         
     | 
| 
       79 
136 
     | 
    
         
             
                          end
         
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
                           
     | 
| 
      
 137 
     | 
    
         
            +
                          if r.size > 4
         
     | 
| 
      
 138 
     | 
    
         
            +
                            ext = r[0,3]
         
     | 
| 
      
 139 
     | 
    
         
            +
                            result = Result.new(size2, ext, r[3..-1], true)
         
     | 
| 
      
 140 
     | 
    
         
            +
                          end
         
     | 
| 
       84 
141 
     | 
    
         
             
                        end
         
     | 
| 
       85 
142 
     | 
    
         
             
                      end
         
     | 
| 
       86 
143 
     | 
    
         
             
                      # no even distribution
         
     | 
| 
       87 
     | 
    
         
            -
                      return unless valid_ext?(data[3,3])
         
     | 
| 
       88 
     | 
    
         
            -
                       
     | 
| 
      
 144 
     | 
    
         
            +
                      #return unless valid_ext?(data[3,3])
         
     | 
| 
      
 145 
     | 
    
         
            +
                      result ||= Result.read(data)
         
     | 
| 
      
 146 
     | 
    
         
            +
                      result.color = force_color if result && force_color
         
     | 
| 
      
 147 
     | 
    
         
            +
                      result
         
     | 
| 
       89 
148 
     | 
    
         
             
                    end
         
     | 
| 
       90 
149 
     | 
    
         | 
| 
       91 
     | 
    
         
            -
                    # XXX require that file extension be 7-bit ASCII
         
     | 
| 
       92 
     | 
    
         
            -
                    def valid_ext? ext
         
     | 
| 
       93 
     | 
    
         
            -
                      ext =~ /\A[\x20-\x7e]+\Z/
         
     | 
| 
       94 
     | 
    
         
            -
                    end
         
     | 
| 
       95 
150 
     | 
    
         
             
                  end
         
     | 
| 
       96 
151 
     | 
    
         
             
                end
         
     | 
| 
       97 
152 
     | 
    
         
             
              end
         
     | 
    
        data/lib/zsteg/checker.rb
    CHANGED
    
    | 
         @@ -1,16 +1,21 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'stringio'
         
     | 
| 
       2 
2 
     | 
    
         
             
            require 'zlib'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'set'
         
     | 
| 
       3 
4 
     | 
    
         | 
| 
       4 
5 
     | 
    
         
             
            module ZSteg
         
     | 
| 
       5 
6 
     | 
    
         
             
              class Checker
         
     | 
| 
       6 
     | 
    
         
            -
                attr_accessor :params, :channels, :verbose
         
     | 
| 
      
 7 
     | 
    
         
            +
                attr_accessor :params, :channels, :verbose, :results
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
                MIN_TEXT_LENGTH 
     | 
| 
      
 9 
     | 
    
         
            +
                MIN_TEXT_LENGTH      = 8
         
     | 
| 
      
 10 
     | 
    
         
            +
                MIN_WHOLETEXT_LENGTH = 6           # when entire data is a text
         
     | 
| 
      
 11 
     | 
    
         
            +
                DEFAULT_BITS         = [1,2,3,4]
         
     | 
| 
      
 12 
     | 
    
         
            +
                DEFAULT_ORDER        = 'auto'
         
     | 
| 
      
 13 
     | 
    
         
            +
                DEFAULT_LIMIT        = 256         # number of checked bytes, 0 = no limit
         
     | 
| 
       9 
14 
     | 
    
         | 
| 
       10 
15 
     | 
    
         
             
                # image can be either filename or ZPNG::Image
         
     | 
| 
       11 
16 
     | 
    
         
             
                def initialize image, params = {}
         
     | 
| 
       12 
17 
     | 
    
         
             
                  @params = params
         
     | 
| 
       13 
     | 
    
         
            -
                  @cache = {}
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @cache = {}; @wastitles = Set.new
         
     | 
| 
       14 
19 
     | 
    
         
             
                  @image = image.is_a?(ZPNG::Image) ? image : ZPNG::Image.load(image)
         
     | 
| 
       15 
20 
     | 
    
         
             
                  @extractor = Extractor.new(@image, params)
         
     | 
| 
       16 
21 
     | 
    
         
             
                  @channels = params[:channels] ||
         
     | 
| 
         @@ -19,32 +24,67 @@ module ZSteg 
     | 
|
| 
       19 
24 
     | 
    
         
             
                    else
         
     | 
| 
       20 
25 
     | 
    
         
             
                      %w'r g b rgb bgr'
         
     | 
| 
       21 
26 
     | 
    
         
             
                    end
         
     | 
| 
       22 
     | 
    
         
            -
                  @verbose = params[:verbose] ||  
     | 
| 
      
 27 
     | 
    
         
            +
                  @verbose = params[:verbose] || -2
         
     | 
| 
       23 
28 
     | 
    
         
             
                  @file_cmd = FileCmd.new
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @results = []
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  @params[:bits]  ||= DEFAULT_BITS
         
     | 
| 
      
 32 
     | 
    
         
            +
                  @params[:order] ||= DEFAULT_ORDER
         
     | 
| 
      
 33 
     | 
    
         
            +
                  @params[:limit] ||= DEFAULT_LIMIT
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                private
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                # catch Kernel#print for easier verbosity handling
         
     | 
| 
      
 39 
     | 
    
         
            +
                def print *args
         
     | 
| 
      
 40 
     | 
    
         
            +
                  Kernel.print(*args) if @verbose >= 0
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                # catch Kernel#printf for easier verbosity handling
         
     | 
| 
      
 44 
     | 
    
         
            +
                def printf *args
         
     | 
| 
      
 45 
     | 
    
         
            +
                  Kernel.printf(*args) if @verbose >= 0
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                # catch Kernel#puts for easier verbosity handling
         
     | 
| 
      
 49 
     | 
    
         
            +
                def puts *args
         
     | 
| 
      
 50 
     | 
    
         
            +
                  Kernel.puts(*args) if @verbose >= 0
         
     | 
| 
       24 
51 
     | 
    
         
             
                end
         
     | 
| 
       25 
52 
     | 
    
         | 
| 
      
 53 
     | 
    
         
            +
                public
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
       26 
55 
     | 
    
         
             
                def check
         
     | 
| 
       27 
56 
     | 
    
         
             
                  @found_anything = false
         
     | 
| 
       28 
57 
     | 
    
         
             
                  @file_cmd.start!
         
     | 
| 
       29 
58 
     | 
    
         | 
| 
       30 
59 
     | 
    
         
             
                  check_extradata
         
     | 
| 
       31 
60 
     | 
    
         
             
                  check_metadata
         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
                   
     | 
| 
       35 
     | 
    
         
            -
                    params[:order] 
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
      
 61 
     | 
    
         
            +
                  check_imagedata
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                  if @image.format == :bmp
         
     | 
| 
      
 64 
     | 
    
         
            +
                    case params[:order].to_s.downcase
         
     | 
| 
      
 65 
     | 
    
         
            +
                    when /all/
         
     | 
| 
      
 66 
     | 
    
         
            +
                      params[:order] = %w'bY xY xy yx XY YX Xy yX Yx'
         
     | 
| 
      
 67 
     | 
    
         
            +
                    when /auto/
         
     | 
| 
      
 68 
     | 
    
         
            +
                      params[:order] = %w'bY xY'
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
                  else
         
     | 
| 
      
 71 
     | 
    
         
            +
                    case params[:order].to_s.downcase
         
     | 
| 
      
 72 
     | 
    
         
            +
                    when /all/
         
     | 
| 
      
 73 
     | 
    
         
            +
                      params[:order] = %w'xy yx XY YX Xy yX xY Yx'
         
     | 
| 
      
 74 
     | 
    
         
            +
                    when /auto/
         
     | 
| 
      
 75 
     | 
    
         
            +
                      params[:order] = 'xy'
         
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
       38 
77 
     | 
    
         
             
                  end
         
     | 
| 
       39 
78 
     | 
    
         | 
| 
       40 
79 
     | 
    
         
             
                  Array(params[:order]).uniq.each do |order|
         
     | 
| 
       41 
     | 
    
         
            -
                     
     | 
| 
       42 
     | 
    
         
            -
                       
     | 
| 
       43 
     | 
    
         
            -
                         
     | 
| 
       44 
     | 
    
         
            -
                         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
      
 80 
     | 
    
         
            +
                    (params[:prime] == :all ? [false,true] : [params[:prime]]).each do |prime|
         
     | 
| 
      
 81 
     | 
    
         
            +
                      Array(params[:bits]).uniq.each do |bits|
         
     | 
| 
      
 82 
     | 
    
         
            +
                        p1 = @params.merge :bits => bits, :order => order, :prime => prime
         
     | 
| 
      
 83 
     | 
    
         
            +
                        if order[/b/i]
         
     | 
| 
      
 84 
     | 
    
         
            +
                          # byte iterator does not need channels
         
     | 
| 
      
 85 
     | 
    
         
            +
                          check_channels nil, p1
         
     | 
| 
      
 86 
     | 
    
         
            +
                        else
         
     | 
| 
      
 87 
     | 
    
         
            +
                          channels.each{ |c| check_channels c, p1 }
         
     | 
| 
       48 
88 
     | 
    
         
             
                        end
         
     | 
| 
       49 
89 
     | 
    
         
             
                      end
         
     | 
| 
       50 
90 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -55,15 +95,22 @@ module ZSteg 
     | 
|
| 
       55 
95 
     | 
    
         
             
                  else
         
     | 
| 
       56 
96 
     | 
    
         
             
                    puts "\r[=] nothing :(" + " "*20 # line cleanup
         
     | 
| 
       57 
97 
     | 
    
         
             
                  end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                  @results
         
     | 
| 
       58 
100 
     | 
    
         
             
                ensure
         
     | 
| 
       59 
101 
     | 
    
         
             
                  @file_cmd.stop!
         
     | 
| 
       60 
102 
     | 
    
         
             
                end
         
     | 
| 
       61 
103 
     | 
    
         | 
| 
      
 104 
     | 
    
         
            +
                def check_imagedata
         
     | 
| 
      
 105 
     | 
    
         
            +
                  h = { :title => "imagedata", :show_title => true }
         
     | 
| 
      
 106 
     | 
    
         
            +
                  process_result @image.imagedata, h
         
     | 
| 
      
 107 
     | 
    
         
            +
                end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
       62 
109 
     | 
    
         
             
                def check_extradata
         
     | 
| 
       63 
110 
     | 
    
         
             
                  if @image.extradata
         
     | 
| 
       64 
111 
     | 
    
         
             
                    @found_anything = true
         
     | 
| 
       65 
112 
     | 
    
         
             
                    title = "data after IEND"
         
     | 
| 
       66 
     | 
    
         
            -
                    show_title title, : 
     | 
| 
      
 113 
     | 
    
         
            +
                    show_title title, :bright_red
         
     | 
| 
       67 
114 
     | 
    
         
             
                    process_result @image.extradata, :special => true, :title => title
         
     | 
| 
       68 
115 
     | 
    
         
             
                  end
         
     | 
| 
       69 
116 
     | 
    
         
             
                end
         
     | 
| 
         @@ -83,24 +130,73 @@ module ZSteg 
     | 
|
| 
       83 
130 
     | 
    
         
             
                    return
         
     | 
| 
       84 
131 
     | 
    
         
             
                  end
         
     | 
| 
       85 
132 
     | 
    
         | 
| 
       86 
     | 
    
         
            -
                  title = ["#{params[:bits]}b",channels,params[:bit_order],params[:order]].compact.join(',')
         
     | 
| 
       87 
     | 
    
         
            -
                  show_title title
         
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
133 
     | 
    
         
             
                  p1 = params.clone
         
     | 
| 
       90 
     | 
    
         
            -
                  p1.delete :channel
         
     | 
| 
       91 
     | 
    
         
            -
                  p1[:title] = title
         
     | 
| 
       92 
134 
     | 
    
         | 
| 
      
 135 
     | 
    
         
            +
                  # number of bits
         
     | 
| 
      
 136 
     | 
    
         
            +
                  # equals to params[:bits] if in range 1..8
         
     | 
| 
      
 137 
     | 
    
         
            +
                  # otherwise equals to number of 1's, like 0b1000_0001
         
     | 
| 
      
 138 
     | 
    
         
            +
                  nbits = p1[:bits] <= 8 ? p1[:bits] : (p1[:bits]&0xff).to_s(2).count("1")
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                  show_bits = true
         
     | 
| 
      
 141 
     | 
    
         
            +
                  # channels is a String
         
     | 
| 
       93 
142 
     | 
    
         
             
                  if channels
         
     | 
| 
       94 
     | 
    
         
            -
                    p1[:channels] = 
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
      
 143 
     | 
    
         
            +
                    p1[:channels] =
         
     | 
| 
      
 144 
     | 
    
         
            +
                      if channels[1] && channels[1] =~ /\A\d\Z/
         
     | 
| 
      
 145 
     | 
    
         
            +
                        # 'r3g2b3'
         
     | 
| 
      
 146 
     | 
    
         
            +
                        a=[]
         
     | 
| 
      
 147 
     | 
    
         
            +
                        cbits = 0
         
     | 
| 
      
 148 
     | 
    
         
            +
                        (channels.size/2).times do |i|
         
     | 
| 
      
 149 
     | 
    
         
            +
                          a << (t=channels[i*2,2])
         
     | 
| 
      
 150 
     | 
    
         
            +
                          cbits += t[1].to_i
         
     | 
| 
      
 151 
     | 
    
         
            +
                        end
         
     | 
| 
      
 152 
     | 
    
         
            +
                        show_bits = false
         
     | 
| 
      
 153 
     | 
    
         
            +
                        @max_hidden_size = cbits * @image.width
         
     | 
| 
      
 154 
     | 
    
         
            +
                        a
         
     | 
| 
      
 155 
     | 
    
         
            +
                      else
         
     | 
| 
      
 156 
     | 
    
         
            +
                        # 'rgb'
         
     | 
| 
      
 157 
     | 
    
         
            +
                        a = channels.chars.to_a
         
     | 
| 
      
 158 
     | 
    
         
            +
                        @max_hidden_size = a.size * @image.width * nbits
         
     | 
| 
      
 159 
     | 
    
         
            +
                        a
         
     | 
| 
      
 160 
     | 
    
         
            +
                      end
         
     | 
| 
      
 161 
     | 
    
         
            +
                    # p1[:channels] is an Array
         
     | 
| 
       96 
162 
     | 
    
         
             
                  elsif params[:order] =~ /b/i
         
     | 
| 
       97 
163 
     | 
    
         
             
                    # byte extractor
         
     | 
| 
       98 
     | 
    
         
            -
                    @max_hidden_size = @image.scanlines[0].decoded_bytes.size
         
     | 
| 
      
 164 
     | 
    
         
            +
                    @max_hidden_size = @image.scanlines[0].decoded_bytes.size * nbits
         
     | 
| 
       99 
165 
     | 
    
         
             
                  else
         
     | 
| 
       100 
166 
     | 
    
         
             
                    raise "invalid params #{params.inspect}"
         
     | 
| 
       101 
167 
     | 
    
         
             
                  end
         
     | 
| 
       102 
     | 
    
         
            -
                  @max_hidden_size *=  
     | 
| 
      
 168 
     | 
    
         
            +
                  @max_hidden_size *= @image.height/8
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                  bits_tag =
         
     | 
| 
      
 171 
     | 
    
         
            +
                    if show_bits
         
     | 
| 
      
 172 
     | 
    
         
            +
                      if params[:bits] > 0x100
         
     | 
| 
      
 173 
     | 
    
         
            +
                        if params[:bits].to_s(2) =~ /(1{1,8})$/
         
     | 
| 
      
 174 
     | 
    
         
            +
                          # mask => number of bits
         
     | 
| 
      
 175 
     | 
    
         
            +
                          "b#{$1.size}"
         
     | 
| 
      
 176 
     | 
    
         
            +
                        else
         
     | 
| 
      
 177 
     | 
    
         
            +
                          # mask
         
     | 
| 
      
 178 
     | 
    
         
            +
                          "b#{(params[:bits]&0xff).to_s(2)}"
         
     | 
| 
      
 179 
     | 
    
         
            +
                        end
         
     | 
| 
      
 180 
     | 
    
         
            +
                      else
         
     | 
| 
      
 181 
     | 
    
         
            +
                        # number of bits
         
     | 
| 
      
 182 
     | 
    
         
            +
                        "b#{params[:bits]}"
         
     | 
| 
      
 183 
     | 
    
         
            +
                      end
         
     | 
| 
      
 184 
     | 
    
         
            +
                    end
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
                  title = [
         
     | 
| 
      
 187 
     | 
    
         
            +
                    bits_tag,
         
     | 
| 
      
 188 
     | 
    
         
            +
                    channels,
         
     | 
| 
      
 189 
     | 
    
         
            +
                    params[:bit_order],
         
     | 
| 
      
 190 
     | 
    
         
            +
                    params[:order],
         
     | 
| 
      
 191 
     | 
    
         
            +
                    params[:prime] ? 'prime' : nil
         
     | 
| 
      
 192 
     | 
    
         
            +
                  ].compact.join(',')
         
     | 
| 
       103 
193 
     | 
    
         | 
| 
      
 194 
     | 
    
         
            +
                  return if @wastitles.include?(title)
         
     | 
| 
      
 195 
     | 
    
         
            +
                  @wastitles << title
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
                  show_title title
         
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
      
 199 
     | 
    
         
            +
                  p1[:title] = title
         
     | 
| 
       104 
200 
     | 
    
         
             
                  data = @extractor.extract p1
         
     | 
| 
       105 
201 
     | 
    
         | 
| 
       106 
202 
     | 
    
         
             
                  @need_cr = !process_result(data, p1) # carriage return needed?
         
     | 
| 
         @@ -108,7 +204,7 @@ module ZSteg 
     | 
|
| 
       108 
204 
     | 
    
         
             
                end
         
     | 
| 
       109 
205 
     | 
    
         | 
| 
       110 
206 
     | 
    
         
             
                def show_title title, color = :gray
         
     | 
| 
       111 
     | 
    
         
            -
                  printf "\r 
     | 
| 
      
 207 
     | 
    
         
            +
                  printf "\r%-20s.. ".send(color), title
         
     | 
| 
       112 
208 
     | 
    
         
             
                  $stdout.flush
         
     | 
| 
       113 
209 
     | 
    
         
             
                end
         
     | 
| 
       114 
210 
     | 
    
         | 
| 
         @@ -129,12 +225,15 @@ module ZSteg 
     | 
|
| 
       129 
225 
     | 
    
         
             
                  # TODO: store hash of data for large datas
         
     | 
| 
       130 
226 
     | 
    
         
             
                  @cache[data] = params[:title]
         
     | 
| 
       131 
227 
     | 
    
         | 
| 
       132 
     | 
    
         
            -
                  result = data2result 
     | 
| 
      
 228 
     | 
    
         
            +
                  if result = data2result(data, params)
         
     | 
| 
      
 229 
     | 
    
         
            +
                    @results << result
         
     | 
| 
      
 230 
     | 
    
         
            +
                  end
         
     | 
| 
       133 
231 
     | 
    
         | 
| 
       134 
232 
     | 
    
         
             
                  case verbose
         
     | 
| 
       135 
233 
     | 
    
         
             
                  when -999..0
         
     | 
| 
       136 
234 
     | 
    
         
             
                    # verbosity=0: only show result if anything interesting found
         
     | 
| 
       137 
235 
     | 
    
         
             
                    if result && !result.is_a?(Result::OneChar)
         
     | 
| 
      
 236 
     | 
    
         
            +
                      show_title params[:title] if params[:show_title]
         
     | 
| 
       138 
237 
     | 
    
         
             
                      puts result
         
     | 
| 
       139 
238 
     | 
    
         
             
                      return true
         
     | 
| 
       140 
239 
     | 
    
         
             
                    else
         
     | 
| 
         @@ -146,6 +245,7 @@ module ZSteg 
     | 
|
| 
       146 
245 
     | 
    
         
             
                  end
         
     | 
| 
       147 
246 
     | 
    
         | 
| 
       148 
247 
     | 
    
         
             
                  # verbosity>1: always show hexdump
         
     | 
| 
      
 248 
     | 
    
         
            +
                  show_title params[:title] if params[:show_title]
         
     | 
| 
       149 
249 
     | 
    
         | 
| 
       150 
250 
     | 
    
         
             
                  if params[:special]
         
     | 
| 
       151 
251 
     | 
    
         
             
                    puts result.is_a?(Result::PartialText) ? nil : result
         
     | 
| 
         @@ -183,24 +283,27 @@ module ZSteg 
     | 
|
| 
       183 
283 
     | 
    
         
             
                    end
         
     | 
| 
       184 
284 
     | 
    
         
             
                  end
         
     | 
| 
       185 
285 
     | 
    
         | 
| 
       186 
     | 
    
         
            -
                  if data =~ /\A[\x20-\x7e\r\n\t]+\Z/
         
     | 
| 
      
 286 
     | 
    
         
            +
                  if data.size >= MIN_WHOLETEXT_LENGTH && data =~ /\A[\x20-\x7e\r\n\t]+\Z/
         
     | 
| 
       187 
287 
     | 
    
         
             
                    # whole ASCII
         
     | 
| 
       188 
288 
     | 
    
         
             
                    return Result::WholeText.new(data, 0)
         
     | 
| 
       189 
289 
     | 
    
         
             
                  end
         
     | 
| 
       190 
290 
     | 
    
         | 
| 
       191 
     | 
    
         
            -
                   
     | 
| 
       192 
     | 
    
         
            -
             
     | 
| 
      
 291 
     | 
    
         
            +
                  # XXX TODO refactor params hack
         
     | 
| 
      
 292 
     | 
    
         
            +
                  if !params.key?(:no_check_file) && (r = @file_cmd.data2result(data))
         
     | 
| 
      
 293 
     | 
    
         
            +
                    return r
         
     | 
| 
       193 
294 
     | 
    
         
             
                  end
         
     | 
| 
       194 
295 
     | 
    
         | 
| 
      
 296 
     | 
    
         
            +
                  # try to find zlib
         
     | 
| 
       195 
297 
     | 
    
         
             
                  # http://blog.w3challs.com/index.php?post/2012/03/25/NDH2k12-Prequals-We-are-looking-for-a-real-hacker-Wallpaper-image
         
     | 
| 
       196 
298 
     | 
    
         
             
                  # http://blog.w3challs.com/public/ndh2k12_prequalls/sp113.bmp
         
     | 
| 
       197 
     | 
    
         
            -
                   
     | 
| 
      
 299 
     | 
    
         
            +
                  # XXX TODO refactor params hack
         
     | 
| 
      
 300 
     | 
    
         
            +
                  if !params.key?(:no_check_zlib) && (idx = data.index(/\x78[\x9c\xda\x01]/))
         
     | 
| 
       198 
301 
     | 
    
         
             
                    begin
         
     | 
| 
       199 
302 
     | 
    
         
             
            #          x = Zlib::Inflate.inflate(data[idx,4096])
         
     | 
| 
       200 
303 
     | 
    
         
             
                      zi = Zlib::Inflate.new(Zlib::MAX_WBITS)
         
     | 
| 
       201 
304 
     | 
    
         
             
                      x = zi.inflate data[idx..-1]
         
     | 
| 
       202 
305 
     | 
    
         
             
                      # decompress OK
         
     | 
| 
       203 
     | 
    
         
            -
                      return Result::Zlib.new x, idx
         
     | 
| 
      
 306 
     | 
    
         
            +
                      return Result::Zlib.new x, idx if x.size > 2
         
     | 
| 
       204 
307 
     | 
    
         
             
                    rescue Zlib::BufError
         
     | 
| 
       205 
308 
     | 
    
         
             
                      # tried to decompress, but got EOF - need more data
         
     | 
| 
       206 
309 
     | 
    
         
             
                      return Result::Zlib.new x, idx
         
     |