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,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) 2017 Ribose Inc.
4
+
5
+ require 'ffi'
6
+
7
+ require 'botan/defaults'
8
+ require 'botan/utils'
9
+
10
+ module Botan
11
+ # Key Derivation Functions
12
+ #
13
+ # == Examples
14
+ # === examples/kdf.rb
15
+ # {include:file:examples/kdf.rb}
16
+ module KDF
17
+ # Derives a key using the given KDF algorithm.
18
+ #
19
+ # @param secret [String] the secret input
20
+ # @param key_length [Integer] the desired length of the key to produce
21
+ # @param label [String] purpose for the derived keying material
22
+ # @param algo [String] the KDF algorithm name
23
+ # @param salt [String] the randomly chosen salt
24
+ # @return [String] the derived key
25
+ def self.kdf(secret:, key_length:,
26
+ label: '',
27
+ algo: DEFAULT_KDF_ALGO,
28
+ salt: RNG.get(DEFAULT_KDF_SALT_LENGTH))
29
+ out_buf = FFI::MemoryPointer.new(:uint8, key_length)
30
+
31
+ secret_buf = FFI::MemoryPointer.from_data(secret)
32
+ salt_buf = FFI::MemoryPointer.from_data(salt)
33
+ label_buf = FFI::MemoryPointer.from_data(label)
34
+ Botan.call_ffi(:botan_kdf,
35
+ algo, out_buf, out_buf.size,
36
+ secret_buf, secret_buf.size,
37
+ salt_buf, salt_buf.size,
38
+ label_buf, label_buf.size)
39
+ out_buf.read_bytes(key_length)
40
+ end
41
+
42
+ # Derives a key using the given PBKDF algorithm.
43
+ #
44
+ # @param password [String] the password to derive the key from
45
+ # @param key_length [Integer] the desired length of the key to produce
46
+ # @param algo [String] the PBKDF algorithm name
47
+ # @param iterations [Integer] the number of iterations to use
48
+ # @param salt [String] the randomly chosen salt
49
+ # @return [String] the derived key
50
+ def self.pbkdf(password:, key_length:,
51
+ algo: DEFAULT_PBKDF_ALGO,
52
+ iterations: DEFAULT_KDF_ITERATIONS,
53
+ salt: RNG.get(DEFAULT_KDF_SALT_LENGTH))
54
+ out_buf = FFI::MemoryPointer.new(:uint8, key_length)
55
+ salt_buf = FFI::MemoryPointer.from_data(salt)
56
+ Botan.call_ffi(:botan_pbkdf,
57
+ algo, out_buf, key_length,
58
+ password, salt_buf, salt_buf.size, iterations)
59
+ out_buf.read_bytes(key_length)
60
+ end
61
+
62
+ # Derives a key using the given PBKDF algorithm.
63
+ #
64
+ # @param password [String] the password to derive the key from
65
+ # @param key_length [Integer] teh desired length of the key to rpoduce
66
+ # @param milliseconds [Integer] the number of milliseconds to run
67
+ # @param algo [String] the PBKDF algorithm name
68
+ # @param salt [String] the randomly chosen salt
69
+ # @return [Hash<Symbol>]
70
+ # * :iterations [Integer] the iteration count used
71
+ # * :key [String] the derived key
72
+ def self.pbkdf_timed(password:, key_length:, milliseconds:,
73
+ algo: DEFAULT_PBKDF_ALGO,
74
+ salt: RNG.get(DEFAULT_KDF_SALT_LENGTH))
75
+ out_buf = FFI::MemoryPointer.new(:uint8, key_length)
76
+ salt_buf = FFI::MemoryPointer.from_data(salt)
77
+ iterations_ptr = FFI::MemoryPointer.new(:size_t)
78
+ Botan.call_ffi(:botan_pbkdf_timed,
79
+ algo, out_buf, key_length,
80
+ password, salt_buf, salt_buf.size,
81
+ milliseconds, iterations_ptr)
82
+ { iterations: iterations_ptr.read(:size_t),
83
+ key: out_buf.read_bytes(key_length) }
84
+ end
85
+ end # module
86
+ end # module
87
+
@@ -0,0 +1,90 @@
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
+ # Message Authentication Code
13
+ #
14
+ # == Examples
15
+ # === examples/mac.rb
16
+ # {include:file:examples/mac.rb}
17
+ class MAC
18
+ # @param algo [String] the MAC algorithm name
19
+ def initialize(algo)
20
+ flags = 0
21
+ ptr = FFI::MemoryPointer.new(:pointer)
22
+ Botan.call_ffi(:botan_mac_init, ptr, algo, flags)
23
+ ptr = ptr.read_pointer
24
+ raise Botan::Error, 'botan_mac_init returned NULL' if ptr.null?
25
+ @ptr = FFI::AutoPointer.new(ptr, self.class.method(:destroy))
26
+ end
27
+
28
+ # @api private
29
+ def self.destroy(ptr)
30
+ LibBotan.botan_mac_destroy(ptr)
31
+ end
32
+
33
+ # Resets the instace back to a clean state, as if no key and
34
+ # input have been supplied.
35
+ #
36
+ # @return [self]
37
+ def reset
38
+ Botan.call_ffi(:botan_mac_clear, @ptr)
39
+ self
40
+ end
41
+
42
+ # Retrieve the output length of the MAC.
43
+ #
44
+ # @return [Integer]
45
+ def output_length
46
+ length_ptr = FFI::MemoryPointer.new(:size_t)
47
+ Botan.call_ffi(:botan_mac_output_length, @ptr, length_ptr)
48
+ length_ptr.read(:size_t)
49
+ end
50
+
51
+ # Sets the key for the MAC.
52
+ # This must be called before {#update}.
53
+ #
54
+ # @param [String] key
55
+ def key=(key)
56
+ Botan.call_ffi(:botan_mac_set_key, @ptr, key, key.bytesize)
57
+ end
58
+
59
+ # Adds input to the MAC computation.
60
+ #
61
+ # @param [String] data
62
+ # @return [self]
63
+ def update(data)
64
+ Botan.call_ffi(:botan_mac_update, @ptr, data, data.bytesize)
65
+ self
66
+ end
67
+
68
+ def digest
69
+ out_buf = FFI::MemoryPointer.new(:uint8, output_length)
70
+ Botan.call_ffi(:botan_mac_final, @ptr, out_buf)
71
+ out_buf.read_bytes(out_buf.size)
72
+ end
73
+
74
+ def hexdigest
75
+ Botan.hex_encode(digest)
76
+ end
77
+
78
+ def inspect
79
+ Botan.inspect_ptr(self)
80
+ end
81
+
82
+ alias << update
83
+
84
+ # TODO: it's not safe to do this at the moment, since these
85
+ # methods mutate the state.
86
+ # alias inspect hexdigest
87
+ # alias to_s hexdigest
88
+ end # class
89
+ end # module
90
+
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) 2017 Ribose Inc.
4
+
5
+ require 'ffi'
6
+
7
+ require 'botan/ffi/libbotan'
8
+ require 'botan/utils'
9
+
10
+ module Botan
11
+ module PK
12
+ # Encrypts with McEliece.
13
+ #
14
+ # @param public_key [Botan::PK::PublicKey] the public key
15
+ # @param plaintext [String] the data to encrypt
16
+ # @param ad [String] the associated data
17
+ # @param aead [String] the (AEAD) cipher+mode
18
+ # @param rng [Botan::RNG] the RNG to use
19
+ # @return [String] the encrypted data
20
+ def self.mceies_encrypt(public_key:, plaintext:, ad:,
21
+ aead: DEFAULT_AEAD,
22
+ rng: Botan::RNG.new)
23
+ pt_buf = FFI::MemoryPointer.from_data(plaintext)
24
+ ad_buf = FFI::MemoryPointer.from_data(ad)
25
+ Botan.call_ffi_with_buffer(lambda { |b, bl|
26
+ LibBotan.botan_mceies_encrypt(public_key.ptr,
27
+ rng.ptr,
28
+ aead,
29
+ pt_buf,
30
+ pt_buf.size,
31
+ ad_buf,
32
+ ad_buf.size,
33
+ b,
34
+ bl)
35
+ })
36
+ end
37
+
38
+ # Decrypts with McEliece.
39
+ #
40
+ # @param private_key [Botan::PK::PrivateKey] the private key
41
+ # @param ciphertext [String] the data to decrypt
42
+ # @param ad [String] the associated data
43
+ # @param aead [String] the (AEAD) cipher+mode
44
+ # @return [String] the decrypted data
45
+ def self.mceies_decrypt(private_key:, ciphertext:, ad:,
46
+ aead: DEFAULT_AEAD)
47
+ ct_buf = FFI::MemoryPointer.from_data(ciphertext)
48
+ ad_buf = FFI::MemoryPointer.from_data(ad)
49
+ Botan.call_ffi_with_buffer(lambda { |b, bl|
50
+ LibBotan.botan_mceies_decrypt(private_key.ptr,
51
+ aead,
52
+ ct_buf,
53
+ ct_buf.size,
54
+ ad_buf,
55
+ ad.size,
56
+ b,
57
+ bl)
58
+ })
59
+ end
60
+ end # module
61
+ end # module
62
+
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) 2017 Ribose Inc.
4
+
5
+ require 'ffi'
6
+
7
+ require 'botan/defaults'
8
+ require 'botan/error'
9
+ require 'botan/ffi/libbotan'
10
+ require 'botan/pk/privatekey'
11
+ require 'botan/utils'
12
+
13
+ module Botan
14
+ module PK
15
+ # Public Key Decrypt Operation
16
+ #
17
+ # See {Botan::PK::PrivateKey#decrypt} for a simpler interface.
18
+ class Decrypt
19
+ # @param key [Botan::PK::PrivateKey] the private key
20
+ # @param padding [String] the padding method name
21
+ def initialize(key:, padding: nil)
22
+ padding ||= Botan::DEFAULT_EME
23
+ unless key.instance_of?(PrivateKey)
24
+ raise Botan::Error, 'Decryption requires an instance of PrivateKey'
25
+ end
26
+ ptr = FFI::MemoryPointer.new(:pointer)
27
+ flags = 0
28
+ Botan.call_ffi(:botan_pk_op_decrypt_create,
29
+ ptr, key.ptr, padding, flags)
30
+ ptr = ptr.read_pointer
31
+ if ptr.null?
32
+ raise Botan::Error, 'botan_pk_op_decrypt_create returned NULL'
33
+ end
34
+ @ptr = FFI::AutoPointer.new(ptr, self.class.method(:destroy))
35
+ end
36
+
37
+ # @api private
38
+ def self.destroy(ptr)
39
+ LibBotan.botan_pk_op_decrypt_destroy(ptr)
40
+ end
41
+
42
+ # Decrypts the provided data.
43
+ #
44
+ # @param msg [String] the data
45
+ # @return [String] the decrypted data
46
+ def decrypt(msg)
47
+ msg_buf = FFI::MemoryPointer.from_data(msg)
48
+ Botan.call_ffi_with_buffer(lambda { |b, bl|
49
+ LibBotan.botan_pk_op_decrypt(@ptr, b, bl, msg_buf, msg_buf.size)
50
+ })
51
+ end
52
+
53
+ def inspect
54
+ Botan.inspect_ptr(self)
55
+ end
56
+ end # class
57
+ end # module
58
+ end # module
59
+
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) 2017 Ribose Inc.
4
+
5
+ require 'ffi'
6
+
7
+ require 'botan/defaults'
8
+ require 'botan/error'
9
+ require 'botan/ffi/libbotan'
10
+ require 'botan/pk/publickey'
11
+ require 'botan/rng'
12
+ require 'botan/utils'
13
+
14
+ module Botan
15
+ module PK
16
+ # Public Key Encrypt Operation
17
+ #
18
+ # See {Botan::PK::PublicKey#encrypt} for a simpler interface.
19
+ class Encrypt
20
+ # @param key [Botan::PK::PublicKey] the public key
21
+ # @param padding [String] the padding method name
22
+ def initialize(key:, padding: nil)
23
+ padding ||= Botan::DEFAULT_EME
24
+ unless key.instance_of?(PublicKey)
25
+ raise Botan::Error, 'Encryption requires an instance of PublicKey'
26
+ end
27
+ ptr = FFI::MemoryPointer.new(:pointer)
28
+ flags = 0
29
+ Botan.call_ffi(:botan_pk_op_encrypt_create,
30
+ ptr, key.ptr, padding, flags)
31
+ ptr = ptr.read_pointer
32
+ if ptr.null?
33
+ raise Botan::Error, 'botan_pk_op_encrypt_create returned NULL'
34
+ end
35
+ @ptr = FFI::AutoPointer.new(ptr, self.class.method(:destroy))
36
+ end
37
+
38
+ # @api private
39
+ def self.destroy(ptr)
40
+ LibBotan.botan_pk_op_encrypt_destroy(ptr)
41
+ end
42
+
43
+ # Encrypts the provided data.
44
+ #
45
+ # @param msg [String] the data
46
+ # @param rng [Botan::PK::RNG] the RNG to use
47
+ # @return [String] the encrypted data
48
+ def encrypt(msg, rng: Botan::RNG.new)
49
+ msg_buf = FFI::MemoryPointer.from_data(msg)
50
+ Botan.call_ffi_with_buffer(lambda { |b, bl|
51
+ LibBotan.botan_pk_op_encrypt(@ptr, rng.ptr, b, bl,
52
+ msg_buf, msg_buf.size)
53
+ })
54
+ end
55
+
56
+ def inspect
57
+ Botan.inspect_ptr(self)
58
+ end
59
+ end # class
60
+ end # module
61
+ end # module
62
+
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) 2017 Ribose Inc.
4
+
5
+ require 'ffi'
6
+
7
+ require 'botan/defaults'
8
+ require 'botan/error'
9
+ require 'botan/ffi/libbotan'
10
+ require 'botan/pk/privatekey'
11
+ require 'botan/utils'
12
+
13
+ module Botan
14
+ module PK
15
+ # Public Key Key Agreement Operation
16
+ class KeyAgreement
17
+ attr_reader :public_value
18
+ # @param key [Botan::PK::PrivateKey] the private key
19
+ # @param kdf [String] the KDF algorithm name
20
+ def initialize(key:, kdf: Botan::DEFAULT_KDF_ALGO)
21
+ unless key.instance_of?(PrivateKey)
22
+ raise Botan::Error, 'KeyAgreement requires an instance of PrivateKey'
23
+ end
24
+ ptr = FFI::MemoryPointer.new(:pointer)
25
+ flags = 0
26
+ Botan.call_ffi(:botan_pk_op_key_agreement_create,
27
+ ptr, key.ptr, kdf, flags)
28
+ ptr = ptr.read_pointer
29
+ if ptr.null?
30
+ raise Botan::Error, 'botan_pk_op_key_agreement_create returned NULL'
31
+ end
32
+ @ptr = FFI::AutoPointer.new(ptr, self.class.method(:destroy))
33
+ @public_value = Botan.call_ffi_with_buffer(lambda { |b, bl|
34
+ LibBotan.botan_pk_op_key_agreement_export_public(key.ptr, b, bl)
35
+ })
36
+ end
37
+
38
+ # @api private
39
+ def self.destroy(ptr)
40
+ LibBotan.botan_pk_op_key_agreement_destroy(ptr)
41
+ end
42
+
43
+ def agree(other_key:, key_length:, salt:)
44
+ other_buf = FFI::MemoryPointer.from_data(other_key)
45
+ salt_buf = FFI::MemoryPointer.from_data(salt)
46
+ Botan.call_ffi_with_buffer(lambda { |b, bl|
47
+ LibBotan.botan_pk_op_key_agreement(@ptr, b, bl,
48
+ other_buf, other_buf.size,
49
+ salt_buf, salt_buf.size)
50
+ }, guess: key_length)
51
+ end
52
+
53
+ def inspect
54
+ Botan.inspect_ptr(self)
55
+ end
56
+ end # class
57
+ end # module
58
+ end # module
59
+
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) 2017 Ribose Inc.
4
+
5
+ require 'ffi'
6
+
7
+ require 'botan/defaults'
8
+ require 'botan/error'
9
+ require 'botan/ffi/libbotan'
10
+ require 'botan/pk/privatekey'
11
+ require 'botan/rng'
12
+ require 'botan/utils'
13
+
14
+ module Botan
15
+ module PK
16
+ # Public Key Sign Operation
17
+ #
18
+ # See {Botan::PK::PrivateKey#sign} for a simpler interface.
19
+ class Sign
20
+ # @param key [Botan::PK::PrivateKey] the private key
21
+ # @param padding [String] the padding method name
22
+ def initialize(key:, padding: nil)
23
+ padding ||= Botan::DEFAULT_EMSA[key.algo]
24
+ unless key.instance_of?(PrivateKey)
25
+ raise Botan::Error, 'Signing requires an instance of PrivateKey'
26
+ end
27
+ ptr = FFI::MemoryPointer.new(:pointer)
28
+ flags = 0
29
+ Botan.call_ffi(:botan_pk_op_sign_create, ptr, key.ptr, padding, flags)
30
+ ptr = ptr.read_pointer
31
+ raise Botan::Error, 'botan_pk_op_sign_create returned NULL' if ptr.null?
32
+ @ptr = FFI::AutoPointer.new(ptr, self.class.method(:destroy))
33
+ end
34
+
35
+ # @api private
36
+ def self.destroy(ptr)
37
+ LibBotan.botan_pk_op_sign_destroy(ptr)
38
+ end
39
+
40
+ # Adds data to the message currently being signed.
41
+ #
42
+ # @param msg [String] the data to add
43
+ # @return [self]
44
+ def update(msg)
45
+ msg_buf = FFI::MemoryPointer.from_data(msg)
46
+ Botan.call_ffi(:botan_pk_op_sign_update, @ptr, msg_buf, msg_buf.size)
47
+ self
48
+ end
49
+
50
+ # Finalizes the signature operation.
51
+ #
52
+ # @param rng [Botan::PK::RNG] the RNG to use
53
+ # @return [String] the signature
54
+ def finish(rng = Botan::RNG.new)
55
+ Botan.call_ffi_with_buffer(lambda { |b, bl|
56
+ LibBotan.botan_pk_op_sign_finish(@ptr, rng.ptr, b, bl)
57
+ })
58
+ end
59
+
60
+ def inspect
61
+ Botan.inspect_ptr(self)
62
+ end
63
+
64
+ alias << update
65
+ end # class
66
+ end # module
67
+ end # module
68
+