botan 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+