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,80 @@
1
+ module Ciphr::Functions::Bitwise
2
+ class BinaryTruncBitwise < Ciphr::Functions::Function
3
+ def apply
4
+ input,keyinput = @args
5
+ Proc.new do
6
+ keychunk = keyinput.read(256)
7
+ inchunk = input.read(256)
8
+ if inchunk && keychunk
9
+ a,b=[inchunk,keychunk].sort_by{|x| x.size}
10
+ a.bytes.each_with_index.map{|c,i|c.send(@options[:op], b.bytes.to_a[i%b.size])}.pack("c*")
11
+ else
12
+ nil
13
+ end
14
+ end
15
+ end
16
+
17
+ def self.variants
18
+ [
19
+ ['and-trunc', {:op=>:&}],
20
+ ['or-trunc', {:op=>:|}],
21
+ [['xor-trunc'], {:op=>:'^'}]
22
+ ]
23
+ end
24
+
25
+ def self.params
26
+ [:input, :input]
27
+ end
28
+ end
29
+
30
+ class BinaryBitwise < Ciphr::Functions::Function
31
+ def apply
32
+ input,keyinput = @args
33
+ keyb, inputb = [keyinput.read.bytes.to_a, input.read.bytes.to_a].sort_by{|a| a.size }
34
+ Proc.new do
35
+ if inputb
36
+ resb = inputb.each_with_index.map{|c,i|c.send(@options[:op], keyb[i%keyb.size])}
37
+ res = resb.pack("c*")
38
+ inputb = nil
39
+ res
40
+ else
41
+ nil
42
+ end
43
+ end
44
+ end
45
+
46
+ def self.variants
47
+ [
48
+ ['and', {:op=>:&}],
49
+ ['or', {:op=>:|}],
50
+ [['xor'], {:op=>:'^'}]
51
+ ]
52
+ end
53
+
54
+ def self.params
55
+ [:input, :input]
56
+ end
57
+ end
58
+
59
+ class UnaryBitwise < Ciphr::Functions::Function
60
+ def apply
61
+ input = @args[0]
62
+ Proc.new do
63
+ inchunk = input.read(1)
64
+ if inchunk
65
+ inchunk.bytes.map{|b| b = ~b }.pack("c*")
66
+ else
67
+ nil
68
+ end
69
+ end
70
+ end
71
+
72
+ def self.variants
73
+ [ ['not', {}] ]
74
+ end
75
+
76
+ def self.params
77
+ [:input]
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,44 @@
1
+ module Ciphr::Functions::Crypto
2
+ class RC4Cipher < Ciphr::Functions::InvertibleFunction
3
+ def apply
4
+ input, key = @args
5
+ keybytes = key.read.unpack('c*')
6
+ s = (0..255).to_a
7
+ j = 0
8
+ (0..255).each do |i|
9
+ j = (j + s[i] + keybytes[i % keybytes.size]) % 256
10
+ swp = s[i]
11
+ s[i] = s[j]
12
+ s[j] = swp
13
+ end
14
+ i = 0
15
+ j = 0
16
+
17
+ $stderr.puts("key: #{keybytes.inspect}")
18
+
19
+ Proc.new do
20
+ byte = input.read(1)
21
+ if byte
22
+ i = (i + 1) % 256
23
+ j = (j + s[i]) % 256
24
+ swp = s[i]
25
+ s[i] = s[j]
26
+ s[j] = swp
27
+ k = s[(s[i] + s[j]) % 256]
28
+ m = [(byte.unpack('c*')[0] ^ k)].pack('c*')
29
+ m
30
+ else
31
+ nil
32
+ end
33
+ end
34
+ end
35
+
36
+ def self.variants
37
+ [[['rc4-ruby'],{}]]
38
+ end
39
+
40
+ def self.params
41
+ [:input, :key]
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,104 @@
1
+ require 'openssl'
2
+
3
+ module Ciphr::Functions::OpenSSL
4
+ OPENSSL_DIGESTS = %w(md4 md5 sha sha1 sha224 sha256 sha384 sha512) # no md2
5
+ #TODO: fail/ignore gracefully with error/warning if openssl unavailable
6
+
7
+ class OpenSslDigest < Ciphr::Functions::Function
8
+ def self.variants
9
+ OPENSSL_DIGESTS.map{|d| [d, {:variant => d}]}
10
+ end
11
+
12
+ def self.params
13
+ [:input]
14
+ end
15
+
16
+ def apply
17
+ input = args[0]
18
+ digester = OpenSSL::Digest.new(@options[:variant])
19
+ while chunk = input.read(256)
20
+ digester.update(chunk)
21
+ end
22
+ digest = digester.digest
23
+ Proc.new do
24
+ d = digest
25
+ digest = nil
26
+ d
27
+ end
28
+ end
29
+ end
30
+
31
+ class OpenSslHmac < OpenSslDigest
32
+ def self.variants
33
+ OPENSSL_DIGESTS.map{|d| [["hmac-#{d}", "hmac#{d}"], {:variant => d}]}
34
+ end
35
+
36
+ def self.params
37
+ [:input, :key]
38
+ end
39
+
40
+ # reuse code from Digest.apply
41
+ def apply
42
+ input, key = @args
43
+ digester = OpenSSL::HMAC.new(key.read, @options[:variant])
44
+ while chunk = input.read(256)
45
+ digester.update(chunk)
46
+ end
47
+ digest = digester.digest
48
+ Proc.new do
49
+ d = digest
50
+ digest = nil
51
+ d
52
+ end
53
+ end
54
+ end
55
+
56
+
57
+
58
+ class OpenSslCipher < Ciphr::Functions::InvertibleFunction
59
+ def apply
60
+ input, key = @args
61
+ cipher = OpenSSL::Cipher.new(@options[:variant])
62
+ cipher.send(invert ? :decrypt : :encrypt)
63
+ cipher.key = key.read
64
+ random_iv = cipher.random_iv
65
+ if random_iv.size > 0
66
+ cipher.iv = invert ? input.read(random_iv.size) : random_iv
67
+ end
68
+ Proc.new do
69
+ if ! invert && random_iv
70
+ begin
71
+ random_iv
72
+ ensure
73
+ random_iv = nil
74
+ end
75
+ else
76
+ chunk = input.read(256)
77
+ if cipher
78
+ if chunk
79
+ cipher.update(chunk)
80
+ else
81
+ begin
82
+ cipher.final
83
+ ensure
84
+ cipher = nil
85
+ end
86
+ end
87
+ else
88
+ nil
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ def self.variants
95
+ OpenSSL::Cipher.ciphers.map{|c| c.downcase}.uniq.map do |c|
96
+ [[c, c.gsub(/-/, "")], {:variant => c}]
97
+ end
98
+ end
99
+
100
+ def self.params
101
+ [:input, :key]
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,44 @@
1
+ # strictly used by parser classes for literals/wiring
2
+ # TODO: disable registration
3
+
4
+ module Ciphr::Functions::Reader
5
+ class StringReader < Ciphr::Functions::Function
6
+ def apply
7
+ StringProc.new(options[:string])
8
+ end
9
+
10
+ class StringProc #extend Proc?
11
+ def initialize(str)
12
+ @str = str
13
+ end
14
+
15
+ def call
16
+ begin
17
+ @str
18
+ ensure
19
+ @str = nil
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ class FileReader < Ciphr::Functions::Function
26
+ def apply
27
+ f = File.open(options[:file], "r")
28
+ Proc.new do
29
+ chunk = f.read(256)
30
+ f.close if ! chunk
31
+ chunk
32
+ end
33
+ end
34
+ end
35
+
36
+ class IoReader < Ciphr::Functions::Function
37
+ def apply
38
+ input = args[0]
39
+ Proc.new do
40
+ input.read(256)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,121 @@
1
+ module Ciphr::Functions::Simple
2
+ class Cat < Ciphr::Functions::Function
3
+ def self.variants
4
+ [[['cat','catenate'], {}]]
5
+ end
6
+
7
+ def self.params
8
+ [:input]
9
+ end
10
+
11
+ def apply
12
+ inputs = @args
13
+ i = 0
14
+ chunk = nil
15
+ Proc.new do
16
+ chunk = inputs[i].read(256)
17
+ if ! chunk
18
+ i += 1
19
+ chunk = inputs[i] && inputs[i].read(256)
20
+ end
21
+ #while !(chunk = inputs[i].read(256)) && i < inputs.size
22
+ # i++
23
+ #end
24
+ chunk
25
+ end
26
+ end
27
+ end
28
+
29
+ class Repack < Ciphr::Functions::Function
30
+ def apply
31
+ input, ch1in, ch2in = @args
32
+ content, ch1, ch2 = [input.read, ch1in.read, ch2in.read]
33
+ Proc.new do
34
+ if content
35
+ begin
36
+ content.unpack(ch1).pack(ch2)
37
+ ensure
38
+ content = nil
39
+ end
40
+ else
41
+ nil
42
+ end
43
+ end
44
+ end
45
+
46
+ def self.variants
47
+ [ [['repack'], {}] ]
48
+ end
49
+
50
+ def self.params
51
+ [:input,:ch1,:ch2]
52
+ end
53
+ end
54
+
55
+ class Translate < Ciphr::Functions::Function
56
+ def apply
57
+ input, ch1in, ch2in = @args
58
+ ch1, ch2 = [ch1in.read, ch2in.read]
59
+ Proc.new do
60
+ inchunk = input.read(1)
61
+ if inchunk
62
+ inchunk.tr(ch1, ch2)
63
+ else
64
+ nil
65
+ end
66
+ end
67
+ end
68
+
69
+ def self.variants
70
+ [ [['tr','translate'], {}] ]
71
+ end
72
+
73
+ def self.params
74
+ [:input,:ch1,:ch2]
75
+ end
76
+ end
77
+
78
+ class Replace < Ciphr::Functions::Function
79
+ def apply
80
+ input, searchin, replacein = @args
81
+ search, replace = [searchin.read, replacein.read]
82
+ buf = ""
83
+ Proc.new do
84
+ if buf.size == search.size && search.size > 0
85
+ buf = ""
86
+ replace
87
+ else
88
+ inchunk = input.read(1)
89
+ if inchunk
90
+ if inchunk == search[buf.size]
91
+ buf += inchunk
92
+ ""
93
+ else
94
+ buf += inchunk
95
+ input.prepend(buf[1,buf.size])
96
+ ret = buf[0]
97
+ buf = ""
98
+ ret
99
+ end
100
+ else
101
+ if buf.size > 0
102
+ ret = buf
103
+ buf = ""
104
+ ret
105
+ else
106
+ nil
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ def self.variants
114
+ [ [['repl','replace'], {}] ]
115
+ end
116
+
117
+ def self.params
118
+ [:input,:search,:replace]
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,38 @@
1
+ require 'cgi'
2
+
3
+ module Ciphr::Functions::URL
4
+ #TODO: differentiate between URL and CGI encoding (with '+' char)
5
+ class UrlEncoding < Ciphr::Functions::InvertibleFunction
6
+ def apply
7
+ input = @args[0]
8
+ if !invert
9
+ Proc.new do
10
+ chunk = input.read(1)
11
+ chunk && CGI.escape(chunk)
12
+ end
13
+ else
14
+ Proc.new do
15
+ chunk = input.read(1)
16
+ if (chunk == "%")
17
+ chunk += input.read(2)
18
+ chunk && CGI.unescape(chunk)
19
+ elsif chunk == '+'
20
+ ' '
21
+ else
22
+ chunk
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ def self.variants
29
+ [
30
+ [['url','uri','cgi'],{}]
31
+ ]
32
+ end
33
+
34
+ def self.params
35
+ [:input]
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,94 @@
1
+ require 'zlib'
2
+
3
+ module Ciphr::Functions::ZLib
4
+ class Deflate < Ciphr::Functions::InvertibleFunction
5
+ def apply
6
+ input = @args[0]
7
+ zstream = invert ? Zlib::Inflate.new : Zlib::Deflate.new
8
+ Proc.new do
9
+ chunk = input.read(256)
10
+ if chunk
11
+ if invert
12
+ zstream.inflate(chunk)
13
+ else
14
+ zstream.deflate(chunk,Zlib::SYNC_FLUSH)
15
+ end
16
+ else
17
+ begin
18
+ #zstream.finish if invert
19
+ ensure
20
+ zstream.close
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ def self.variants
27
+ [
28
+ [['deflate'], {}]
29
+ ]
30
+ end
31
+
32
+ def self.params
33
+ [:input]
34
+ end
35
+ end
36
+
37
+
38
+ class Gzip < Ciphr::Functions::InvertibleFunction
39
+ class UncloseableIOProxy # hack to prevent GzipWriter from closing StringIO
40
+ def initialize(delegate)
41
+ @delegate = delegate
42
+ end
43
+
44
+ def method_missing(meth, *args, &block)
45
+ if meth.to_s != "close"
46
+ @delegate.send(meth, *args, &block)
47
+ else
48
+ nil
49
+ end
50
+ end
51
+ end
52
+
53
+ def apply
54
+ input = @args[0]
55
+ sio = StringIO.new
56
+ gz = !invert ? Zlib::GzipWriter.new(UncloseableIOProxy.new(sio)) : Zlib::GzipReader.new(input)
57
+ Proc.new do
58
+ if invert # unzip
59
+ gz.read(256)
60
+ else # zip
61
+ chunk = input.read(256)
62
+ if chunk
63
+ gz.write chunk
64
+ sio.rewind
65
+ ret = sio.read
66
+ sio.rewind
67
+ sio.truncate(0)
68
+ ret
69
+ elsif gz
70
+ gz.close
71
+ gz = nil
72
+ sio.rewind
73
+ ret = sio.read
74
+ sio.rewind
75
+ sio.truncate(0)
76
+ ret
77
+ else
78
+ nil
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ def self.variants
85
+ [
86
+ [['gzip','gz'], {}]
87
+ ]
88
+ end
89
+
90
+ def self.params
91
+ [:input]
92
+ end
93
+ end
94
+ end