cryptdoh 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/cryptdoh.rb +100 -0
- metadata +60 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 15c9aee6732af55538874d25d581bd5da3cf6bc4
|
4
|
+
data.tar.gz: 2ce02dfb3f15742f778b9b1dccbf551629b557c5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4153032d11cbce77c85122e26e6737114028f60d6afd4c8efeaaf98cc387d37eedd0ec46a1f6454f779296cfbf37e9e556d724e0568686a7bdbf9e6351228377
|
7
|
+
data.tar.gz: f273763c41ff1ebefa309ba22eb13806d6f35cfd89b75f778284a2c7ff9b5ae65b453b60914ee2bb7920fc4c9671f8feb9d4a94d1e8f4fd6246e884bba3da209
|
data/lib/cryptdoh.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'base64'
|
3
|
+
require 'securerandom'
|
4
|
+
require 'cracklib'
|
5
|
+
|
6
|
+
class UserError < StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
class EvilError < StandardError
|
10
|
+
end
|
11
|
+
|
12
|
+
module Cryptdoh
|
13
|
+
|
14
|
+
MIN_PASSWORD_LENGTH = 8
|
15
|
+
IV_LENGTH = 16
|
16
|
+
SALT_LENGTH = 16
|
17
|
+
ITERATIONS = 100 * 1000
|
18
|
+
KEY_LENGTH = 32
|
19
|
+
DIGEST = OpenSSL::Digest::SHA256.new
|
20
|
+
VERSION = "1"
|
21
|
+
|
22
|
+
def self.encrypt(password, message, args = {})
|
23
|
+
_check_password_length(password)
|
24
|
+
_check_password_strength(password) unless args[:skip_strength_check]
|
25
|
+
|
26
|
+
(salt, key) = _kdf(password)
|
27
|
+
cipher_key = key[0..KEY_LENGTH-1]
|
28
|
+
hmac_key = key[KEY_LENGTH..-1]
|
29
|
+
|
30
|
+
cipher = OpenSSL::Cipher::AES.new(KEY_LENGTH * 8, :CBC)
|
31
|
+
cipher.encrypt
|
32
|
+
iv = cipher.random_iv
|
33
|
+
cipher.key = cipher_key
|
34
|
+
|
35
|
+
ciphertext = cipher.update(message) + cipher.final
|
36
|
+
|
37
|
+
cipher_message = [VERSION, _encode(iv), _encode(salt), _encode(ciphertext)].join('.')
|
38
|
+
hmac = _hmac(hmac_key, cipher_message)
|
39
|
+
|
40
|
+
[cipher_message, _encode(hmac)].join('.')
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.decrypt(password, message)
|
44
|
+
(version, encoded_iv, encoded_salt, encoded_ciphertext, encoded_hmac) = message.split('.')
|
45
|
+
|
46
|
+
(salt, key) = _kdf(password, _decode(encoded_salt))
|
47
|
+
cipher_key = key[0..KEY_LENGTH-1]
|
48
|
+
hmac_key = key[KEY_LENGTH..-1]
|
49
|
+
|
50
|
+
hmac = _hmac(hmac_key, [version, encoded_iv, encoded_salt, encoded_ciphertext].join('.'))
|
51
|
+
raise EvilError, 'Invalid HMAC' unless _decode(encoded_hmac) == hmac
|
52
|
+
|
53
|
+
decipher = OpenSSL::Cipher::AES.new(KEY_LENGTH * 8, :CBC)
|
54
|
+
decipher.decrypt
|
55
|
+
decipher.iv = _decode(encoded_iv)
|
56
|
+
decipher.key = cipher_key
|
57
|
+
|
58
|
+
decipher.update(_decode(encoded_ciphertext)) + decipher.final
|
59
|
+
end
|
60
|
+
|
61
|
+
def self._check_password_strength(password)
|
62
|
+
c = CrackLib::Fascist(password)
|
63
|
+
raise UserError, "Crappy password: #{c.reason}" unless c.ok?
|
64
|
+
end
|
65
|
+
|
66
|
+
def self._check_password_length(password)
|
67
|
+
raise UserError, "Crappy password: too short. Must be at least 8 bytes" unless password.size >= MIN_PASSWORD_LENGTH
|
68
|
+
end
|
69
|
+
|
70
|
+
def self._kdf(password, salt = nil)
|
71
|
+
salt ||= SecureRandom.random_bytes(SALT_LENGTH)
|
72
|
+
raise UserError, "Salt is the wrong size" unless salt.size == SALT_LENGTH
|
73
|
+
key = OpenSSL::PKCS5.pbkdf2_hmac(password, salt, ITERATIONS, KEY_LENGTH * 2, DIGEST)
|
74
|
+
[salt, key]
|
75
|
+
end
|
76
|
+
|
77
|
+
def self._hmac(key, message)
|
78
|
+
# Only require 128 bits of security, so cut in half
|
79
|
+
OpenSSL::HMAC.digest(DIGEST, key, message)[0..15]
|
80
|
+
end
|
81
|
+
|
82
|
+
def self._encode(data)
|
83
|
+
Base64.encode64(data).chomp
|
84
|
+
end
|
85
|
+
|
86
|
+
def self._decode(data)
|
87
|
+
Base64.decode64(data)
|
88
|
+
rescue
|
89
|
+
raise EvilError, 'Bad base64 data'
|
90
|
+
end
|
91
|
+
|
92
|
+
def self._verify
|
93
|
+
message = 'this is a secret message'
|
94
|
+
password = 'dZ]av}a]i4qK2:1Z:t |Ju.'
|
95
|
+
|
96
|
+
decrypt(password, encrypt(password, message)) == message
|
97
|
+
rescue
|
98
|
+
false
|
99
|
+
end
|
100
|
+
end
|
metadata
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cryptdoh
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Fraser Scott
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ruby-cracklib
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
description: |2
|
28
|
+
Most crypto libraries require the user to make significant usage decisions. Without understanding the concepts behind all the options, it is easy for the users to pick something inappropriate, resulting in insecure systems. Also, libraries often allow silly defaults, such as an IV set to all 0s or forgetting a salt etc. This library enforces best-practices, so if you need more control you should use a lower level library.
|
29
|
+
email: fraser.scott@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- lib/cryptdoh.rb
|
35
|
+
homepage: https://github.com/zeroXten/cryptdoh
|
36
|
+
licenses:
|
37
|
+
- MIT
|
38
|
+
metadata: {}
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
requirements: []
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 2.2.2
|
56
|
+
signing_key:
|
57
|
+
specification_version: 4
|
58
|
+
summary: An easy to use, secure, and opinionated encryption wrapper library for Ruby.
|
59
|
+
test_files: []
|
60
|
+
has_rdoc:
|