zsteg 0.2.11 → 0.2.13

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/Gemfile.lock +34 -33
  4. data/README.md +14 -25
  5. data/Rakefile +1 -1
  6. data/VERSION +1 -1
  7. data/cmp_png.rb +1 -1
  8. data/lib/zsteg/checker/steganography_png.rb +36 -0
  9. data/lib/zsteg/checker.rb +65 -32
  10. data/lib/zsteg/cli/cli.rb +47 -34
  11. data/lib/zsteg/extractor/byte_extractor.rb +5 -2
  12. data/lib/zsteg/extractor/color_extractor.rb +5 -5
  13. data/lib/zsteg.rb +0 -4
  14. data/spec/checker_spec.rb +3 -3
  15. data/spec/spec_helper.rb +2 -1
  16. data/spec/steganography_png_spec.rb +13 -0
  17. data/spec/zlib_spec.rb +1 -1
  18. data/zsteg.gemspec +10 -38
  19. metadata +9 -37
  20. data/pngsteg.gemspec +0 -65
  21. data/samples/hackquest/crypt.bmp +0 -0
  22. data/samples/hackquest/square.bmp +0 -0
  23. data/samples/newbiecontest/alph1-surprise.bmp.7z +0 -0
  24. data/samples/wbstego/wbsteg_blowfish_pass_1.bmp +0 -0
  25. data/samples/wbstego/wbsteg_cast128_pass_1.bmp +0 -0
  26. data/samples/wbstego/wbsteg_enc_pass_pass.bmp +0 -0
  27. data/samples/wbstego/wbsteg_enc_pass_pass_even.bmp +0 -0
  28. data/samples/wbstego/wbsteg_mix_pass_1.bmp +0 -0
  29. data/samples/wbstego/wbsteg_mix_pass_1_even.bmp +0 -0
  30. data/samples/wbstego/wbsteg_mix_pass_foobar.bmp +0 -0
  31. data/samples/wbstego/wbsteg_mix_pass_pass.bmp +0 -0
  32. data/samples/wbstego/wbsteg_mixenc_pass_pass_even.bmp +0 -0
  33. data/samples/wbstego/wbsteg_noenc.bmp +0 -0
  34. data/samples/wbstego/wbsteg_noenc.png +0 -0
  35. data/samples/wbstego/wbsteg_noenc_.bmp +0 -0
  36. data/samples/wbstego/wbsteg_noenc_17.bmp +0 -0
  37. data/samples/wbstego/wbsteg_noenc__.bmp +0 -0
  38. data/samples/wbstego/wbsteg_noenc_even.bmp +0 -0
  39. data/samples/wbstego/wbsteg_noenc_even2.bmp +0 -0
  40. data/samples/wbstego/wbsteg_noenc_even_17.bmp +0 -0
  41. data/samples/wbstego/wbsteg_noenc_even_17_.bmp +0 -0
  42. data/samples/wbstego/wbsteg_noenc_ext_ABC.bmp +0 -0
  43. data/samples/wbstego/wbsteg_rijndael_pass_1.bmp +0 -0
  44. data/samples/wbstego/wbsteg_rijndael_pass_pass.bmp +0 -0
  45. data/samples/wbstego/wbsteg_rijndael_pass_pass_even.bmp +0 -0
  46. data/samples/wbstego/wbsteg_twofish_pass_1.bmp +0 -0
  47. data/samples/wechall/5ZMGcCLxpcpsru03.g00000010.png +0 -0
  48. data/samples/wechall/5ZMGcCLxpcpsru03.png +0 -0
  49. data/samples/wechall/stegano1.bmp +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 492cf8819fa642e0485ae66c7b0942746f785b25fa10c3d0b6029ad93078783a
4
- data.tar.gz: cde21ec01b7e5b3ea7a85e6817df0497ac2f91fb145739ae6702dcf7b3ee6832
3
+ metadata.gz: 05bf462c6bc2696efead731d0ce3bda8cf371435cc9448b100892b7084364c64
4
+ data.tar.gz: c12f610fe42706271d763620100a71572477696c07010d9323c1bb97f7440fbe
5
5
  SHA512:
6
- metadata.gz: e0894f6e7d76dee86646251dd6768c0887c654ae0f5d560be4c65726666a4b7cf6028fb003ab0468cb8f33706fdecaabcd3b19b36e25e39537b7539482bb6455
7
- data.tar.gz: ac61068f1b9d4c914f9543a81623c387e826d996e35a57ed5db6fa449cff9a303345e44d7d1e0070e70aacdf03509441589824d6978208ce5b63957c0adb99de
6
+ metadata.gz: 3340516e94d8248446ddb5df7a64269aed8fb4b09a1bf10057d603581b352e39adc595104ae4b75fa042d8895459532dac21c2304cc49bfe222ffc0df358fa55
7
+ data.tar.gz: d4bd9eaf13356a534eeb3be2807b524c73549dc0d3fbe44f349393930f0f4a31be1430b434d4ef8fb42ea2c2eda42dd13eb013222fc37714ce9801973358ba8e
data/Gemfile CHANGED
@@ -1,7 +1,7 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- gem "zpng", ">= 0.4.3"
4
- gem "iostruct"
3
+ gem "zpng", ">= 0.4.5"
4
+ gem "iostruct", ">= 0.0.5"
5
5
  gem "prime"
6
6
 
7
7
  group :development do
data/Gemfile.lock CHANGED
@@ -1,13 +1,13 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- addressable (2.8.0)
5
- public_suffix (>= 2.0.2, < 5.0)
4
+ addressable (2.8.1)
5
+ public_suffix (>= 2.0.2, < 6.0)
6
6
  builder (3.2.4)
7
7
  descendants_tracker (0.0.4)
8
8
  thread_safe (~> 0.3, >= 0.3.1)
9
9
  diff-lcs (1.5.0)
10
- faraday (1.10.0)
10
+ faraday (1.10.3)
11
11
  faraday-em_http (~> 1.0)
12
12
  faraday-em_synchrony (~> 1.0)
13
13
  faraday-excon (~> 1.1)
@@ -30,8 +30,9 @@ GEM
30
30
  faraday-patron (1.0.0)
31
31
  faraday-rack (1.0.0)
32
32
  faraday-retry (1.0.3)
33
- forwardable (1.3.2)
34
- git (1.11.0)
33
+ forwardable (1.3.3)
34
+ git (1.13.2)
35
+ addressable (~> 2.8)
35
36
  rchardet (~> 1.8)
36
37
  github_api (0.19.0)
37
38
  addressable (~> 2.4)
@@ -40,8 +41,8 @@ GEM
40
41
  hashie (~> 3.5, >= 3.5.2)
41
42
  oauth2 (~> 1.0)
42
43
  hashie (3.6.0)
43
- highline (2.0.3)
44
- iostruct (0.0.4)
44
+ highline (2.1.0)
45
+ iostruct (0.0.5)
45
46
  juwelier (2.4.9)
46
47
  builder
47
48
  bundler
@@ -54,65 +55,65 @@ GEM
54
55
  rake
55
56
  rdoc
56
57
  semver2
57
- jwt (2.4.1)
58
+ jwt (2.7.0)
58
59
  kamelcase (0.0.2)
59
60
  semver2 (~> 3)
60
- mini_portile2 (2.8.0)
61
+ mini_portile2 (2.8.1)
61
62
  multi_json (1.15.0)
62
63
  multi_xml (0.6.0)
63
- multipart-post (2.2.3)
64
- nokogiri (1.13.6)
64
+ multipart-post (2.3.0)
65
+ nokogiri (1.14.2)
65
66
  mini_portile2 (~> 2.8.0)
66
67
  racc (~> 1.4)
67
- oauth2 (1.4.9)
68
+ oauth2 (1.4.11)
68
69
  faraday (>= 0.17.3, < 3.0)
69
70
  jwt (>= 1.0, < 3.0)
70
71
  multi_json (~> 1.3)
71
72
  multi_xml (~> 0.5)
72
- rack (>= 1.2, < 3)
73
+ rack (>= 1.2, < 4)
73
74
  prime (0.1.2)
74
75
  forwardable
75
76
  singleton
76
- psych (4.0.4)
77
+ psych (5.1.0)
77
78
  stringio
78
- public_suffix (4.0.7)
79
- racc (1.6.0)
80
- rack (2.2.3.1)
79
+ public_suffix (5.0.1)
80
+ racc (1.6.2)
81
+ rack (3.0.4.1)
81
82
  rainbow (3.1.1)
82
83
  rake (13.0.6)
83
84
  rchardet (1.8.0)
84
- rdoc (6.4.0)
85
+ rdoc (6.5.0)
85
86
  psych (>= 4.0.0)
86
- rspec (3.11.0)
87
- rspec-core (~> 3.11.0)
88
- rspec-expectations (~> 3.11.0)
89
- rspec-mocks (~> 3.11.0)
90
- rspec-core (3.11.0)
91
- rspec-support (~> 3.11.0)
92
- rspec-expectations (3.11.0)
87
+ rspec (3.12.0)
88
+ rspec-core (~> 3.12.0)
89
+ rspec-expectations (~> 3.12.0)
90
+ rspec-mocks (~> 3.12.0)
91
+ rspec-core (3.12.1)
92
+ rspec-support (~> 3.12.0)
93
+ rspec-expectations (3.12.2)
93
94
  diff-lcs (>= 1.2.0, < 2.0)
94
- rspec-support (~> 3.11.0)
95
- rspec-mocks (3.11.1)
95
+ rspec-support (~> 3.12.0)
96
+ rspec-mocks (3.12.3)
96
97
  diff-lcs (>= 1.2.0, < 2.0)
97
- rspec-support (~> 3.11.0)
98
- rspec-support (3.11.0)
98
+ rspec-support (~> 3.12.0)
99
+ rspec-support (3.12.0)
99
100
  ruby2_keywords (0.0.5)
100
101
  semver2 (3.4.2)
101
102
  singleton (0.1.1)
102
- stringio (3.0.2)
103
+ stringio (3.0.5)
103
104
  thread_safe (0.3.6)
104
- zpng (0.4.3)
105
+ zpng (0.4.5)
105
106
  rainbow (~> 3.1.1)
106
107
 
107
108
  PLATFORMS
108
109
  ruby
109
110
 
110
111
  DEPENDENCIES
111
- iostruct
112
+ iostruct (>= 0.0.5)
112
113
  juwelier
113
114
  prime
114
115
  rspec
115
- zpng (>= 0.4.3)
116
+ zpng (>= 0.4.5)
116
117
 
117
118
  BUNDLED WITH
118
119
  2.3.12
data/README.md CHANGED
@@ -28,26 +28,32 @@ Usage
28
28
 
29
29
  Usage: zsteg [options] filename.png [param_string]
30
30
 
31
+ -a, --all try all known methods
32
+ -E, --extract NAME extract specified payload, NAME is like '1b,rgb,lsb'
33
+
34
+ Iteration/extraction params:
35
+ -o, --order X pixel iteration order (default: 'auto')
36
+ valid values: ALL,xy,yx,XY,YX,xY,Xy,bY,...
31
37
  -c, --channels X channels (R/G/B/A) or any combination, comma separated
32
38
  valid values: r,g,b,a,rg,bgr,rgba,r3g2b3,...
33
- -l, --limit N limit bytes checked, 0 = no limit (default: 256)
34
39
  -b, --bits N number of bits, single int value or '1,3,5' or range '1-8'
35
40
  advanced: specify individual bits like '00001110' or '0x88'
36
- --lsb least significant BIT comes first
37
- --msb most significant BIT comes first
41
+ --lsb least significant bit comes first
42
+ --msb most significant bit comes first
38
43
  -P, --prime analyze/extract only prime bytes/pixels
44
+ --shift N prepend N zero bits
45
+ --step N step
39
46
  --invert invert bits (XOR 0xff)
40
- -a, --all try all known methods
41
- -o, --order X pixel iteration order (default: 'auto')
42
- valid values: ALL,xy,yx,XY,YX,xY,Xy,bY,...
43
- -E, --extract NAME extract specified payload, NAME is like '1b,rgb,lsb'
47
+ --pixel-align pixel-align hidden data
48
+
49
+ Analysis params:
50
+ -l, --limit N limit bytes checked, 0 = no limit (default: 256)
44
51
 
45
52
  --[no-]file use 'file' command to detect data type (default: YES)
46
53
  --no-strings disable ASCII strings finding (default: enabled)
47
54
  -s, --strings X ASCII strings find mode: first, all, longest, none
48
55
  (default: first)
49
56
  -n, --min-str-len X minimum string length (default: 8)
50
- --shift N prepend N zero bits
51
57
 
52
58
  -v, --verbose Run verbosely (can be used multiple times)
53
59
  -q, --quiet Silent any warnings (can be used multiple times)
@@ -85,23 +91,6 @@ Examples
85
91
 
86
92
  # zsteg wbstego/wbsteg_noenc_even.bmp 1b,lsb,bY -v
87
93
 
88
- imagedata .. file: FoxPro FPT, blocks size 1, next free block index 65537
89
- 00000000: 00 01 00 01 00 00 00 01 00 00 00 00 00 00 00 00 |................|
90
- 00000010: 00 00 00 00 00 00 00 00 00 00 00 01 00 01 01 00 |................|
91
- 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
92
- 00000030: 00 01 01 01 00 01 00 00 00 00 00 00 01 01 00 01 |................|
93
- 00000040: 01 00 01 01 00 01 00 01 00 01 01 01 01 00 00 00 |................|
94
- 00000050: 00 00 00 01 01 01 01 00 01 00 01 00 00 00 00 01 |................|
95
- 00000060: 00 00 01 01 01 00 00 01 00 01 01 01 00 01 00 00 |................|
96
- 00000070: 01 01 01 00 01 00 00 00 00 00 01 01 01 00 00 00 |................|
97
- 00000080: 00 01 00 01 00 00 01 01 01 01 00 00 00 01 01 00 |................|
98
- 00000090: 00 01 00 01 00 01 01 00 01 00 00 01 00 01 00 00 |................|
99
- 000000a0: 00 01 01 01 00 01 00 01 01 01 00 01 00 00 00 01 |................|
100
- 000000b0: 01 00 01 00 00 01 00 01 00 01 01 01 00 00 00 00 |................|
101
- 000000c0: 01 00 00 00 00 01 00 00 01 01 00 00 01 00 00 00 |................|
102
- 000000d0: 00 00 01 00 00 01 01 01 00 01 01 00 00 01 00 01 |................|
103
- 000000e0: 01 01 01 01 01 01 01 00 00 00 00 00 01 00 00 00 |................|
104
- 000000f0: 00 01 01 01 00 00 01 00 00 00 01 01 00 01 00 01 |................|
105
94
  b1,lsb,bY .. <wbStego size=22, data="xtSuperSecretMessage\n", even=true, mix=true, controlbyte="t">
106
95
  00000000: 51 00 00 16 00 00 74 0d b5 78 1e a1 39 74 e8 38 |Q.....t..x..9t.8|
107
96
  00000010: 53 c6 56 94 75 d1 a5 70 84 c8 27 65 fe 08 72 35 |S.V.u..p..'e..r5|
data/Rakefile CHANGED
@@ -24,7 +24,7 @@ Juwelier::Tasks.new do |gem|
24
24
  #gem.executables = %w'zsteg'
25
25
  gem.files.include "lib/**/*.rb"
26
26
  gem.files.include "bin/*"
27
- gem.files.exclude "samples/*"
27
+ gem.files.exclude "samples/**/*"
28
28
  # dependencies defined in Gemfile
29
29
  end
30
30
  Juwelier::RubygemsDotOrgTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.11
1
+ 0.2.13
data/cmp_png.rb CHANGED
@@ -5,7 +5,7 @@ require 'awesome_print'
5
5
  images = ARGV.map{ |fname| ZPNG::Image.load(fname) }
6
6
  raise "need at least 2 images" if images.size < 2
7
7
 
8
- limit = 20
8
+ limit = 100
9
9
  alpha_used = images.any?(&:alpha_used?)
10
10
  channels = alpha_used ? %w'r g b a' : %w'r g b'
11
11
 
@@ -0,0 +1,36 @@
1
+ # coding: binary
2
+ module ZSteg
3
+ class Checker
4
+ module SteganographyPNG
5
+
6
+ URL = "https://github.com/pedrooaugusto/steganography-png"
7
+
8
+ # https://github.com/pedrooaugusto/steganography-png/blob/2a0e038c135e41438b4c2c93821227a2289b4203/scanlines/scanlines.go#L234
9
+ #
10
+ # The secret metadata is stored in the last bytes of the last scanline in the form of:
11
+ # 17 107 [bitloss] [secret size - 4 bytes] [secret type] [secret type length]
12
+ # 17 107 1 4096 "text/plain" 10
13
+
14
+ class Result < IOStruct.new "nCNa*", :magic, :bitloss, :secret_size, :secret_type
15
+ def valid?
16
+ magic == 0x116b && (1..8).include?(bitloss)
17
+ end
18
+
19
+ def to_s
20
+ super.sub('#<struct ZSteg::Checker::SteganographyPNG::Result', 'SteganographyPNG').sub(/>$/,'').bright_red
21
+ end
22
+ end
23
+
24
+ def self.check_image image, _params = {}
25
+ ls = image.scanlines.last
26
+ data = ls.decoded_bytes
27
+ secret_type_length = data[-1].ord
28
+ return nil if secret_type_length > data.size - 8
29
+ data = data[ -secret_type_length-8 .. -2 ]
30
+ # data.size to prevent "want 8 bytes, got 7" IOStruct warning when secret_type_length == 0
31
+ r = Result.read(data, data.size)
32
+ r.valid? && [r, URL]
33
+ end
34
+ end
35
+ end
36
+ end
data/lib/zsteg/checker.rb CHANGED
@@ -3,6 +3,11 @@ require 'stringio'
3
3
  require 'zlib'
4
4
  require 'set'
5
5
 
6
+ require 'zsteg/checker/scanline_checker'
7
+ require 'zsteg/checker/steganography_png'
8
+ require 'zsteg/checker/wbstego'
9
+ require 'zsteg/checker/zlib'
10
+
6
11
  module ZSteg
7
12
  class Checker
8
13
  attr_accessor :params, :channels, :verbose, :results
@@ -46,20 +51,20 @@ module ZSteg
46
51
 
47
52
  private
48
53
 
49
- # catch Kernel#print for easier verbosity handling
50
- def print *args
51
- Kernel.print(*args) if @verbose >= 0
52
- end
53
-
54
- # catch Kernel#printf for easier verbosity handling
55
- def printf *args
56
- Kernel.printf(*args) if @verbose >= 0
57
- end
58
-
59
- # catch Kernel#puts for easier verbosity handling
60
- def puts *args
61
- Kernel.puts(*args) if @verbose >= 0
62
- end
54
+ # # catch Kernel#print for easier verbosity handling
55
+ # def print *args
56
+ # Kernel.print(*args) if @verbose >= 0
57
+ # end
58
+ #
59
+ # # catch Kernel#printf for easier verbosity handling
60
+ # def printf *args
61
+ # Kernel.printf(*args) if @verbose >= 0
62
+ # end
63
+ #
64
+ # # catch Kernel#puts for easier verbosity handling
65
+ # def puts *args
66
+ # Kernel.puts(*args) if @verbose >= 0
67
+ # end
63
68
 
64
69
  public
65
70
 
@@ -92,12 +97,26 @@ module ZSteg
92
97
  Array(params[:order]).uniq.each do |order|
93
98
  (params[:prime] == :all ? [false,true] : [params[:prime]]).each do |prime|
94
99
  Array(params[:bits]).uniq.each do |bits|
95
- p1 = @params.merge :bits => bits, :order => order, :prime => prime
96
- if order[/b/i]
97
- # byte iterator does not need channels
98
- check_channels nil, p1
100
+ if params[:pixel_align] == :all
101
+ [false, true].each do |pixel_align|
102
+ # skip cases when output will be identical for pixel_align true/false
103
+ next if pixel_align && (8%bits) == 0
104
+ p1 = @params.merge bits: bits, order: order, prime: prime, pixel_align: pixel_align
105
+ if order[/b/i]
106
+ # byte iterator does not need channels
107
+ check_channels nil, p1
108
+ else
109
+ channels.each{ |c| check_channels c, p1 }
110
+ end
111
+ end
99
112
  else
100
- channels.each{ |c| check_channels c, p1 }
113
+ p1 = @params.merge bits: bits, order: order, prime: prime
114
+ if order[/b/i]
115
+ # byte iterator does not need channels
116
+ check_channels nil, p1
117
+ else
118
+ channels.each{ |c| check_channels c, p1 }
119
+ end
101
120
  end
102
121
  end
103
122
  end
@@ -150,6 +169,13 @@ module ZSteg
150
169
  show_title title, :bright_red
151
170
  process_result data, :special => true, :title => title
152
171
  end
172
+
173
+ if r = SteganographyPNG.check_image(@image, @params)
174
+ @found_anything = true
175
+ title = "image"
176
+ show_title title, :bright_red
177
+ process_result nil, title: title, result: r
178
+ end
153
179
  end
154
180
 
155
181
  def check_metadata
@@ -220,6 +246,8 @@ module ZSteg
220
246
  end
221
247
  end
222
248
 
249
+ bits_tag << "p" if params[:pixel_align]
250
+
223
251
  title = [
224
252
  bits_tag,
225
253
  channels,
@@ -268,21 +296,26 @@ module ZSteg
268
296
  def process_result data, params
269
297
  verbose = params[:special] ? [@verbose,1.5].max : @verbose
270
298
 
271
- if @cache[data]
272
- if verbose > 1
273
- puts "[same as #{@cache[data].inspect}]".gray
274
- return true
275
- else
276
- # silent return
277
- return false
299
+ result = nil
300
+ if data
301
+ if @cache[data]
302
+ if verbose > 1
303
+ puts "[same as #{@cache[data].inspect}]".gray
304
+ return true
305
+ else
306
+ # silent return
307
+ return false
308
+ end
278
309
  end
279
- end
280
310
 
281
- # TODO: store hash of data for large datas
282
- @cache[data] = params[:title]
311
+ # TODO: store hash of data for large datas
312
+ @cache[data] = params[:title]
283
313
 
284
- if result = data2result(data, params)
285
- @results << result
314
+ if result = data2result(data, params)
315
+ @results << result
316
+ end
317
+ elsif !(result = params[:result])
318
+ raise "[?] No data nor result"
286
319
  end
287
320
 
288
321
  case verbose
@@ -309,7 +342,7 @@ module ZSteg
309
342
  else
310
343
  show_result result, params
311
344
  end
312
- if data.size > 0 && !result.is_a?(Result::OneChar) && !result.is_a?(Result::WholeText)
345
+ if data && data.size > 0 && !result.is_a?(Result::OneChar) && !result.is_a?(Result::WholeText)
313
346
  # newline if no results and want hexdump
314
347
  puts if !result || result == []
315
348
  limit = (params[:limit] || @params[:limit]).to_i
data/lib/zsteg/cli/cli.rb CHANGED
@@ -11,14 +11,39 @@ module ZSteg
11
11
  def run
12
12
  @actions = []
13
13
  @options = {
14
- :verbose => 0,
15
- :limit => Checker::DEFAULT_LIMIT,
16
- :order => Checker::DEFAULT_ORDER
14
+ verbose: 0,
15
+ limit: Checker::DEFAULT_LIMIT,
16
+ order: Checker::DEFAULT_ORDER,
17
+ step: 1,
18
+ ystep: 1,
17
19
  }
18
20
  optparser = OptionParser.new do |opts|
19
21
  opts.banner = "Usage: zsteg [options] filename.png [param_string]"
20
22
  opts.separator ""
21
23
 
24
+ opts.on "-a", "--all", "try all known methods" do
25
+ @options[:prime] = :all
26
+ @options[:order] = :all
27
+ @options[:pixel_align] = :all
28
+ @options[:bits] = (1..8).to_a
29
+ # specifying --all on command line explicitly enables extra checks
30
+ @options[:extra_checks] = true
31
+ end
32
+
33
+ opts.on "-E", "--extract NAME", "extract specified payload, NAME is like '1b,rgb,lsb'" do |x|
34
+ @options[:verbose] = -2 # silent ZPNG warnings
35
+ @actions << [:extract, x]
36
+ end
37
+
38
+ #################################################################################
39
+ opts.separator "\nIteration/extraction params:"
40
+ #################################################################################
41
+
42
+ opts.on("-o", "--order X", /all|auto|[bxy,]+/i,
43
+ "pixel iteration order (default: '#{@options[:order]}')",
44
+ "valid values: ALL,xy,yx,XY,YX,xY,Xy,bY,...",
45
+ ){ |x| @options[:order] = x.split(',') }
46
+
22
47
  opts.on("-c", "--channels X", /[rgba,1-8]+/,
23
48
  "channels (R/G/B/A) or any combination, comma separated",
24
49
  "valid values: r,g,b,a,rg,bgr,rgba,r3g2b3,..."
@@ -28,14 +53,14 @@ module ZSteg
28
53
  @options[:extra_checks] = false
29
54
  end
30
55
 
31
- opts.on("-l", "--limit N", Integer,
32
- "limit bytes checked, 0 = no limit (default: #{@options[:limit]})"
33
- ){ |n| @options[:limit] = n }
34
-
35
56
  opts.on("-b", "--bits N", "number of bits, single int value or '1,3,5' or range '1-8'",
36
57
  "advanced: specify individual bits like '00001110' or '0x88'"
37
58
  ) do |x|
38
59
  a = []
60
+ if x[-1] == 'p'
61
+ @options[:pixel_align] = true
62
+ x = x[0..-2]
63
+ end
39
64
  x = '1-8' if x == 'all'
40
65
  x.split(',').each do |x1|
41
66
  if x1['-']
@@ -50,10 +75,10 @@ module ZSteg
50
75
  @options[:extra_checks] = false
51
76
  end
52
77
 
53
- opts.on "--lsb", "least significant BIT comes first" do
78
+ opts.on "--lsb", "least significant bit comes first" do
54
79
  @options[:bit_order] = :lsb
55
80
  end
56
- opts.on "--msb", "most significant BIT comes first" do
81
+ opts.on "--msb", "most significant bit comes first" do
57
82
  @options[:bit_order] = :msb
58
83
  end
59
84
 
@@ -62,31 +87,20 @@ module ZSteg
62
87
  # specifying prime on command line disables extra checks
63
88
  @options[:extra_checks] = false
64
89
  end
65
- opts.on "--invert", "invert bits (XOR 0xff)" do
66
- @options[:invert] = true
67
- end
68
90
 
69
- # opts.on "--pixel-align", "pixel-align hidden data (EasyBMP)" do
70
- # @options[:pixel_align] = true
71
- # end
91
+ opts.on("--shift N", Integer, "prepend N zero bits"){ |x| @options[:shift] = x }
92
+ #opts.on("--step N", Integer, "step") { |x| @options[:step] = x }
93
+ opts.on("--invert", "invert bits (XOR 0xff)") { @options[:invert] = true }
72
94
 
73
- opts.on "-a", "--all", "try all known methods" do
74
- @options[:prime] = :all
75
- @options[:order] = :all
76
- @options[:bits] = (1..8).to_a
77
- # specifying --all on command line explicitly enables extra checks
78
- @options[:extra_checks] = true
95
+ opts.on "--pixel-align", "pixel-align hidden data" do
96
+ @options[:pixel_align] = true
79
97
  end
80
98
 
81
- opts.on("-o", "--order X", /all|auto|[bxy,]+/i,
82
- "pixel iteration order (default: '#{@options[:order]}')",
83
- "valid values: ALL,xy,yx,XY,YX,xY,Xy,bY,...",
84
- ){ |x| @options[:order] = x.split(',') }
99
+ #################################################################################
100
+ opts.separator "\nAnalysis params:"
101
+ #################################################################################
85
102
 
86
- opts.on "-E", "--extract NAME", "extract specified payload, NAME is like '1b,rgb,lsb'" do |x|
87
- @options[:verbose] = -2 # silent ZPNG warnings
88
- @actions << [:extract, x]
89
- end
103
+ opts.on("-l", "--limit N", Integer, "limit bytes checked, 0 = no limit (default: #{@options[:limit]})"){ |n| @options[:limit] = n }
90
104
 
91
105
  opts.separator ""
92
106
 
@@ -112,10 +126,6 @@ module ZSteg
112
126
  @options[:min_str_len] = x
113
127
  end
114
128
 
115
- opts.on "--shift N", Integer, "prepend N zero bits" do |x|
116
- @options[:shift] = x
117
- end
118
-
119
129
  opts.separator ""
120
130
  opts.on "-v", "--verbose", "Run verbosely (can be used multiple times)" do |v|
121
131
  @options[:verbose] += 1
@@ -201,8 +211,11 @@ module ZSteg
201
211
  h[:bit_order] = :lsb
202
212
  when 'msb'
203
213
  h[:bit_order] = :msb
204
- when /^(\d)b$/, /^b(\d)$/
214
+ when /^(\d)b$/, /^b(\d+)$/
215
+ h[:bits] = parse_bits($1)
216
+ when /^(\d)bp$/, /^b(\d+)p$/
205
217
  h[:bits] = parse_bits($1)
218
+ h[:pixel_align] = true
206
219
  when /\A[rgba]+\Z/
207
220
  h[:channels] = [x]
208
221
  when /\Axy|yx|yb|by\Z/i
@@ -32,8 +32,8 @@ module ZSteg
32
32
  else
33
33
  8.times{ |i| byte |= (a.shift<<(7-i))}
34
34
  end
35
- #printf "[d] %02x %08b\n", byte, byte
36
35
  data << byte.chr
36
+ #a = []
37
37
  if data.size >= @limit
38
38
  print "[limit #@limit]".gray if @verbose > 1
39
39
  break
@@ -77,12 +77,15 @@ module ZSteg
77
77
  [@image.height-1, 0, -1]
78
78
  end
79
79
 
80
+ xstep *= params[:step] if params[:step]
81
+ ystep *= params[:ystep] if params[:ystep]
82
+
80
83
  # cannot join these lines from ByteExtractor and ColorExtractor into
81
84
  # one method for performance reason:
82
85
  # it will require additional yield() for EACH BYTE iterated
83
86
 
84
87
  if type[0,1].downcase == 'b'
85
- # ROW iterator
88
+ # ROW iterator (natural)
86
89
  if params[:prime]
87
90
  idx = 0
88
91
  y0.step(y1,ystep){ |y| x0.step(x1,xstep){ |x|
@@ -6,7 +6,7 @@ module ZSteg
6
6
 
7
7
  def color_extract params = {}
8
8
  channels = Array(params[:channels])
9
- #pixel_align = params[:pixel_align]
9
+ pixel_align = params[:pixel_align]
10
10
 
11
11
  ch_masks = []
12
12
  case channels.first.size
@@ -42,28 +42,28 @@ module ZSteg
42
42
  color = @image[x,y]
43
43
 
44
44
  ch_masks.each do |c,bidxs|
45
+ bidxs = bidxs[a.size-8..] if pixel_align && a.size + bidxs.size > 8
45
46
  value = color.send(c)
46
47
  bidxs.each do |bidx|
47
48
  a << value[bidx]
48
49
  end
49
50
  end
50
- #p [x,y,a.size,a]
51
51
 
52
52
  while a.size >= 8
53
53
  byte = 0
54
- #puts a.join
54
+ # a0 = a.dup
55
55
  if params[:bit_order] == :msb
56
56
  8.times{ |i| byte |= (a.shift<<i)}
57
57
  else
58
58
  8.times{ |i| byte |= (a.shift<<(7-i))}
59
59
  end
60
- #printf "[d] %02x %08b\n", byte, byte
60
+ # printf "[d] %-10s -> %-10s : %s %02x %08b x=%d y=%d\n", a0.join, a.join, byte.chr.inspect, byte, byte, x, y
61
61
  data << byte.chr
62
62
  if data.size >= @limit
63
63
  print "[limit #@limit]".gray if @verbose > 1
64
64
  throw :limit
65
65
  end
66
- #a.clear if pixel_align
66
+ a.clear if pixel_align && a.size < 8
67
67
  end
68
68
  end
69
69
  end
data/lib/zsteg.rb CHANGED
@@ -9,10 +9,6 @@ require 'zsteg/checker'
9
9
  require 'zsteg/result'
10
10
  require 'zsteg/file_cmd'
11
11
 
12
- require 'zsteg/checker/wbstego'
13
- require 'zsteg/checker/scanline_checker'
14
- require 'zsteg/checker/zlib'
15
-
16
12
  require 'zsteg/masker'
17
13
 
18
14
  require 'zsteg/analyzer'
data/spec/checker_spec.rb CHANGED
@@ -17,9 +17,9 @@ describe Checker do
17
17
  end
18
18
  end
19
19
 
20
- it "should be quiet by default" do
21
- @out.should == ""
22
- end
20
+ # it "should be quiet by default" do
21
+ # @out.should == ""
22
+ # end
23
23
 
24
24
  it "returned results should be equal to #results" do
25
25
  @results.should == @checker.results
data/spec/spec_helper.rb CHANGED
@@ -40,6 +40,7 @@ def cli *args
40
40
  else
41
41
  ZSteg::CLI
42
42
  end
43
+ args << "-qqq"
43
44
  args << "--no-color" unless args.any?{|x| x['color']}
44
45
  orig_stdout, out = $stdout, ""
45
46
  begin
@@ -48,7 +49,7 @@ def cli *args
48
49
  ensure
49
50
  $stdout = orig_stdout
50
51
  end
51
- out.strip
52
+ out
52
53
  end
53
54
  end
54
55
 
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ # https://github.com/pedrooaugusto/steganography-png
4
+ each_sample("steganography-png/*.png") do |fname|
5
+ describe fname do
6
+ it "should reveal secret message" do
7
+ r = cli fname, "--limit", "64", "-a", "--no-file"
8
+ r.should include("SteganographyPNG")
9
+ r.should include(ZSteg::Checker::SteganographyPNG::URL)
10
+ r.should_not include("ZSteg::Checker::SteganographyPNG")
11
+ end
12
+ end
13
+ end
data/spec/zlib_spec.rb CHANGED
@@ -16,7 +16,7 @@ sample("ndh2k12_sp113.bmp") do |fname|
16
16
  subject{ cli(fname, "--extract b1,rgb,lsb,yx,zlib") }
17
17
 
18
18
  it { should include "%PDF-1.4" }
19
- it { subject.size.should == 202383 }
19
+ it { subject.size.should == 202386 }
20
20
  end
21
21
  end
22
22
  end
data/zsteg.gemspec CHANGED
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: zsteg 0.2.11 ruby lib
5
+ # stub: zsteg 0.2.13 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "zsteg".freeze
9
- s.version = "0.2.11"
9
+ s.version = "0.2.13"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Andrey \"Zed\" Zaikin".freeze]
14
- s.date = "2022-08-29"
14
+ s.date = "2023-02-19"
15
15
  s.email = "zed.0xff@gmail.com".freeze
16
16
  s.executables = ["zsteg".freeze, "zsteg-mask".freeze, "zsteg-reflow".freeze]
17
17
  s.extra_rdoc_files = [
@@ -36,6 +36,7 @@ Gem::Specification.new do |s|
36
36
  "lib/zsteg/analyzer.rb",
37
37
  "lib/zsteg/checker.rb",
38
38
  "lib/zsteg/checker/scanline_checker.rb",
39
+ "lib/zsteg/checker/steganography_png.rb",
39
40
  "lib/zsteg/checker/wbstego.rb",
40
41
  "lib/zsteg/checker/zlib.rb",
41
42
  "lib/zsteg/cli/cli.rb",
@@ -47,36 +48,6 @@ Gem::Specification.new do |s|
47
48
  "lib/zsteg/file_cmd.rb",
48
49
  "lib/zsteg/masker.rb",
49
50
  "lib/zsteg/result.rb",
50
- "pngsteg.gemspec",
51
- "samples/hackquest/crypt.bmp",
52
- "samples/hackquest/square.bmp",
53
- "samples/newbiecontest/alph1-surprise.bmp.7z",
54
- "samples/wbstego/wbsteg_blowfish_pass_1.bmp",
55
- "samples/wbstego/wbsteg_cast128_pass_1.bmp",
56
- "samples/wbstego/wbsteg_enc_pass_pass.bmp",
57
- "samples/wbstego/wbsteg_enc_pass_pass_even.bmp",
58
- "samples/wbstego/wbsteg_mix_pass_1.bmp",
59
- "samples/wbstego/wbsteg_mix_pass_1_even.bmp",
60
- "samples/wbstego/wbsteg_mix_pass_foobar.bmp",
61
- "samples/wbstego/wbsteg_mix_pass_pass.bmp",
62
- "samples/wbstego/wbsteg_mixenc_pass_pass_even.bmp",
63
- "samples/wbstego/wbsteg_noenc.bmp",
64
- "samples/wbstego/wbsteg_noenc.png",
65
- "samples/wbstego/wbsteg_noenc_.bmp",
66
- "samples/wbstego/wbsteg_noenc_17.bmp",
67
- "samples/wbstego/wbsteg_noenc__.bmp",
68
- "samples/wbstego/wbsteg_noenc_even.bmp",
69
- "samples/wbstego/wbsteg_noenc_even2.bmp",
70
- "samples/wbstego/wbsteg_noenc_even_17.bmp",
71
- "samples/wbstego/wbsteg_noenc_even_17_.bmp",
72
- "samples/wbstego/wbsteg_noenc_ext_ABC.bmp",
73
- "samples/wbstego/wbsteg_rijndael_pass_1.bmp",
74
- "samples/wbstego/wbsteg_rijndael_pass_pass.bmp",
75
- "samples/wbstego/wbsteg_rijndael_pass_pass_even.bmp",
76
- "samples/wbstego/wbsteg_twofish_pass_1.bmp",
77
- "samples/wechall/5ZMGcCLxpcpsru03.g00000010.png",
78
- "samples/wechall/5ZMGcCLxpcpsru03.png",
79
- "samples/wechall/stegano1.bmp",
80
51
  "spec/bin_spec.rb",
81
52
  "spec/camouflage_spec.rb",
82
53
  "spec/cats_spec.rb",
@@ -93,6 +64,7 @@ Gem::Specification.new do |s|
93
64
  "spec/r3g2b3_spec.rb",
94
65
  "spec/simple_spec.rb",
95
66
  "spec/spec_helper.rb",
67
+ "spec/steganography_png_spec.rb",
96
68
  "spec/wbstego_spec.rb",
97
69
  "spec/wechall_spec.rb",
98
70
  "spec/zlib_spec.rb",
@@ -103,7 +75,7 @@ Gem::Specification.new do |s|
103
75
  ]
104
76
  s.homepage = "http://github.com/zed-0xff/zsteg".freeze
105
77
  s.licenses = ["MIT".freeze]
106
- s.rubygems_version = "3.1.6".freeze
78
+ s.rubygems_version = "3.3.7".freeze
107
79
  s.summary = "Detect stegano-hidden data in PNG & BMP files.".freeze
108
80
 
109
81
  if s.respond_to? :specification_version then
@@ -111,14 +83,14 @@ Gem::Specification.new do |s|
111
83
  end
112
84
 
113
85
  if s.respond_to? :add_runtime_dependency then
114
- s.add_runtime_dependency(%q<zpng>.freeze, [">= 0.4.3"])
115
- s.add_runtime_dependency(%q<iostruct>.freeze, [">= 0"])
86
+ s.add_runtime_dependency(%q<zpng>.freeze, [">= 0.4.5"])
87
+ s.add_runtime_dependency(%q<iostruct>.freeze, [">= 0.0.5"])
116
88
  s.add_runtime_dependency(%q<prime>.freeze, [">= 0"])
117
89
  s.add_development_dependency(%q<rspec>.freeze, [">= 0"])
118
90
  s.add_development_dependency(%q<juwelier>.freeze, [">= 0"])
119
91
  else
120
- s.add_dependency(%q<zpng>.freeze, [">= 0.4.3"])
121
- s.add_dependency(%q<iostruct>.freeze, [">= 0"])
92
+ s.add_dependency(%q<zpng>.freeze, [">= 0.4.5"])
93
+ s.add_dependency(%q<iostruct>.freeze, [">= 0.0.5"])
122
94
  s.add_dependency(%q<prime>.freeze, [">= 0"])
123
95
  s.add_dependency(%q<rspec>.freeze, [">= 0"])
124
96
  s.add_dependency(%q<juwelier>.freeze, [">= 0"])
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zsteg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.11
4
+ version: 0.2.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey "Zed" Zaikin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-29 00:00:00.000000000 Z
11
+ date: 2023-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zpng
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.4.3
19
+ version: 0.4.5
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.4.3
26
+ version: 0.4.5
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: iostruct
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 0.0.5
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 0.0.5
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: prime
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +108,7 @@ files:
108
108
  - lib/zsteg/analyzer.rb
109
109
  - lib/zsteg/checker.rb
110
110
  - lib/zsteg/checker/scanline_checker.rb
111
+ - lib/zsteg/checker/steganography_png.rb
111
112
  - lib/zsteg/checker/wbstego.rb
112
113
  - lib/zsteg/checker/zlib.rb
113
114
  - lib/zsteg/cli/cli.rb
@@ -119,36 +120,6 @@ files:
119
120
  - lib/zsteg/file_cmd.rb
120
121
  - lib/zsteg/masker.rb
121
122
  - lib/zsteg/result.rb
122
- - pngsteg.gemspec
123
- - samples/hackquest/crypt.bmp
124
- - samples/hackquest/square.bmp
125
- - samples/newbiecontest/alph1-surprise.bmp.7z
126
- - samples/wbstego/wbsteg_blowfish_pass_1.bmp
127
- - samples/wbstego/wbsteg_cast128_pass_1.bmp
128
- - samples/wbstego/wbsteg_enc_pass_pass.bmp
129
- - samples/wbstego/wbsteg_enc_pass_pass_even.bmp
130
- - samples/wbstego/wbsteg_mix_pass_1.bmp
131
- - samples/wbstego/wbsteg_mix_pass_1_even.bmp
132
- - samples/wbstego/wbsteg_mix_pass_foobar.bmp
133
- - samples/wbstego/wbsteg_mix_pass_pass.bmp
134
- - samples/wbstego/wbsteg_mixenc_pass_pass_even.bmp
135
- - samples/wbstego/wbsteg_noenc.bmp
136
- - samples/wbstego/wbsteg_noenc.png
137
- - samples/wbstego/wbsteg_noenc_.bmp
138
- - samples/wbstego/wbsteg_noenc_17.bmp
139
- - samples/wbstego/wbsteg_noenc__.bmp
140
- - samples/wbstego/wbsteg_noenc_even.bmp
141
- - samples/wbstego/wbsteg_noenc_even2.bmp
142
- - samples/wbstego/wbsteg_noenc_even_17.bmp
143
- - samples/wbstego/wbsteg_noenc_even_17_.bmp
144
- - samples/wbstego/wbsteg_noenc_ext_ABC.bmp
145
- - samples/wbstego/wbsteg_rijndael_pass_1.bmp
146
- - samples/wbstego/wbsteg_rijndael_pass_pass.bmp
147
- - samples/wbstego/wbsteg_rijndael_pass_pass_even.bmp
148
- - samples/wbstego/wbsteg_twofish_pass_1.bmp
149
- - samples/wechall/5ZMGcCLxpcpsru03.g00000010.png
150
- - samples/wechall/5ZMGcCLxpcpsru03.png
151
- - samples/wechall/stegano1.bmp
152
123
  - spec/bin_spec.rb
153
124
  - spec/camouflage_spec.rb
154
125
  - spec/cats_spec.rb
@@ -165,6 +136,7 @@ files:
165
136
  - spec/r3g2b3_spec.rb
166
137
  - spec/simple_spec.rb
167
138
  - spec/spec_helper.rb
139
+ - spec/steganography_png_spec.rb
168
140
  - spec/wbstego_spec.rb
169
141
  - spec/wechall_spec.rb
170
142
  - spec/zlib_spec.rb
@@ -191,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
191
163
  - !ruby/object:Gem::Version
192
164
  version: '0'
193
165
  requirements: []
194
- rubygems_version: 3.1.6
166
+ rubygems_version: 3.3.7
195
167
  signing_key:
196
168
  specification_version: 4
197
169
  summary: Detect stegano-hidden data in PNG & BMP files.
data/pngsteg.gemspec DELETED
@@ -1,65 +0,0 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
- # -*- encoding: utf-8 -*-
5
-
6
- Gem::Specification.new do |s|
7
- s.name = "pngsteg"
8
- s.version = "0.0.0"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Andrey \"Zed\" Zaikin"]
12
- s.date = "2013-01-06"
13
- s.email = "zed.0xff@gmail.com"
14
- s.executables = ["pngsteg"]
15
- s.files = [
16
- "Gemfile",
17
- "Gemfile.lock",
18
- "Rakefile",
19
- "VERSION",
20
- "bin/pngsteg",
21
- "lib/pngsteg.rb",
22
- "lib/pngsteg/checker.rb",
23
- "lib/pngsteg/cli.rb",
24
- "lib/pngsteg/extractor.rb",
25
- "samples/flower.png",
26
- "samples/flower_rgb1.png",
27
- "samples/flower_rgb2.png",
28
- "samples/flower_rgb3.png",
29
- "samples/flower_rgb4.png",
30
- "samples/flower_rgb5.png",
31
- "samples/flower_rgb6.png",
32
- "spec/samples_spec.rb",
33
- "spec/spec_helper.rb"
34
- ]
35
- s.homepage = "http://github.com/zed-0xff/pngsteg"
36
- s.licenses = ["MIT"]
37
- s.require_paths = ["lib"]
38
- s.rubygems_version = "1.8.24"
39
- s.summary = "Detect stegano-hidden data in PNG files"
40
-
41
- if s.respond_to? :specification_version then
42
- s.specification_version = 3
43
-
44
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
45
- s.add_runtime_dependency(%q<zpng>, [">= 0.2.1"])
46
- s.add_development_dependency(%q<rspec>, [">= 2.8.0"])
47
- s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
48
- s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
49
- s.add_development_dependency(%q<awesome_print>, [">= 0"])
50
- else
51
- s.add_dependency(%q<zpng>, [">= 0.2.1"])
52
- s.add_dependency(%q<rspec>, [">= 2.8.0"])
53
- s.add_dependency(%q<bundler>, [">= 1.0.0"])
54
- s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
55
- s.add_dependency(%q<awesome_print>, [">= 0"])
56
- end
57
- else
58
- s.add_dependency(%q<zpng>, [">= 0.2.1"])
59
- s.add_dependency(%q<rspec>, [">= 2.8.0"])
60
- s.add_dependency(%q<bundler>, [">= 1.0.0"])
61
- s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
62
- s.add_dependency(%q<awesome_print>, [">= 0"])
63
- end
64
- end
65
-
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file