botan 0.1.0

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,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) 2017 Ribose Inc.
4
+
5
+ require 'ffi'
6
+
7
+ require 'botan/error'
8
+ require 'botan/ffi/libbotan'
9
+ require 'botan/utils'
10
+
11
+ module Botan
12
+ # Random Number Generator
13
+ class RNG
14
+ # @api private
15
+ attr_reader :ptr
16
+ # @param rng_type [String] the type of RNG to create
17
+ def initialize(rng_type = nil)
18
+ ptr = FFI::MemoryPointer.new(:pointer)
19
+ Botan.call_ffi(:botan_rng_init, ptr, rng_type)
20
+ ptr = ptr.read_pointer
21
+ raise Botan::Error, 'botan_rng_init returned NULL' if ptr.null?
22
+ @ptr = FFI::AutoPointer.new(ptr, self.class.method(:destroy))
23
+ end
24
+
25
+ # @api private
26
+ def self.destroy(ptr)
27
+ LibBotan.botan_rng_destroy(ptr)
28
+ end
29
+
30
+ # Retrieves some data from the default RNG.
31
+ #
32
+ # @param length [Integer] the number of bytes to retrieve
33
+ # @return [String]
34
+ def self.get(length)
35
+ RNG.new.get(length)
36
+ end
37
+
38
+ # Reseeds the RNG from the system RNG.
39
+ #
40
+ # @param bits [Integer] the number of bits to reseed with
41
+ # @return [self]
42
+ def reseed(bits = 256)
43
+ Botan.call_ffi(:botan_rng_reseed, @ptr, bits)
44
+ self
45
+ end
46
+
47
+ # Retrieves some data from the RNG.
48
+ #
49
+ # @param length [Integer] the number of bytes to retrieve
50
+ # @return [String]
51
+ def get(length)
52
+ out_buf = FFI::MemoryPointer.new(:uint8, length)
53
+ Botan.call_ffi(:botan_rng_get, @ptr, out_buf, length)
54
+ out_buf.read_bytes(length)
55
+ end
56
+
57
+ def inspect
58
+ Botan.inspect_ptr(self)
59
+ end
60
+ end # class
61
+ end # module
62
+
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) 2017 Ribose Inc.
4
+
5
+ require 'ffi'
6
+
7
+ require 'botan/error'
8
+ require 'botan/ffi/libbotan'
9
+
10
+ module Botan
11
+ # Encodes the provided data as a hexadecimal string.
12
+ #
13
+ # @param data [String] the data to encode
14
+ # @return [String] the data as a hexadecimal string
15
+ def self.hex_encode(data)
16
+ data.unpack('H*')[0]
17
+ end
18
+
19
+ # Decodes the provided hexadecimal string to a byte string.
20
+ #
21
+ # @param hexs [String] the hexadecimal string
22
+ # @return [String] the decoded data
23
+ def self.hex_decode(hexs)
24
+ [hexs].pack('H*')
25
+ end
26
+
27
+ # @api private
28
+ #
29
+ # Calls the LibBotan FFI function indicated and returns the return code.
30
+ # If the return code is <0, an error will be raised.
31
+ #
32
+ # @param fn [Symbol] the name of the function to call
33
+ # @param args the arguments to pass to the FFI function
34
+ # @return [Integer] the return code
35
+ def self.call_ffi_rc(fn, *args)
36
+ rc = LibBotan.method(fn).call(*args)
37
+ raise Botan::Error, "FFI call to #{fn} failed (rc: #{rc})" if rc.negative?
38
+ rc
39
+ end
40
+
41
+ # @api private
42
+ #
43
+ # Calls the LibBotan FFI function indicated.
44
+ # If the return code is <0, an error will be raised.
45
+ #
46
+ # @param fn [Symbol] the name of the function to call
47
+ # @param args the arguments to pass to the FFI function
48
+ # @return [void]
49
+ def self.call_ffi(fn, *args)
50
+ call_ffi_rc(fn, *args)
51
+ nil
52
+ end
53
+
54
+ # @api private
55
+ #
56
+ # Calls the LibBotan FFI function indicated
57
+ # If the return code is <0, an error will be raised.
58
+ #
59
+ # @param fn [#call] a proc/lambda taking two parameters.
60
+ # @param guess [Integer] an initial guess for the buffer size
61
+ # @param string [Boolean] true if the returned buffer is expected
62
+ # to be a NULL-terminated string.
63
+ # @return [String] the data
64
+ def self.call_ffi_with_buffer(fn, guess: 4096, string: false)
65
+ buf = FFI::MemoryPointer.new(:uint8, guess)
66
+ buf_len_ptr = FFI::MemoryPointer.new(:size_t)
67
+ buf_len_ptr.write(:size_t, buf.size)
68
+
69
+ rc = fn.call(buf, buf_len_ptr)
70
+ buf_len = buf_len_ptr.read(:size_t)
71
+ # Call should only fail if buffer was inadequate, and should
72
+ # only succeed if buffer was adequate.
73
+ if (rc.negative? && buf_len <= buf.size) || (rc >= 0 && buf_len > buf.size)
74
+ raise Botan::Error, 'FFI call unexpectedly failed'
75
+ end
76
+
77
+ if rc.negative?
78
+ return call_ffi_with_buffer(fn, guess: buf_len, string: string)
79
+ else
80
+ string ? buf.read_string : buf.read_bytes(buf_len)
81
+ end
82
+ end
83
+
84
+ # @api private
85
+ def self.inspect_ptr(myself)
86
+ ptr_format = "0x%0#{FFI::Pointer.size * 2}x"
87
+ ptr_s = format(ptr_format, myself.instance_variable_get(:@ptr).address)
88
+ class_name = myself.class.to_s
89
+ "#<#{class_name}:#{ptr_s}>"
90
+ end
91
+
92
+ # TODO: Upstream this.
93
+ unless FFI::MemoryPointer.respond_to?(:from_data)
94
+ # @api private
95
+ class << FFI::MemoryPointer
96
+ def from_data(data)
97
+ buf = FFI::MemoryPointer.new(:uint8, data.bytesize)
98
+ buf.write_bytes(data)
99
+ buf
100
+ end
101
+ end
102
+ end
103
+ end # module
104
+
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) 2017 Ribose Inc.
4
+
5
+ module Botan
6
+ VERSION = '0.1.0'
7
+ end # module
8
+
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) 2017 Ribose Inc.
4
+
5
+ require 'date'
6
+ require 'ffi'
7
+
8
+ require 'botan/error'
9
+ require 'botan/ffi/libbotan'
10
+ require 'botan/pk/publickey'
11
+ require 'botan/utils'
12
+
13
+ module Botan
14
+ module X509
15
+ class Certificate
16
+ def initialize(ptr)
17
+ if ptr.null?
18
+ raise Botan::Error, 'X509::Certificate received a NULL pointer'
19
+ end
20
+ @ptr = FFI::AutoPointer.new(ptr, self.class.method(:destroy))
21
+ end
22
+
23
+ def self.destroy(ptr)
24
+ LibBotan.botan_x509_cert_destroy(ptr)
25
+ end
26
+
27
+ def self.from_file(filename)
28
+ ptr = FFI::MemoryPointer.new(:pointer)
29
+ Botan.call_ffi(:botan_x509_cert_load_file, ptr, filename)
30
+ Certificate.new(ptr.read_pointer)
31
+ end
32
+
33
+ def self.from_data(data)
34
+ ptr = FFI::MemoryPointer.new(:pointer)
35
+ buf = FFI::MemoryPointer.from_data(data)
36
+ Botan.call_ffi(:botan_x509_cert_load, ptr, buf, buf.size)
37
+ Certificate.new(ptr.read_pointer)
38
+ end
39
+
40
+ def time_starts
41
+ time = Botan.call_ffi_with_buffer(lambda { |b, bl|
42
+ LibBotan.botan_x509_cert_get_time_starts(@ptr, b, bl)
43
+ }, guess: 16, string: true)
44
+ case time.size
45
+ when 13
46
+ ::DateTime.strptime(time, '%y%m%d%H%M%SZ')
47
+ when 15
48
+ ::DateTime.strptime(time, '%Y%m%d%H%M%SZ')
49
+ else
50
+ raise Botan::Error, 'X509::Certificate time_starts invalid format'
51
+ end
52
+ end
53
+
54
+ def time_expires
55
+ time = Botan.call_ffi_with_buffer(lambda { |b, bl|
56
+ LibBotan.botan_x509_cert_get_time_expires(@ptr, b, bl)
57
+ }, guess: 16, string: true)
58
+ case time.size
59
+ when 13
60
+ ::DateTime.strptime(time, '%y%m%d%H%M%SZ')
61
+ when 15
62
+ ::DateTime.strptime(time, '%Y%m%d%H%M%SZ')
63
+ else
64
+ raise Botan::Error, 'X509::Certificate time_expires invalid format'
65
+ end
66
+ end
67
+
68
+ def to_s
69
+ Botan.call_ffi_with_buffer(lambda { |b, bl|
70
+ LibBotan.botan_x509_cert_to_string(@ptr, b, bl)
71
+ }, string: true)
72
+ end
73
+
74
+ def fingerprint(hash_algo = 'SHA-256')
75
+ n = Botan::Digest.new(hash_algo).length * 3
76
+ Botan.call_ffi_with_buffer(lambda { |b, bl|
77
+ LibBotan.botan_x509_cert_get_fingerprint(@ptr, hash_algo, b, bl)
78
+ }, guess: n, string: true)
79
+ end
80
+
81
+ def serial_number
82
+ Botan.call_ffi_with_buffer(lambda { |b, bl|
83
+ LibBotan.botan_x509_cert_get_serial_number(@ptr, b, bl)
84
+ })
85
+ end
86
+
87
+ def authority_key_id
88
+ Botan.call_ffi_with_buffer(lambda { |b, bl|
89
+ LibBotan.botan_x509_cert_get_authority_key_id(@ptr, b, bl)
90
+ })
91
+ end
92
+
93
+ def subject_key_id
94
+ Botan.call_ffi_with_buffer(lambda { |b, bl|
95
+ LibBotan.botan_x509_cert_get_subject_key_id(@ptr, b, bl)
96
+ })
97
+ end
98
+
99
+ def subject_public_key_bits
100
+ Botan.call_ffi_with_buffer(lambda { |b, bl|
101
+ LibBotan.botan_x509_cert_get_public_key_bits(@ptr, b, bl)
102
+ })
103
+ end
104
+
105
+ def subject_public_key
106
+ ptr = FFI::MemoryPointer.new(:pointer)
107
+ Botan.call_ffi(:botan_x509_cert_get_public_key, @ptr, ptr)
108
+ pub = ptr.read_pointer
109
+ if pub.null?
110
+ raise Botan::Error, 'botan_x509_cert_get_public_key returned NULL'
111
+ end
112
+ Botan::PK::PublicKey.new(pub)
113
+ end
114
+
115
+ def issuer_info(key, index = 0)
116
+ Botan.call_ffi_with_buffer(lambda { |b, bl|
117
+ LibBotan.botan_x509_cert_get_issuer_dn(@ptr, key, index, b, bl)
118
+ }, string: true)
119
+ end
120
+
121
+ def subject_info(key, index = 0)
122
+ Botan.call_ffi_with_buffer(lambda { |b, bl|
123
+ LibBotan.botan_x509_cert_get_subject_dn(@ptr, key, index, b, bl)
124
+ }, string: true)
125
+ end
126
+
127
+ def allowed_usage?(usage)
128
+ rc = Botan.call_ffi_rc(:botan_x509_cert_allowed_usage,
129
+ @ptr, usage)
130
+ rc.zero?
131
+ end
132
+
133
+ def inspect
134
+ Botan.inspect_ptr(self)
135
+ end
136
+ end # class
137
+ end # module
138
+ end # module
139
+
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) 2017 Ribose Inc.
4
+
5
+ module Botan
6
+ module X509
7
+ module Constraints
8
+ DECIPHER_ONLY = 1 << 7
9
+ ENCIPHER_ONLY = 1 << 8
10
+ CRL_SIGN = 1 << 9
11
+ KEY_CERT_SIGN = 1 << 10
12
+ KEY_AGREEMENT = 1 << 11
13
+ DATA_ENCIPHERMENT = 1 << 12
14
+ KEY_ENCIPHERMENT = 1 << 13
15
+ NON_REPUDIATION = 1 << 14
16
+ DIGITAL_SIGNATURE = 1 << 15
17
+ end
18
+ end # module
19
+ end # module
20
+
metadata ADDED
@@ -0,0 +1,197 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: botan
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ribose Inc.
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-07-01 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.13'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
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.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.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.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.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.14'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.14'
69
+ - !ruby/object:Gem::Dependency
70
+ name: codecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.1'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: yard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.8.7
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.8.7
97
+ - !ruby/object:Gem::Dependency
98
+ name: redcarpet
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.4'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.4'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.49.1
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.49.1
125
+ - !ruby/object:Gem::Dependency
126
+ name: ffi
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.9'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '1.9'
139
+ description:
140
+ email:
141
+ - packaging@ribose.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files:
145
+ - README.md
146
+ - LICENSE.txt
147
+ files:
148
+ - LICENSE.txt
149
+ - README.md
150
+ - lib/botan.rb
151
+ - lib/botan/bcrypt.rb
152
+ - lib/botan/cipher.rb
153
+ - lib/botan/defaults.rb
154
+ - lib/botan/digest.rb
155
+ - lib/botan/error.rb
156
+ - lib/botan/ffi/libbotan.rb
157
+ - lib/botan/kdf.rb
158
+ - lib/botan/mac.rb
159
+ - lib/botan/pk/mceies.rb
160
+ - lib/botan/pk/op/decrypt.rb
161
+ - lib/botan/pk/op/encrypt.rb
162
+ - lib/botan/pk/op/keyagreement.rb
163
+ - lib/botan/pk/op/sign.rb
164
+ - lib/botan/pk/op/verify.rb
165
+ - lib/botan/pk/privatekey.rb
166
+ - lib/botan/pk/publickey.rb
167
+ - lib/botan/rng.rb
168
+ - lib/botan/utils.rb
169
+ - lib/botan/version.rb
170
+ - lib/botan/x509/certificate.rb
171
+ - lib/botan/x509/constraints.rb
172
+ homepage: https://www.ribose.com
173
+ licenses:
174
+ - MIT
175
+ metadata:
176
+ yard.run: yard
177
+ post_install_message:
178
+ rdoc_options: []
179
+ require_paths:
180
+ - lib
181
+ required_ruby_version: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ version: '0'
186
+ required_rubygems_version: !ruby/object:Gem::Requirement
187
+ requirements:
188
+ - - ">="
189
+ - !ruby/object:Gem::Version
190
+ version: '0'
191
+ requirements: []
192
+ rubyforge_project:
193
+ rubygems_version: 2.5.2
194
+ signing_key:
195
+ specification_version: 4
196
+ summary: The Ruby interface for Botan.
197
+ test_files: []