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