ffi-libsodium 0.1.10 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e8f824b533e203a30b75bd97267e79eefbee9b04
4
- data.tar.gz: e791838d822463c909f23b885f48d9651e2c8dbc
3
+ metadata.gz: 95a7d9bb37cc560f3dfbb7a72a6bcf31ffdf63d6
4
+ data.tar.gz: 636823f16c86f508ff3180c56edb357a6b8afa2c
5
5
  SHA512:
6
- metadata.gz: de9b091d5911cfe41e0f34d15789a6a3dc4a2c608c760e0148542e7ec7c245531e7e2ac67879df21405dca1ea8931c64b02a817a25be73350395bf1bba7157a3
7
- data.tar.gz: 1336f51e32015d717ea5b409806fef90d342458528478d8c061a661e458f0c01e1f506c757da58d5b186a9c49817f454abc45b23c6ad0c7afab730598c5c5468
6
+ metadata.gz: e101ac68e41004c5b1dab8594baf37a6bd3c68fa6bb4981fdc556ef7d6d9cfac3e5aadaaec9c4ff11c524570fcf49500459aca5eed2486c8af7835235a0a5b61
7
+ data.tar.gz: 9c3e394cdf2941d370ad3c690c0bf17a335ba4cc9aba9aea5fa61b88bdff986369493be2348aa3d6663fff6e6e98c3aa6901d5fbefd5b59a5d3893f5bc696fa1
data/README.md CHANGED
@@ -11,7 +11,7 @@ bundle update
11
11
  require 'bundler/setup'
12
12
  require 'libsodium'
13
13
 
14
- password = 'test123'
14
+ password = Crypto.generichash('test123')
15
15
 
16
16
  salt = Crypto::PwHash::ScryptSalsa208SHA256.salt
17
17
  key = Crypto::PwHash.scryptsalsa208sha256(Crypto::Auth::KEYBYTES, password, salt)
@@ -46,7 +46,6 @@ module Crypto
46
46
  check_length(key, KEYBYTES, :SecretKey)
47
47
 
48
48
  ciphertext = Sodium::Buffer.new(:uchar, message_len + ABYTES)
49
- ciphertext.primitive = PRIMITIVE
50
49
  key.readonly if key.is_a?(Sodium::SecretBuffer)
51
50
  crypto_aead_chacha20poly1305_encrypt(ciphertext, nil, message, message_len, additional_data, get_size(additional_data), nil, nonce, key)
52
51
 
@@ -56,22 +55,28 @@ module Crypto
56
55
  end
57
56
 
58
57
  def decrypt(ciphertext, additional_data, nonce, key)
59
- unless ((ciphertext_len = get_size(ciphertext)) - ABYTES) > 0
58
+ ciphertext_len = get_size(ciphertext)
59
+ if (decrypted_len = ciphertext_len - ABYTES) > 0
60
+ check_length(nonce, NPUBBYTES, :Nonce)
61
+ check_length(key, KEYBYTES, :SecretKey)
62
+
63
+ decrypted = Sodium::Buffer.new(:uchar, decrypted_len)
64
+ key.readonly if key.is_a?(Sodium::SecretBuffer)
65
+ if crypto_aead_chacha20poly1305_decrypt(decrypted, nil, nil, ciphertext, ciphertext_len, additional_data, get_size(additional_data), nonce, key) == 0
66
+ decrypted
67
+ else
68
+ raise Sodium::CryptoError, "Message forged", caller
69
+ end
70
+ else
60
71
  fail Sodium::LengthError, "Ciphertext is too short", caller
61
72
  end
62
- check_length(nonce, NPUBBYTES, :Nonce)
63
- check_length(key, KEYBYTES, :SecretKey)
64
-
65
- decrypted = Sodium::Buffer.new(:uchar, ciphertext_len - ABYTES)
66
- key.readonly if key.is_a?(Sodium::SecretBuffer)
67
- unless crypto_aead_chacha20poly1305_decrypt(decrypted, nil, nil, ciphertext, ciphertext_len, additional_data, get_size(additional_data), nonce, key).zero?
68
- raise Sodium::CryptoError, "Message forged", caller
69
- end
70
-
71
- decrypted
72
73
  ensure
73
74
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
74
75
  end
75
76
  end
77
+
78
+ Chacha20Poly1305.freeze
76
79
  end
80
+
81
+ AEAD.freeze
77
82
  end
data/lib/crypto/auth.rb CHANGED
@@ -27,7 +27,6 @@ module Crypto
27
27
  check_length(key, KEYBYTES, :SecretKey)
28
28
 
29
29
  mac = Sodium::Buffer.new(:uchar, BYTES)
30
- mac.primitive = PRIMITIVE
31
30
  key.readonly if key.is_a?(Sodium::SecretBuffer)
32
31
  crypto_auth(mac, message, get_size(message), key)
33
32
 
@@ -41,12 +40,14 @@ module Crypto
41
40
  check_length(key, KEYBYTES, :SecretKey)
42
41
 
43
42
  key.readonly if key.is_a?(Sodium::SecretBuffer)
44
- crypto_auth_verify(mac, message, get_size(message), key).zero?
43
+ crypto_auth_verify(mac, message, get_size(message), key) == 0
45
44
  ensure
46
45
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
47
46
  end
48
47
  end
49
48
 
49
+ Auth.freeze
50
+
50
51
  module_function
51
52
 
52
53
  def auth(*args)
data/lib/crypto/box.rb CHANGED
@@ -40,9 +40,7 @@ module Crypto
40
40
 
41
41
  def keypair
42
42
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
43
- public_key.primitive = PRIMITIVE
44
43
  secret_key = Sodium::Buffer.new(:uchar, SECRETKEYBYTES)
45
- secret_key.primitive = PRIMITIVE
46
44
  crypto_box_keypair(public_key, secret_key)
47
45
 
48
46
  [public_key, secret_key]
@@ -52,9 +50,7 @@ module Crypto
52
50
  check_length(seed, SEEDBYTES, :Seed)
53
51
 
54
52
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
55
- public_key.primitive = PRIMITIVE
56
53
  secret_key = Sodium::Buffer.new(:uchar, SECRETKEYBYTES)
57
- secret_key.primitive = PRIMITIVE
58
54
  seed.readonly if seed.is_a?(Sodium::SecretBuffer)
59
55
  crypto_box_seed_keypair(public_key, secret_key, seed)
60
56
 
@@ -65,8 +61,7 @@ module Crypto
65
61
 
66
62
  def memory_locked_keypair
67
63
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
68
- public_key.primitive = PRIMITIVE
69
- secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES, PRIMITIVE)
64
+ secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES)
70
65
  crypto_box_keypair(public_key, secret_key)
71
66
  secret_key.noaccess
72
67
 
@@ -77,8 +72,7 @@ module Crypto
77
72
  check_length(seed, SEEDBYTES, :Seed)
78
73
 
79
74
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
80
- public_key.primitive = PRIMITIVE
81
- secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES, PRIMITIVE)
75
+ secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES)
82
76
  seed.readonly if seed.is_a?(Sodium::SecretBuffer)
83
77
  crypto_box_seed_keypair(public_key, secret_key, seed)
84
78
  secret_key.noaccess
@@ -95,7 +89,6 @@ module Crypto
95
89
  check_length(secret_key, SECRETKEYBYTES, :SecretKey)
96
90
 
97
91
  ciphertext = Sodium::Buffer.new(:uchar, message_len + MACBYTES)
98
- ciphertext.primitive = PRIMITIVE
99
92
  secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
100
93
  crypto_box_easy(ciphertext, message, message_len, nonce, public_key, secret_key)
101
94
 
@@ -112,22 +105,22 @@ module Crypto
112
105
 
113
106
  decrypted = Sodium::Buffer.new(:uchar, ciphertext_len - MACBYTES)
114
107
  secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
115
- unless crypto_box_open_easy(decrypted, ciphertext, ciphertext_len, nonce, public_key, secret_key).zero?
108
+ if crypto_box_open_easy(decrypted, ciphertext, ciphertext_len, nonce, public_key, secret_key) == 0
109
+ decrypted
110
+ else
116
111
  raise Sodium::CryptoError, "Message forged", caller
117
112
  end
118
-
119
- decrypted
120
113
  ensure
121
114
  secret_key.noaccess if secret_key.is_a?(Sodium::SecretBuffer)
122
115
  end
123
116
 
124
117
  def easy_in_place(data, nonce, public_key, secret_key)
125
- message = get_string(data)
118
+ message = String(data)
126
119
  check_length(nonce, NONCEBYTES, :Nonce)
127
120
  check_length(public_key, PUBLICKEYBYTES, :PublicKey)
128
121
  check_length(secret_key, SECRETKEYBYTES, :SecretKey)
129
122
 
130
- message_len = get_size(message)
123
+ message_len = message.bytesize
131
124
  message << zeros(MACBYTES)
132
125
  secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
133
126
  crypto_box_easy(message, message, message_len, nonce, public_key, secret_key)
@@ -137,33 +130,36 @@ module Crypto
137
130
  secret_key.noaccess if secret_key.is_a?(Sodium::SecretBuffer)
138
131
  end
139
132
 
140
- def open_easy_in_place(data, nonce, public_key, secret_key, utf8 = false)
141
- ciphertext = get_string(data)
142
- unless (message_len = get_size(ciphertext) - MACBYTES) > 0
143
- fail Sodium::LengthError, "Ciphertext is too short", caller
144
- end
145
-
146
- check_length(nonce, NONCEBYTES, :Nonce)
147
- check_length(public_key, PUBLICKEYBYTES, :PublicKey)
148
- check_length(secret_key, SECRETKEYBYTES, :SecretKey)
149
-
150
- secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
151
- unless crypto_box_open_easy(ciphertext, ciphertext, get_size(ciphertext), nonce, public_key, secret_key).zero?
152
- raise Sodium::CryptoError, "Message forged", caller
153
- end
154
-
155
- if utf8
156
- ciphertext.slice!(message_len..-1).force_encoding(Encoding::UTF_8)
133
+ def open_easy_in_place(data, nonce, public_key, secret_key, encoding = false)
134
+ ciphertext = String(data)
135
+ ciphertext_len = ciphertext.bytesize
136
+ if (message_len = ciphertext_len - MACBYTES) > 0
137
+ check_length(nonce, NONCEBYTES, :Nonce)
138
+ check_length(public_key, PUBLICKEYBYTES, :PublicKey)
139
+ check_length(secret_key, SECRETKEYBYTES, :SecretKey)
140
+
141
+ secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
142
+ if crypto_box_open_easy(ciphertext, ciphertext, ciphertext_len, nonce, public_key, secret_key) == 0
143
+ if encoding
144
+ ciphertext.slice!(message_len..-1).force_encoding(encoding)
145
+ else
146
+ ciphertext.slice!(message_len..-1)
147
+ end
148
+
149
+ ciphertext
150
+ else
151
+ raise Sodium::CryptoError, "Message forged", caller
152
+ end
157
153
  else
158
- ciphertext.slice!(message_len..-1)
154
+ fail Sodium::LengthError, "Ciphertext is too short", caller
159
155
  end
160
-
161
- ciphertext
162
156
  ensure
163
157
  secret_key.noaccess if secret_key.is_a?(Sodium::SecretBuffer)
164
158
  end
165
159
  end
166
160
 
161
+ Box.freeze
162
+
167
163
  module_function
168
164
 
169
165
  def box(*args)
@@ -1,8 +1,8 @@
1
1
  require 'ffi'
2
2
  require_relative '../sodium/utils'
3
- require_relative '../sodium/errors'
4
3
  require_relative '../sodium/buffer'
5
4
  require_relative '../sodium/secret_buffer'
5
+ require_relative '../sodium/errors'
6
6
 
7
7
  module Crypto
8
8
  module GenericHash
@@ -46,28 +46,19 @@ module Crypto
46
46
  module_function
47
47
 
48
48
  def generichash(message, hash_size = BYTES, key = nil)
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} bytes", caller
51
- end
52
-
53
49
  if key
54
50
  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
51
  else
60
52
  key_len = 0
61
53
  end
62
54
 
63
55
  blake2b = Sodium::Buffer.new(:uchar, hash_size)
64
- blake2b.primitive = PRIMITIVE
65
56
  key.readonly if key.is_a?(Sodium::SecretBuffer)
66
- unless crypto_generichash(blake2b, hash_size, message, get_size(message), key, key_len).zero?
57
+ if crypto_generichash(blake2b, hash_size, message, get_size(message), key, key_len) == 0
58
+ blake2b
59
+ else
67
60
  raise Sodium::CryptoError
68
61
  end
69
-
70
- blake2b
71
62
  ensure
72
63
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
73
64
  end
@@ -75,47 +66,36 @@ module Crypto
75
66
  def init(key = nil, hash_size = BYTES)
76
67
  if key
77
68
  key_len = get_size(key)
78
-
79
- if key_len > KEYBYTES_MAX ||key_len < KEYBYTES_MIN
80
- fail Sodium::LengthError, "Key length must be between #{KEYBYTES_MIN} and #{KEYBYTES_MAX} bytes, got length=#{key_len} bytes", caller
81
- end
82
69
  else
83
70
  key_len = 0
84
71
  end
85
72
 
86
- if hash_size > BYTES_MAX ||hash_size < BYTES_MIN
87
- fail Sodium::LengthError, "Hash size must be between #{BYTES_MIN} and #{BYTES_MAX} bytes, got size=#{hash_size} bytes", caller
88
- end
89
-
90
73
  state = State.new
91
- blake2b = Sodium::Buffer.new(:uchar, hash_size)
92
- blake2b.primitive = PRIMITIVE
93
74
  key.readonly if key.is_a?(Sodium::SecretBuffer)
94
-
95
- unless crypto_generichash_init(state, key, key_len, hash_size).zero?
75
+ if crypto_generichash_init(state, key, key_len, hash_size) == 0
76
+ [state, Sodium::Buffer.new(:uchar, hash_size)]
77
+ else
96
78
  raise Sodium::CryptoError
97
79
  end
98
-
99
- [state, blake2b]
100
80
  ensure
101
81
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
102
82
  end
103
83
 
104
84
  def update(state, message)
105
- unless crypto_generichash_update(state, message, get_size(message)).zero?
106
- raise Sodium::CryptoError
107
- end
85
+ crypto_generichash_update(state, message, get_size(message))
108
86
  end
109
87
 
110
88
  def final(state, blake2b)
111
- unless crypto_generichash_final(state, blake2b, blake2b.size).zero?
89
+ if crypto_generichash_final(state, blake2b, blake2b.size) == 0
90
+ blake2b
91
+ else
112
92
  raise Sodium::CryptoError
113
93
  end
114
-
115
- blake2b
116
94
  end
117
95
  end
118
96
 
97
+ GenericHash.freeze
98
+
119
99
  module_function
120
100
 
121
101
  def generichash(*args)
@@ -36,7 +36,6 @@ module Crypto
36
36
  check_length(key, KEYBYTES, :SecretKey)
37
37
 
38
38
  out = Sodium::Buffer.new(:uchar, BYTES)
39
- out.primitive = PRIMITIVE
40
39
  key.readonly if key.is_a?(Sodium::SecretBuffer)
41
40
  crypto_onetimeauth(out, message, get_size(message), key)
42
41
 
@@ -50,7 +49,7 @@ module Crypto
50
49
  check_length(key, KEYBYTES, :SecretKey)
51
50
 
52
51
  key.readonly if key.is_a?(Sodium::SecretBuffer)
53
- crypto_onetimeauth_verify(out, message, get_size(message), key).zero?
52
+ crypto_onetimeauth_verify(out, message, get_size(message), key) == 0
54
53
  ensure
55
54
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
56
55
  end
@@ -73,13 +72,13 @@ module Crypto
73
72
 
74
73
  def final(state)
75
74
  out = Sodium::Buffer.new(:uchar, BYTES)
76
- out.primitive = PRIMITIVE
77
75
  crypto_onetimeauth_final(state, out)
78
-
79
76
  out
80
77
  end
81
78
  end
82
79
 
80
+ OneTimeAuth.freeze
81
+
83
82
  module_function
84
83
 
85
84
  def onetimeauth(*args)
@@ -49,51 +49,40 @@ module Crypto
49
49
  end
50
50
 
51
51
  def scryptsalsa208sha256(outlen, passwd, salt, opslimit = OPSLIMIT_INTERACTIVE, memlimit = MEMLIMIT_INTERACTIVE)
52
- out = nil
53
52
  check_length(salt, SALTBYTES, :Salt)
54
- if opslimit < OPSLIMIT_INTERACTIVE
55
- fail Sodium::LengthError, "Opslimit must be at least #{OPSLIMIT_INTERACTIVE}, got #{opslimit}", caller
56
- end
57
- if memlimit < MEMLIMIT_INTERACTIVE
58
- fail Sodium::LengthError, "Memlimit must be at least #{MEMLIMIT_INTERACTIVE}, got #{memlimit}", caller
59
- end
60
53
 
61
- out = Sodium::SecretBuffer.new(outlen, PRIMITIVE)
62
- unless crypto_pwhash_scryptsalsa208sha256(out, outlen, passwd, get_size(passwd), salt, opslimit, memlimit).zero?
54
+ out = Sodium::SecretBuffer.new(outlen)
55
+ if crypto_pwhash_scryptsalsa208sha256(out, outlen, passwd, get_size(passwd), salt, opslimit, memlimit) == 0
56
+ out.noaccess
57
+ out
58
+ else
63
59
  raise NoMemoryError, "Failed to allocate memory max size=#{memlimit} bytes", caller
64
60
  end
65
-
66
- out
67
- ensure
68
- out.noaccess if out
69
61
  end
70
62
 
71
63
  def str(passwd, opslimit = OPSLIMIT_INTERACTIVE, memlimit = MEMLIMIT_INTERACTIVE)
72
- if opslimit < OPSLIMIT_INTERACTIVE
73
- fail Sodium::LengthError, "Opslimit must be at least #{OPSLIMIT_INTERACTIVE}, got #{opslimit}", caller
74
- end
75
- if memlimit < MEMLIMIT_INTERACTIVE
76
- fail Sodium::LengthError, "Memlimit must be at least #{MEMLIMIT_INTERACTIVE}, got #{memlimit}", caller
77
- end
78
-
79
64
  hashed_password = FFI::MemoryPointer.new(:char, STRBYTES)
80
- unless crypto_pwhash_scryptsalsa208sha256_str(hashed_password, passwd, get_size(passwd), opslimit, memlimit).zero?
65
+ if crypto_pwhash_scryptsalsa208sha256_str(hashed_password, passwd, get_size(passwd), opslimit, memlimit) == 0
66
+ hashed_password.get_string(0)
67
+ else
81
68
  raise NoMemoryError, "Failed to allocate memory max size=#{memlimit} bytes", caller
82
69
  end
83
-
84
- hashed_password.get_string(0)
85
70
  end
86
71
 
87
72
  def str_verify(str, passwd)
88
73
  check_length(str, STRBYTES - 1, :Str)
89
- crypto_pwhash_scryptsalsa208sha256_str_verify(str, passwd, get_size(passwd)).zero?
74
+ crypto_pwhash_scryptsalsa208sha256_str_verify(str, passwd, get_size(passwd)) == 0
90
75
  end
91
76
  end
92
77
 
78
+ ScryptSalsa208SHA256.freeze
79
+
93
80
  module_function
94
81
 
95
82
  def scryptsalsa208sha256(*args)
96
83
  ScryptSalsa208SHA256.scryptsalsa208sha256(*args)
97
84
  end
98
85
  end
86
+
87
+ PwHash.freeze
99
88
  end
@@ -27,7 +27,6 @@ module Crypto
27
27
  check_length(secret_key, SCALARBYTES, :SecretKey)
28
28
 
29
29
  public_key = Sodium::Buffer.new(:uchar, BYTES)
30
- public_key.primitive = PRIMITIVE
31
30
  secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
32
31
  crypto_scalarmult_base(public_key, secret_key)
33
32
 
@@ -40,7 +39,7 @@ module Crypto
40
39
  check_length(secret_key, SCALARBYTES, :SecretKey)
41
40
  check_length(public_key, BYTES, :PublicKey)
42
41
 
43
- shared_secret = Sodium::SecretBuffer.new(BYTES, PRIMITIVE)
42
+ shared_secret = Sodium::SecretBuffer.new(BYTES)
44
43
  secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
45
44
  crypto_scalarmult(shared_secret, secret_key, public_key)
46
45
  shared_secret.noaccess
@@ -51,6 +50,8 @@ module Crypto
51
50
  end
52
51
  end
53
52
 
53
+ ScalarMult.freeze
54
+
54
55
  module_function
55
56
 
56
57
  def scalarmut(*args)
@@ -37,7 +37,6 @@ module Crypto
37
37
  check_length(key, KEYBYTES, :SecretKey)
38
38
 
39
39
  ciphertext = Sodium::Buffer.new(:uchar, message_len + MACBYTES)
40
- ciphertext.primitive = PRIMITIVE
41
40
  key.readonly if key.is_a?(Sodium::SecretBuffer)
42
41
  crypto_secretbox_easy(ciphertext, message, message_len, nonce, key)
43
42
 
@@ -53,22 +52,21 @@ module Crypto
53
52
 
54
53
  decrypted = Sodium::Buffer.new(:uchar, ciphertext_len - MACBYTES)
55
54
  key.readonly if key.is_a?(Sodium::SecretBuffer)
56
-
57
- unless crypto_secretbox_open_easy(decrypted, ciphertext, ciphertext_len, nonce, key).zero?
55
+ if crypto_secretbox_open_easy(decrypted, ciphertext, ciphertext_len, nonce, key) == 0
56
+ decrypted
57
+ else
58
58
  raise Sodium::CryptoError, "Message forged", caller
59
59
  end
60
-
61
- decrypted
62
60
  ensure
63
61
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
64
62
  end
65
63
 
66
64
  def easy_in_place(data, nonce, key)
67
- message = get_string(data)
65
+ message = String(data)
68
66
  check_length(nonce, NONCEBYTES, :Nonce)
69
67
  check_length(key, KEYBYTES, :SecretKey)
70
68
 
71
- message_len = get_size(message)
69
+ message_len = message.bytesize
72
70
  message << zeros(MACBYTES)
73
71
  key.readonly if key.is_a?(Sodium::SecretBuffer)
74
72
  crypto_secretbox_easy(message, message, message_len, nonce, key)
@@ -78,32 +76,35 @@ module Crypto
78
76
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
79
77
  end
80
78
 
81
- def open_easy_in_place(data, nonce, key, utf8 = false)
82
- ciphertext = get_string(data)
83
- unless (message_len = get_size(ciphertext) - MACBYTES) > 0
84
- fail Sodium::LengthError, "Ciphertext is too short", caller
85
- end
86
-
87
- check_length(nonce, NONCEBYTES, :Nonce)
88
- check_length(key, KEYBYTES, :SecretKey)
89
-
90
- key.readonly if key.is_a?(Sodium::SecretBuffer)
91
- unless crypto_secretbox_open_easy(ciphertext, ciphertext, get_size(ciphertext), nonce, key).zero?
92
- raise Sodium::CryptoError, "Message forged", caller
93
- end
94
-
95
- if utf8
96
- ciphertext.slice!(message_len..-1).force_encoding(Encoding::UTF_8)
79
+ def open_easy_in_place(data, nonce, key, encoding = false)
80
+ ciphertext = String(data)
81
+ ciphertext_len = ciphertext.bytesize
82
+ if (message_len = ciphertext_len - MACBYTES) > 0
83
+ check_length(nonce, NONCEBYTES, :Nonce)
84
+ check_length(key, KEYBYTES, :SecretKey)
85
+
86
+ key.readonly if key.is_a?(Sodium::SecretBuffer)
87
+ if crypto_secretbox_open_easy(ciphertext, ciphertext, ciphertext_len, nonce, key) == 0
88
+ if encoding
89
+ ciphertext.slice!(message_len..-1).force_encoding(encoding)
90
+ else
91
+ ciphertext.slice!(message_len..-1)
92
+ end
93
+
94
+ ciphertext
95
+ else
96
+ raise Sodium::CryptoError, "Message forged", caller
97
+ end
97
98
  else
98
- ciphertext.slice!(message_len..-1)
99
+ fail Sodium::LengthError, "Ciphertext is too short", caller
99
100
  end
100
-
101
- ciphertext
102
101
  ensure
103
102
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
104
103
  end
105
104
  end
106
105
 
106
+ SecretBox.freeze
107
+
107
108
  module_function
108
109
 
109
110
  def secretbox(*args)
@@ -26,7 +26,6 @@ module Crypto
26
26
  check_length(key, KEYBYTES, :SecretKey)
27
27
 
28
28
  siphash = Sodium::Buffer.new(:uchar, BYTES)
29
- siphash.primitive = PRIMITIVE
30
29
  key.readonly if key.is_a?(Sodium::SecretBuffer)
31
30
  crypto_shorthash(siphash, short_data, get_size(short_data), key)
32
31
 
@@ -36,6 +35,8 @@ module Crypto
36
35
  end
37
36
  end
38
37
 
38
+ ShortHash.freeze
39
+
39
40
  module_function
40
41
 
41
42
  def shorthash(*args)
data/lib/crypto/sign.rb CHANGED
@@ -33,9 +33,7 @@ module Crypto
33
33
 
34
34
  def keypair
35
35
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
36
- public_key.primitive = PRIMITIVE
37
36
  secret_key = Sodium::Buffer.new(:uchar, SECRETKEYBYTES)
38
- secret_key.primitive = PRIMITIVE
39
37
  crypto_sign_keypair(public_key, secret_key)
40
38
 
41
39
  [public_key, secret_key]
@@ -45,9 +43,7 @@ module Crypto
45
43
  check_length(seed, SEEDBYTES, :Seed)
46
44
 
47
45
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
48
- public_key.primitive = PRIMITIVE
49
46
  secret_key = Sodium::Buffer.new(:uchar, SECRETKEYBYTES)
50
- secret_key.primitive = PRIMITIVE
51
47
  seed.readonly if seed.is_a?(Sodium::SecretBuffer)
52
48
  crypto_sign_seed_keypair(public_key, secret_key, seed)
53
49
 
@@ -58,8 +54,7 @@ module Crypto
58
54
 
59
55
  def memory_locked_keypair
60
56
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
61
- public_key.primitive = PRIMITIVE
62
- secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES, PRIMITIVE)
57
+ secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES)
63
58
  crypto_sign_keypair(public_key, secret_key)
64
59
  secret_key.noaccess
65
60
 
@@ -70,8 +65,7 @@ module Crypto
70
65
  check_length(seed, SEEDBYTES, :Seed)
71
66
 
72
67
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
73
- public_key.primitive = PRIMITIVE
74
- secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES, PRIMITIVE)
68
+ secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES)
75
69
  seed.readonly if seed.is_a?(Sodium::SecretBuffer)
76
70
  crypto_sign_seed_keypair(public_key, secret_key, seed)
77
71
  secret_key.noaccess
@@ -86,7 +80,6 @@ module Crypto
86
80
  check_length(secret_key, SECRETKEYBYTES, :SecretKey)
87
81
 
88
82
  sealed_message = Sodium::Buffer.new(:uchar, message_len + BYTES)
89
- sealed_message.primitive = PRIMITIVE
90
83
  secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
91
84
  crypto_sign(sealed_message, nil, message, message_len, secret_key)
92
85
 
@@ -100,15 +93,17 @@ module Crypto
100
93
  check_length(public_key, PUBLICKEYBYTES, :PublicKey)
101
94
 
102
95
  unsealed_message = Sodium::Buffer.new(:uchar, sealed_message_len - BYTES)
103
- unsealed_message_len = FFI::MemoryPointer.new(:pointer)
104
- unless crypto_sign_open(unsealed_message, unsealed_message_len, sealed_message, sealed_message_len, public_key).zero?
96
+ unsealed_message_len = FFI::MemoryPointer.new(:ulong_long)
97
+ if crypto_sign_open(unsealed_message, unsealed_message_len, sealed_message, sealed_message_len, public_key) == 0
98
+ unsealed_message
99
+ else
105
100
  raise Sodium::CryptoError, "Incorrect signature", caller
106
101
  end
107
-
108
- unsealed_message
109
102
  end
110
103
  end
111
104
 
105
+ Sign.freeze
106
+
112
107
  module_function
113
108
 
114
109
  def sign(*args)
@@ -54,5 +54,7 @@ module Crypto
54
54
  secret_key.noaccess if secret_key.is_a?(Sodium::SecretBuffer)
55
55
  end
56
56
  end
57
+
58
+ Ed25519.freeze
57
59
  end
58
60
  end
data/lib/libsodium.rb CHANGED
@@ -2,19 +2,22 @@
2
2
  require_relative 'sodium'
3
3
  require_relative 'sodium/utils'
4
4
  require_relative 'sodium/buffer'
5
+ require_relative 'sodium/mprotect'
5
6
  require_relative 'sodium/secret_buffer'
7
+ Sodium.freeze
6
8
  require_relative 'random_bytes'
7
9
  require_relative 'crypto/secret_box'
8
10
  require_relative 'crypto/auth'
9
11
  require_relative 'crypto/aead/chacha20_poly1305'
10
12
  require_relative 'crypto/box'
13
+ require_relative 'crypto/sign/ed25519'
11
14
  require_relative 'crypto/sign'
12
15
  require_relative 'crypto/generic_hash'
13
16
  require_relative 'crypto/short_hash'
14
17
  require_relative 'crypto/pw_hash/scrypt_salsa208_sha256'
15
18
  require_relative 'crypto/one_time_auth'
16
19
  require_relative 'crypto/scalar_mult'
17
- require_relative 'crypto/sign/ed25519'
20
+ Crypto.freeze
18
21
 
19
22
  Thread.exclusive do
20
23
  if Sodium.init == -1
data/lib/random_bytes.rb CHANGED
@@ -20,3 +20,5 @@ module RandomBytes
20
20
  buf
21
21
  end
22
22
  end
23
+
24
+ RandomBytes.freeze
data/lib/sodium.rb CHANGED
@@ -16,53 +16,22 @@ module Sodium
16
16
  attach_function :sodium_munlock, [:pointer, :size_t], :int
17
17
  attach_function :sodium_malloc, [:size_t], :pointer
18
18
  attach_function :sodium_allocarray, [:size_t, :size_t], :pointer
19
- attach_function :sodium_mprotect_noaccess, [:pointer], :int
20
- attach_function :sodium_mprotect_readonly, [:pointer], :int
21
- attach_function :sodium_mprotect_readwrite, [:pointer], :int
22
19
 
23
20
  module_function
24
21
 
25
22
  def mlock(addr, len)
26
- unless sodium_mlock(addr, len).zero?
27
- raise MemoryError, "Could not lock length=#{len} bytes memory at address=#{addr.address}", caller
28
- end
23
+ sodium_mlock(addr, len) == 0 || raise(MemoryError, "Could not lock length=#{len} bytes memory at address=#{addr.address}", caller)
29
24
  end
30
25
 
31
26
  def munlock(addr, len)
32
- unless sodium_munlock(addr, len).zero?
33
- raise MemoryError, "Could not unlock length=#{len} bytes memory at address=#{addr.address}", caller
34
- end
27
+ sodium_munlock(addr, len) == 0 || raise(MemoryError, "Could not unlock length=#{len} bytes memory at address=#{addr.address}", caller)
35
28
  end
36
29
 
37
30
  def malloc(size)
38
- unless (mem = sodium_malloc(size))
39
- raise NoMemoryError, "Failed to allocate memory size=#{size} bytes", caller
40
- end
41
- mem
31
+ sodium_malloc(size) || raise(NoMemoryError, "Failed to allocate memory size=#{size} bytes", caller)
42
32
  end
43
33
 
44
34
  def allocarray(count, size)
45
- unless (mem = sodium_allocarray(count, size))
46
- raise NoMemoryError, "Failed to allocate memory size=#{count * size} bytes", caller
47
- end
48
- mem
49
- end
50
-
51
- def noaccess(ptr)
52
- unless sodium_mprotect_noaccess(ptr).zero?
53
- raise MemoryError, "Memory at address=#{ptr.address} is not secured with #{self}.malloc", caller
54
- end
55
- end
56
-
57
- def readonly(ptr)
58
- unless sodium_mprotect_readonly(ptr).zero?
59
- raise MemoryError, "Memory at address=#{ptr.address} is not secured with #{self}.malloc", caller
60
- end
61
- end
62
-
63
- def readwrite(ptr)
64
- unless sodium_mprotect_readwrite(ptr).zero?
65
- raise MemoryError, "Memory at address=#{ptr.address} is not secured with #{self}.malloc", caller
66
- end
35
+ sodium_allocarray(count, size) || raise(NoMemoryError, "Failed to allocate memory size=#{count * size} bytes", caller)
67
36
  end
68
37
  end
data/lib/sodium/buffer.rb CHANGED
@@ -2,12 +2,10 @@
2
2
 
3
3
  module Sodium
4
4
  class Buffer < FFI::MemoryPointer
5
- attr_accessor :primitive
6
-
7
- def to_bytes
5
+ def to_str
8
6
  read_bytes(size)
9
7
  end
10
-
11
- alias_method :to_str, :to_bytes
12
8
  end
9
+
10
+ Buffer.freeze
13
11
  end
data/lib/sodium/errors.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Sodium
2
- class CryptoError < StandardError; end
3
- class LengthError < ArgumentError; end
4
- class MemoryError < StandardError; end
2
+ CryptoError = Class.new(StandardError).freeze
3
+ LengthError = Class.new(ArgumentError).freeze
4
+ MemoryError = Class.new(StandardError).freeze
5
5
  end
@@ -0,0 +1,30 @@
1
+ require 'ffi'
2
+ require_relative 'errors'
3
+ require_relative 'utils'
4
+
5
+ module Sodium
6
+ module Mprotect
7
+ extend FFI::Library
8
+ ffi_lib :libsodium
9
+
10
+ attach_function :sodium_mprotect_noaccess, [:pointer], :int
11
+ attach_function :sodium_mprotect_readonly, [:pointer], :int
12
+ attach_function :sodium_mprotect_readwrite, [:pointer], :int
13
+
14
+ module_function
15
+
16
+ def noaccess(ptr)
17
+ sodium_mprotect_noaccess(ptr) == 0 || raise(MemoryError, "Memory at address=#{ptr.address} is not secured with Sodium.malloc", caller)
18
+ end
19
+
20
+ def readonly(ptr)
21
+ sodium_mprotect_readonly(ptr) == 0 || raise(MemoryError, "Memory at address=#{ptr.address} is not secured with Sodium.malloc", caller)
22
+ end
23
+
24
+ def readwrite(ptr)
25
+ sodium_mprotect_readwrite(ptr) == 0 || raise(MemoryError, "Memory at address=#{ptr.address} is not secured with Sodium.malloc", caller)
26
+ end
27
+ end
28
+
29
+ Mprotect.freeze
30
+ end
@@ -1,58 +1,61 @@
1
1
  require 'forwardable'
2
- require_relative 'utils'
3
2
  require_relative '../sodium'
3
+ require_relative 'mprotect'
4
4
  require 'ffi'
5
5
 
6
6
  module Sodium
7
7
  class SecretBuffer
8
8
  extend Forwardable
9
9
 
10
- attr_reader :size, :primitive, :to_ptr
11
- def_delegators :to_ptr, :address, :to_i
10
+ attr_reader :size, :to_ptr
11
+ def_delegators :@to_ptr, :address, :to_i
12
12
 
13
- def initialize(size, primitive = nil)
14
- @size = Utils.get_int(size)
15
- @primitive = primitive
16
- @to_ptr = Sodium.malloc(self.size)
13
+ def initialize(size)
14
+ @size = Integer(size)
15
+ @to_ptr = Sodium.malloc(@size)
17
16
  setup_finalizer
18
17
  end
19
18
 
20
19
  def free
21
20
  remove_finalizer
22
- readwrite
23
- Sodium.free(to_ptr)
24
- @size = @primitive = @to_ptr = nil
21
+ Sodium::Mprotect.readonly(@to_ptr)
22
+ Sodium.free(@to_ptr)
23
+ remove_instance_variable(:@size)
24
+ remove_instance_variable(:@to_ptr)
25
+ true
25
26
  end
26
27
 
27
28
  def noaccess
28
- Sodium.noaccess(to_ptr)
29
+ Sodium::Mprotect.noaccess(@to_ptr)
29
30
  end
30
31
 
31
32
  def readonly
32
- Sodium.readonly(to_ptr)
33
+ Sodium::Mprotect.readonly(@to_ptr)
33
34
  end
34
35
 
35
36
  def readwrite
36
- Sodium.readwrite(to_ptr)
37
+ Sodium::Mprotect.readwrite(@to_ptr)
37
38
  end
38
39
 
39
40
  private
40
41
 
41
42
  def setup_finalizer
42
- ObjectSpace.define_finalizer(to_ptr, self.class.free(to_ptr.address))
43
+ ObjectSpace.define_finalizer(@to_ptr, self.class.free(@to_ptr.address))
43
44
  end
44
45
 
45
46
  def remove_finalizer
46
- ObjectSpace.undefine_finalizer to_ptr
47
+ ObjectSpace.undefine_finalizer @to_ptr
47
48
  end
48
49
 
49
50
  def self.free(address)
50
51
  ->(obj_id) do
51
52
  ptr = FFI::Pointer.new(address)
52
- Sodium.readwrite(ptr)
53
+ Sodium::Mprotect.readonly(ptr)
53
54
  Sodium.free(ptr)
54
55
  true
55
56
  end
56
57
  end
57
58
  end
59
+
60
+ SecretBuffer.freeze
58
61
  end
data/lib/sodium/utils.rb CHANGED
@@ -1,68 +1,41 @@
1
- require_relative 'errors'
2
- require 'ffi'
1
+ require 'ffi'
2
+ require_relative 'secret_buffer'
3
+ require_relative 'errors'
3
4
 
4
5
  module Sodium
5
6
  module Utils
6
7
 
7
8
  module_function
8
9
 
9
- def check_length(data, length, description)
10
- if data.is_a?(String) ||data.respond_to?(:bytesize)
11
- unless data.bytesize == length
12
- fail Sodium::LengthError, "Expected a length=#{length} bytes #{description}, got size=#{data.bytesize} bytes", caller
13
- end
14
- elsif data.is_a?(FFI::Pointer) ||data.respond_to?(:size)
15
- unless data.size == length
16
- fail Sodium::LengthError, "Expected a length=#{length} bytes #{description}, got size=#{data.size} bytes", caller
17
- end
18
- else
19
- fail ArgumentError, "#{description} must be of type String or FFI::Pointer and be length=#{length} bytes long", caller
20
- end
21
-
22
- true
23
- end
24
-
25
- def get_pointer(ptr)
26
- if ptr.is_a?(FFI::Pointer)
27
- ptr
28
- elsif ptr.respond_to?(:to_ptr)
29
- ptr.to_ptr
30
- else
31
- fail ArgumentError, "#{ptr.class} is not a FFI::Pointer", caller
32
- end
33
- end
34
-
35
- def get_string(string)
36
- if string.is_a?(String)
37
- string
38
- elsif string.respond_to?(:to_str)
39
- string.to_str
40
- elsif string.respond_to?(:get_string)
41
- string.get_string(0)
42
- else
43
- fail ArgumentError, "#{string.class} is not a String", caller
44
- end
45
- end
46
-
47
- def get_int(int)
48
- if int.is_a?(Fixnum)
49
- int
50
- elsif int.respond_to?(:to_int)
51
- int.to_int
10
+ def get_size(data)
11
+ case data
12
+ when FFI::Pointer, SecretBuffer
13
+ data.size
14
+ when String
15
+ data.bytesize
16
+ when NilClass
17
+ 0
52
18
  else
53
- fail ArgumentError, "#{int.class} is not a Integer", caller
19
+ fail TypeError, "#{data.class} must be of type FFI::Pointer, Sodium::SecretBufffer, String or NilClass", caller
54
20
  end
55
21
  end
56
22
 
57
- def get_size(data)
58
- if data.is_a?(String) ||data.respond_to?(:bytesize)
59
- data.bytesize
60
- elsif data.is_a?(FFI::Pointer) ||data.respond_to?(:size)
61
- data.size
62
- elsif data.nil?
63
- 0
23
+ def check_length(data, length, description)
24
+ case data
25
+ when FFI::Pointer, SecretBuffer
26
+ if data.size == length
27
+ true
28
+ else
29
+ fail LengthError, "Expected a length=#{length} bytes #{description}, got size=#{data.size} bytes", caller
30
+ end
31
+ when String
32
+ if data.bytesize == length
33
+ true
34
+ else
35
+ fail LengthError, "Expected a length=#{length} bytes #{description}, got size=#{data.bytesize} bytes", caller
36
+ end
64
37
  else
65
- fail ArgumentError, "#{data.class} doesn't respond to :bytesize or :size", caller
38
+ fail TypeError, "#{data.class} must be of type FFI::Pointer, Sodium::SecretBufffer or String", caller
66
39
  end
67
40
  end
68
41
 
@@ -82,4 +55,6 @@ module Sodium
82
55
  [hex].pack(HEXY)
83
56
  end
84
57
  end
58
+
59
+ Utils.freeze
85
60
  end
@@ -1,3 +1,3 @@
1
1
  module Sodium
2
- VERSION = Gem::Version.new('0.1.10')
2
+ VERSION = Gem::Version.new('0.2.0')
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffi-libsodium
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hendrik Beskow
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-11 00:00:00.000000000 Z
11
+ date: 2014-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -62,6 +62,7 @@ files:
62
62
  - lib/sodium.rb
63
63
  - lib/sodium/buffer.rb
64
64
  - lib/sodium/errors.rb
65
+ - lib/sodium/mprotect.rb
65
66
  - lib/sodium/secret_buffer.rb
66
67
  - lib/sodium/utils.rb
67
68
  - lib/sodium/version.rb