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.
@@ -0,0 +1,77 @@
1
+ require 'parslet'
2
+
3
+ class Ciphr::Parser < Parslet::Parser
4
+ def pad(&p)
5
+ spaces? >> p.call >> spaces?
6
+ end
7
+
8
+ def wrapstr(d)
9
+ str(d) >> ( str('\\') >> any | str(d).absent? >> any ).repeat.maybe.as(:string) >> str(d)
10
+ end
11
+
12
+ def wrapbraces(bs,&p)
13
+ exp = str('')
14
+ bs.each{|b|
15
+ exp = ( str(b[0]) >> p.call >> str(b[1]) ) | exp
16
+ }
17
+ exp
18
+ end
19
+
20
+ rule(:spaces) { match('\s').repeat(1) }
21
+ rule(:spaces?) { spaces.maybe }
22
+ rule(:name) { (match('[a-z]') >> match('[a-z0-9\-_]').repeat).as(:name) }
23
+ rule(:literal) { pad { b2 | b8 | b10 | b16 | b64 | string | file } }
24
+ rule(:file) { str('@') >> spaces? >> ( string | match('[^ ()\[\]{},|]' ).repeat ).as(:file) }
25
+ rule(:string) { wrapstr("'") | wrapstr('"') }
26
+ rule(:b2) { str('0b') >> match('[0-1]').repeat(1).as(:b2) }
27
+ rule(:b8) { ( match('0').repeat(1) >> match('o').maybe >> match('[0-7]').repeat(1).as(:b8) ) }
28
+ rule(:b10) { ( match('[1-9]') >> match('[0-9]').repeat ).as(:b10) }
29
+ rule(:b16) { str('0x') >> match('[0-9a-fA-F]').repeat(1).as(:b16) }
30
+ rule(:b64) { str('=') >> match('[0-9a-zA-Z+/=]').repeat(1).as(:b64) }
31
+ rule(:call) { pad { match('[~!^]').maybe.as(:invert) } >> pad { name.as(:name) } >> pad { wrapbraces(['()','[]','{}']) { pad { (expression >> (str(',') >> expression).repeat).maybe.as(:arguments) } }.maybe } }
32
+ rule(:expression) { ( ( call | literal ) >> ( str('|') | str(' ').repeat >> ( call | literal ) ).repeat ).as(:operations) }
33
+ root :expression
34
+ end
35
+
36
+ class Ciphr::Transformer < Parslet::Transform
37
+ def initialize(input)
38
+ super()
39
+ @input = input
40
+
41
+ #in ctor to provide instance scope to rule blocks
42
+ rule(:name => simple(:v)) { v }
43
+ rule(:file => simple(:v)) {|d| Ciphr::Functions::Reader::FileReader.new({:file => d[:v].to_s}, [])}
44
+ #eagerly eval these?
45
+ #trim to nearest byte vs chunk?
46
+ rule(:string => simple(:v)) {|d| Ciphr::Functions::Reader::StringReader.new({:string => d[:v]},[]) }
47
+ rule(:b2 => simple(:v)) {|d| Ciphr::Functions::Base::Base2.new({:radix => 2}, [Ciphr::Functions::Reader::StringReader.new({:string => lpad(d[:v].to_s,8,"0")},[])]).tap{|f| f.invert = true} }
48
+ rule(:b8 => simple(:v)) {|d| Ciphr::Functions::Base::Base8.new({:radix => 8}, [Ciphr::Functions::Reader::StringReader.new({:string => lpad(d[:v].to_s,8,"0")},[])]).tap{|f| f.invert = true} }
49
+ rule(:b10 => simple(:v)) {|d| Ciphr::Functions::Radix::Radix.new({:radix => 10}, [Ciphr::Functions::Reader::StringReader.new({:string => d[:v].to_s},[])]).tap{|f| f.invert = true} }
50
+ rule(:b16 => simple(:v)) {|d| Ciphr::Functions::Base::Base16.new({:radix => 16}, [Ciphr::Functions::Reader::StringReader.new({:string => lpad(d[:v].to_s,2,"0")},[])]).tap{|f| f.invert = true} }
51
+ rule(:b64 => simple(:v)) {|d| Ciphr::Functions::Base::Base64.new({:chars => "+/="}, [Ciphr::Functions::Reader::StringReader.new({:string => d[:v]},[])]).tap{|f| f.invert = true} }
52
+ rule(:arguments => sequence(:arguments), :invert => simple(:invert), :name => simple(:name)) {|d| transform_call(d) }
53
+ rule(:arguments => simple(:arguments), :invert => simple(:invert), :name => simple(:name)) {|d| transform_call(d) }
54
+ rule(:invert => simple(:invert), :name => simple(:name)) {|d| transform_call(d) }
55
+ rule(:operations => simple(:operations)) {|d| transform_operations(d)}
56
+ rule(:operations => sequence(:operations)) {|d| transform_operations(d)}
57
+ end
58
+
59
+ def lpad(s,n,p)
60
+ s.size % n == 0 ? s : p * (n - s.size % n) + s
61
+ end
62
+
63
+ def transform_operations(d)
64
+ operations = [d[:operations]].flatten
65
+ if operations[0].args.size < operations[0].class.params.size
66
+ operations.unshift(Ciphr::Functions::Reader::IoReader.new({},[@input]))
67
+ end
68
+ operations.inject{|m,f| f.args = [f.args||[]].flatten.unshift(m); f }
69
+ end
70
+
71
+ def transform_call(d)
72
+ klass, options = Ciphr::FunctionRegistry.global[d[:name].to_s]
73
+ f = klass.new(options, [d[:arguments]||[]].flatten)
74
+ f.invert = true if d[:invert]
75
+ f
76
+ end
77
+ end
@@ -0,0 +1,49 @@
1
+ module Ciphr
2
+ class Stream
3
+ def initialize(reader)
4
+ @reader = reader
5
+ @buffer = ""
6
+ @eof = false
7
+ end
8
+
9
+ def read(n=nil) #fix this
10
+ if n
11
+ init
12
+ while @buffer.size < n && !@eof
13
+ fill
14
+ end
15
+ if @buffer.size > 0
16
+ ret = @buffer[0,n]
17
+ @buffer = @buffer[n..-1] || ''
18
+ else
19
+ ret = nil
20
+ end
21
+ ret
22
+ else
23
+ buff = ""
24
+ while chunk=read(256)
25
+ buff+=chunk
26
+ end
27
+ buff
28
+ end
29
+ end
30
+
31
+ def prepend(str)
32
+ @buffer = str + @buffer
33
+ end
34
+
35
+ private
36
+ def fill
37
+ data = @reader.call
38
+ @eof = true if !data
39
+ @buffer = @buffer + data if data
40
+ end
41
+
42
+ def init #hack
43
+ if !@init
44
+ @init = true
45
+ @reader = @reader.apply if @reader.respond_to?(:apply)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ module Ciphr
2
+ VERSION = "0.0.1"
3
+ end
Binary file
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+ require 'ciphr'
3
+
4
+ describe Ciphr do
5
+ describe :transform do
6
+ it "works for some simple test cases" do
7
+ Ciphr.transform("md5 hex","").should be == "d41d8cd98f00b204e9800998ecf8427e"
8
+ Ciphr.transform("b64 ~b64","foobar").should be == "foobar"
9
+ Ciphr.transform("b2 b16 ~b16 ~b2","foobar").should be == "foobar"
10
+ Ciphr.transform('"foobar"',"").should be == "foobar"
11
+ Ciphr.transform('=ABBB b64',"").should be == "ABBB"
12
+ Ciphr.transform('0x41',"").should be == "A"
13
+ Ciphr.transform('0b01000001',"").should be == "A"
14
+ Ciphr.transform('0x43 xor[0x01]',"").should be == "B"
15
+ Ciphr.transform('0x4343 xor[0x01]',"").should be == "BB"
16
+ Ciphr.transform('0x01 xor[0x4343]',"").should be == "BB"
17
+ Ciphr.transform('0x00 url', "").should be == '%00'
18
+ Ciphr.transform('"foo" cat', "").should be == 'foo'
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ require 'ciphr'
3
+
4
+ describe Ciphr::FunctionRegistry do
5
+ describe :setup do
6
+ it "sets up the specified functions" do
7
+ Ciphr::FunctionRegistry.global.setup([Ciphr::Functions::Base::Base2, Ciphr::Functions::Simple::Cat])
8
+ Ciphr::FunctionRegistry.global.functions.should ==
9
+ [
10
+ [Ciphr::Functions::Base::Base2, [[["b2", "base2", "bin", "binary"], {}]]],
11
+ [Ciphr::Functions::Simple::Cat, [[["cat", "catenate"], {}]]]
12
+ ]
13
+ Ciphr::FunctionRegistry.global.function_aliases.should ==
14
+ {
15
+ "b2"=>[Ciphr::Functions::Base::Base2, {}],
16
+ "base2"=>[Ciphr::Functions::Base::Base2, {}],
17
+ "bin"=>[Ciphr::Functions::Base::Base2, {}],
18
+ "binary"=>[Ciphr::Functions::Base::Base2, {}],
19
+ "cat"=>[Ciphr::Functions::Simple::Cat, {}],
20
+ "catenate"=>[Ciphr::Functions::Simple::Cat, {}]
21
+ }
22
+ end
23
+ it "sets up the automatically registered functions" do
24
+ Ciphr::FunctionRegistry.global.setup
25
+ Ciphr::FunctionRegistry.global.functions.should include(
26
+ [Ciphr::Functions::Base::Base2, [[["b2", "base2","bin","binary"], {}]]])
27
+ Ciphr::FunctionRegistry.global.functions.should include(
28
+ [Ciphr::Functions::Simple::Cat, [[["cat", "catenate"], {}]]])
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+ require 'ciphr'
3
+
4
+ # considerations:
5
+ # invertable
6
+ # deterministic
7
+ # padded
8
+ # zero-input
9
+
10
+ describe Ciphr::Functions do
11
+ r = Random.new(0) #deterministic
12
+ tests = [""] + (1..50).map do |i|
13
+ mag = r.rand(4)+1
14
+ len = r.rand(10**mag)
15
+ #len = (0.00001*r.rand(100000)**1.7).floor
16
+ #$stderr.puts len
17
+ r.bytes(len)
18
+ end
19
+
20
+ # temporarily disable randomization
21
+ tests = [""," ", "\x00", "\x00 A"]
22
+
23
+ Ciphr::FunctionRegistry.global.setup
24
+ #TODO: run shorter/smaller tests first
25
+
26
+ #TODO: decompose property tests into small, composable tests
27
+ functions = Ciphr::FunctionRegistry.global.functions
28
+ functions.find_all{|f| f[0].params.size == 1}.each do |f|
29
+ f[1].each do |v|
30
+ tests.each do |t|
31
+ it "#{v[0][0]} #{t.inspect}" do
32
+ result = Ciphr.transform(v[0][0],t)
33
+ if f[0] != Ciphr::Functions::Simple::Cat && t != ""
34
+ expect(result).not_to eq(t)
35
+ end
36
+ if f[0].invertable? && t != ""
37
+ inv = Ciphr.transform("~" + v[0][0],result)
38
+ #FIXME: need to enforce consistent encoding
39
+ inv,t = [inv,t].map{|s| s.force_encoding('binary')}
40
+ case f[0].aligned # FIXME: this is horrible
41
+ when :left
42
+ expect(inv).to start_with(t)
43
+ when :right
44
+ expect(t).to end_with(inv) # FIXME: horribly backwards
45
+ else
46
+ expect(inv).to eq(t)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+
@@ -0,0 +1,4 @@
1
+ #require 'coveralls'
2
+ #require "codeclimate-test-reporter"
3
+ #Coveralls.wear!
4
+ #CodeClimate::TestReporter.start
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'ciphr'
3
+
4
+ describe Ciphr::Stream do
5
+ describe :read do
6
+ it "returns nil after proc does" do
7
+ s = Ciphr::Stream.new Proc.new { nil }
8
+ s.read(1).should be == nil
9
+ end
10
+
11
+ it "buffers and returns data as requested" do
12
+ fills = ["abc", "def", "ghi"]
13
+ s = Ciphr::Stream.new Proc.new { fills.shift }
14
+ s.read(1).should be == "a"
15
+ s.read(3).should be == "bcd"
16
+ s.read(1).should be == "e"
17
+ s.read(2).should be == "fg"
18
+ s.read(4).should be == "hi"
19
+ s.read(1).should be == nil
20
+ end
21
+
22
+ it "can prepend data and read it back out" do
23
+ fills = ["abc", "def", "ghi"]
24
+ s = Ciphr::Stream.new Proc.new { fills.shift }
25
+ s.read(1).should be == "a"
26
+ s.read(3).should be == "bcd"
27
+ s.prepend("cd")
28
+ s.read(1).should be == "c"
29
+ s.read(1).should be == "d"
30
+ s.read(1).should be == "e"
31
+ s.prepend("cde")
32
+ s.read(3).should be == "cde"
33
+ s.read(2).should be == "fg"
34
+ s.read(4).should be == "hi"
35
+ s.read(1).should be == nil
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,30 @@
1
+ cat | while read line; do subline=`echo $line | sed -r "s/ciphr/bundle exec ruby -Ilib bin\/ciphr/g"`; echo '$' $line; eval "$subline"; done << EOF
2
+ ciphr '"abc"'
3
+ ciphr '"abc"' hex
4
+ ciphr '"abc"' hex ~hex
5
+ ciphr '"616263"' ~hex
6
+ ciphr 0x616263
7
+ ciphr 0x616263 hex
8
+ ciphr 0b10101010 bin
9
+ ciphr 0b10101010 hex
10
+ ciphr 255 hex
11
+ ciphr 65
12
+ ciphr '""' md5 hex
13
+ echo -n "" | ciphr md5 hex
14
+ ciphr '"abc"' sha1 hex
15
+ echo -n "abc" | ciphr sha1 | xxd -ps
16
+ echo -n "abc" | ciphr 'xor["abc"] hex'
17
+ echo -n "abc" | ciphr xor[0x01] hex
18
+ echo -n "abc" | ciphr xor[0x01]
19
+ echo -n "abc" | ciphr xor[0x020304]
20
+ echo -n "abc" | ciphr 'aes128cbc["super secret key"] hex'
21
+ echo -n "abc" | ciphr 'aes128cbc["super secret key"] hex ~hex ~aes128cbc["super secret key"]'
22
+ ciphr @/etc/hosts
23
+ ciphr @/etc/hosts md5 hex
24
+ ciphr @/etc/hosts xor[0x01]
25
+ ciphr @/etc/hosts aes-128-cbc[@/etc/hosts]
26
+ ciphr @/etc/hosts aes-128-cbc[@/etc/hosts] hex
27
+ ciphr @/etc/hosts aes-128-cbc[@/etc/hosts] ~aes-128-cbc[@/etc/hosts]
28
+ ciphr @/etc/hosts aes-128-cbc[0xdeadbeefdeadbeefdeadbeefdeadbeef] hex
29
+ ciphr @/etc/hosts aes-128-cbc[0xdeadbeefdeadbeefdeadbeefdeadbeef] ~aes-128-cbc[0xdeadbeefdeadbeefdeadbeefdeadbeef]
30
+ EOF
Binary file
Binary file
Binary file
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ciphr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Chris Frohoff
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-02-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 10.5.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 10.5.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.4.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.4.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: parslet
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 1.5.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.5.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: slop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 3.6.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 3.6.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: base32
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.3.2
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.3.2
97
+ description: ''
98
+ email:
99
+ - chris@frohoff.org
100
+ executables:
101
+ - ciphr
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - Gemfile
106
+ - Gemfile.lock
107
+ - LICENSE.txt
108
+ - README.md
109
+ - Rakefile
110
+ - TODO
111
+ - bin/ciphr
112
+ - ciphr.gemspec
113
+ - lib/ciphr.rb
114
+ - lib/ciphr/function_registry.rb
115
+ - lib/ciphr/functions.rb
116
+ - lib/ciphr/functions/base_radix.rb
117
+ - lib/ciphr/functions/bitwise.rb
118
+ - lib/ciphr/functions/crypto.rb
119
+ - lib/ciphr/functions/openssl.rb
120
+ - lib/ciphr/functions/reader.rb
121
+ - lib/ciphr/functions/simple.rb
122
+ - lib/ciphr/functions/url.rb
123
+ - lib/ciphr/functions/zlib.rb
124
+ - lib/ciphr/parser.rb
125
+ - lib/ciphr/stream.rb
126
+ - lib/ciphr/version.rb
127
+ - pkg/ciphr-0.0.1.gem
128
+ - spec/ciphr_spec.rb
129
+ - spec/functions_spec.rb
130
+ - spec/randomizer_spec.rb
131
+ - spec/spec_helper.rb
132
+ - spec/stream_spec.rb
133
+ - tests/commands.sh
134
+ - tests/output.r26.2.0.0.bin
135
+ - tests/output.r26.2.1.1.bin
136
+ - tests/output.r30.2.0.0.bin
137
+ - tests/output.r30.2.1.1.bin
138
+ - tests/output.r34.2.0.0.bin
139
+ - tests/output.r34.2.1.1.bin
140
+ - tests/testcase.r26.bin
141
+ - tests/testcase.r30.bin
142
+ - tests/testcase.r34.bin
143
+ homepage: ''
144
+ licenses:
145
+ - MIT
146
+ metadata: {}
147
+ post_install_message:
148
+ rdoc_options: []
149
+ require_paths:
150
+ - lib
151
+ required_ruby_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ required_rubygems_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ requirements: []
162
+ rubyforge_project:
163
+ rubygems_version: 2.4.8
164
+ signing_key:
165
+ specification_version: 4
166
+ summary: gem for composing (en|de)coding, digest, cipher operations
167
+ test_files:
168
+ - spec/ciphr_spec.rb
169
+ - spec/functions_spec.rb
170
+ - spec/randomizer_spec.rb
171
+ - spec/spec_helper.rb
172
+ - spec/stream_spec.rb
173
+ has_rdoc: