gibberish 1.4.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +0 -1
- data/CHANGELOG.mdown +11 -0
- data/Gemfile +6 -3
- data/Makefile +16 -0
- data/README.markdown +57 -58
- data/gibberish.gemspec +4 -2
- data/lib/gibberish/aes.rb +188 -10
- data/lib/gibberish/digest.rb +6 -12
- data/lib/gibberish/hmac.rb +34 -16
- data/lib/gibberish/version.rb +1 -1
- data/spec/aes_benchmark.rb +20 -0
- data/spec/aes_spec.rb +88 -2
- data/spec/hmac_spec.rb +14 -13
- data/spec/spec_helper.rb +1 -0
- metadata +17 -16
- data/.yardoc/checksums +0 -6
- data/.yardoc/objects/root.dat +0 -0
- data/.yardoc/proxy_types +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6eca32966c5ac459d70f832120c67175359ab581
|
4
|
+
data.tar.gz: 9ea06902e68d9e6c71410e9f6b79ce42642c46d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 036a7424a015301eb8df8f95bdfa50d924aa9aa0589667d6795bd01ca5db791572a9f0b5015d357ec1cd61d3cbe09b9686d28b0ff9ed0d46c7276d231b13943e
|
7
|
+
data.tar.gz: 119793a0005f102286c3a79b389e539952b4015c739b5269862028a8fc4e4656d32bbb31c1cb277e0f4b6ae8b6b278819604c97ad64f3ff5f60e83737a390488
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.mdown
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
### v2.0.0
|
2
|
+
* Breaking changes to default AES mode
|
3
|
+
- Moving to [SJCL](http://bitwiseshiftleft.github.io/sjcl/) compatible AES
|
4
|
+
- AES now uses only authenticated modes ("GCM" and "CCM")
|
5
|
+
- Deprecating streaming and file AES encryption. This would be better handled
|
6
|
+
by another library. Gibberish will focus on compatibility with Javascript/Browser encryption.
|
7
|
+
- 1.x CBC encryption/decryption is still available. You can still encrypt and decrypt
|
8
|
+
older Gibberish generated AES ciphertexts, but you must call it explicitly
|
9
|
+
* Breaking change to HMAC - User must explicitly choose a digest. No longer defaults to SHA1
|
10
|
+
* Deprecating Ruby 1.9.3 since its OpenSSL bindings do not allow for authenticated modes
|
11
|
+
|
1
12
|
### v1.4.0
|
2
13
|
* Fix deprecation. Support for 1.8.7 is deprecated, so bumping minor rev [PR #15](https://github.com/mdp/gibberish/pull/15)
|
3
14
|
|
data/Gemfile
CHANGED
data/Makefile
ADDED
data/README.markdown
CHANGED
@@ -1,28 +1,19 @@
|
|
1
|
-
# Gibberish -
|
2
|
-
![Travis](https://secure.travis-ci.org/mdp/gibberish.png)
|
1
|
+
# Gibberish - A ruby encryption library
|
2
|
+
[![Travis](https://secure.travis-ci.org/mdp/gibberish.png)](https://travis-ci.org/mdp/gibberish)
|
3
3
|
|
4
|
-
|
5
|
-
Gibberish is an opinionated cryptography library for Ruby. Its objective is easy but secure
|
6
|
-
encryption in Ruby.
|
4
|
+
*NOTICE: Breaking Changes in 2.0*
|
7
5
|
|
8
|
-
|
9
|
-
While OpenSSL is an extremely capable encryption library, it lacks a terse and clean
|
10
|
-
interface in Ruby.
|
11
|
-
|
12
|
-
### Goals
|
13
|
-
- This library should remain easily iteroperable with the OpenSSL command
|
14
|
-
line interface. Each function will include documentation on how to perform
|
15
|
-
the same routine via the command line with OpenSSL
|
16
|
-
|
17
|
-
- It should default to a reasonably secure setting, e.g. 256-bit AES, or SHA1 for HMAC
|
18
|
-
But it should allow the user to specify a stronger setting, within reason.
|
19
|
-
|
20
|
-
- Procedures should be well tested and be compatible with Ruby 1.8.7 and 1.9
|
6
|
+
Checkout the [Changelog](CHANGELOG.mdown) for a full list of changes in 2.0
|
21
7
|
|
8
|
+
## Goals
|
9
|
+
- AES encryption should have sensible defaults
|
10
|
+
- AES should be interoperable with SJCL for browser based decryption/encryption
|
11
|
+
- Simple API for HMAC/Digests
|
12
|
+
- Targets more recent versions of Ruby(>=2.0) with better OpenSSL support
|
22
13
|
|
23
14
|
## Requirements
|
24
15
|
|
25
|
-
Ruby compiled with OpenSSL support
|
16
|
+
Ruby 2.0 or later, compiled with OpenSSL support
|
26
17
|
|
27
18
|
## Installation
|
28
19
|
|
@@ -30,55 +21,49 @@ Ruby compiled with OpenSSL support
|
|
30
21
|
|
31
22
|
## AES
|
32
23
|
|
33
|
-
|
24
|
+
AES encryption with sensible defaults:
|
34
25
|
|
35
|
-
|
36
|
-
|
37
|
-
|
26
|
+
- 100,000 iterations of PBKDF2 password hardening
|
27
|
+
- GCM mode with authentication
|
28
|
+
- Ability to include authenticated data
|
29
|
+
- Compatible with [SJCL](http://bitwiseshiftleft.github.io/sjcl/), meaning all ciphertext is decryptable in JS via [SJCL](http://bitwiseshiftleft.github.io/sjcl/)
|
38
30
|
|
39
|
-
|
40
|
-
#=> "Some top secret data"
|
31
|
+
### Encrypting
|
41
32
|
|
42
|
-
|
33
|
+
cipher = Gibberish::AES.new('p4ssw0rd')
|
34
|
+
cipher.encrypt("some secret text")
|
35
|
+
# => Outputs a JSON string containing everything that needs to be saved for future decryption
|
36
|
+
# Example:
|
37
|
+
# '{"v":1,"adata":"","ks":256,"ct":"ay2varjSFUMUmtvZeh9755GVyCkWHG0/BglJLQ==","ts":96,"mode":"gcm",
|
38
|
+
# "cipher":"aes","iter":100000,"iv":"K4ZShCQGL3UZr78y","salt":"diDUzbc9Euo="}'
|
43
39
|
|
44
|
-
|
40
|
+
### Decrypting
|
45
41
|
|
46
|
-
cipher.
|
42
|
+
cipher = Gibberish::AES.new('p4ssw0rd')
|
43
|
+
cipher.decrypt('{"v":1,"adata":"","ks":256,"ct":"ay2varjSFUMUmtvZeh9755GVyCkWHG0/BglJLQ==","ts":96,"mode":"gcm","cipher":"aes","iter":100000,"iv":"K4ZShCQGL3UZr78y","salt":"diDUzbc9Euo="}')
|
44
|
+
# => "some secret text"
|
47
45
|
|
48
|
-
|
46
|
+
### Interoperability with SJCL (JavaScript - Browser/Node.js)
|
49
47
|
|
50
|
-
|
51
|
-
|
48
|
+
AES ciphertext from Gibberish is compatible with [SJCL](http://bitwiseshiftleft.github.io/sjcl/), a JavaScript library which
|
49
|
+
works in the browser and Node.js
|
52
50
|
|
53
|
-
|
51
|
+
[See the full docs](http://www.rubydoc.info/github/mdp/gibberish/Gibberish/AES) for information on SJCL interoperability.
|
54
52
|
|
55
|
-
|
53
|
+
### Gibberish 1.x Encryption (CBC)
|
56
54
|
|
57
|
-
|
55
|
+
Prior to Gibberish 2.0, the default encryption mode was CBC. You can still access this
|
56
|
+
by calling it explicitly:
|
58
57
|
|
59
|
-
|
60
|
-
cipher
|
61
|
-
enc = cipher.encrypt("Some data")
|
62
|
-
# Defaults to Base64 output
|
63
|
-
#=> "JKm98wKyJljqmpx7kP8ZsdeXiShllEMcRHVnjUjc4ecyYK/doKAkVTLho1Gp\ng697qrljyClF0AcIH+XZmeF/TrqYUuCEUyhOD6OL1bs5dn8vFQefS5KdaC5Y\ndLADvh3mSfE/w/gs4vaf/OtbZNBeSl6ROCZasWTfRewp4n1RDmE=\n"
|
64
|
-
cipher = Gibberish::RSA.new(k.private_key)
|
65
|
-
dec = cipher.decrypt(enc)
|
66
|
-
|
67
|
-
[Find out more](http://mdp.github.com/gibberish/Gibberish/RSA.html)
|
58
|
+
cipher = Gibberish::AES::CBC.new('p4ssw0rd')
|
59
|
+
cipher.encrypt("Some secret text")
|
68
60
|
|
69
61
|
## HMAC
|
70
62
|
|
71
|
-
|
72
|
-
|
73
|
-
Gibberish::HMAC("key", "some data")
|
74
|
-
#=> 521677c580722c5c52fa15d978e8656341c4f3c5
|
75
|
-
|
76
|
-
Other digests can be used
|
63
|
+
Gibberish::HMAC256("password", "data")
|
64
|
+
# => "cccf6f0334130a7010d62332c75b53e7d8cea715e52692b06e9cd41b05644be3"
|
77
65
|
|
78
|
-
|
79
|
-
#=> 01add3f98ce4d49403d98362a046c6cca2c79d778426282c53e4f628f648c12b
|
80
|
-
|
81
|
-
[Find out more](http://mdp.github.com/gibberish/Gibberish/HMAC.html)
|
66
|
+
[See the full docs](http://www.rubydoc.info/github/mdp/gibberish/Gibberish/HMAC)
|
82
67
|
|
83
68
|
## Digests
|
84
69
|
|
@@ -100,15 +85,29 @@ Other digests can be used
|
|
100
85
|
Gibberish::SHA512("somedata")
|
101
86
|
#=> a053441b6de662599ecb14c580d6637dcb856a66b2a40a952d39df772e47e98ea22f9e105b31463c5cf2472feae7649464fe89d99ceb6b0bc398a6926926f416
|
102
87
|
|
103
|
-
[
|
88
|
+
[See the full docs](http://www.rubydoc.info/github/mdp/gibberish/Gibberish/Digest)
|
89
|
+
|
90
|
+
## RSA
|
91
|
+
|
92
|
+
k = Gibberish::RSA.generate_keypair(2048)
|
93
|
+
cipher = Gibberish::RSA.new(k.public_key)
|
94
|
+
enc = cipher.encrypt("Some data")
|
95
|
+
# Defaults to Base64 output
|
96
|
+
#=> "JKm98wKyJljqmpx7kP8ZsdeXiShllEMcRHVnjUjc4ecyYK/doKAkVTLho1Gp\ng697qrljyClF0AcIH+XZmeF/TrqYUuCEUyhOD6OL1bs5dn8vFQefS5KdaC5Y\ndLADvh3mSfE/w/gs4vaf/OtbZNBeSl6ROCZasWTfRewp4n1RDmE=\n"
|
97
|
+
cipher = Gibberish::RSA.new(k.private_key)
|
98
|
+
dec = cipher.decrypt(enc)
|
99
|
+
|
100
|
+
[See the full docs](http://mdp.github.com/gibberish/Gibberish/RSA.html)
|
104
101
|
|
105
102
|
## Run the tests
|
106
103
|
|
107
104
|
git clone https://github.com/mdp/gibberish.git
|
108
105
|
cd gibberish
|
109
|
-
|
110
|
-
|
106
|
+
make
|
107
|
+
|
108
|
+
### Benchmarking AES with PBKDF2
|
111
109
|
|
112
|
-
|
110
|
+
make benchmark
|
111
|
+
# Change the PBKDF2 iterations
|
112
|
+
ITER=10000 make benchmark
|
113
113
|
|
114
|
-
- Cover OpenSSL exceptions with more reasonable and easier to understand exceptions.
|
data/gibberish.gemspec
CHANGED
@@ -7,10 +7,12 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.version = Gibberish::VERSION
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.authors = ["Mark Percival"]
|
10
|
-
s.email = ["
|
10
|
+
s.email = ["m@mdp.im"]
|
11
11
|
s.homepage = "http://github.com/mdp/gibberish"
|
12
12
|
s.summary = %q{An opinionated ruby encryption library}
|
13
|
-
s.description = %q{Supports
|
13
|
+
s.description = %q{Supports SJCL compatible AES encryption, HMAC, and Digests}
|
14
|
+
s.required_ruby_version = '>= 2.0.0'
|
15
|
+
s.license = "MIT"
|
14
16
|
|
15
17
|
s.rubyforge_project = "gibberish"
|
16
18
|
|
data/lib/gibberish/aes.rb
CHANGED
@@ -1,9 +1,16 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'delegate'
|
3
|
+
require 'securerandom'
|
4
|
+
|
1
5
|
module Gibberish
|
2
|
-
#
|
3
|
-
#
|
6
|
+
# # Handles AES encryption and decryption with some sensible defaults
|
7
|
+
# - 256 bit AES encryption
|
8
|
+
# - GCM mode with Authentication
|
9
|
+
# - 100,000 iterations of PBKDF2_HMAC for key strengthening
|
4
10
|
#
|
5
|
-
#
|
6
|
-
#
|
11
|
+
# ## Compatibility with SJCL
|
12
|
+
# It outputs into a format that is compatible with SJCL and easy to
|
13
|
+
# consume in browsers/Node.js
|
7
14
|
#
|
8
15
|
# ## Basic Usage
|
9
16
|
#
|
@@ -11,22 +18,193 @@ module Gibberish
|
|
11
18
|
#
|
12
19
|
# cipher = Gibberish::AES.new('p4ssw0rd')
|
13
20
|
# cipher.encrypt("some secret text")
|
14
|
-
# #=>
|
15
|
-
# cipher.encrypt_file("secret.txt", "secret.txt.enc")
|
21
|
+
# #=> Outputs a JSON string containing all the necessary information
|
16
22
|
#
|
17
23
|
# ### Decrypting
|
18
24
|
#
|
19
25
|
# cipher = Gibberish::AES.new('p4ssw0rd')
|
20
|
-
# cipher.decrypt(""
|
26
|
+
# cipher.decrypt('{"iv":"I4XKgNfMNkYhvzXc","v":1,"iter":1000,"ks":128,"ts":64,"mode":"gcm","adata":"123abc","cipher":"aes","salt":"PJsit8L16Ug=","ct":"5sEBsHXQqLXLOjxuVQK7fGZVdrMyRGDJ"}')
|
27
|
+
# #=> "some secret text"
|
28
|
+
#
|
29
|
+
# #### Including Authenticated data.
|
30
|
+
#
|
31
|
+
# GCM mode allows you to include "Authenticated Data" with the ciphertext, if you wish.
|
32
|
+
# For an overview of Authenticated Data, see this post: [http://crypto.stackexchange.com/a/15701](http://crypto.stackexchange.com/a/15701)
|
33
|
+
#
|
34
|
+
# Using AD is easy with Gibberish
|
35
|
+
#
|
36
|
+
# cipher = Gibberish::AES.new('p4ssw0rd')
|
37
|
+
# ciphertext = cipher.encrypt("Some secret data", "my authenticated data")
|
38
|
+
# plaintext = cipher.decrypt(ciphertext)
|
21
39
|
# #=> "some secret text"
|
22
|
-
#
|
40
|
+
# plaintext.adata
|
41
|
+
# # => "my authenticated data"
|
42
|
+
#
|
43
|
+
# ## Interoperability with SJCL's GCM mode AES
|
44
|
+
#
|
45
|
+
# #### Decrypting
|
46
|
+
#
|
47
|
+
# ```javascript
|
48
|
+
# // In the browser
|
49
|
+
# var cleartext = sjcl.decrypt('key', '[output from Gibberish AES]');
|
50
|
+
# ```
|
51
|
+
#
|
52
|
+
# #### Encrypting
|
53
|
+
#
|
54
|
+
# Ruby OpenSSL cannot handle an IV longer than 12 bytes, therefore we need to tell SJCL to
|
55
|
+
# only use a 3 word IV value. See: https://github.com/bitwiseshiftleft/sjcl/issues/180
|
23
56
|
#
|
24
|
-
#
|
57
|
+
# ```javascript
|
58
|
+
# // In the browser
|
59
|
+
# var ciphertext = sjcl.encrypt('key', 'plain text', {mode: 'gcm', iv: sjcl.random.randomWords(3, 0)});
|
60
|
+
# ```
|
25
61
|
#
|
62
|
+
# ## Backward compatibility with older pre 2.0 Gibberish
|
63
|
+
#
|
64
|
+
# Gibberish was previously designed to be compatible with OpenSSL on the command line with CBC mode AES.
|
65
|
+
# This has been deprecated in favor of GCM mode. However, you may still
|
66
|
+
# decrypt and encrypt using legacy convenience methods below:
|
67
|
+
#
|
68
|
+
# (Note: OpenSSL "enc" uses a non-standard file format which lacks [key stretching](http://en.wikipedia.org/wiki/Key_stretching), this means less secure passwords are more susceptible to brute forcing.)
|
69
|
+
#
|
70
|
+
# ### AES-256-CBC mode
|
71
|
+
#
|
72
|
+
# cipher = Gibberish::AES::CBC.new('p4ssw0rd')
|
73
|
+
# cipher_text = cipher.encrypt("some secret text")
|
74
|
+
# # => U2FsdGVkX1/D7z2azGmmQELbMNJV/n9T/9j2iBPy2AM=
|
75
|
+
#
|
76
|
+
# cipher.decrypt(cipher_text)
|
77
|
+
#
|
78
|
+
# # From the command line
|
26
79
|
# echo "U2FsdGVkX1/D7z2azGmmQELbMNJV/n9T/9j2iBPy2AM=\n" | openssl enc -d -aes-256-cbc -a -k p4ssw0rd
|
27
|
-
# openssl aes-256-cbc -d -in secret.txt.enc -out secret.txt -k p4ssw0rd
|
28
80
|
#
|
29
81
|
class AES
|
82
|
+
# Returns the AES object
|
83
|
+
#
|
84
|
+
# @param [String] password
|
85
|
+
# @param [Hash] opts
|
86
|
+
# @option opts [Symbol] :mode ('gcm') the AES mode to use
|
87
|
+
# @option opts [Symbol] :ks (256) keystrength
|
88
|
+
# @option opts [Symbol] :iter (100_000) number of PBKDF2 iterations to run on the password
|
89
|
+
# @option opts [Symbol] :max_iter (100_000) maximum allow iterations, set to prevent DOS attack of someone setting a large 'iter' value in the ciphertext JSON
|
90
|
+
# @option opts [Symbol] :ts (64) length of the authentication data hash
|
91
|
+
def initialize(password, opts={})
|
92
|
+
@cipher = SJCL.new(password, opts)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns the ciphertext in the form of a JSON string
|
96
|
+
#
|
97
|
+
# @param [String] data
|
98
|
+
# @param [String] authenticated_data (Won't be encrypted)
|
99
|
+
def encrypt(data, authenticated_data='')
|
100
|
+
@cipher.encrypt(data, authenticated_data)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns a Plaintext object (essentially a String with an additional 'adata' attribute)
|
104
|
+
#
|
105
|
+
# @param [String] ciphertext
|
106
|
+
def decrypt(ciphertext)
|
107
|
+
@cipher.decrypt(ciphertext)
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
class AES::SJCL
|
113
|
+
class CipherOptionsError < ArgumentError; end
|
114
|
+
class DecryptionError < StandardError; end
|
115
|
+
class Plaintext < SimpleDelegator
|
116
|
+
attr_reader :adata
|
117
|
+
def initialize(str, adata)
|
118
|
+
@adata = adata;
|
119
|
+
super(str)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
MAX_ITER = 100_000
|
124
|
+
ALLOWED_MODES = ['ccm', 'gcm']
|
125
|
+
ALLOWED_KS = [128, 192, 256]
|
126
|
+
ALLOWED_TS = [64, 96, 128]
|
127
|
+
DEFAULTS = {
|
128
|
+
v:1, iter:100_000, ks:256, ts:96,
|
129
|
+
mode:"gcm", adata:"", cipher:"aes", max_iter: MAX_ITER
|
130
|
+
}
|
131
|
+
def initialize(password, opts={})
|
132
|
+
@password = password
|
133
|
+
@opts = DEFAULTS.merge(opts)
|
134
|
+
check_cipher_options(@opts)
|
135
|
+
end
|
136
|
+
|
137
|
+
def encrypt(plaintext, adata='')
|
138
|
+
salt = SecureRandom.random_bytes(8)
|
139
|
+
iv = SecureRandom.random_bytes(12)
|
140
|
+
key = OpenSSL::PKCS5.pbkdf2_hmac(@password, salt, @opts[:iter], @opts[:ks]/8, 'SHA256')
|
141
|
+
cipherMode = "#{@opts[:cipher]}-#{@opts[:ks]}-#{@opts[:mode]}"
|
142
|
+
c = OpenSSL::Cipher.new(cipherMode)
|
143
|
+
c.encrypt
|
144
|
+
c.key = key
|
145
|
+
c.iv = iv
|
146
|
+
c.auth_data = adata
|
147
|
+
ct = c.update(plaintext) + c.final
|
148
|
+
tag = c.auth_tag(@opts[:ts]/8);
|
149
|
+
ct = ct + tag
|
150
|
+
out = {
|
151
|
+
v: @opts[:v], adata: adata, ks: @opts[:ks], ct: Base64.strict_encode64(ct).encode('utf-8'), ts: tag.length * 8,
|
152
|
+
mode: @opts[:mode], cipher: 'aes', iter: @opts[:iter], iv: Base64.strict_encode64(iv),
|
153
|
+
salt: Base64.strict_encode64(salt)
|
154
|
+
}
|
155
|
+
out.to_json
|
156
|
+
end
|
157
|
+
|
158
|
+
def decrypt(h)
|
159
|
+
begin
|
160
|
+
h = JSON.parse(h, {:symbolize_names => true})
|
161
|
+
rescue
|
162
|
+
raise "Unable to parse JSON of crypted text"
|
163
|
+
end
|
164
|
+
check_cipher_options(h)
|
165
|
+
key = OpenSSL::PKCS5.pbkdf2_hmac(@password, Base64.decode64(h[:salt]), h[:iter], h[:ks]/8, 'SHA256')
|
166
|
+
iv = Base64.decode64(h[:iv])
|
167
|
+
ct = Base64.decode64(h[:ct])
|
168
|
+
tag = ct[ct.length-h[:ts]/8,ct.length]
|
169
|
+
ct = ct[0,ct.length-h[:ts]/8]
|
170
|
+
cipherMode = "#{h[:cipher]}-#{h[:ks]}-#{h[:mode]}"
|
171
|
+
begin
|
172
|
+
c = OpenSSL::Cipher.new(cipherMode)
|
173
|
+
rescue RuntimeError => e
|
174
|
+
raise "OpenSSL error when initializing: #{e.message}"
|
175
|
+
end
|
176
|
+
c.decrypt
|
177
|
+
c.key = key
|
178
|
+
c.iv = iv
|
179
|
+
c.auth_tag = tag;
|
180
|
+
c.auth_data = h[:adata] || ""
|
181
|
+
begin
|
182
|
+
out = c.update(ct) + c.final();
|
183
|
+
rescue OpenSSL::Cipher::CipherError => e
|
184
|
+
raise DecryptionError.new();
|
185
|
+
end
|
186
|
+
return Plaintext.new(out.force_encoding('utf-8'), h[:adata])
|
187
|
+
end
|
188
|
+
|
189
|
+
# Assume the worst
|
190
|
+
def check_cipher_options(c_opts)
|
191
|
+
if @opts[:max_iter] < c_opts[:iter]
|
192
|
+
# Prevent DOS attacks from high PBKDF iterations
|
193
|
+
# You an increase this by passing in opts[:max_iter]
|
194
|
+
raise CipherOptionsError.new("Iteration count of #{c_opts[:iter]} exceeds the maximum of #{@opts[:max_iter]}")
|
195
|
+
elsif !ALLOWED_MODES.include?(c_opts[:mode])
|
196
|
+
raise CipherOptionsError.new("Mode '#{c_opts[:mode]}' not supported")
|
197
|
+
elsif !ALLOWED_KS.include?(c_opts[:ks])
|
198
|
+
raise CipherOptionsError.new("Keystrength of #{c_opts[:ks]} not supported")
|
199
|
+
elsif !ALLOWED_TS.include?(c_opts[:ts])
|
200
|
+
raise CipherOptionsError.new("Tag length of #{c_opts[:ts]} not supported")
|
201
|
+
elsif c_opts[:iv] && Base64.decode64(c_opts[:iv]).length > 12
|
202
|
+
raise CipherOptionsError.new("Initialization vector's greater than 12 bytes are not supported in Ruby.")
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
class AES::CBC
|
30
208
|
|
31
209
|
BUFFER_SIZE = 4096
|
32
210
|
|
data/lib/gibberish/digest.rb
CHANGED
@@ -34,9 +34,8 @@ module Gibberish
|
|
34
34
|
#
|
35
35
|
# Shorcut alias: Gibberish::SHA1(data)
|
36
36
|
#
|
37
|
-
# @param [String] key
|
38
37
|
# @param [#to_s] data
|
39
|
-
# @param [Hash]
|
38
|
+
# @param [Hash] opts
|
40
39
|
# @option opts [Boolean] :binary (false) encode the data in binary, not Base64
|
41
40
|
def self.sha1(data, opts={})
|
42
41
|
data = data.to_s
|
@@ -51,9 +50,8 @@ module Gibberish
|
|
51
50
|
#
|
52
51
|
# Shorcut alias: Gibberish::SHA224(data)
|
53
52
|
#
|
54
|
-
# @param [String] key
|
55
53
|
# @param [#to_s] data
|
56
|
-
# @param [Hash]
|
54
|
+
# @param [Hash] opts
|
57
55
|
# @option opts [Boolean] :binary (false) encode the data in binary, not Base64
|
58
56
|
def self.sha224(data, opts={})
|
59
57
|
data = data.to_s
|
@@ -68,9 +66,8 @@ module Gibberish
|
|
68
66
|
#
|
69
67
|
# Shorcut alias: Gibberish::SHA256(data)
|
70
68
|
#
|
71
|
-
# @param [String] key
|
72
69
|
# @param [#to_s] data
|
73
|
-
# @param [Hash]
|
70
|
+
# @param [Hash] opts
|
74
71
|
# @option opts [Boolean] :binary (false) encode the data in binary, not Base64
|
75
72
|
def self.sha256(data, opts={})
|
76
73
|
data = data.to_s
|
@@ -85,9 +82,8 @@ module Gibberish
|
|
85
82
|
#
|
86
83
|
# Shorcut alias: Gibberish::SHA384(data)
|
87
84
|
#
|
88
|
-
# @param [String] key
|
89
85
|
# @param [#to_s] data
|
90
|
-
# @param [Hash]
|
86
|
+
# @param [Hash] opts
|
91
87
|
# @option opts [Boolean] :binary (false) encode the data in binary, not Base64
|
92
88
|
def self.sha384(data, opts={})
|
93
89
|
data = data.to_s
|
@@ -102,9 +98,8 @@ module Gibberish
|
|
102
98
|
#
|
103
99
|
# Shorcut alias: Gibberish::SHA512(data)
|
104
100
|
#
|
105
|
-
# @param [String] key
|
106
101
|
# @param [#to_s] data
|
107
|
-
# @param [Hash]
|
102
|
+
# @param [Hash] opts
|
108
103
|
# @option opts [Boolean] :binary (false) encode the data in binary, not Base64
|
109
104
|
def self.sha512(data, opts={})
|
110
105
|
data = data.to_s
|
@@ -119,9 +114,8 @@ module Gibberish
|
|
119
114
|
#
|
120
115
|
# Shorcut alias: Gibberish::MD5(data)
|
121
116
|
#
|
122
|
-
# @param [String] key
|
123
117
|
# @param [#to_s] data
|
124
|
-
# @param [Hash]
|
118
|
+
# @param [Hash] opts
|
125
119
|
# @option opts [Boolean] :binary (false) encode the data in binary, not Base64
|
126
120
|
def self.md5(data, opts={})
|
127
121
|
data = data.to_s
|
data/lib/gibberish/hmac.rb
CHANGED
@@ -1,27 +1,28 @@
|
|
1
1
|
module Gibberish
|
2
|
-
# Easy to use HMAC
|
2
|
+
# Easy to use HMAC
|
3
3
|
#
|
4
4
|
# ## Example
|
5
5
|
#
|
6
|
-
# Gibberish::
|
7
|
-
# Gibberish::HMAC('key', 'data', :digest => :sha224)
|
8
|
-
# #=> 19424d4210e50d7a4521b5f0d54b4b0cff3060deddccfd894fda5b3b
|
9
|
-
# Gibberish::HMAC('key', 'data', :digest => :sha256)
|
6
|
+
# Gibberish::HMAC256('key', 'data')
|
10
7
|
# #=> 5031fe3d989c6d1537a013fa6e739da23463fdaec3b70137d828e36ace221bd0
|
11
|
-
# Gibberish::
|
8
|
+
# Gibberish::HMAC1('key', 'data') # SHA1
|
9
|
+
# #=> 104152c5bfdca07bc633eebd46199f0255c9f49d
|
10
|
+
# Gibberish::HMAC224('key', 'data') # SHA224
|
11
|
+
# #=> 19424d4210e50d7a4521b5f0d54b4b0cff3060deddccfd894fda5b3b
|
12
|
+
# Gibberish::HMAC384('key', 'data') # SHA384
|
12
13
|
# #=> c5f97ad9fd1020c174d7dc02cf83c4c1bf15ee20ec555b690ad58e62da8a00ee
|
13
14
|
# 44ccdb65cb8c80acfd127ebee568958a
|
14
|
-
# Gibberish::
|
15
|
+
# Gibberish::HMAC512('key', 'data') # SHA512
|
15
16
|
# #=> 3c5953a18f7303ec653ba170ae334fafa08e3846f2efe317b87efce82376253c
|
16
17
|
# b52a8c31ddcde5a3a2eee183c2b34cb91f85e64ddbc325f7692b199473579c58
|
17
18
|
#
|
18
19
|
# ## OpenSSL CLI Interop
|
19
20
|
#
|
20
|
-
# echo -n "stuff" | openssl dgst -
|
21
|
+
# echo -n "stuff" | openssl dgst -sha256 -hmac 'password'
|
21
22
|
#
|
22
23
|
# is the same as
|
23
24
|
#
|
24
|
-
# Gibberish::
|
25
|
+
# Gibberish::HMAC256('password', 'stuff')
|
25
26
|
#
|
26
27
|
class HMAC
|
27
28
|
DIGEST = {
|
@@ -38,21 +39,38 @@ module Gibberish
|
|
38
39
|
#
|
39
40
|
# @param [String] key
|
40
41
|
# @param [#to_s] data
|
41
|
-
# @param [
|
42
|
+
# @param [Symbol] digest
|
43
|
+
# @param [Hash] opts
|
42
44
|
# @option opts [Symbol] :digest (:sha1) the digest to encode with
|
43
45
|
# @option opts [Boolean] :binary (false) encode the data in binary, not Base64
|
44
|
-
def self.digest(key, data, opts={})
|
46
|
+
def self.digest(key, data, digest, opts={})
|
45
47
|
data = data.to_s
|
46
|
-
digest_type = opts[:digest] || :sha1
|
47
48
|
if opts[:binary]
|
48
|
-
OpenSSL::HMAC.digest(DIGEST[
|
49
|
+
OpenSSL::HMAC.digest(DIGEST[digest], key, data)
|
49
50
|
else
|
50
|
-
OpenSSL::HMAC.hexdigest(DIGEST[
|
51
|
+
OpenSSL::HMAC.hexdigest(DIGEST[digest], key, data)
|
51
52
|
end
|
52
53
|
end
|
53
54
|
end
|
54
55
|
|
55
|
-
def self.
|
56
|
-
Gibberish::HMAC.digest(key, data,
|
56
|
+
def self.HMAC1(key, data)
|
57
|
+
Gibberish::HMAC.digest(key, data, :sha1)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.HMAC224(key, data)
|
61
|
+
Gibberish::HMAC.digest(key, data, :sha224)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.HMAC256(key, data)
|
65
|
+
Gibberish::HMAC.digest(key, data, :sha256)
|
57
66
|
end
|
67
|
+
|
68
|
+
def self.HMAC384(key, data)
|
69
|
+
Gibberish::HMAC.digest(key, data, :sha384)
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.HMAC512(key, data)
|
73
|
+
Gibberish::HMAC.digest(key, data, :sha512)
|
74
|
+
end
|
75
|
+
|
58
76
|
end
|
data/lib/gibberish/version.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'benchmark'
|
4
|
+
require 'gibberish'
|
5
|
+
|
6
|
+
N = 50
|
7
|
+
ITERATIONS = ENV["ITER"].to_i || 100_000
|
8
|
+
PLAINTEXT = "Doner meatball turducken pig chuck turkey cow. Beef ribs picanha leberkas filet mignon chicken sirloin kevin jerky. Turkey venison beef ribs, turducken capicola biltong pork loin meatball cupim jowl pork chop pancetta. Filet mignon t-bone flank spare ribs chuck kielbasa capicola turkey shank doner shoulder meatloaf pancetta. Pork belly t-bone pork loin hamburger brisket alcatra. Ham tail brisket sausage hamburger, filet mignon landjaeger jerky corned beef biltong pork chop ball tip. Shoulder pork loin ham hock pastrami brisket chuck flank. Doner meatball turducken pig chuck turkey cow. Beef ribs picanha leberkas filet mignon chicken sirloin kevin jerky. Turkey venison beef ribs, turducken capicola biltong pork loin meatball cupim jowl pork chop pancetta. Filet mignon t-bone flank spare ribs chuck kielbasa capicola turkey shank doner shoulder meatloaf pancetta. Pork belly t-bone pork loin hamburger brisket alcatra. Ham tail brisket sausage hamburger, filet mignon landjaeger jerky corned beef biltong pork chop ball tip. Shoulder pork loin ham hock pastrami brisket chuck flank. Doner meatball turducken pig chuck turkey cow. Beef ribs picanha leberkas filet mignon chicken sirloin kevin jerky. Turkey venison beef ribs, turducken capicola biltong pork loin meatball cupim jowl pork chop pancetta. Filet mignon t-bone flank spare ribs chuck kielbasa capicola turkey shank doner shoulder meatloaf pancetta. Pork belly t-bone pork loin hamburger brisket alcatra. Ham tail brisket sausage hamburger, filet mignon landjaeger jerky corned beef biltong pork chop ball tip. Shoulder pork loin ham hock pastrami brisket chuck flank. Doner meatball turducken pig chuck turkey cow. Beef ribs picanha leberkas filet mignon chicken sirloin kevin jerky. Turkey venison beef ribs, turducken capicola biltong pork loin meatball cupim jowl pork chop pancetta. Filet mignon t-bone flank spare ribs chuck kielbasa capicola turkey shank doner shoulder meatloaf pancetta. Pork belly t-bone pork loin hamburger brisket alcatra. Ham tail brisket sausage hamburger, filet mignon landjaeger jerky corned beef biltong pork chop ball tip. Shoulder pork loin ham hock pastrami brisket chuck flank."
|
9
|
+
|
10
|
+
puts "Benchmarking AES GCM: Encrypting 512 bytes #{N} times, at #{ITERATIONS} iterations\n"
|
11
|
+
cipher = Gibberish::AES.new("s33krit", iter: ITERATIONS)
|
12
|
+
plaintext = PLAINTEXT.slice(0,512)
|
13
|
+
time = Benchmark.realtime {
|
14
|
+
N.times {
|
15
|
+
cipher.encrypt(plaintext)
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
puts "Avg time per encryption: #{'%.5f' % (time/N)}ms"
|
20
|
+
|
data/spec/aes_spec.rb
CHANGED
@@ -1,10 +1,96 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
1
2
|
require 'spec_helper'
|
2
3
|
require 'tempfile'
|
3
4
|
|
4
|
-
describe "the aes
|
5
|
+
describe "the sjcl compatible implementation of aes" do
|
6
|
+
|
7
|
+
describe "decryption" do
|
8
|
+
|
9
|
+
before do
|
10
|
+
@cipher = Gibberish::AES.new("s33krit")
|
11
|
+
end
|
12
|
+
it "should decrypt gcm encoded text from SJCL" do
|
13
|
+
# With a 64bit authentication tag
|
14
|
+
json = '{"iv":"pO1RiSKSfmlLPMIS","v":1,"iter":1000,"ks":128,"ts":64,"mode":"gcm","adata":"","cipher":"aes","salt":"BC60XoGJqnY=","ct":"Jgm8bExXvpbEDxOxFDroBuFmczMlfF4G"}'
|
15
|
+
@cipher.decrypt(json).must_equal("This is a secret");
|
16
|
+
# With a 96bit authentication tag
|
17
|
+
json = '{"iv":"6ru5wmyPl2hfhMmb","v":1,"iter":1000,"ks":128,"ts":96,"mode":"gcm","adata":"","cipher":"aes","salt":"KhrgNREkjN4=","ct":"/0LMJz7pYDXSdFa+x3vL7uc46Nz7y5kV9DhEBQ=="}'
|
18
|
+
@cipher.decrypt(json).must_equal("This is a secret");
|
19
|
+
# With a 128bit authentication tag
|
20
|
+
json = '{"iv":"S79wFwpjbSMz1FSB","v":1,"iter":1000,"ks":128,"ts":128,"mode":"gcm","adata":"","cipher":"aes","salt":"KhrgNREkjN4=","ct":"j8pJmmilaJ6We2fEq/NvAxka4Z70F7IEK/m9/y3hHoo="}'
|
21
|
+
@cipher.decrypt(json).must_equal("This is a secret");
|
22
|
+
end
|
23
|
+
it "should include the adata with the plaintext" do
|
24
|
+
json = '{"iv":"w9Iugnn0HztMpm+y","v":1,"iter":1000,"ks":128,"ts":64,"mode":"gcm","adata":"123abc","cipher":"aes","salt":"Sw6NOinzVZ8=","ct":"djCIRln1PbuiLEkMb2AJZdT/"}'
|
25
|
+
plaintext = @cipher.decrypt(json)
|
26
|
+
plaintext.must_equal("plain text")
|
27
|
+
plaintext.adata.must_equal("123abc")
|
28
|
+
end
|
29
|
+
describe "exceptions" do
|
30
|
+
it "should check the iterations length before attempting to decrypt" do
|
31
|
+
json = '{"iv":"S79wFwpjbSMz1FSB","v":1,"iter":1000000,"ks":128,"ts":128,"mode":"gcm","adata":"","cipher":"aes","salt":"KhrgNREkjN4=","ct":"j8pJmmilaJ6We2fEq/NvAxka4Z70F7IEK/m9/y3hHoo="}'
|
32
|
+
e = assert_raises(Gibberish::AES::SJCL::CipherOptionsError) { @cipher.decrypt(json) }
|
33
|
+
assert_match(/Iteration count/, e.message)
|
34
|
+
end
|
35
|
+
it "should only allow authenticated modes" do
|
36
|
+
json = '{"iv":"6ru5wmyPl2hfhMmb","v":1,"iter":1000,"ks":128,"ts":96,"mode":"cbc","adata":"","cipher":"aes","salt":"KhrgNREkjN4=","ct":"/0LMJz7pYDXSdFa+x3vL7uc46Nz7y5kV9DhEBQ=="}'
|
37
|
+
e = assert_raises(Gibberish::AES::SJCL::CipherOptionsError) { @cipher.decrypt(json) }
|
38
|
+
assert_equal("Mode 'cbc' not supported", e.message)
|
39
|
+
end
|
40
|
+
it "should fail gracefully when attempting to decrypt an SJCL generated ciphertext with a >12 byte IV" do
|
41
|
+
json = '{"iv":"fGuapJg66vk0eNNyLHUk1w==","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"GRywsuW0M8E=","ct":"MUq4sLzEHtnUy2nTF8NEJQ=="}'
|
42
|
+
e = assert_raises(Gibberish::AES::SJCL::CipherOptionsError) { @cipher.decrypt(json) }
|
43
|
+
assert_match(/Initialization vector/, e.message)
|
44
|
+
end
|
45
|
+
it "should fail if the password is incorrect" do
|
46
|
+
json = '{"iv":"ovFbwlWH+tTHFORl","v":1,"iter":1000,"ks":128,"ts":64,"mode":"gcm","adata":"","cipher":"aes","salt":"ib5/ig2qqL8=","ct":"ruxTz/VWArVfte4qzUwF/z74"}'
|
47
|
+
assert_raises(Gibberish::AES::SJCL::DecryptionError) { @cipher.decrypt(json) }
|
48
|
+
end
|
49
|
+
it "should fail if the adata has be modified" do
|
50
|
+
json = '{"iv":"S79wFwpjbSMz1FSB","v":1,"iter":1000,"ks":128,"ts":128,"mode":"gcm","adata":"foo","cipher":"aes","salt":"KhrgNREkjN4=","ct":"j8pJmmilaJ6We2fEq/NvAxka4Z70F7IEK/m9/y3hHoo="}'
|
51
|
+
assert_raises(Gibberish::AES::SJCL::DecryptionError) {
|
52
|
+
@cipher.decrypt(json)
|
53
|
+
}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "encryption" do
|
59
|
+
|
60
|
+
it "should encrypt text" do
|
61
|
+
@cipher = Gibberish::AES.new("s33krit")
|
62
|
+
plaintext = "This is some text, and some UTF-8 中华人民共和"
|
63
|
+
ciphertext = @cipher.encrypt(plaintext)
|
64
|
+
@cipher.decrypt(ciphertext).must_equal(plaintext);
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should allow users to override the number of iterations" do
|
68
|
+
@cipher = Gibberish::AES.new("s33krit", {iter: 10_000})
|
69
|
+
plaintext = "This is some text"
|
70
|
+
ciphertext = @cipher.encrypt(plaintext)
|
71
|
+
JSON.parse(ciphertext)["iter"].must_equal(10_000)
|
72
|
+
@cipher.decrypt(ciphertext).must_equal(plaintext);
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should set the correct JSON attributes in the ciphertext" do
|
76
|
+
@cipher = Gibberish::AES.new("s33krit")
|
77
|
+
plaintext = "This is some text"
|
78
|
+
ciphertext = JSON.parse(@cipher.encrypt(plaintext))
|
79
|
+
ciphertext["iter"].must_equal(100_000)
|
80
|
+
ciphertext["v"].must_equal(1)
|
81
|
+
ciphertext["ks"].must_equal(256)
|
82
|
+
ciphertext["ts"].must_equal(96)
|
83
|
+
ciphertext["mode"].must_equal("gcm")
|
84
|
+
ciphertext["cipher"].must_equal("aes")
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "the openssl command line compatible aes cipher" do
|
5
91
|
|
6
92
|
before do
|
7
|
-
@cipher = Gibberish::AES.new("password")
|
93
|
+
@cipher = Gibberish::AES::CBC.new("password")
|
8
94
|
end
|
9
95
|
|
10
96
|
it "should encrypt text and be compatible with OpenSSL CLI" do
|
data/spec/hmac_spec.rb
CHANGED
@@ -2,55 +2,56 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe "HMAC" do
|
4
4
|
|
5
|
-
it "should
|
6
|
-
Gibberish::
|
5
|
+
it "should just work and default to sha256" do
|
6
|
+
Gibberish::HMAC256("password", "data").must_equal(
|
7
|
+
"cccf6f0334130a7010d62332c75b53e7d8cea715e52692b06e9cd41b05644be3")
|
7
8
|
end
|
8
9
|
|
9
10
|
it "should work with OpenSSL HMAC" do
|
10
|
-
hmac = Gibberish::
|
11
|
-
o_hmac = `echo "data" | openssl dgst -
|
11
|
+
hmac = Gibberish::HMAC256("password", "data\n")
|
12
|
+
o_hmac = `echo "data" | openssl dgst -sha256 -hmac 'password' | sed 's/^.*= //'`
|
12
13
|
hmac.must_equal(o_hmac.chomp)
|
13
14
|
end
|
14
15
|
|
15
16
|
it "should hopefully work for sha224" do
|
16
|
-
Gibberish::
|
17
|
+
Gibberish::HMAC224("password", "data").must_equal(
|
17
18
|
"f66aa39e91d003f7d3fc1205f77bd4947af51735a49e197fbd478728")
|
18
19
|
end
|
19
20
|
|
20
21
|
it "should work with OpenSSL HMAC for sha224" do
|
21
|
-
hmac = Gibberish::
|
22
|
+
hmac = Gibberish::HMAC224("password", "data\n")
|
22
23
|
o_hmac = `echo "data" | openssl dgst -sha224 -hmac 'password' | sed 's/^.*= //'`
|
23
24
|
hmac.must_equal(o_hmac.chomp)
|
24
25
|
end
|
25
26
|
|
26
27
|
it "should hopefully work for sha256" do
|
27
|
-
Gibberish::
|
28
|
+
Gibberish::HMAC256("password", "data").must_equal(
|
28
29
|
"cccf6f0334130a7010d62332c75b53e7d8cea715e52692b06e9cd41b05644be3")
|
29
30
|
end
|
30
31
|
|
31
32
|
it "should work with OpenSSL HMAC for sha256" do
|
32
|
-
hmac = Gibberish::
|
33
|
+
hmac = Gibberish::HMAC256("password", "data\n")
|
33
34
|
o_hmac = `echo "data" | openssl dgst -sha256 -hmac 'password' | sed 's/^.*= //'`
|
34
35
|
hmac.must_equal(o_hmac.chomp)
|
35
36
|
end
|
36
37
|
|
37
|
-
it "should
|
38
|
-
Gibberish::
|
38
|
+
it "should work for sha384" do
|
39
|
+
Gibberish::HMAC384("password", "data").must_equal(
|
39
40
|
"2ed475691214fb85d086577d8d525c609b92520ebd793a74856b3ffd8d3477eaaf0b06ef9e06c8aa81cf29f95078aca6")
|
40
41
|
end
|
41
42
|
|
42
43
|
it "should work with OpenSSL HMAC for sha384" do
|
43
|
-
hmac = Gibberish::
|
44
|
+
hmac = Gibberish::HMAC384("password", "data\n")
|
44
45
|
o_hmac = `echo "data" | openssl dgst -sha384 -hmac 'password' | sed 's/^.*= //'`
|
45
46
|
hmac.must_equal(o_hmac.chomp)
|
46
47
|
end
|
47
48
|
|
48
49
|
it "should hopefully work for sha512" do
|
49
|
-
Gibberish::
|
50
|
+
Gibberish::HMAC512("password", "data").must_equal("abf85192282b501874f4803ea08672f2c9d6e656c57801023a0b1f4dd9492ba960efdb560a8618ec783327d6dc31577422651a4cf7eaf722d2caefbc04038c6e")
|
50
51
|
end
|
51
52
|
|
52
53
|
it "should work with OpenSSL HMAC for sha512" do
|
53
|
-
hmac = Gibberish::
|
54
|
+
hmac = Gibberish::HMAC512("password", "data\n")
|
54
55
|
o_hmac = `echo "data" | openssl dgst -sha512 -hmac 'password' | sed 's/^.*= //'`
|
55
56
|
hmac.must_equal(o_hmac.chomp)
|
56
57
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,32 +1,30 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gibberish
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Percival
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: Supports
|
13
|
+
description: Supports SJCL compatible AES encryption, HMAC, and Digests
|
14
14
|
email:
|
15
|
-
-
|
15
|
+
- m@mdp.im
|
16
16
|
executables: []
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
|
-
- .gitignore
|
21
|
-
- .gitmodules
|
22
|
-
- .travis.yml
|
23
|
-
- .
|
24
|
-
- .yardoc/objects/root.dat
|
25
|
-
- .yardoc/proxy_types
|
26
|
-
- .yardopts
|
20
|
+
- ".gitignore"
|
21
|
+
- ".gitmodules"
|
22
|
+
- ".travis.yml"
|
23
|
+
- ".yardopts"
|
27
24
|
- CHANGELOG.mdown
|
28
25
|
- Gemfile
|
29
26
|
- LICENSE
|
27
|
+
- Makefile
|
30
28
|
- README.markdown
|
31
29
|
- Rakefile
|
32
30
|
- gibberish.gemspec
|
@@ -36,6 +34,7 @@ files:
|
|
36
34
|
- lib/gibberish/hmac.rb
|
37
35
|
- lib/gibberish/rsa.rb
|
38
36
|
- lib/gibberish/version.rb
|
37
|
+
- spec/aes_benchmark.rb
|
39
38
|
- spec/aes_spec.rb
|
40
39
|
- spec/digest_spec.rb
|
41
40
|
- spec/fixtures/secret.txt
|
@@ -48,7 +47,8 @@ files:
|
|
48
47
|
- spec/rsa_spec.rb
|
49
48
|
- spec/spec_helper.rb
|
50
49
|
homepage: http://github.com/mdp/gibberish
|
51
|
-
licenses:
|
50
|
+
licenses:
|
51
|
+
- MIT
|
52
52
|
metadata: {}
|
53
53
|
post_install_message:
|
54
54
|
rdoc_options: []
|
@@ -56,18 +56,19 @@ require_paths:
|
|
56
56
|
- lib
|
57
57
|
required_ruby_version: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 2.0.0
|
62
62
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
63
|
requirements:
|
64
|
-
- -
|
64
|
+
- - ">="
|
65
65
|
- !ruby/object:Gem::Version
|
66
66
|
version: '0'
|
67
67
|
requirements: []
|
68
68
|
rubyforge_project: gibberish
|
69
|
-
rubygems_version: 2.
|
69
|
+
rubygems_version: 2.2.2
|
70
70
|
signing_key:
|
71
71
|
specification_version: 4
|
72
72
|
summary: An opinionated ruby encryption library
|
73
73
|
test_files: []
|
74
|
+
has_rdoc:
|
data/.yardoc/checksums
DELETED
@@ -1,6 +0,0 @@
|
|
1
|
-
lib/gibberish.rb 802b1397065b8f34b094cd5e797446a42c2c9b7e
|
2
|
-
lib/gibberish/rsa.rb 84ee338b25ac16484c1b652b63c802a8085c9a82
|
3
|
-
lib/gibberish/aes.rb c0f393617c375e47516948a7540eb2bd9f9a261c
|
4
|
-
lib/gibberish/hmac.rb 51804f85036f2bea4885506ea92ec5b4d88e1486
|
5
|
-
lib/gibberish/digest.rb 7ba5c16118b415ac12ef1aadbe11ca95e5d73902
|
6
|
-
lib/gibberish/version.rb d2287491a538f55ab0e5d861eaf18da07ab46c89
|
data/.yardoc/objects/root.dat
DELETED
Binary file
|
data/.yardoc/proxy_types
DELETED