ciphr 0.0.1
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 +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +40 -0
- data/LICENSE.txt +22 -0
- data/README.md +316 -0
- data/Rakefile +7 -0
- data/TODO +320 -0
- data/bin/ciphr +62 -0
- data/ciphr.gemspec +32 -0
- data/lib/ciphr.rb +35 -0
- data/lib/ciphr/function_registry.rb +47 -0
- data/lib/ciphr/functions.rb +62 -0
- data/lib/ciphr/functions/base_radix.rb +205 -0
- data/lib/ciphr/functions/bitwise.rb +80 -0
- data/lib/ciphr/functions/crypto.rb +44 -0
- data/lib/ciphr/functions/openssl.rb +104 -0
- data/lib/ciphr/functions/reader.rb +44 -0
- data/lib/ciphr/functions/simple.rb +121 -0
- data/lib/ciphr/functions/url.rb +38 -0
- data/lib/ciphr/functions/zlib.rb +94 -0
- data/lib/ciphr/parser.rb +77 -0
- data/lib/ciphr/stream.rb +49 -0
- data/lib/ciphr/version.rb +3 -0
- data/pkg/ciphr-0.0.1.gem +0 -0
- data/spec/ciphr_spec.rb +21 -0
- data/spec/functions_spec.rb +31 -0
- data/spec/randomizer_spec.rb +55 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/stream_spec.rb +38 -0
- data/tests/commands.sh +30 -0
- data/tests/output.r26.2.0.0.bin +0 -0
- data/tests/output.r26.2.1.1.bin +0 -0
- data/tests/output.r30.2.0.0.bin +0 -0
- data/tests/output.r30.2.1.1.bin +0 -0
- data/tests/output.r34.2.0.0.bin +0 -0
- data/tests/output.r34.2.1.1.bin +0 -0
- data/tests/testcase.r26.bin +0 -0
- data/tests/testcase.r30.bin +0 -0
- data/tests/testcase.r34.bin +0 -0
- metadata +173 -0
data/bin/ciphr
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'ciphr'
|
4
|
+
require 'slop'
|
5
|
+
|
6
|
+
Slop.parse do
|
7
|
+
banner "Usage: #{File.basename $0} [options] [spec]"
|
8
|
+
on :h, :help
|
9
|
+
on :v, :verbose
|
10
|
+
on :n, :'no-newline'
|
11
|
+
on :N, :'newline'
|
12
|
+
on :x, :'xargs-mode'
|
13
|
+
on :'0', :null
|
14
|
+
|
15
|
+
run do |opts, args|
|
16
|
+
Ciphr::FunctionRegistry.global.setup
|
17
|
+
if opts[:help] || args.size == 0
|
18
|
+
puts opts
|
19
|
+
if opts[:verbose]
|
20
|
+
puts "Available Functions: aliases ([args])"
|
21
|
+
Ciphr::FunctionRegistry.global.functions.flat_map{|c,vs| vs.map{|v| [c,v] }}.each{|a|
|
22
|
+
c,v = a
|
23
|
+
puts " #{v[0].map{|v|v.to_s}.join(", ")} (#{c.params.map{|p| p.to_s}.join(", ")})"
|
24
|
+
}
|
25
|
+
end
|
26
|
+
else
|
27
|
+
newline = opts[:newline] || opts[:'xargs-mode'] || STDOUT.tty? && ! opts[:'no-newline']
|
28
|
+
spec = args.join(" ")
|
29
|
+
begin
|
30
|
+
parsed = Ciphr::Parser.new.parse(spec)
|
31
|
+
if opts[:'xargs-mode']
|
32
|
+
delim = opts['null'] ? "\x00" : "\n"
|
33
|
+
$stdin.each_line(delim) do |line|
|
34
|
+
transformed = Ciphr::Transformer.new(StringIO.new(line.tr(delim,''))).apply(parsed)
|
35
|
+
$stdout.print transformed.read
|
36
|
+
puts if newline
|
37
|
+
end
|
38
|
+
else
|
39
|
+
transformed = Ciphr::Transformer.new($stdin).apply(parsed)
|
40
|
+
while (chunk = transformed.read(256)) && ! $stdout.closed?
|
41
|
+
begin
|
42
|
+
$stdout.print(chunk)
|
43
|
+
rescue Errno::EPIPE
|
44
|
+
break
|
45
|
+
end
|
46
|
+
end
|
47
|
+
puts if newline
|
48
|
+
end
|
49
|
+
rescue Parslet::ParseFailed => e
|
50
|
+
$stderr.puts e.cause
|
51
|
+
$stderr.puts spec
|
52
|
+
$stderr.puts " " * (e.cause.pos) + "^"
|
53
|
+
rescue Ciphr::FunctionRegistry::InvalidFunctionError => e
|
54
|
+
$stderr.puts "invalid function '#{e.name}'"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
|
data/ciphr.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ciphr/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ciphr"
|
8
|
+
spec.version = Ciphr::VERSION
|
9
|
+
spec.authors = ["Chris Frohoff"]
|
10
|
+
spec.email = ["chris@frohoff.org"]
|
11
|
+
spec.description = ""
|
12
|
+
spec.summary = "gem for composing (en|de)coding, digest, cipher operations"
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = Dir['**/*']
|
17
|
+
spec.executables << 'ciphr'
|
18
|
+
spec.test_files = Dir['test/**/*', 'spec/**/*']
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.5.0"
|
23
|
+
spec.add_development_dependency "rspec", "~> 3.4.0"
|
24
|
+
#spec.add_development_dependency 'coveralls'
|
25
|
+
#spec.add_development_dependency 'codeclimate-test-reporter'
|
26
|
+
|
27
|
+
spec.add_dependency "parslet", "~> 1.5.0"
|
28
|
+
spec.add_dependency "slop", "~> 3.6.0"
|
29
|
+
spec.add_dependency "base32", "~> 0.3.2"
|
30
|
+
#spec.add_dependency "base32-crockford"
|
31
|
+
#spec.add_dependency "zbase32"
|
32
|
+
end
|
data/lib/ciphr.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require "ciphr/version"
|
2
|
+
require "ciphr/functions"
|
3
|
+
require "ciphr/stream"
|
4
|
+
require "ciphr/parser"
|
5
|
+
|
6
|
+
module Ciphr
|
7
|
+
@@init = false
|
8
|
+
|
9
|
+
def self.init()
|
10
|
+
@@init = true
|
11
|
+
Ciphr::FunctionRegistry.global.setup
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.transform(spec, input = STDIN, output = STDOUT)
|
15
|
+
init if !@@init
|
16
|
+
if input.is_a? String
|
17
|
+
input = StringIO.new(input)
|
18
|
+
input.close_write
|
19
|
+
output = StringIO.new()
|
20
|
+
end
|
21
|
+
|
22
|
+
parsed = Ciphr::Parser.new.parse(spec)
|
23
|
+
transformed = Ciphr::Transformer.new(input).apply(parsed)
|
24
|
+
|
25
|
+
while chunk = transformed.read(256)
|
26
|
+
output.write chunk
|
27
|
+
end
|
28
|
+
|
29
|
+
if output.is_a? StringIO
|
30
|
+
output.string
|
31
|
+
else
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Ciphr
|
2
|
+
class FunctionRegistry
|
3
|
+
def initialize()
|
4
|
+
@function_classes = []
|
5
|
+
@functions = []
|
6
|
+
@function_aliases = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def register(klass)
|
10
|
+
@function_classes << klass
|
11
|
+
end
|
12
|
+
|
13
|
+
def setup(classes=@function_classes)
|
14
|
+
@functions = classes.map{|c| [c,c.variants]}.select{|a| a[1] && a[1].size > 0}.map{|a|
|
15
|
+
[a[0], a[1].map{|v| [[v[0]].flatten.uniq, v[1]]}]}
|
16
|
+
@function_aliases = Hash[@functions.map{|c,vs| vs.map{|v| [v[0]].flatten.map{|n| [n,[c, v[1]]]}}.flatten(1)}.flatten(1)]
|
17
|
+
end
|
18
|
+
|
19
|
+
def function_aliases
|
20
|
+
@function_aliases
|
21
|
+
end
|
22
|
+
|
23
|
+
def [](name)
|
24
|
+
@function_aliases[name] || (raise InvalidFunctionError.new(name))
|
25
|
+
end
|
26
|
+
|
27
|
+
def functions
|
28
|
+
@functions
|
29
|
+
end
|
30
|
+
|
31
|
+
# http://stackoverflow.com/questions/746207/ruby-design-pattern-how-to-make-an-extensible-factory-class
|
32
|
+
# global instance for load-time registration
|
33
|
+
|
34
|
+
@@global = FunctionRegistry.new()
|
35
|
+
|
36
|
+
def self.global
|
37
|
+
@@global
|
38
|
+
end
|
39
|
+
|
40
|
+
class InvalidFunctionError < StandardError
|
41
|
+
attr_reader :name
|
42
|
+
def initialize(name)
|
43
|
+
@name = name
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
|
2
|
+
#require 'base32/crockford'
|
3
|
+
#require 'zbase32'
|
4
|
+
require_relative 'function_registry'
|
5
|
+
|
6
|
+
module Ciphr::Functions
|
7
|
+
class Function
|
8
|
+
def initialize(options, args)
|
9
|
+
@options = options
|
10
|
+
@args = args
|
11
|
+
@stream = Ciphr::Stream.new(self)
|
12
|
+
end
|
13
|
+
attr_accessor :options, :args #don't like that these are both writable, but c'est la vie
|
14
|
+
|
15
|
+
def self.variants
|
16
|
+
[]
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.inherited(subclass)
|
20
|
+
Ciphr::FunctionRegistry.global.register(subclass)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.params
|
24
|
+
[]
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.invertable?
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.aligned
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def read(*args)
|
36
|
+
@stream.read(*args)
|
37
|
+
end
|
38
|
+
|
39
|
+
def prepend(*args)
|
40
|
+
@stream.prepend(*args)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class InvertibleFunction < Function
|
45
|
+
@invert = false
|
46
|
+
attr_accessor :invert
|
47
|
+
|
48
|
+
def self.invertable?
|
49
|
+
true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
require_relative 'functions/openssl'
|
55
|
+
require_relative 'functions/base_radix'
|
56
|
+
require_relative 'functions/zlib'
|
57
|
+
require_relative 'functions/bitwise'
|
58
|
+
require_relative 'functions/reader'
|
59
|
+
require_relative 'functions/url'
|
60
|
+
require_relative 'functions/simple'
|
61
|
+
require_relative 'functions/crypto'
|
62
|
+
|
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'base32'
|
3
|
+
|
4
|
+
module Ciphr::Functions::Base
|
5
|
+
class Base < Ciphr::Functions::InvertibleFunction
|
6
|
+
def self.aligned
|
7
|
+
:left
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Base2 < Base
|
12
|
+
def self.variants
|
13
|
+
[[['b2','base2', 'bin','binary'], {}]]
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.params
|
17
|
+
[:input]
|
18
|
+
end
|
19
|
+
|
20
|
+
def apply
|
21
|
+
input = @args[0]
|
22
|
+
if !invert
|
23
|
+
Proc.new do
|
24
|
+
chunk = input.read(1)
|
25
|
+
chunk && chunk.unpack("B*")[0]
|
26
|
+
end
|
27
|
+
else
|
28
|
+
Proc.new do
|
29
|
+
chunk = input.read(8)
|
30
|
+
chunk && [chunk].pack("B*")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Base8 < Base
|
37
|
+
def self.variants
|
38
|
+
[[['b8','base8','oct','octal'], {}]]
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.params
|
42
|
+
[:input]
|
43
|
+
end
|
44
|
+
|
45
|
+
def apply
|
46
|
+
input = @args[0]
|
47
|
+
if !invert
|
48
|
+
Proc.new do
|
49
|
+
chunk = input.read(3)
|
50
|
+
chunk = chunk && chunk + "\x00"*(3-chunk.size) #pad
|
51
|
+
chunk && chunk.unpack("B*")[0].bytes.to_a.each_slice(3).to_a.map{|a|a.pack("c*").to_i(2).to_s(8)}.join
|
52
|
+
end
|
53
|
+
else
|
54
|
+
Proc.new do
|
55
|
+
chunk = input.read(8)
|
56
|
+
chunk = chunk && chunk + "0"*(8-chunk.size) #pad
|
57
|
+
chunk && chunk.unpack("aaaaaaaa").map{|o| o.to_i.to_s(2).rjust(3,"0")}.join.unpack("a8a8a8").map{|b| b.to_i(2)}.pack("C*")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class Base16 < Base
|
64
|
+
def self.variants
|
65
|
+
[[['b16','base16','hex','hexidecimal'], {}]]
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.params
|
69
|
+
[:input]
|
70
|
+
end
|
71
|
+
|
72
|
+
def apply
|
73
|
+
input = @args[0]
|
74
|
+
if !invert
|
75
|
+
Proc.new do
|
76
|
+
chunk = input.read(1)
|
77
|
+
chunk && chunk.unpack("H*")[0]
|
78
|
+
end
|
79
|
+
else
|
80
|
+
Proc.new do
|
81
|
+
chunk = input.read(2)
|
82
|
+
chunk && [chunk].pack("H*")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
class Base32 < Base
|
90
|
+
def self.variants
|
91
|
+
[
|
92
|
+
[['b32','base32','b32-std','base32-std'], {:object => ::Base32 }]#,
|
93
|
+
#broken
|
94
|
+
#[['b32-crockford','base32-crockford'], {:object => ::Base32::Crockford }],
|
95
|
+
#[['b32-z','base32-z'], {:object => ZBase32.new }]
|
96
|
+
]
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.params
|
100
|
+
[:input]
|
101
|
+
end
|
102
|
+
|
103
|
+
def apply
|
104
|
+
input = @args[0]
|
105
|
+
if !invert
|
106
|
+
Proc.new do
|
107
|
+
chunk = input.read(5)
|
108
|
+
chunk && options[:object].encode(chunk)
|
109
|
+
end
|
110
|
+
else
|
111
|
+
Proc.new do
|
112
|
+
chunk = input.read(8)
|
113
|
+
chunk && options[:object].decode(chunk)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class Base64 < Base
|
120
|
+
def self.aligned
|
121
|
+
nil # preserves alignment
|
122
|
+
end
|
123
|
+
|
124
|
+
def apply
|
125
|
+
input = @args[0]
|
126
|
+
if !invert
|
127
|
+
Proc.new do
|
128
|
+
chunk = input.read(3)
|
129
|
+
chunk && ::Base64.encode64(chunk).gsub(/\s/,'').tr("+/", options[:chars][0,2]).tr("=", options[:chars][2,3])
|
130
|
+
end
|
131
|
+
else
|
132
|
+
Proc.new do
|
133
|
+
chunk = input.read(4)
|
134
|
+
chunk = chunk && chunk + "="*(4-chunk.size) #pad
|
135
|
+
chunk && ::Base64.decode64(chunk.tr(options[:chars][0,2],"+/").tr(options[:chars][2,3],"=").ljust(4,"="))
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.variants
|
141
|
+
chars = {"+"=>"p", "-"=>"h", "_"=>"u", ":"=>"c", "/"=>"s", "." => "d", "!"=>"x", "="=>"q"}
|
142
|
+
types = {"+/=" => ["std"], "+/" => "utf7", "+-" => "file", "-_" => "url", "._-" => "yui",
|
143
|
+
".-" => "xml-name", "_:" => "xml-id", "_-" => "prog-id-1", "._" => "prog-id-2", "!-" => "regex"}
|
144
|
+
variants = types.map{|c,n| [["b64","base64"].product([c.chars.map{|c| chars[c] }.join,n]).map{|a| a.join("-")}, {:chars => c}]}
|
145
|
+
std = variants.select{|v| v[0].include? "b64-std"}[0] #add short aliases for standard
|
146
|
+
std[0] = ["b64","base64"].concat(std[0])
|
147
|
+
variants
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.params
|
151
|
+
[:input]
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
module Ciphr::Functions::Radix
|
158
|
+
|
159
|
+
|
160
|
+
class Radix < Ciphr::Functions::InvertibleFunction
|
161
|
+
def self.aligned
|
162
|
+
:right
|
163
|
+
end
|
164
|
+
|
165
|
+
def self.variants
|
166
|
+
(2..36).map{|r| [["r#{r}","rad#{r}","radix#{r}"], {:radix => r}]}
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.params
|
170
|
+
[:input]
|
171
|
+
end
|
172
|
+
|
173
|
+
def apply
|
174
|
+
radix = options[:radix]
|
175
|
+
input = @args[0]
|
176
|
+
if !invert
|
177
|
+
num = 0
|
178
|
+
while chunk = input.read(1)
|
179
|
+
num = (num << 8) + chunk.bytes.to_a[0]
|
180
|
+
end
|
181
|
+
Proc.new do
|
182
|
+
begin
|
183
|
+
num && num.to_s(radix)
|
184
|
+
ensure
|
185
|
+
num = nil
|
186
|
+
end
|
187
|
+
end
|
188
|
+
else
|
189
|
+
num = input.read().to_i(radix)
|
190
|
+
bytes = []
|
191
|
+
while num > 0
|
192
|
+
bytes.unshift(num & 0xff)
|
193
|
+
num = num >> 8
|
194
|
+
end
|
195
|
+
Proc.new do
|
196
|
+
begin
|
197
|
+
bytes && bytes.pack("c*")
|
198
|
+
ensure
|
199
|
+
bytes = nil
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|