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 +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
|