zsteg 0.2.12 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b50a98cd405613a299041cc60c497f4f9a73a099e3112f44b27dee3fddf4831d
4
- data.tar.gz: 8c58dd150ce32f42cc381a67592eded9c9c38e7dc0c4026642ec4773081f4bea
3
+ metadata.gz: 05bf462c6bc2696efead731d0ce3bda8cf371435cc9448b100892b7084364c64
4
+ data.tar.gz: c12f610fe42706271d763620100a71572477696c07010d9323c1bb97f7440fbe
5
5
  SHA512:
6
- metadata.gz: 726aa00d6e7cc127072b7dbebe5418d668bc7d62dd119267ab05341b96d63ca71ce23cb2e2cb189e5b59cb8cbd48c09700d736b0d581b32b1feeb30a9ac3b390
7
- data.tar.gz: 22811b2e9c2ffc3e4ce09aa67d3a65c7dd3636d84740b09664e80dca20d02456f5632214a7df8354affac0f9e8ffd7ccaeb466606608f3bd8e1222ca3dec34c9
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.4"
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)
@@ -31,7 +31,7 @@ GEM
31
31
  faraday-rack (1.0.0)
32
32
  faraday-retry (1.0.3)
33
33
  forwardable (1.3.3)
34
- git (1.13.1)
34
+ git (1.13.2)
35
35
  addressable (~> 2.8)
36
36
  rchardet (~> 1.8)
37
37
  github_api (0.19.0)
@@ -41,8 +41,8 @@ GEM
41
41
  hashie (~> 3.5, >= 3.5.2)
42
42
  oauth2 (~> 1.0)
43
43
  hashie (3.6.0)
44
- highline (2.0.3)
45
- iostruct (0.0.4)
44
+ highline (2.1.0)
45
+ iostruct (0.0.5)
46
46
  juwelier (2.4.9)
47
47
  builder
48
48
  bundler
@@ -55,13 +55,13 @@ GEM
55
55
  rake
56
56
  rdoc
57
57
  semver2
58
- jwt (2.4.1)
58
+ jwt (2.7.0)
59
59
  kamelcase (0.0.2)
60
60
  semver2 (~> 3)
61
61
  mini_portile2 (2.8.1)
62
62
  multi_json (1.15.0)
63
63
  multi_xml (0.6.0)
64
- multipart-post (2.2.3)
64
+ multipart-post (2.3.0)
65
65
  nokogiri (1.14.2)
66
66
  mini_portile2 (~> 2.8.0)
67
67
  racc (~> 1.4)
@@ -74,46 +74,46 @@ GEM
74
74
  prime (0.1.2)
75
75
  forwardable
76
76
  singleton
77
- psych (4.0.4)
77
+ psych (5.1.0)
78
78
  stringio
79
- public_suffix (4.0.7)
79
+ public_suffix (5.0.1)
80
80
  racc (1.6.2)
81
81
  rack (3.0.4.1)
82
82
  rainbow (3.1.1)
83
83
  rake (13.0.6)
84
84
  rchardet (1.8.0)
85
- rdoc (6.4.0)
85
+ rdoc (6.5.0)
86
86
  psych (>= 4.0.0)
87
- rspec (3.11.0)
88
- rspec-core (~> 3.11.0)
89
- rspec-expectations (~> 3.11.0)
90
- rspec-mocks (~> 3.11.0)
91
- rspec-core (3.11.0)
92
- rspec-support (~> 3.11.0)
93
- 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)
94
94
  diff-lcs (>= 1.2.0, < 2.0)
95
- rspec-support (~> 3.11.0)
96
- rspec-mocks (3.11.1)
95
+ rspec-support (~> 3.12.0)
96
+ rspec-mocks (3.12.3)
97
97
  diff-lcs (>= 1.2.0, < 2.0)
98
- rspec-support (~> 3.11.0)
99
- rspec-support (3.11.0)
98
+ rspec-support (~> 3.12.0)
99
+ rspec-support (3.12.0)
100
100
  ruby2_keywords (0.0.5)
101
101
  semver2 (3.4.2)
102
102
  singleton (0.1.1)
103
- stringio (3.0.2)
103
+ stringio (3.0.5)
104
104
  thread_safe (0.3.6)
105
- zpng (0.4.4)
105
+ zpng (0.4.5)
106
106
  rainbow (~> 3.1.1)
107
107
 
108
108
  PLATFORMS
109
109
  ruby
110
110
 
111
111
  DEPENDENCIES
112
- iostruct
112
+ iostruct (>= 0.0.5)
113
113
  juwelier
114
114
  prime
115
115
  rspec
116
- zpng (>= 0.4.4)
116
+ zpng (>= 0.4.5)
117
117
 
118
118
  BUNDLED WITH
119
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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.12
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
@@ -203,6 +213,9 @@ module ZSteg
203
213
  h[:bit_order] = :msb
204
214
  when /^(\d)b$/, /^b(\d+)$/
205
215
  h[:bits] = parse_bits($1)
216
+ when /^(\d)bp$/, /^b(\d+)p$/
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
@@ -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/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.12 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.12"
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 = "2023-02-14"
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",
@@ -63,6 +64,7 @@ Gem::Specification.new do |s|
63
64
  "spec/r3g2b3_spec.rb",
64
65
  "spec/simple_spec.rb",
65
66
  "spec/spec_helper.rb",
67
+ "spec/steganography_png_spec.rb",
66
68
  "spec/wbstego_spec.rb",
67
69
  "spec/wechall_spec.rb",
68
70
  "spec/zlib_spec.rb",
@@ -81,14 +83,14 @@ Gem::Specification.new do |s|
81
83
  end
82
84
 
83
85
  if s.respond_to? :add_runtime_dependency then
84
- s.add_runtime_dependency(%q<zpng>.freeze, [">= 0.4.4"])
85
- 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"])
86
88
  s.add_runtime_dependency(%q<prime>.freeze, [">= 0"])
87
89
  s.add_development_dependency(%q<rspec>.freeze, [">= 0"])
88
90
  s.add_development_dependency(%q<juwelier>.freeze, [">= 0"])
89
91
  else
90
- s.add_dependency(%q<zpng>.freeze, [">= 0.4.4"])
91
- 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"])
92
94
  s.add_dependency(%q<prime>.freeze, [">= 0"])
93
95
  s.add_dependency(%q<rspec>.freeze, [">= 0"])
94
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.12
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: 2023-02-14 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.4
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.4
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
@@ -135,6 +136,7 @@ files:
135
136
  - spec/r3g2b3_spec.rb
136
137
  - spec/simple_spec.rb
137
138
  - spec/spec_helper.rb
139
+ - spec/steganography_png_spec.rb
138
140
  - spec/wbstego_spec.rb
139
141
  - spec/wechall_spec.rb
140
142
  - spec/zlib_spec.rb