ffi-libsodium 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.
@@ -0,0 +1,123 @@
1
+ require_relative '../sodium'
2
+ require_relative '../sodium/utils'
3
+ require_relative '../sodium/buffer'
4
+ require_relative '../sodium/secret_buffer'
5
+
6
+ module Crypto
7
+ module GenericHash
8
+ extend FFI::Library
9
+ extend Sodium::Utils
10
+
11
+ ffi_lib :libsodium
12
+
13
+ attach_function :primitive, :crypto_generichash_primitive, [], :string
14
+ attach_function :bytes_min, :crypto_generichash_bytes_min, [], :size_t
15
+ attach_function :bytes_max, :crypto_generichash_bytes_max, [], :size_t
16
+ attach_function :bytes, :crypto_generichash_bytes, [], :size_t
17
+ attach_function :keybytes_min, :crypto_generichash_keybytes_min, [], :size_t
18
+ attach_function :keybytes_max, :crypto_generichash_keybytes_max, [], :size_t
19
+ attach_function :keybytes, :crypto_generichash_keybytes, [], :size_t
20
+
21
+ PRIMITIVE = primitive.freeze
22
+ BYTES_MIN = bytes_min.freeze
23
+ BYTES_MAX = bytes_max.freeze
24
+ BYTES = bytes.freeze
25
+ KEYBYTES_MIN = keybytes_min.freeze
26
+ KEYBYTES_MAX = keybytes_max.freeze
27
+ KEYBYTES = keybytes.freeze
28
+
29
+ attach_function :crypto_generichash, [:buffer_out, :size_t, :buffer_in, :ulong_long, :buffer_in, :size_t], :int, blocking: true
30
+
31
+ class State < FFI::Struct
32
+ pack 64
33
+ layout :h, [:uint64, 8],
34
+ :t, [:uint64, 2],
35
+ :f, [:uint64, 2],
36
+ :buf, [:uint8, 2 * 128],
37
+ :buflen, :size_t,
38
+ :last_node, :uint8
39
+ end
40
+
41
+ attach_function :crypto_generichash_init, [State.ptr, :buffer_in, :size_t, :size_t], :int, blocking: true
42
+ attach_function :crypto_generichash_update, [State.ptr, :buffer_in, :ulong_long], :int, blocking: true
43
+ attach_function :crypto_generichash_final, [State.ptr, :buffer_out, :ulong_long], :int, blocking: true
44
+
45
+ module_function
46
+
47
+ def generichash(message, hash_size = BYTES, key = nil)
48
+ message_len = get_size(message)
49
+ if hash_size > BYTES_MAX ||hash_size < BYTES_MIN
50
+ fail Sodium::LengthError, "Hash size must be between #{BYTES_MIN} and #{BYTES_MAX} bytes, got size=#{hash_size.to_int} bytes", caller
51
+ end
52
+
53
+ if key
54
+ key_len = get_size(key)
55
+
56
+ if key_len > KEYBYTES_MAX ||key_len < KEYBYTES_MIN
57
+ fail Sodium::LengthError, "Key length must be between #{KEYBYTES_MIN} and #{KEYBYTES_MAX} bytes, got length=#{key_len} bytes", caller
58
+ end
59
+ else
60
+ key_len = 0
61
+ end
62
+
63
+ blake2b = Sodium::Buffer.new(:uchar, hash_size)
64
+ key.readonly if key.is_a?(Sodium::SecretBuffer)
65
+ rc = crypto_generichash(blake2b, hash_size, message, message_len, key, key_len)
66
+ key.noaccess if key.is_a?(Sodium::SecretBuffer)
67
+ if rc == -1
68
+ raise Sodium::CryptoError
69
+ end
70
+
71
+ blake2b
72
+ end
73
+
74
+ def init(key = nil, hash_size = BYTES)
75
+ if key
76
+ key_len = get_size(key)
77
+
78
+ if key_len > KEYBYTES_MAX ||key_len < KEYBYTES_MIN
79
+ fail Sodium::LengthError, "Key length must be between #{KEYBYTES_MIN} and #{KEYBYTES_MAX} bytes, got length=#{key_len} bytes", caller
80
+ end
81
+ else
82
+ key_len = 0
83
+ end
84
+
85
+ if hash_size > BYTES_MAX ||hash_size < BYTES_MIN
86
+ fail Sodium::LengthError, "Hash size must be between #{BYTES_MIN} and #{BYTES_MAX} bytes, got size=#{hash_size.to_int} bytes", caller
87
+ end
88
+
89
+ state = State.new
90
+ blake2b = Sodium::Buffer.new(:uchar, hash_size)
91
+ key.readonly if key.is_a?(Sodium::SecretBuffer)
92
+ rc = crypto_generichash_init(state, key, key_len, hash_size)
93
+ key.noaccess if key.is_a?(Sodium::SecretBuffer)
94
+ if rc == -1
95
+ raise Sodium::CryptoError
96
+ end
97
+
98
+ [state, blake2b]
99
+ end
100
+
101
+ def update(state, message)
102
+ message_len = get_size(message)
103
+
104
+ if crypto_generichash_update(state, message, message_len) == -1
105
+ raise Sodium::CryptoError
106
+ end
107
+ end
108
+
109
+ def final(state, blake2b)
110
+ get_pointer(blake2b)
111
+
112
+ if crypto_generichash_final(state, blake2b, blake2b.size) == -1
113
+ raise Sodium::CryptoError
114
+ end
115
+
116
+ blake2b
117
+ end
118
+ end
119
+
120
+ def self.generichash(*args)
121
+ GenericHash.generichash(*args)
122
+ end
123
+ end
@@ -0,0 +1,87 @@
1
+ require_relative '../sodium'
2
+ require_relative '../sodium/utils'
3
+ require_relative '../sodium/buffer'
4
+ require_relative '../sodium/secret_buffer'
5
+
6
+ module Crypto
7
+ module OneTimeAuth
8
+ extend FFI::Library
9
+ extend Sodium::Utils
10
+
11
+ ffi_lib :libsodium
12
+
13
+ attach_function :primitive, :crypto_onetimeauth_primitive, [], :string
14
+ attach_function :bytes, :crypto_onetimeauth_bytes, [], :size_t
15
+ attach_function :keybytes, :crypto_onetimeauth_keybytes, [], :size_t
16
+
17
+ PRIMITIVE = primitive.freeze
18
+ BYTES = bytes.freeze
19
+ KEYBYTES = keybytes.freeze
20
+
21
+ attach_function :crypto_onetimeauth, [:buffer_out, :buffer_in, :ulong_long, :buffer_in], :int
22
+ attach_function :crypto_onetimeauth_verify, [:buffer_in, :buffer_in, :ulong_long, :buffer_in], :int
23
+
24
+ class State < FFI::Struct
25
+ layout :aligner, :ulong_long,
26
+ :opaque, [:uchar, 136]
27
+ end
28
+
29
+ attach_function :crypto_onetimeauth_init, [State.ptr, :buffer_in], :int
30
+ attach_function :crypto_onetimeauth_update, [State.ptr, :buffer_in, :ulong_long], :int
31
+ attach_function :crypto_onetimeauth_final, [State.ptr, :buffer_out], :int
32
+
33
+ module_function
34
+
35
+ def onetimeauth(message, key)
36
+ message_len = get_size(message)
37
+ check_length(key, KEYBYTES, :SecretKey)
38
+
39
+ out = Sodium::Buffer.new(:uchar, BYTES)
40
+ key.readonly if key.is_a?(Sodium::SecretBuffer)
41
+ crypto_onetimeauth(out, message, message_len, key)
42
+ key.noaccess if key.is_a?(Sodium::SecretBuffer)
43
+
44
+ out
45
+ end
46
+
47
+ def verify(out, message, key)
48
+ check_length(out, BYTES, :Authenticator)
49
+ message_len = get_size(message)
50
+ check_length(key, KEYBYTES, :SecretKey)
51
+
52
+ key.readonly if key.is_a?(Sodium::SecretBuffer)
53
+ rc = crypto_onetimeauth_verify(out, message, message_len, key)
54
+ key.noaccess if key.is_a?(Sodium::SecretBuffer)
55
+
56
+ rc == 0
57
+ end
58
+
59
+ def init(key)
60
+ check_length(key, KEYBYTES, :SecretKey)
61
+
62
+ state = State.new
63
+ key.readonly if key.is_a?(Sodium::SecretBuffer)
64
+ crypto_onetimeauth_init(state, key)
65
+ key.noaccess if key.is_a?(Sodium::SecretBuffer)
66
+
67
+ state
68
+ end
69
+
70
+ def update(state, message)
71
+ message_len = get_size(message)
72
+
73
+ crypto_onetimeauth_update(state, message, message_len)
74
+ end
75
+
76
+ def final(state)
77
+ out = Sodium::Buffer.new(:uchar, BYTES)
78
+ crypto_onetimeauth_final(state, out)
79
+
80
+ out
81
+ end
82
+ end
83
+
84
+ def self.onetimeauth(*args)
85
+ OneTimeAuth.onetimeauth(*args)
86
+ end
87
+ end
@@ -0,0 +1,101 @@
1
+ require_relative '../../sodium'
2
+ require_relative '../../sodium/utils'
3
+ require_relative '../../sodium/buffer'
4
+ require_relative '../../sodium/secret_buffer'
5
+ require_relative '../../random_bytes'
6
+
7
+ module Crypto
8
+ module PwHash
9
+ module ScryptSalsa208SHA256
10
+ PACK_C = 'c*'.freeze
11
+ PRIMITIVE = 'scryptsalsa208sha256'.freeze
12
+
13
+ extend FFI::Library
14
+ extend Sodium::Utils
15
+
16
+ ffi_lib :libsodium
17
+
18
+ class << self
19
+ def crypto_pwhash_scryptsalsa208sha256_primitive
20
+ PRIMITIVE
21
+ end
22
+
23
+ alias_method :primitive, :crypto_pwhash_scryptsalsa208sha256_primitive
24
+ end
25
+
26
+ attach_function :saltbytes, :crypto_pwhash_scryptsalsa208sha256_saltbytes, [], :size_t
27
+ attach_function :strbytes, :crypto_pwhash_scryptsalsa208sha256_strbytes, [], :size_t
28
+ attach_function :strprefix, :crypto_pwhash_scryptsalsa208sha256_strprefix, [], :string
29
+ attach_function :opslimit_interactive, :crypto_pwhash_scryptsalsa208sha256_opslimit_interactive, [], :size_t
30
+ attach_function :memlimit_interactive, :crypto_pwhash_scryptsalsa208sha256_memlimit_interactive, [], :size_t
31
+ attach_function :opslimit_sensitive, :crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive, [], :size_t
32
+ attach_function :memlimit_sensitive, :crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive, [], :size_t
33
+
34
+ SALTBYTES = saltbytes.freeze
35
+ STRBYTES = strbytes.freeze
36
+ STRPREFIX = strprefix.freeze
37
+ OPSLIMIT_INTERACTIVE = opslimit_interactive.freeze
38
+ MEMLIMIT_INTERACTIVE = memlimit_interactive.freeze
39
+ OPSLIMIT_SENSITIVE = opslimit_sensitive.freeze
40
+ MEMLIMIT_SENSITIVE = memlimit_sensitive.freeze
41
+
42
+ attach_function :crypto_pwhash_scryptsalsa208sha256, [:buffer_out, :ulong_long, :buffer_in, :ulong_long, :buffer_in, :ulong_long, :size_t], :int, blocking: true
43
+ attach_function :crypto_pwhash_scryptsalsa208sha256_str, [:buffer_out, :buffer_in, :ulong_long, :ulong_long, :size_t], :int, blocking: true
44
+ attach_function :crypto_pwhash_scryptsalsa208sha256_str_verify, [:buffer_in, :buffer_in, :ulong_long], :int, blocking: true
45
+
46
+ module_function
47
+
48
+ def salt
49
+ RandomBytes.buf(SALTBYTES)
50
+ end
51
+
52
+ def scryptsalsa208sha256(passwd, outlen, salt, opslimit = OPSLIMIT_INTERACTIVE, memlimit = MEMLIMIT_INTERACTIVE)
53
+ passwd_len = get_size(passwd)
54
+ check_length(salt, SALTBYTES, :Salt)
55
+ if opslimit < OPSLIMIT_INTERACTIVE
56
+ fail Sodium::LengthError, "Opslimit must be at least #{OPSLIMIT_INTERACTIVE}, got #{opslimit.to_int}", caller
57
+ end
58
+ if memlimit < MEMLIMIT_INTERACTIVE
59
+ fail Sodium::LengthError, "Memlimit must be at least #{MEMLIMIT_INTERACTIVE}, got #{memlimit.to_int}", caller
60
+ end
61
+
62
+ out = Sodium::SecretBuffer.new(outlen)
63
+ rc = crypto_pwhash_scryptsalsa208sha256(out, outlen, passwd, passwd_len, salt, opslimit, memlimit)
64
+ out.noaccess
65
+ if rc == -1
66
+ raise NoMemoryError, "Failed to allocate memory max size=#{memlimit.to_int} bytes", caller
67
+ end
68
+
69
+ out
70
+ end
71
+
72
+ def str(passwd, opslimit = OPSLIMIT_INTERACTIVE, memlimit = MEMLIMIT_INTERACTIVE)
73
+ passwd_len = get_size(passwd)
74
+ if opslimit < OPSLIMIT_INTERACTIVE
75
+ fail Sodium::LengthError, "Opslimit must be at least #{OPSLIMIT_INTERACTIVE}, got #{opslimit.to_int}", caller
76
+ end
77
+ if memlimit < MEMLIMIT_INTERACTIVE
78
+ fail Sodium::LengthError, "Memlimit must be at least #{MEMLIMIT_INTERACTIVE}, got #{memlimit.to_int}", caller
79
+ end
80
+
81
+ hashed_password = FFI::MemoryPointer.new(:char, STRBYTES)
82
+ if crypto_pwhash_scryptsalsa208sha256_str(hashed_password, passwd, passwd_len, opslimit, memlimit) == -1
83
+ raise NoMemoryError, "Failed to allocate memory max size=#{memlimit.to_int} bytes", caller
84
+ end
85
+
86
+ hashed_password.read_array_of_char(STRBYTES).pack(PACK_C)
87
+ end
88
+
89
+ def str_verify(str, passwd)
90
+ check_length(str, STRBYTES, :Str)
91
+ passwd_len = get_size(passwd)
92
+
93
+ crypto_pwhash_scryptsalsa208sha256_str_verify(str, passwd, passwd_len) == 0
94
+ end
95
+ end
96
+
97
+ def self.scryptsalsa208sha256(*args)
98
+ ScryptSalsa208SHA256.scryptsalsa208sha256(*args)
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,55 @@
1
+ require_relative '../sodium'
2
+ require_relative '../sodium/utils'
3
+ require_relative '../sodium/buffer'
4
+ require_relative '../sodium/secret_buffer'
5
+ require_relative '../random_bytes'
6
+
7
+ module Crypto
8
+ module ScalarMult
9
+ extend FFI::Library
10
+ extend Sodium::Utils
11
+
12
+ ffi_lib :libsodium
13
+
14
+ attach_function :primitive, :crypto_scalarmult_primitive, [], :string
15
+ attach_function :bytes, :crypto_scalarmult_bytes, [], :size_t
16
+ attach_function :scalarbytes, :crypto_scalarmult_scalarbytes, [], :size_t
17
+
18
+ PRIMITIVE = primitive.freeze
19
+ BYTES = bytes.freeze
20
+ SCALARBYTES = scalarbytes.freeze
21
+
22
+ attach_function :crypto_scalarmult_base, [:buffer_out, :buffer_in], :int
23
+ attach_function :crypto_scalarmult, [:buffer_out, :buffer_in, :buffer_in], :int
24
+
25
+ module_function
26
+
27
+ def base(secret_key)
28
+ check_length(secret_key, SCALARBYTES, :SecretKey)
29
+
30
+ public_key = Sodium::Buffer.new(:uchar, BYTES)
31
+ secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
32
+ crypto_scalarmult_base(public_key, secret_key)
33
+ secret_key.noaccess if secret_key.is_a?(Sodium::SecretBuffer)
34
+
35
+ public_key
36
+ end
37
+
38
+ def scalarmut(secret_key, public_key)
39
+ check_length(secret_key, SCALARBYTES, :SecretKey)
40
+ check_length(public_key, SCALARBYTES, :PublicKey)
41
+
42
+ shared_secret = Sodium::SecretBuffer.new(BYTES)
43
+ secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
44
+ crypto_scalarmult(shared_secret, secret_key, public_key)
45
+ secret_key.noaccess if secret_key.is_a?(Sodium::SecretBuffer)
46
+ shared_secret.noaccess
47
+
48
+ shared_secret
49
+ end
50
+ end
51
+
52
+ def self.scalarmut(*args)
53
+ ScalarMult.scalarmut(*args)
54
+ end
55
+ end
@@ -0,0 +1,101 @@
1
+ require_relative '../sodium'
2
+ require_relative '../sodium/utils'
3
+ require_relative '../sodium/buffer'
4
+ require_relative '../sodium/secret_buffer'
5
+ require_relative '../random_bytes'
6
+
7
+ module Crypto
8
+ module SecretBox
9
+ extend FFI::Library
10
+ extend Sodium::Utils
11
+
12
+ ffi_lib :libsodium
13
+
14
+ attach_function :primitive, :crypto_secretbox_primitive, [], :string
15
+ attach_function :keybytes, :crypto_secretbox_keybytes, [], :size_t
16
+ attach_function :noncebytes, :crypto_secretbox_noncebytes, [], :size_t
17
+ attach_function :macbytes, :crypto_secretbox_macbytes, [], :size_t
18
+
19
+ PRIMITIVE = primitive.freeze
20
+ KEYBYTES = keybytes.freeze
21
+ NONCEBYTES = noncebytes.freeze
22
+ MACBYTES = macbytes.freeze
23
+
24
+ attach_function :crypto_secretbox_easy, [:buffer_out, :buffer_in, :ulong_long, :buffer_in, :buffer_in], :int, blocking: true
25
+ attach_function :crypto_secretbox_open_easy, [:buffer_out, :buffer_in, :ulong_long, :buffer_in, :buffer_in], :int, blocking: true
26
+
27
+ module_function
28
+
29
+ def nonce
30
+ RandomBytes.buf(NONCEBYTES)
31
+ end
32
+
33
+ def easy(message, nonce, key)
34
+ message_len = get_size(message)
35
+ check_length(nonce, NONCEBYTES, :Nonce)
36
+ check_length(key, KEYBYTES, :SecretKey)
37
+
38
+ ciphertext = Sodium::Buffer.new(:uchar, MACBYTES + message_len)
39
+ key.readonly if key.is_a?(Sodium::SecretBuffer)
40
+ crypto_secretbox_easy(ciphertext, message, message_len, nonce, key)
41
+ key.noaccess if key.is_a?(Sodium::SecretBuffer)
42
+
43
+ ciphertext
44
+ end
45
+
46
+ def open_easy(ciphertext, nonce, key)
47
+ ciphertext_len = get_size(ciphertext)
48
+ check_length(nonce, NONCEBYTES, :Nonce)
49
+ check_length(key, KEYBYTES, :SecretKey)
50
+
51
+ decrypted = Sodium::Buffer.new(:uchar, ciphertext_len - MACBYTES)
52
+ key.readonly if key.is_a?(Sodium::SecretBuffer)
53
+ rc = crypto_secretbox_open_easy(decrypted, ciphertext, ciphertext_len, nonce, key)
54
+ key.noaccess if key.is_a?(Sodium::SecretBuffer)
55
+ if rc == -1
56
+ raise Sodium::CryptoError, "Message forged", caller
57
+ end
58
+
59
+ decrypted
60
+ end
61
+
62
+ def easy_in_place(data, nonce, key)
63
+ message = get_string(data)
64
+ check_length(nonce, NONCEBYTES, :Nonce)
65
+ check_length(key, KEYBYTES, :SecretKey)
66
+
67
+ message_len = message.bytesize
68
+ message << zeros(MACBYTES)
69
+ key.readonly if key.is_a?(Sodium::SecretBuffer)
70
+ crypto_secretbox_easy(message, message, message_len, nonce, key)
71
+ key.noaccess if key.is_a?(Sodium::SecretBuffer)
72
+
73
+ message
74
+ end
75
+
76
+ def open_easy_in_place(data, nonce, key, utf8 = false)
77
+ ciphertext = get_string(data)
78
+ unless (message_len = ciphertext.bytesize - MACBYTES) > 0
79
+ fail Sodium::LengthError, "Ciphertext is too short", caller
80
+ end
81
+
82
+ check_length(nonce, NONCEBYTES, :Nonce)
83
+ check_length(key, KEYBYTES, :SecretKey)
84
+
85
+ key.readonly if key.is_a?(Sodium::SecretBuffer)
86
+ rc = crypto_secretbox_open_easy(ciphertext, ciphertext, ciphertext.bytesize, nonce, key)
87
+ key.noaccess if key.is_a?(Sodium::SecretBuffer)
88
+ if rc == -1
89
+ raise Sodium::CryptoError, "Message forged", caller
90
+ end
91
+
92
+ if utf8
93
+ ciphertext.slice!(message_len..-1).force_encoding(Encoding::UTF_8)
94
+ else
95
+ ciphertext.slice!(message_len..-1)
96
+ end
97
+
98
+ ciphertext
99
+ end
100
+ end
101
+ end