sixword 0.1.0 → 0.2.0
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/bin/sixword +123 -0
- data/lib/sixword.rb +6 -10
- data/lib/sixword/cli.rb +202 -0
- data/lib/sixword/hex.rb +49 -0
- data/lib/sixword/version.rb +1 -1
- data/spec/sixword/hex_spec.rb +124 -0
- data/spec/sixword_spec.rb +4 -4
- metadata +11 -5
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
|
data/lib/sixword/cli.rb
ADDED
@@ -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
|
data/lib/sixword/hex.rb
ADDED
@@ -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
|
data/lib/sixword/version.rb
CHANGED
@@ -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.
|
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.
|
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.
|
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.
|
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.
|
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-
|
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:
|
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:
|
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
|