krypt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +82 -0
  3. data/lib/krypt.rb +49 -0
  4. data/lib/krypt/asn1.rb +3 -0
  5. data/lib/krypt/asn1/common.rb +96 -0
  6. data/lib/krypt/asn1/template.rb +257 -0
  7. data/lib/krypt/codec.rb +57 -0
  8. data/lib/krypt/codec/base64.rb +140 -0
  9. data/lib/krypt/codec/base_codec.rb +36 -0
  10. data/lib/krypt/codec/hex.rb +122 -0
  11. data/lib/krypt/digest.rb +112 -0
  12. data/lib/krypt/hmac.rb +69 -0
  13. data/lib/krypt/pkcs5.rb +1 -0
  14. data/lib/krypt/pkcs5/pbkdf2.rb +41 -0
  15. data/lib/krypt/provider.rb +35 -0
  16. data/lib/krypt/x509.rb +3 -0
  17. data/lib/krypt/x509/certificate.rb +36 -0
  18. data/lib/krypt/x509/common.rb +41 -0
  19. data/lib/krypt/x509/crl.rb +33 -0
  20. data/lib/krypt_missing.rb +32 -0
  21. data/spec/krypt-core/MEMO.txt +85 -0
  22. data/spec/krypt-core/asn1/asn1_bit_string_spec.rb +475 -0
  23. data/spec/krypt-core/asn1/asn1_boolean_spec.rb +392 -0
  24. data/spec/krypt-core/asn1/asn1_constants_spec.rb +71 -0
  25. data/spec/krypt-core/asn1/asn1_data_spec.rb +1153 -0
  26. data/spec/krypt-core/asn1/asn1_end_of_contents_spec.rb +133 -0
  27. data/spec/krypt-core/asn1/asn1_enumerated_spec.rb +458 -0
  28. data/spec/krypt-core/asn1/asn1_generalized_time_spec.rb +492 -0
  29. data/spec/krypt-core/asn1/asn1_integer_spec.rb +557 -0
  30. data/spec/krypt-core/asn1/asn1_null_spec.rb +360 -0
  31. data/spec/krypt-core/asn1/asn1_object_id_spec.rb +495 -0
  32. data/spec/krypt-core/asn1/asn1_octet_string_spec.rb +456 -0
  33. data/spec/krypt-core/asn1/asn1_parser_spec.rb +503 -0
  34. data/spec/krypt-core/asn1/asn1_pem_spec.rb +282 -0
  35. data/spec/krypt-core/asn1/asn1_sequence_spec.rb +637 -0
  36. data/spec/krypt-core/asn1/asn1_set_spec.rb +795 -0
  37. data/spec/krypt-core/asn1/asn1_utc_time_spec.rb +495 -0
  38. data/spec/krypt-core/asn1/asn1_utf8_string_spec.rb +404 -0
  39. data/spec/krypt-core/asn1/resources.rb +53 -0
  40. data/spec/krypt-core/base64/base64_spec.rb +97 -0
  41. data/spec/krypt-core/digest/digest_spec.rb +707 -0
  42. data/spec/krypt-core/hex/hex_spec.rb +102 -0
  43. data/spec/krypt-core/pem/pem_decode_spec.rb +235 -0
  44. data/spec/krypt-core/resources.rb +1 -0
  45. data/spec/krypt-core/template/template_choice_parse_spec.rb +289 -0
  46. data/spec/krypt-core/template/template_dsl_spec.rb +351 -0
  47. data/spec/krypt-core/template/template_seq_of_parse_spec.rb +64 -0
  48. data/spec/krypt-core/template/template_seq_parse_spec.rb +1241 -0
  49. data/spec/krypt/codec/base64_decoder_spec.rb +94 -0
  50. data/spec/krypt/codec/base64_encoder_spec.rb +94 -0
  51. data/spec/krypt/codec/base64_mixed_spec.rb +16 -0
  52. data/spec/krypt/codec/hex_decoder_spec.rb +94 -0
  53. data/spec/krypt/codec/hex_encoder_spec.rb +94 -0
  54. data/spec/krypt/codec/hex_mixed_spec.rb +17 -0
  55. data/spec/krypt/codec/identity_shared.rb +119 -0
  56. data/spec/krypt/hmac/hmac_spec.rb +311 -0
  57. data/spec/krypt/pkcs5/pbkdf2_spec.rb +79 -0
  58. data/spec/krypt/provider/provider_spec.rb +83 -0
  59. data/spec/res/ca-bundle.crt +11758 -0
  60. data/spec/res/certificate.cer +0 -0
  61. data/spec/res/certificate.pem +20 -0
  62. data/spec/res/multiple_certs.pem +60 -0
  63. data/spec/resources.rb +66 -0
  64. data/test/helper.rb +8 -0
  65. data/test/res/certificate.cer +0 -0
  66. data/test/resources.rb +48 -0
  67. data/test/scratch.rb +28 -0
  68. data/test/test_krypt_asn1.rb +119 -0
  69. data/test/test_krypt_parser.rb +331 -0
  70. metadata +134 -0
@@ -0,0 +1,57 @@
1
+ module Krypt
2
+
3
+ # Abstract class that represents filters that can be combined with ordinary
4
+ # IO instances, filtering the output before reading/writing to the underlying
5
+ # IO. IOFilter instances can be stacked on top of each other, forming a
6
+ # "filter chain" that "peels of" multiple layers of encoding for example.
7
+ #
8
+ # IOFilter supports a basic IO interface that responds to IO#read, IO#write
9
+ # and IO#close.
10
+ #
11
+ # When reading from the IOFilter, the data will first be read from the IO,
12
+ # processed according to the rules of the filter and only then passed on.
13
+ #
14
+ # When writing to the IOFilter, the data will first be processed by
15
+ # applying the filter and only then written to the IO instance.
16
+ #
17
+ # Closing the IOFilter with IOFilter#close guarantees (among possibly
18
+ # additional things) a call to IO#close on the underlying IO.
19
+ class IOFilter
20
+
21
+ #
22
+ # call-seq:
23
+ # IOFilter.new(io) [{ |filter| block }] -> IOFilter
24
+ #
25
+ # Constructs a new IOFilter with +io+ as its underlying IO.
26
+ # Takes an optional block which is yielded the IOFilter +filter+.
27
+ # After execution of the block, it is guaranteed that IOFilter#close
28
+ # gets called on the IOFilter.
29
+ #
30
+ def initialize(io)
31
+ @io = io
32
+ if block_given?
33
+ begin
34
+ yield self
35
+ ensure
36
+ close
37
+ end
38
+ end
39
+ end
40
+
41
+ #
42
+ # call-seq:
43
+ # io.close -> nil
44
+ #
45
+ # Calls, among possibly additional cleanup, IO#close on the underlying
46
+ # IO.
47
+ def close
48
+ @io.close
49
+ end
50
+ end
51
+
52
+
53
+ end
54
+
55
+ require_relative 'codec/hex'
56
+ require_relative 'codec/base64'
57
+
@@ -0,0 +1,140 @@
1
+ require_relative 'base_codec'
2
+
3
+ module Krypt::Base64
4
+
5
+ module Base64Impl #:nodoc:
6
+ include Krypt::BaseCodec
7
+
8
+ def compute_len(len, a, b)
9
+ len -= @buf.size if @buf
10
+ ret = a * len / b
11
+ remainder = ret % a
12
+ if remainder
13
+ ret += a - remainder
14
+ end
15
+ ret
16
+ end
17
+
18
+ def compute_encode_read_len(len)
19
+ compute_len(len, 3, 4)
20
+ end
21
+
22
+ def compute_decode_read_len(len)
23
+ compute_len(len, 4, 3)
24
+ end
25
+
26
+ def generic_close
27
+ if @write
28
+ @io.write(Krypt::Base64.encode(@buf)) if @buf
29
+ else
30
+ raise Krypt::Base64::Base64Error.new("Remaining bytes in buffer") if @buf
31
+ end
32
+ end
33
+ end
34
+
35
+ private_constant :Base64Impl
36
+
37
+ # Base64-encodes any data written or read from it in the process.
38
+ #
39
+ # === Example: Base64-encode data and write it to a file
40
+ #
41
+ # f = File.open("b64", "wb")
42
+ # b64 = Krypt::Base64::Encoder.new(f)
43
+ # b64 << "one"
44
+ # b64 << "two"
45
+ # b64.close # => contents in file will be encoded
46
+ #
47
+ # === Example: Reading from a file and Base64-encoding the data
48
+ #
49
+ # f = File.open("document", "rb")
50
+ # b64 = Krypt::Base64::Encoder.new(f)
51
+ # b64data = b64.read # => result is encoded
52
+ # b64.close
53
+ #
54
+ class Encoder < Krypt::IOFilter
55
+ include Base64Impl
56
+
57
+ #
58
+ # call-seq:
59
+ # in.read([len=nil]) -> String or nil
60
+ #
61
+ # Reads from the underlying IO and Base64-encodes the data.
62
+ # Please see IO#read for details. Note that in-place reading into
63
+ # a buffer is not supported.
64
+ #
65
+ def read(len=nil)
66
+ read_len = len ? compute_encode_read_len(len) : nil
67
+ generic_read(len, read_len) { |data| Krypt::Base64.encode(data) }
68
+ end
69
+
70
+ #
71
+ # call-seq:
72
+ # out.write(string) -> Integer
73
+ #
74
+ # Base64-encodes +string+ and writes it to the underlying IO.
75
+ # Please see IO#write for further details.
76
+ #
77
+ def write(data)
78
+ generic_write(data, 3) { |data| Krypt::Base64.encode(data) }
79
+ end
80
+ alias << write
81
+
82
+ def close
83
+ generic_close
84
+ super
85
+ end
86
+
87
+ end
88
+
89
+ # Base64-decodes any data written or read from it in the process.
90
+ #
91
+ # === Example: Reading and decoding Base64-encoded data from a file
92
+ #
93
+ # f = File.open("b64", "rb")
94
+ # b64 = Krypt::Base64::Decoder.new(f)
95
+ # plain = b64.read # => result is decoded
96
+ # b64.close
97
+ #
98
+ # === Example: Writing to a file while Base64-decoding the data
99
+ #
100
+ # f = File.open("document", "wb")
101
+ # b64 = Krypt::Base64::Decoder.new(f)
102
+ # b64data = ... #some Base64-encoded data
103
+ # b64 << b64data
104
+ # b64.close # => contents in file will be decoded
105
+ #
106
+ class Decoder < Krypt::IOFilter
107
+ include Base64Impl
108
+
109
+ #
110
+ # call-seq:
111
+ # in.read([len=nil]) -> String or nil
112
+ #
113
+ # Reads from the underlying IO and Base64-decodes the data.
114
+ # Please see IO#read for further details. Note that in-place reading into
115
+ # a buffer is not supported.
116
+ #
117
+ def read(len=nil)
118
+ read_len = len ? compute_decode_read_len(len) : nil
119
+ generic_read(len, read_len) { |data| Krypt::Base64.decode(data) }
120
+ end
121
+
122
+ #
123
+ # call-seq:
124
+ # out.write(string) -> Integer
125
+ #
126
+ # Base64-decodes string and writes it to the underlying IO.
127
+ # Please see IO#write for further details.
128
+ #
129
+ def write(data)
130
+ generic_write(data, 4) { |data| Krypt::Base64.decode(data) }
131
+ end
132
+ alias << write
133
+
134
+ def close
135
+ generic_close
136
+ super
137
+ end
138
+ end
139
+
140
+ end
@@ -0,0 +1,36 @@
1
+ module Krypt::BaseCodec #:nodoc:
2
+
3
+ def generic_read(len, read_len)
4
+ data = @io.read(read_len)
5
+ data = yield data if data
6
+ if @buf
7
+ data = data || ""
8
+ data = @buf << data
9
+ end
10
+ return data unless len && data
11
+ dlen = data.size
12
+ remainder = dlen - len
13
+ update_buffer(data, dlen, remainder)
14
+ data
15
+ end
16
+
17
+ def generic_write(data, blk_size)
18
+ return 0 unless data
19
+ @write = true
20
+ data = @buf ? @buf << data : data.dup
21
+ dlen = data.size
22
+ remainder = dlen % blk_size
23
+ update_buffer(data, dlen, remainder)
24
+ @io.write(yield data) if data.size > 0
25
+ end
26
+
27
+ def update_buffer(data, dlen, remainder)
28
+ if remainder > 0
29
+ @buf = data.slice!(dlen - remainder, remainder)
30
+ else
31
+ @buf = nil
32
+ end
33
+ end
34
+
35
+ end
36
+
@@ -0,0 +1,122 @@
1
+ require_relative 'base_codec'
2
+
3
+ module Krypt::Hex
4
+
5
+ module HexImpl #:nodoc:
6
+ include Krypt::BaseCodec
7
+
8
+ def compute_encode_read_len(len)
9
+ len
10
+ end
11
+
12
+ def compute_decode_read_len(len)
13
+ len * 2
14
+ end
15
+
16
+ def generic_close
17
+ raise Krypt::Hex::HexError.new("Remaining bytes in buffer") if @buf
18
+ end
19
+ end
20
+
21
+ private_constant :HexImpl
22
+
23
+
24
+ # Hex-encodes any data written or read from it in the process.
25
+ #
26
+ # === Example: Hex-encode data and write it to a file
27
+ #
28
+ # f = File.open("hex", "wb")
29
+ # hex = Krypt::Hex::Encoder.new(f)
30
+ # hex << "one"
31
+ # hex << "two"
32
+ # hex.close # => contents in file will be encoded
33
+ #
34
+ # === Example: Reading from a file and hex-encoding the data
35
+ #
36
+ # f = File.open("document", "rb")
37
+ # hex = Krypt::Hex::Encoder.new(f)
38
+ # hexdata = hex.read # => result is encoded
39
+ # hex.close
40
+ #
41
+ class Encoder < Krypt::IOFilter
42
+ include HexImpl
43
+
44
+ #
45
+ # call-seq:
46
+ # in.read([len=nil]) -> String or nil
47
+ #
48
+ # Reads from the underlying IO and hex-encodes the data.
49
+ # Please see IO#read for details. Note that in-place reading into
50
+ # a buffer is not supported.
51
+ #
52
+ def read(len=nil)
53
+ read_len = len ? compute_encode_read_len(len) : nil
54
+ generic_read(len, read_len) { |data| Krypt::Hex.encode(data) }
55
+ end
56
+
57
+ #
58
+ # call-seq:
59
+ # out.write(string) -> Integer
60
+ #
61
+ # Hex-encodes +string+ and writes it to the underlying IO.
62
+ # Please see IO#write for further details.
63
+ #
64
+ def write(data)
65
+ generic_write(data, 1) { |data| Krypt::Hex.encode(data) }
66
+ end
67
+ alias << write
68
+
69
+ end
70
+
71
+ # Hex-decodes any data written or read from it in the process.
72
+ #
73
+ # === Example: Reading and decoding hex-encoded data from a file
74
+ #
75
+ # f = File.open("hex", "rb")
76
+ # hex = Krypt::Hex::Decoder.new(f)
77
+ # plain = hex.read # => result is decoded
78
+ # hex.close
79
+ #
80
+ # === Example: Writing to a file while hex-decoding the data
81
+ #
82
+ # f = File.open("document", "wb")
83
+ # hex = Krypt::Hex::Decoder.new(f)
84
+ # hexdata = ... #some hex-encoded data
85
+ # hex << hexdata
86
+ # hex.close # => contents in file will be decoded
87
+ #
88
+ class Decoder < Krypt::IOFilter
89
+ include HexImpl
90
+
91
+ #
92
+ # call-seq:
93
+ # in.read([len=nil], [buf=nil]) -> String or nil
94
+ #
95
+ # Reads from the underlying IO and hex-decodes the data.
96
+ # Please see IO#read for further details. Note that in-place reading into
97
+ # a buffer is not supported.
98
+ #
99
+ def read(len=nil)
100
+ read_len = len ? compute_decode_read_len(len) : nil
101
+ generic_read(len, read_len) { |data| Krypt::Hex.decode(data) }
102
+ end
103
+
104
+ #
105
+ # call-seq:
106
+ # out.write(string) -> Integer
107
+ #
108
+ # Hex-decodes string and writes it to the underlying IO.
109
+ # Please see IO#write for further details.
110
+ #
111
+ def write(data)
112
+ generic_write(data, 2) { |data| Krypt::Hex.decode(data) }
113
+ end
114
+ alias << write
115
+
116
+ def close
117
+ generic_close
118
+ super
119
+ end
120
+
121
+ end
122
+ end
@@ -0,0 +1,112 @@
1
+ ##
2
+ # Digest allows you to compute message digests (sometimes
3
+ # interchangeably called "hashes") of arbitrary data that are
4
+ # cryptographically secure, i.e. a Digest implements a secure one-way
5
+ # function.
6
+ #
7
+ # One-way functions offer some useful properties. E.g. given two
8
+ # distinct inputs the probability that both yield the same output
9
+ # is highly unlikely. Combined with the fact that every message digest
10
+ # algorithm has a fixed-length output of just a few bytes, digests are
11
+ # often used to create unique identifiers for arbitrary data. A common
12
+ # example is the creation of a unique id for binary documents that are
13
+ # stored in a database.
14
+ #
15
+ # Another useful characteristic of one-way functions (and thus the name)
16
+ # is that given a digest there is no indication about the original
17
+ # data that produced it, i.e. the only way to identify the original input
18
+ # is to "brute-force" through every possible combination of inputs.
19
+ #
20
+ # These characteristics make one-way functions also ideal companions
21
+ # for public key signature algorithms: instead of signing an entire
22
+ # document, first a hash of the document is produced with a considerably
23
+ # faster message digest algorithm and only the few bytes of its output
24
+ # need to be signed using the slower public key algorithm. To validate
25
+ # the integrity of a signed document, it suffices to re-compute the hash
26
+ # and verify that it is equal to that in the signature.
27
+ #
28
+ # Among the supported message digest algorithms are:
29
+ # * SHA1, SHA224, SHA256, SHA384 and SHA512
30
+ # * MD5
31
+ # * RIPEMD160
32
+ #
33
+ # For each of these algorithms, there is a convenient way to create
34
+ # instances of Digest using them, for example
35
+ #
36
+ # digest = Krypt::Digest::SHA1.new
37
+ #
38
+ # === Creating Digest by name or by Object Identifier
39
+ #
40
+ # Each supported digest algorithm has an Object Identifier (OID) associated
41
+ # with it. A Digest can either be created by passing the string
42
+ # representation of the corresponding object identifier or by a string
43
+ # representation of the algorithm name.
44
+ #
45
+ # For example, the OBJECT IDENTIFIER for SHA-1 is 1.3.14.3.2.26, so it can
46
+ # be instantiated like this:
47
+ #
48
+ # d = Krypt::Digest.new("1.3.14.3.2.26")
49
+ # d = Krypt::Digest.new("SHA1")
50
+ # d = Krypt::Digest.new("sha1")
51
+ #
52
+ # Algorithm names may either be all upper- or all lowercase, hyphens are
53
+ # generally stripped: for instance SHA-1 becomes "SHA1", RIPEMD-160
54
+ # becomes "RIPEMD160".
55
+ #
56
+ # "Breaking" a message digest algorithm means defying its one-way
57
+ # function characteristics, i.e. producing a collision or finding a way
58
+ # to get to the original data by means that are more efficient than
59
+ # brute-forcing etc. Older digest algorithms can be considered broken
60
+ # in this sense, even the very popular MD5 and SHA1 algorithms. Should
61
+ # security be your highest concern, then you should probably rely on
62
+ # SHA224, SHA256, SHA384 or SHA512.
63
+ #
64
+ # === Hashing a file
65
+ #
66
+ # data = File.read('document')
67
+ # sha256 = Krypt::Digest::SHA256.new
68
+ # digest = sha256.digest(data)
69
+ #
70
+ # === Hashing several pieces of data at once
71
+ #
72
+ # data1 = File.read('file1')
73
+ # data2 = File.read('file2')
74
+ # data3 = File.read('file3')
75
+ # sha256 = Krypt::Digest::SHA256.new
76
+ # sha256 << data1
77
+ # sha256 << data2
78
+ # sha256 << data3
79
+ # digest = sha256.digest
80
+ #
81
+ # === Reuse a Digest instance
82
+ #
83
+ # data1 = File.read('file1')
84
+ # sha256 = Krypt::Digest::SHA256.new
85
+ # digest1 = sha256.digest(data1)
86
+ #
87
+ # data2 = File.read('file2')
88
+ # sha256.reset
89
+ # digest2 = sha256.digest(data2)
90
+ #
91
+ module Krypt::Digest
92
+
93
+ ##
94
+ # Raised whenever a problem with digests occurs.
95
+ #
96
+ class DigestError < Krypt::Error; end
97
+
98
+ def self.new(name_or_oid, provider=nil)
99
+ receiver = provider ? provider : Krypt::Provider
100
+ f = ->(_) { new_service(Krypt::Digest, name_or_oid) }
101
+ receiver.instance_eval(&f)
102
+ end
103
+
104
+ %w(SHA1 SHA224 SHA256 SHA384 SHA512 RIPEMD160 MD5).each do |alg|
105
+ mod = Module.new do
106
+ define_singleton_method(:new) { Krypt::Digest.new(alg) }
107
+ end
108
+ const_set(alg, mod)
109
+ end
110
+
111
+ end
112
+