sixword 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/sixword ADDED
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require_relative '../lib/sixword'
5
+
6
+ BaseName = File.basename($0)
7
+
8
+ def puts_err(message)
9
+ $stderr.puts(BaseName + ': ' + message)
10
+ end
11
+
12
+ def parse_args
13
+ options = {pad: true}
14
+ optparse = OptionParser.new do |opts|
15
+ opts.banner = <<-EOM
16
+ usage: #{BaseName} [OPTION]... [FILE]
17
+
18
+ Six-word encode or decode FILE, or standard input, to standard output.
19
+
20
+ The data are encoded using the 2048 word dictionary created for S/Key (tm) and
21
+ standardized by RFC 2289, RFC 1760, and RFC 1751. It also supports an optional
22
+ custom padding scheme to allow for messages that are not a multiple of 8 bytes.
23
+
24
+ With no FILE, or when FILE is -, read standard input.
25
+
26
+ #{BaseName} understands a few different styles of hexadecimal input and output.
27
+ When encoding, the input will first be decoded to binary data before being
28
+ encoded to words. When decoding, the output will be encoded in hex.
29
+
30
+
31
+ Hex styles:
32
+
33
+ lower/lowercase:
34
+ Accept a variety of inputs, but don't include whitespace in output.
35
+
36
+ Encoding:
37
+ '48:69:20:77:6f:72:6c:64' => 'Hi world' => 'ACRE ADEN INN SLID MAD PAP'
38
+ Decoding:
39
+ 'ACRE ADEN INN SLID MAD PAP' => 'Hi world' => '486920776f726c64'
40
+
41
+ finger/fingerprint:
42
+ Accept a variety of inputs, and include whitespace in output.
43
+ This is intended to look something like GPG fingerprints.
44
+
45
+ Encoding:
46
+ '4869 2077 6F72 6C64' => 'Hi world' => 'ACRE ADEN INN SLID MAP PAP'
47
+ Decoding:
48
+ 'ACRE ADEN INN SLID MAP PAP' => 'Hi world' => '4869 2077 6F72 6C64'
49
+
50
+
51
+ Options:
52
+ EOM
53
+
54
+ opts.on('-h', '--help', 'Display this message', ' ') do
55
+ $stderr.puts opts, ''
56
+ exit 0
57
+ end
58
+
59
+ #
60
+
61
+ opts.on('-d', '--decode', 'Decode data') do
62
+ options[:mode] = :decode
63
+ end
64
+
65
+ opts.on('-p', '--no-pad', "Don't use custom padding scheme", ' ') do
66
+ options[:pad] = false
67
+ end
68
+
69
+ #
70
+
71
+ opts.on('-S', '--hex-style STYLE',
72
+ 'Treat input (when encoding) or print',
73
+ 'output (when decoding) as hex') do |style|
74
+ options[:hex_style] = style
75
+ end
76
+
77
+ opts.on('-H', '--hex', 'Short for --hex-style lowercase') do
78
+ options[:hex_style] = 'lowercase'
79
+ end
80
+
81
+ opts.on('-f', '--fingerprint', 'Short for --hex-style fingerprint') do
82
+ options[:hex_style] = 'fingerprint'
83
+ end
84
+ end
85
+
86
+ optparse.parse!
87
+
88
+ case ARGV.length
89
+ when 0
90
+ filename = '-'
91
+ when 1
92
+ filename = ARGV.fetch(0)
93
+ else
94
+ $stderr.puts optparse, ''
95
+ puts_err "extra operand #{ARGV.fetch(1).inspect}"
96
+ exit 1
97
+ end
98
+
99
+ begin
100
+ runner = Sixword::CLI.new(filename, options)
101
+ runner.run!
102
+ rescue Sixword::CLI::CLIError => err
103
+ puts_err err.message
104
+ exit 2
105
+ rescue Sixword::InvalidParity => err
106
+ puts_err err.message
107
+ exit 3
108
+ rescue Sixword::UnknownWord => err
109
+ puts_err err.message
110
+ exit 4
111
+ rescue Sixword::InvalidWord => err
112
+ puts_err err.message
113
+ exit 5
114
+ rescue Sixword::InputError => err
115
+ puts_err err.message
116
+ exit 10
117
+ rescue Interrupt
118
+ $stderr.puts
119
+ exit 130 # not actually the same as signalled exit, but oh well
120
+ end
121
+ end
122
+
123
+ parse_args
data/lib/sixword.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require_relative 'sixword/cli'
2
+ require_relative 'sixword/hex'
1
3
  require_relative 'sixword/lib'
2
4
  require_relative 'sixword/version'
3
5
  require_relative 'sixword/words'
@@ -44,6 +46,10 @@ module Sixword
44
46
  words_per_slice = options.fetch(:words_per_slice)
45
47
  pad = options.fetch(:pad)
46
48
 
49
+ unless byte_string
50
+ raise ArgumentError.new("byte_string is falsy")
51
+ end
52
+
47
53
  unless block_given?
48
54
  return Enumerator.new(self, :encode_iter, byte_string, options)
49
55
  end
@@ -107,14 +113,4 @@ module Sixword
107
113
  def self.pad_decode(string_or_words)
108
114
  decode(string_or_words, padding_ok: true)
109
115
  end
110
-
111
- def self.hex_string_to_byte_string(hex_string)
112
- # strip whitespace, make sure it's valid hex
113
- hex_string = hex_string.gsub(/\s+/, '')
114
- if hex_string =~ /[^a-fA-F0-9]/
115
- raise ArgumentError.new("Invalid value for hex: #{hex_string.inspect}")
116
- end
117
-
118
- [hex_string].pack('H*')
119
- end
120
116
  end
@@ -0,0 +1,202 @@
1
+ module Sixword
2
+ class CLI
3
+ class CLIError < StandardError; end
4
+
5
+ attr_reader :filename, :options, :stream, :mode
6
+
7
+ def initialize(filename, options)
8
+ @filename = filename
9
+ @options = {mode: :encode, pad: false}.merge(options)
10
+
11
+ if filename == '-'
12
+ # dup stdin and put it into binary mode
13
+ @stream = $stdin.dup
14
+ @stream.binmode
15
+ else
16
+ # read in binary mode even on unix so ruby yields binary encoding
17
+ @stream = File.open(filename, 'rb')
18
+ end
19
+
20
+
21
+ @mode = @options.fetch(:mode)
22
+ unless [:encode, :decode].include?(mode)
23
+ raise ArgumentError.new("Invalid mode: #{mode.inspect}")
24
+ end
25
+ end
26
+
27
+ def pad?
28
+ options.fetch(:pad)
29
+ end
30
+
31
+ def encoding?
32
+ mode == :encode
33
+ end
34
+
35
+ def hex_style
36
+ options[:hex_style]
37
+ end
38
+
39
+ def print_hex(data, chunk_index, cols=80)
40
+ case hex_style
41
+ when 'lower', 'lowercase'
42
+ # encode to lowercase hex with no newlines
43
+ print Sixword::Hex.encode(data)
44
+ when 'finger', 'fingerprint'
45
+ # encode to GPG fingerprint like hex with newlines
46
+ newlines_every = cols / 5
47
+ if chunk_index != 0
48
+ if chunk_index % newlines_every == 0
49
+ print "\n"
50
+ else
51
+ print ' '
52
+ end
53
+ end
54
+ print Sixword::Hex.encode_fingerprint(data)
55
+ when 'colon', 'colons'
56
+ # encode to SSL/SSH fingerprint like hex with colons
57
+ print ':' unless chunk_index == 0
58
+ print Sixword::Hex.encode_colons(data)
59
+ end
60
+ end
61
+
62
+ def run!
63
+ if encoding?
64
+ do_encode! do |encoded|
65
+ puts encoded
66
+ end
67
+ else
68
+ chunk_index = 0
69
+ do_decode! do |decoded|
70
+ if hex_style
71
+ print_hex(decoded, chunk_index)
72
+ chunk_index += 1
73
+ else
74
+ print decoded
75
+ end
76
+ end
77
+
78
+ # add trailing newline for hex output
79
+ puts if hex_style
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ def do_decode!
86
+ unless block_given?
87
+ raise ArgumentError.new("block is required")
88
+ end
89
+
90
+ arr = []
91
+ read_input_by_6_words do |arr|
92
+ yield Sixword.decode(arr, padding_ok: pad?)
93
+ end
94
+ end
95
+
96
+ def do_encode!
97
+ process_encode_input do |chunk|
98
+ Sixword.encode_iter(chunk, words_per_slice:6, pad:pad?) do |encoded|
99
+ yield encoded
100
+ end
101
+ end
102
+ end
103
+
104
+ def process_encode_input
105
+ unless block_given?
106
+ raise ArgumentError.new("block is required")
107
+ end
108
+
109
+ if hex_style
110
+ # yield data in chunks from accumulate_hex_input until EOF
111
+ accumulate_hex_input do |hex|
112
+ begin
113
+ data = Sixword::Hex.decode(hex)
114
+ rescue ArgumentError => err
115
+ # expose hex decoding failures to user
116
+ raise CLIError.new(err.message)
117
+ else
118
+ yield data
119
+ end
120
+ end
121
+ else
122
+ # yield data 8 bytes at a time until EOF
123
+ while true
124
+ buf = stream.read(8)
125
+ if buf
126
+ yield buf
127
+ else
128
+ # EOF
129
+ break
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ # Yield data 6 words at a time until EOF
136
+ def read_input_by_6_words
137
+ block_size = 2048
138
+ word_arr = []
139
+
140
+ while true
141
+ buf = stream.read(block_size)
142
+ if buf.nil?
143
+ break #EOF
144
+ end
145
+
146
+ buf.scan(/\S+/) do |word|
147
+ word_arr << word
148
+
149
+ # return the array if we have accumulated 6 words
150
+ if word_arr.length == 6
151
+ yield word_arr
152
+ word_arr.clear
153
+ end
154
+ end
155
+ end
156
+
157
+ # yield whatever we have left, if anything
158
+ if !word_arr.empty?
159
+ yield word_arr
160
+ end
161
+ end
162
+
163
+ def accumulate_hex_input
164
+ unless block_given?
165
+ raise ArgumentError.new("must pass block")
166
+ end
167
+
168
+ # these are actually treated the same at the moment
169
+ case hex_style
170
+ when 'lower', 'lowercase'
171
+ when 'finger', 'fingerprint'
172
+ else
173
+ raise CLIError.new("unknown hex style: #{hex_style.inspect}")
174
+ end
175
+
176
+ while true
177
+ buf = ''
178
+
179
+ # try to accumulate 8 bytes (16 chars) before yielding the hex
180
+ while buf.length < 16
181
+ char = stream.getc
182
+ if char.nil?
183
+ # EOF, so yield whatever we have if it's non-empty
184
+ yield buf unless buf.empty?
185
+ return
186
+ end
187
+
188
+ if Sixword::Hex.valid_hex?(char)
189
+ buf << char
190
+ next
191
+ elsif Sixword::Hex.strip_char?(char)
192
+ next
193
+ end
194
+
195
+ raise CLIError.new("invalid hex character: #{char.inspect}")
196
+ end
197
+
198
+ yield buf
199
+ end
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,49 @@
1
+ module Sixword
2
+ module Hex
3
+ HexValid = /\A[a-fA-F0-9]+\z/
4
+ HexStrip = /[\s:.-]+/
5
+
6
+ def self.valid_hex?(string)
7
+ !!(string =~ HexValid)
8
+ end
9
+
10
+ def self.strip_char?(char)
11
+ unless char.length == 1
12
+ raise ArgumentError.new("Must pass single character string")
13
+ end
14
+ !!(char =~ HexStrip)
15
+ end
16
+
17
+ def self.encode(bytes)
18
+ bytes.unpack('H*').fetch(0)
19
+ end
20
+
21
+ def self.encode_slice(bytes, slice, delimiter)
22
+ encode(bytes).each_char.each_slice(slice).map(&:join).join(delimiter)
23
+ end
24
+
25
+ def self.encode_fingerprint(bytes)
26
+ encode_slice(bytes, 4, ' ').upcase
27
+ end
28
+
29
+ def self.encode_colons(bytes)
30
+ encode_slice(bytes, 2, ':')
31
+ end
32
+
33
+ def self.decode(hex_string, strip_chars=true)
34
+ if strip_chars
35
+ hex_string = hex_string.gsub(HexStrip, '')
36
+ end
37
+
38
+ unless valid_hex?(hex_string)
39
+ raise ArgumentError.new("Invalid value for hex: #{hex_string.inspect}")
40
+ end
41
+
42
+ unless hex_string.length % 2 == 0
43
+ raise ArgumentError.new("Odd length hex: #{hex_string.inspect}")
44
+ end
45
+
46
+ [hex_string].pack('H*')
47
+ end
48
+ end
49
+ end
@@ -1,3 +1,3 @@
1
1
  module Sixword
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -0,0 +1,124 @@
1
+ require_relative '../rspec_helper'
2
+
3
+ describe Sixword::Hex do
4
+ TestCases = {
5
+ "\x73\xe2\x16\xb5\x36\x3f\x23\x77" => [
6
+ "73e216b5363f2377",
7
+ "73E2 16B5 363F 2377",
8
+ "73:e2:16:b5:36:3f:23:77",
9
+ ],
10
+ "\xfe\xfb\x90\x3d\x12\x59\x36\xee" => [
11
+ "fefb903d125936ee",
12
+ "FEFB 903D 1259 36EE",
13
+ "fe:fb:90:3d:12:59:36:ee",
14
+ ],
15
+ "\x41\x2e\xb9\x92\xe8\x34\xe9\x90" => [
16
+ "412eb992e834e990",
17
+ "412E B992 E834 E990",
18
+ "41:2e:b9:92:e8:34:e9:90",
19
+ ],
20
+ "\x76\x55\x69\x21\x5c\x74\x1b\xda" => [
21
+ "765569215c741bda",
22
+ "7655 6921 5C74 1BDA",
23
+ "76:55:69:21:5c:74:1b:da",
24
+ ],
25
+ "\x62\xec\x83\xdf\x92\x2f\x8a\x7d" => [
26
+ "62ec83df922f8a7d",
27
+ "62EC 83DF 922F 8A7D",
28
+ "62:ec:83:df:92:2f:8a:7d",
29
+ ],
30
+ "\xe2\x65\x2a\x67\xe8\x32\x41\x19" => [
31
+ "e2652a67e8324119",
32
+ "E265 2A67 E832 4119",
33
+ "e2:65:2a:67:e8:32:41:19",
34
+ ],
35
+ "\xd2\x6b\x73\x44\x17\xad\x7f\x93" => [
36
+ "d26b734417ad7f93",
37
+ "D26B 7344 17AD 7F93",
38
+ "d2:6b:73:44:17:ad:7f:93",
39
+ ],
40
+ "\xc5\x3c\xab\x0e\x0c\xf5\x2a\xe8" => [
41
+ "c53cab0e0cf52ae8",
42
+ "C53C AB0E 0CF5 2AE8",
43
+ "c5:3c:ab:0e:0c:f5:2a:e8",
44
+ ],
45
+
46
+ "\x34\x59\xa1\x13\x01\x94\xc3\xf6\xe8\xa9\xec\xf6\x44\xb5\xba\x41" => [
47
+ "3459a1130194c3f6e8a9ecf644b5ba41",
48
+ "3459 A113 0194 C3F6 E8A9 ECF6 44B5 BA41",
49
+ "34:59:a1:13:01:94:c3:f6:e8:a9:ec:f6:44:b5:ba:41",
50
+ ],
51
+ "\x8e\x93\x05\x97\xec\x03\x41\x9d\x13\x1c\x05\x7a\x6a\xa9\xc5\x73" => [
52
+ "8e930597ec03419d131c057a6aa9c573",
53
+ "8E93 0597 EC03 419D 131C 057A 6AA9 C573",
54
+ "8e:93:05:97:ec:03:41:9d:13:1c:05:7a:6a:a9:c5:73",
55
+ ],
56
+ "\xc6\xb4\x10\xe9\x26\x71\x1a\x7c\x4f\x67\x98\xf9\x92\x0e\xdf\x4c" => [
57
+ "c6b410e926711a7c4f6798f9920edf4c",
58
+ "C6B4 10E9 2671 1A7C 4F67 98F9 920E DF4C",
59
+ "c6:b4:10:e9:26:71:1a:7c:4f:67:98:f9:92:0e:df:4c",
60
+ ],
61
+ "\x83\x6a\x14\xd4\x0b\xf0\xc6\xed\xb5\xa8\x1f\xb7\xc0\xcc\xc5\x22" => [
62
+ "836a14d40bf0c6edb5a81fb7c0ccc522",
63
+ "836A 14D4 0BF0 C6ED B5A8 1FB7 C0CC C522",
64
+ "83:6a:14:d4:0b:f0:c6:ed:b5:a8:1f:b7:c0:cc:c5:22",
65
+ ],
66
+ "\x26\xb8\xdf\xd0\x00\x35\x98\xff\xec\x95\xc3\xa1\x1e\x64\x97\x08" => [
67
+ "26b8dfd0003598ffec95c3a11e649708",
68
+ "26B8 DFD0 0035 98FF EC95 C3A1 1E64 9708",
69
+ "26:b8:df:d0:00:35:98:ff:ec:95:c3:a1:1e:64:97:08",
70
+ ],
71
+ "\xd9\xff\xcb\x22\xe5\x2e\x92\x0c\xfd\x45\xcb\x0c\x18\x18\x08\x10" => [
72
+ "d9ffcb22e52e920cfd45cb0c18180810",
73
+ "D9FF CB22 E52E 920C FD45 CB0C 1818 0810",
74
+ "d9:ff:cb:22:e5:2e:92:0c:fd:45:cb:0c:18:18:08:10",
75
+ ],
76
+ "\x73\x13\xc0\x90\x96\xd1\x5b\xbd\x10\x04\x69\x34\xf0\xbe\xf9\x60" => [
77
+ "7313c09096d15bbd10046934f0bef960",
78
+ "7313 C090 96D1 5BBD 1004 6934 F0BE F960",
79
+ "73:13:c0:90:96:d1:5b:bd:10:04:69:34:f0:be:f9:60",
80
+ ],
81
+ "\x18\x3b\xa9\x75\x54\x57\xf9\x5d\x00\x13\x5e\x3c\x87\x9f\x1c\x17" => [
82
+ "183ba9755457f95d00135e3c879f1c17",
83
+ "183B A975 5457 F95D 0013 5E3C 879F 1C17",
84
+ "18:3b:a9:75:54:57:f9:5d:00:13:5e:3c:87:9f:1c:17",
85
+ ],
86
+ }
87
+
88
+ it 'should decode and encode random hex strings correctly' do
89
+ TestCases.each do |binary, hexes|
90
+ lower, finger, colons = hexes
91
+ Sixword::Hex.encode(binary).should == lower
92
+ Sixword::Hex.decode(lower).should == binary
93
+ end
94
+ end
95
+
96
+ it 'should decode and encode random hex fingerprints correctly' do
97
+ TestCases.each do |binary, hexes|
98
+ lower, finger, colons = hexes
99
+ Sixword::Hex.encode_fingerprint(binary).should == finger
100
+ Sixword::Hex.decode(finger).should == binary
101
+ end
102
+ end
103
+
104
+ it 'should decode and encode random colon hexes correctly' do
105
+ TestCases.each do |binary, hexes|
106
+ lower, finger, colons = hexes
107
+ Sixword::Hex.encode_colons(binary).should == colons
108
+ Sixword::Hex.decode(colons).should == binary
109
+ end
110
+ end
111
+
112
+ it 'should accept all valid hex characters' do
113
+ Sixword::Hex.valid_hex?('abcdefABCDEF0123456789').should == true
114
+ end
115
+
116
+ it 'should reject invalid hex characters' do
117
+ ('g'..'z').each do |c|
118
+ Sixword::Hex.valid_hex?(c).should == false
119
+ end
120
+ ('G'..'Z').each do |c|
121
+ Sixword::Hex.valid_hex?(c).should == false
122
+ end
123
+ end
124
+ end
data/spec/sixword_spec.rb CHANGED
@@ -5,7 +5,7 @@ describe Sixword do
5
5
  Sixword::TestVectors::HexTests.each do |section, tests|
6
6
  tests.each do |hex, sentence|
7
7
  words = sentence.split
8
- byte_string = Sixword.hex_string_to_byte_string(hex)
8
+ byte_string = Sixword::Hex.decode(hex)
9
9
  debug_puts "Encode 0x#{hex} => #{words.inspect}"
10
10
  Sixword.encode(byte_string).should == words
11
11
  end
@@ -16,7 +16,7 @@ describe Sixword do
16
16
  Sixword::TestVectors::HexTests.each do |section, tests|
17
17
  tests.each do |hex, sentence|
18
18
  words = sentence.split
19
- byte_string = Sixword.hex_string_to_byte_string(hex)
19
+ byte_string = Sixword::Hex.decode(hex)
20
20
  debug_puts "Decode #{words.inspect} => 0x#{hex}"
21
21
  Sixword.decode(words).should == byte_string
22
22
  end
@@ -49,7 +49,7 @@ describe Sixword do
49
49
  Sixword::TestVectors::HexTests.fetch('rfc 1751').each do |hex, sentence|
50
50
  # group into 6-word sentences
51
51
  sentences = sentence.split.each_slice(6).map {|s| s.join(' ')}
52
- byte_string = Sixword.hex_string_to_byte_string(hex)
52
+ byte_string = Sixword::Hex.decode(hex)
53
53
  debug_puts "Encoding #{hex.inspect} to sentences"
54
54
  debug_puts " => #{sentences.inspect}"
55
55
  Sixword.encode_to_sentences(byte_string).should == sentences
@@ -71,7 +71,7 @@ describe Sixword do
71
71
  "6C617A7920646F672E" =>
72
72
  "The quick brown fox jumps over the lazy dog.",
73
73
  }.each do |hex_string, byte_string|
74
- Sixword.hex_string_to_byte_string(hex_string).should == byte_string
74
+ Sixword::Hex.decode(hex_string).should == byte_string
75
75
  end
76
76
  end
77
77
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sixword
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-09-26 00:00:00.000000000 Z
12
+ date: 2013-09-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -68,7 +68,8 @@ description: ! " Sixword implements the 6-word binary encoding created for S/
68
68
  Word List, Diceware, Base64, Base32\n"
69
69
  email:
70
70
  - abrody@abrody.com
71
- executables: []
71
+ executables:
72
+ - sixword
72
73
  extensions: []
73
74
  extra_rdoc_files: []
74
75
  files:
@@ -77,12 +78,16 @@ files:
77
78
  - LICENSE.txt
78
79
  - README.md
79
80
  - Rakefile
81
+ - bin/sixword
80
82
  - lib/sixword.rb
83
+ - lib/sixword/cli.rb
84
+ - lib/sixword/hex.rb
81
85
  - lib/sixword/lib.rb
82
86
  - lib/sixword/version.rb
83
87
  - lib/sixword/words.rb
84
88
  - sixword.gemspec
85
89
  - spec/rspec_helper.rb
90
+ - spec/sixword/hex_spec.rb
86
91
  - spec/sixword/lib_spec.rb
87
92
  - spec/sixword_spec.rb
88
93
  - spec/test_vectors.rb
@@ -101,7 +106,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
101
106
  version: '0'
102
107
  segments:
103
108
  - 0
104
- hash: 2348163145907655780
109
+ hash: -1062992431278592122
105
110
  required_rubygems_version: !ruby/object:Gem::Requirement
106
111
  none: false
107
112
  requirements:
@@ -110,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
115
  version: '0'
111
116
  segments:
112
117
  - 0
113
- hash: 2348163145907655780
118
+ hash: -1062992431278592122
114
119
  requirements: []
115
120
  rubyforge_project:
116
121
  rubygems_version: 1.8.23
@@ -119,6 +124,7 @@ specification_version: 3
119
124
  summary: Implementation of RFC 2289 compatible 6-word encoding
120
125
  test_files:
121
126
  - spec/rspec_helper.rb
127
+ - spec/sixword/hex_spec.rb
122
128
  - spec/sixword/lib_spec.rb
123
129
  - spec/sixword_spec.rb
124
130
  - spec/test_vectors.rb