aes 0.3.0 → 0.4.0
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.
- data/README.rdoc +24 -15
- data/VERSION +1 -1
- data/aes.gemspec +3 -2
- data/lib/aes.rb +1 -128
- data/lib/aes/aes.rb +150 -0
- data/test/test_aes.rb +14 -5
- metadata +5 -4
data/README.rdoc
CHANGED
@@ -1,28 +1,37 @@
|
|
1
1
|
= aes
|
2
2
|
|
3
|
-
An AES encrypt/decrypt gem built
|
3
|
+
An AES encrypt/decrypt gem built on top of OpenSSL. Not as quick as FastAES but doesn't require building native extensions - also supports Base64 encoded input and output.
|
4
4
|
|
5
5
|
Usage:
|
6
6
|
|
7
|
-
require 'aes'
|
7
|
+
require 'aes'
|
8
8
|
|
9
|
-
# Generate a random key
|
10
|
-
key = AES.key
|
11
|
-
|
9
|
+
# Generate a random key
|
10
|
+
key = AES.key
|
11
|
+
=> "290c3c5d812a4ba7ce33adf09598a462"
|
12
|
+
|
13
|
+
# Encrypt a string. Default output is base_64 encoded, init_vector and cipher_text are joined with "$"
|
14
|
+
b64 = AES.encrypt("A super secret message", key)
|
15
|
+
=> "IJjbgbv/OvPIAf4R5qAWyg==$fy0v7JwRX4kyAWflgouQlt9XGmiDKvbQMRHmQ+vy1fA="
|
12
16
|
|
13
|
-
#
|
14
|
-
|
15
|
-
|
17
|
+
# Same as above but minus the base64 encoding, init_vector and cipher_text are shoved into an array
|
18
|
+
plain = AES.encrypt("A super secret message", key, {:format => :plain}) #
|
19
|
+
=> [";\202\222\306\376<\206\343\023\245\312\225\214KAm",
|
20
|
+
"C\343\023\323U~W>\023y\217\341\201\371\352\334\311^\307\352{\020 H(DVw\3224N\223"]
|
16
21
|
|
17
|
-
#
|
18
|
-
|
19
|
-
|
22
|
+
# Generate a random initialization vector
|
23
|
+
iv = AES.iv(:base_64)
|
24
|
+
=> "IJjbgbv/OvPIAf4R5qAWyg=="
|
20
25
|
|
21
|
-
|
22
|
-
|
26
|
+
# Encrypt a string, with a provided key and init_vector.
|
27
|
+
b64_iv = AES.encrypt("A super secret message", key, {:iv => iv})
|
28
|
+
=> "IJjbgbv/OvPIAf4R5qAWyg==$fy0v7JwRX4kyAWflgouQlt9XGmiDKvbQMRHmQ+vy1fA="
|
23
29
|
|
24
|
-
AES.decrypt(
|
25
|
-
=> "A super secret message"
|
30
|
+
AES.decrypt(b64, key)
|
31
|
+
=> "A super secret message"
|
32
|
+
|
33
|
+
AES.decrypt(plain, key, {:format => :plain})
|
34
|
+
=> "A super secret message"
|
26
35
|
|
27
36
|
== Contributing to aes
|
28
37
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/aes.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{aes}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Carl Hicks"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-01-03}
|
13
13
|
s.description = %q{An AES encrypt/decrypt gem built ontop of OpenSSL. Not as quick as FastAES, but it doesn't require building
|
14
14
|
native extensions and supports Base64 encoded input and output.}
|
15
15
|
s.email = %q{carl.hicks@gmail.com}
|
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
|
|
26
26
|
"VERSION",
|
27
27
|
"aes.gemspec",
|
28
28
|
"lib/aes.rb",
|
29
|
+
"lib/aes/aes.rb",
|
29
30
|
"test/helper.rb",
|
30
31
|
"test/test_aes.rb"
|
31
32
|
]
|
data/lib/aes.rb
CHANGED
@@ -1,130 +1,3 @@
|
|
1
1
|
require 'openssl'
|
2
2
|
require 'base64'
|
3
|
-
|
4
|
-
class AES
|
5
|
-
class << self
|
6
|
-
# Encrypts the plain_text with the provided key
|
7
|
-
def encrypt(key, plain_text, opts={})
|
8
|
-
AES.new(key,opts).encrypt(plain_text)
|
9
|
-
end
|
10
|
-
# Decrypts the cipher_text with the provided key
|
11
|
-
def decrypt(key, cipher_text, opts={})
|
12
|
-
AES.new(key,opts).decrypt(cipher_text)
|
13
|
-
end
|
14
|
-
# Generates a random key of the specified length in bits
|
15
|
-
# Default output is
|
16
|
-
def key(length=256,format=:plain)
|
17
|
-
key = AES.new("").random_key(256)
|
18
|
-
case format
|
19
|
-
when :base_64
|
20
|
-
Base64.encode64(key)
|
21
|
-
else
|
22
|
-
key
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
attr :options
|
28
|
-
attr :key
|
29
|
-
attr :cipher
|
30
|
-
attr :cipher_text
|
31
|
-
attr :plain_text
|
32
|
-
|
33
|
-
def initialize(key, opts={})
|
34
|
-
merge_options opts
|
35
|
-
@key = key
|
36
|
-
self
|
37
|
-
end
|
38
|
-
|
39
|
-
# Encrypts
|
40
|
-
def encrypt(plain_text)
|
41
|
-
@plain_text = plain_text
|
42
|
-
_setup(:encrypt)
|
43
|
-
case @options[:format]
|
44
|
-
when :base_64
|
45
|
-
@cipher_text = b64_e(_iv) << "$" << b64_e(_encrypt)
|
46
|
-
else
|
47
|
-
@cipher_text = [_iv, _encrypt]
|
48
|
-
end
|
49
|
-
@cipher_text
|
50
|
-
end
|
51
|
-
|
52
|
-
# Decrypts
|
53
|
-
def decrypt(cipher_text)
|
54
|
-
@cipher_text = cipher_text
|
55
|
-
_setup(:decrypt)
|
56
|
-
case @options[:format]
|
57
|
-
when :base_64
|
58
|
-
ctext = b64_d(@cipher_text)
|
59
|
-
else
|
60
|
-
ctext = @cipher_text
|
61
|
-
end
|
62
|
-
@cipher.iv = ctext[0]
|
63
|
-
@plain_text = @cipher.update(ctext[1]) + @cipher.final
|
64
|
-
end
|
65
|
-
|
66
|
-
# Generate a random initialization vector
|
67
|
-
def random_iv
|
68
|
-
_setup(:encrypt)
|
69
|
-
_iv
|
70
|
-
end
|
71
|
-
|
72
|
-
# Generate a random key
|
73
|
-
def random_key(length=256)
|
74
|
-
_random_seed.unpack('H*')[0][0..((length/8)-1)]
|
75
|
-
#Digest::SHA256.digest(_random_seed)[0..(length / 8)]
|
76
|
-
end
|
77
|
-
|
78
|
-
private
|
79
|
-
|
80
|
-
# Generates a random seed value
|
81
|
-
def _random_seed(size=32)
|
82
|
-
if defined? OpenSSL::Random
|
83
|
-
return OpenSSL::Random.random_bytes(size)
|
84
|
-
else
|
85
|
-
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
|
86
|
-
(1..size).collect{|a| chars[rand(chars.size)] }.join
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
# Un-Base64's the IV and CipherText
|
91
|
-
# Returns an array containing the IV, and CipherText
|
92
|
-
def b64_d(data)
|
93
|
-
iv_ctext = []
|
94
|
-
data.split('$').each do |part|
|
95
|
-
iv_ctext << Base64.decode64(part)
|
96
|
-
end
|
97
|
-
iv_ctext
|
98
|
-
end
|
99
|
-
|
100
|
-
# Base64 Encodes a string
|
101
|
-
def b64_e(data)
|
102
|
-
Base64.encode64(data).chomp
|
103
|
-
end
|
104
|
-
|
105
|
-
# Generates and returns a random initialization vector
|
106
|
-
def _iv
|
107
|
-
@cipher.random_iv
|
108
|
-
end
|
109
|
-
|
110
|
-
# Encrypts @plain_text
|
111
|
-
def _encrypt
|
112
|
-
@cipher.update(@plain_text) + @cipher.final
|
113
|
-
end
|
114
|
-
|
115
|
-
# Merge init options with defaults
|
116
|
-
def merge_options(opts)
|
117
|
-
@options = {
|
118
|
-
:format => :base_64,
|
119
|
-
:cipher => "AES-256-CBC"
|
120
|
-
}.merge! opts
|
121
|
-
end
|
122
|
-
|
123
|
-
# Create a new cipher using the cipher type specified
|
124
|
-
def _setup(action)
|
125
|
-
@cipher = OpenSSL::Cipher::Cipher.new(@options[:cipher])
|
126
|
-
# Toggles encryption mode
|
127
|
-
@cipher.send(action)
|
128
|
-
@cipher.key = @key.unpack('a2'*32).map{|x| x.hex}.pack('c'*32)
|
129
|
-
end
|
130
|
-
end
|
3
|
+
require 'aes/aes'
|
data/lib/aes/aes.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
module AES
|
2
|
+
class << self
|
3
|
+
# Encrypts the plain_text with the provided key
|
4
|
+
def encrypt(plain_text, key, opts={})
|
5
|
+
::AES::AES.new(key, opts).encrypt(plain_text)
|
6
|
+
end
|
7
|
+
# Decrypts the cipher_text with the provided key
|
8
|
+
def decrypt(cipher_text, key, opts={})
|
9
|
+
::AES::AES.new(key, opts).decrypt(cipher_text)
|
10
|
+
end
|
11
|
+
# Generates a random key of the specified length in bits
|
12
|
+
# Default format is :plain
|
13
|
+
def key(length=256,format=:plain)
|
14
|
+
key = ::AES::AES.new("").random_key(256)
|
15
|
+
case format
|
16
|
+
when :base_64
|
17
|
+
Base64.encode64(key).chomp
|
18
|
+
else
|
19
|
+
key
|
20
|
+
end
|
21
|
+
end
|
22
|
+
# Generates a random iv
|
23
|
+
# Default format is :plain
|
24
|
+
def iv(format=:plain)
|
25
|
+
iv = ::AES::AES.new("").random_iv
|
26
|
+
case format
|
27
|
+
when :base_64
|
28
|
+
Base64.encode64(iv).chomp
|
29
|
+
else
|
30
|
+
iv
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class AES
|
36
|
+
attr :options
|
37
|
+
attr :key
|
38
|
+
attr :iv
|
39
|
+
attr :cipher
|
40
|
+
attr :cipher_text
|
41
|
+
attr :plain_text
|
42
|
+
|
43
|
+
def initialize(key, opts={})
|
44
|
+
merge_options opts
|
45
|
+
@cipher = nil
|
46
|
+
@key = key
|
47
|
+
@iv ||= random_iv
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
# Encrypts
|
52
|
+
def encrypt(plain_text)
|
53
|
+
@plain_text = plain_text
|
54
|
+
_setup(:encrypt)
|
55
|
+
@cipher.iv = @iv
|
56
|
+
case @options[:format]
|
57
|
+
when :base_64
|
58
|
+
@cipher_text = b64_e(@iv) << "$" << b64_e(_encrypt)
|
59
|
+
else
|
60
|
+
@cipher_text = [@iv, _encrypt]
|
61
|
+
end
|
62
|
+
@cipher_text
|
63
|
+
end
|
64
|
+
|
65
|
+
# Decrypts
|
66
|
+
def decrypt(cipher_text)
|
67
|
+
@cipher_text = cipher_text
|
68
|
+
_setup(:decrypt)
|
69
|
+
case @options[:format]
|
70
|
+
when :base_64
|
71
|
+
ctext = b64_d(@cipher_text)
|
72
|
+
else
|
73
|
+
ctext = @cipher_text
|
74
|
+
end
|
75
|
+
@cipher.iv = ctext[0]
|
76
|
+
@plain_text = @cipher.update(ctext[1]) + @cipher.final
|
77
|
+
end
|
78
|
+
|
79
|
+
# Generate a random initialization vector
|
80
|
+
def random_iv
|
81
|
+
_setup(:encrypt)
|
82
|
+
@cipher.random_iv
|
83
|
+
end
|
84
|
+
|
85
|
+
# Generate a random key
|
86
|
+
def random_key(length=256)
|
87
|
+
_random_seed.unpack('H*')[0][0..((length/8)-1)]
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
# Generates a random seed value
|
93
|
+
def _random_seed(size=32)
|
94
|
+
if defined? OpenSSL::Random
|
95
|
+
return OpenSSL::Random.random_bytes(size)
|
96
|
+
else
|
97
|
+
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
|
98
|
+
(1..size).collect{|a| chars[rand(chars.size)] }.join
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Un-Base64's the IV and CipherText
|
103
|
+
# Returns an array containing the IV, and CipherText
|
104
|
+
def b64_d(data)
|
105
|
+
iv_and_ctext = []
|
106
|
+
data.split('$').each do |part|
|
107
|
+
iv_and_ctext << Base64.decode64(part)
|
108
|
+
end
|
109
|
+
iv_and_ctext
|
110
|
+
end
|
111
|
+
|
112
|
+
# Base64 Encodes a string
|
113
|
+
def b64_e(data)
|
114
|
+
Base64.encode64(data).chomp
|
115
|
+
end
|
116
|
+
|
117
|
+
# Encrypts @plain_text
|
118
|
+
def _encrypt
|
119
|
+
@cipher.update(@plain_text) + @cipher.final
|
120
|
+
end
|
121
|
+
|
122
|
+
# Merge init options with defaults
|
123
|
+
def merge_options(opts)
|
124
|
+
@options = {
|
125
|
+
:format => :base_64,
|
126
|
+
:cipher => "AES-256-CBC",
|
127
|
+
:iv => nil,
|
128
|
+
}.merge! opts
|
129
|
+
_handle_iv
|
130
|
+
end
|
131
|
+
|
132
|
+
def _handle_iv
|
133
|
+
@iv = @options[:iv]
|
134
|
+
return if @iv.nil?
|
135
|
+
|
136
|
+
case @options[:format]
|
137
|
+
when :base_64
|
138
|
+
@iv = Base64.decode64(@options[:iv])
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Create a new cipher using the cipher type specified
|
143
|
+
def _setup(action)
|
144
|
+
@cipher ||= OpenSSL::Cipher::Cipher.new(@options[:cipher])
|
145
|
+
# Toggles encryption mode
|
146
|
+
@cipher.send(action)
|
147
|
+
@cipher.key = @key.unpack('a2'*32).map{|x| x.hex}.pack('c'*32)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
data/test/test_aes.rb
CHANGED
@@ -5,15 +5,24 @@ class TestAES < Test::Unit::TestCase
|
|
5
5
|
should "encrypt and decrypt a string" do
|
6
6
|
key = "01234567890123456789012345678901"
|
7
7
|
msg = "This is a message that nobody should ever see"
|
8
|
-
enc = AES.encrypt(
|
9
|
-
assert_equal msg, AES.decrypt(
|
10
|
-
enc = AES.encrypt(
|
11
|
-
assert_equal msg, AES.decrypt(
|
8
|
+
enc = AES.encrypt(msg, key)
|
9
|
+
assert_equal msg, AES.decrypt(enc, key)
|
10
|
+
enc = AES.encrypt(msg, key, {:format => :plain})
|
11
|
+
assert_equal msg, AES.decrypt(enc, key, {:format => :plain})
|
12
|
+
end
|
13
|
+
|
14
|
+
should "produce the same encrypted string when provided an identical key and iv" do
|
15
|
+
key = "01234567890123456789012345678901"
|
16
|
+
msg = "This is a message that nobody should ever see"
|
17
|
+
iv = AES.iv(:base_64)
|
18
|
+
enc1 = AES.encrypt(msg, key, {:iv => iv})
|
19
|
+
enc2 = AES.encrypt(msg, key, {:iv => iv})
|
20
|
+
assert_equal enc1, enc2
|
12
21
|
end
|
13
22
|
|
14
23
|
should "generate a new key when AES#key" do
|
15
24
|
assert_equal 32, AES.key.length
|
16
|
-
assert_equal
|
25
|
+
assert_equal 44, AES.key(256, :base_64).length
|
17
26
|
end
|
18
27
|
|
19
28
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 4
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Carl Hicks
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-01-03 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -98,6 +98,7 @@ files:
|
|
98
98
|
- VERSION
|
99
99
|
- aes.gemspec
|
100
100
|
- lib/aes.rb
|
101
|
+
- lib/aes/aes.rb
|
101
102
|
- test/helper.rb
|
102
103
|
- test/test_aes.rb
|
103
104
|
has_rdoc: true
|