messagesodium 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +14 -0
- data/README.md +69 -0
- data/Rakefile +2 -1
- data/lib/messagesodium.rb +17 -17
- data/lib/messagesodium/version.rb +1 -1
- data/messagesodium.gemspec +2 -2
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3bbe8437f3f0156fccf90bb3defdf1b565057196
|
4
|
+
data.tar.gz: 01b0de5ed925df8cc9c501b83b07899acfa83b9b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d901c443944865798e2485a7d78da76abdd6110d2d432f1255887c5352bd5470691290cfb74b3c297e6b4f98d71d3348f2cb7d6c3c22ee3c71e21bb6b271a15
|
7
|
+
data.tar.gz: 75cb3cafda0ebbd2792c8f7a049f3fa0854dcfe8e10e88ccb0b7a2968c654f5bfb0af74acb80d7ce04e83d1657e494da41bc4b352f8fe231c2b539fe4001ff21
|
data/.rubocop.yml
ADDED
data/README.md
CHANGED
@@ -3,3 +3,72 @@
|
|
3
3
|
Project status: Turbo Pre-alpha
|
4
4
|
|
5
5
|
Patches Cookiestore to use libsodium for encryption and verification.
|
6
|
+
|
7
|
+
# Cookistore
|
8
|
+
|
9
|
+
Rails [Cookiestore](https://www.justinweiss.com/articles/how-rails-sessions-work/) is a heavily underrated feature. It bought commonsense to session management at a time when [saving every user session in its own tmpfile on a server](http://php.net/manual/en/function.session-start.php) was slow and unreasonable to scale, and XXX.
|
10
|
+
|
11
|
+
This gem brings an alternative backend to CookieStore.
|
12
|
+
|
13
|
+
# Use
|
14
|
+
|
15
|
+
Just insert this gem into your Gemfile like any other:
|
16
|
+
|
17
|
+
gem 'messagesodium'
|
18
|
+
|
19
|
+
And run your usual bundle installation. Any existing sessions will be invalidated, much like if you changed your secret key.
|
20
|
+
You can test it is active by looking at any session cookie. The absence of the "--" delimeter will confirm you are using this gem.
|
21
|
+
|
22
|
+
# Demonstration
|
23
|
+
|
24
|
+
[This gist](https://gist.github.com/technion/5cb2c6fbc570f6c1bc66e30bfb072cdf) shows a few interesting benchmarks, which we can refer to when describing what this gem offers.
|
25
|
+
|
26
|
+
```
|
27
|
+
|
28
|
+
Cookiestore data is: SWFQbTg0dCtheE45TXU0dWRtT25ndjJVSEdWTE8vei9LMVpZYWVjaWZjaFppdUk5aklVRWZEUy9TOUJuMFpYd2dDMndVZkt0eTR5Sm04Y1FjQzk0M00wRnhTRERHdDhnT3c1dTBvTnRad009LS16WlFaeE82dy84VzA4NThYQzk5bTVBPT0=--efcb8809421d2dc1665c9d9afa9638c1c2a763eb
|
29
|
+
which is 222 in length
|
30
|
+
Sodium data is: SGwQn0DD+pOvTPo68nvNYQLRFMt+Mf7rFU6BkiKhA0qHGT8BHVuqXRqEOYy+xcOoMCCRh99eeb/sVWlPzA4/FavTyg4U0PUAns0bx/Q9j4gcoD6K/h0z8yZvW0425g==
|
31
|
+
which is 128 in length
|
32
|
+
user system total real
|
33
|
+
to_json 2.470000 0.000000 2.470000 ( 2.514048)
|
34
|
+
JSON.dump 0.520000 0.000000 0.520000 ( 0.534084)
|
35
|
+
cookiestore encrypt and sign 1.810000 0.030000 1.840000 ( 1.915375)
|
36
|
+
cookiestore decrypt and verify 2.730000 0.000000 2.730000 ( 2.824819)
|
37
|
+
libsodium encrypt and sign 1.580000 0.060000 1.640000 ( 1.738750)
|
38
|
+
libsodium decrypt 1.010000 0.000000 1.010000 ( 1.035354)
|
39
|
+
|
40
|
+
```
|
41
|
+
|
42
|
+
## Smaller cookies
|
43
|
+
|
44
|
+
A welcome consequence is that of smaller cookies. This isn't strictly the result of changed encryption algorithms, but CookieStore's message packing is somewhat ineffecient. It is effectively:
|
45
|
+
|
46
|
+
Base64(Base64(iv) || "--" || Base64(message)) || "--" HMAC
|
47
|
+
|
48
|
+
If you can understand the reasoning for double Base64 encoding you're smarter than I am, but it adds to the four delimiting bytes. The authenticator on Poly1305 is also four bytes shorter than SHA1. You can see the end result in the above benchmark - 222 bytes vs 128 for our sample.
|
49
|
+
|
50
|
+
Smaller cookies are a good thing. It's less data on the wire for every single page hit, and it's more room to move around the 4Kb limit.
|
51
|
+
|
52
|
+
## More performant
|
53
|
+
|
54
|
+
The above benchmark shows our approach as much more performant. Some of that is just crypto, which can be hardware dependant.
|
55
|
+
|
56
|
+
But some of this is down to the message packing. Dipping into Base64 functions three separate times to open one cookie is ineffecient. When the IV is known to be of BLOCKSIZE length, choosing to cut it by using split() and a delimiter is the long way around. In the end, performance is great.
|
57
|
+
|
58
|
+
## A modern security approach
|
59
|
+
|
60
|
+
Let's be clear about the fact that I have no known issue with the current CookieStore implementation. However, it's worth having a read of the view of [Google's Adam Langley](https://www.imperialviolet.org/2013/10/07/chacha20.html) when describing "a strong motivation to replace it" when describing CBC mode.
|
61
|
+
|
62
|
+
Indeed, the are several comments in the original Rails source code to the effect of "this dance is done in the hope we don't introduce a vulnerability".
|
63
|
+
|
64
|
+
What you'll find in this gem is a much smaller, more easily audited codebase without any hoops to jump through.
|
65
|
+
|
66
|
+
# Approach
|
67
|
+
|
68
|
+
This gem is designed largely as a drop-in replacement for MessageEncryptor, which in turn is used by CookieStore. In a defualt environment, Rails astracts away everything I say below.
|
69
|
+
|
70
|
+
MessageEncryptor takes a "secret", and a "signing secret", using them as two different secrets. Libsodium only needs a 256-bit secret.
|
71
|
+
|
72
|
+
MessageEncryptor offers the option to provide an OpenSSL cipher. Obviously none of these apply to our gem. Finally, MessageEncryptor offers its choice of serializers. It defaults to Marshal, which was always a bad move, so Rails started to implicitly set JSON as the serializer in version 4.1. There's no reason in my view to let people have a footgun like this, so all this gem supports is JSON.
|
73
|
+
|
74
|
+
In order to make this "drop in", all the above parameters can still be provided, they are just ignored.
|
data/Rakefile
CHANGED
data/lib/messagesodium.rb
CHANGED
@@ -10,37 +10,37 @@ module ActiveSupport
|
|
10
10
|
#
|
11
11
|
# The cipher text and initialization vector are base64 encoded and returned
|
12
12
|
# to you.
|
13
|
-
#
|
14
13
|
class MessageEncryptor
|
15
14
|
class InvalidMessage < StandardError; end
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
# Uses "secret" as a libsodium Simplebox initialiser
|
17
|
+
# Secret must be 32 bytes (256-bit) long
|
18
|
+
# The options and signature fields are unused as lidsodium does not require
|
19
|
+
# a second key for an HMAC.
|
20
|
+
# However we need to retain them as they exist in the original function
|
21
|
+
def initialize(secret, *_signature_key_or_options)
|
20
22
|
@box = RbNaCl::SimpleBox.from_secret_key(secret)
|
21
23
|
end
|
22
24
|
|
23
|
-
# Encrypt and
|
24
|
-
#
|
25
|
+
# Encrypt and authenticate using libsodium XSalsa20/Poly1305
|
26
|
+
# Serialise with JSON.dump
|
27
|
+
# Returns base64(random nonce + cipher + auth tag)
|
25
28
|
def encrypt_and_sign(value)
|
26
|
-
Base64.strict_encode64(@box.encrypt(value
|
29
|
+
Base64.strict_encode64(@box.encrypt(::JSON.dump(value)))
|
27
30
|
end
|
28
31
|
|
29
|
-
# Decrypt
|
30
|
-
# avoid padding attacks. Reference: http://www.limited-entropy.com/padding-oracle-attacks.
|
32
|
+
# Decrypt the message, and check the auth tag in the process.
|
31
33
|
def decrypt_and_verify(value)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
raise InvalidMessage
|
36
|
-
end
|
34
|
+
::JSON.parse(@box.decrypt(Base64.decode64(value)), symbolize_names: true)
|
35
|
+
rescue RbNaCl::CryptoError
|
36
|
+
raise InvalidMessage
|
37
37
|
end
|
38
38
|
|
39
|
-
# Given a cipher, returns the key length of the cipher to help generate
|
40
|
-
|
39
|
+
# Given a cipher, returns the key length of the cipher to help generate
|
40
|
+
# the key of desired size
|
41
|
+
def self.key_len(_cipher = nil)
|
41
42
|
# Ignore the cipher - libsodium knows what it's doing.
|
42
43
|
RbNaCl::SecretBox.key_bytes
|
43
44
|
end
|
44
45
|
end
|
45
|
-
|
46
46
|
end
|
data/messagesodium.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Technion"]
|
10
10
|
spec.email = ["technion@lolware.net"]
|
11
11
|
|
12
|
-
spec.summary = %q{Patches Cookiestore to use Libsodium
|
13
|
-
spec.description = %q{
|
12
|
+
spec.summary = %q{Patches MessageEncryptor/Cookiestore to use Libsodium .}
|
13
|
+
spec.description = %q{Introduces modern crypto, higher performance, smaller cookies to your sessions.}
|
14
14
|
spec.homepage = "https://github.com/technion/messagesodium"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: messagesodium
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Technion
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-09-
|
11
|
+
date: 2017-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbnacl-libsodium
|
@@ -66,7 +66,8 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '5.0'
|
69
|
-
description:
|
69
|
+
description: Introduces modern crypto, higher performance, smaller cookies to your
|
70
|
+
sessions.
|
70
71
|
email:
|
71
72
|
- technion@lolware.net
|
72
73
|
executables: []
|
@@ -74,6 +75,7 @@ extensions: []
|
|
74
75
|
extra_rdoc_files: []
|
75
76
|
files:
|
76
77
|
- ".gitignore"
|
78
|
+
- ".rubocop.yml"
|
77
79
|
- ".travis.yml"
|
78
80
|
- Gemfile
|
79
81
|
- LICENSE.txt
|
@@ -107,5 +109,5 @@ rubyforge_project:
|
|
107
109
|
rubygems_version: 2.6.11
|
108
110
|
signing_key:
|
109
111
|
specification_version: 4
|
110
|
-
summary: Patches Cookiestore to use Libsodium
|
112
|
+
summary: Patches MessageEncryptor/Cookiestore to use Libsodium .
|
111
113
|
test_files: []
|