encrypted_text 0.1.1 → 0.1.2
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.md +8 -5
- data/lib/encrypted_text/codec.rb +13 -28
- data/lib/encrypted_text/version.rb +1 -1
- metadata +2 -2
data/README.md
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
encrypted_text
|
2
2
|
==============
|
3
3
|
|
4
|
-
Password-based, two-way encryption with string output. Uses AES encryption
|
4
|
+
Password-based, two-way encryption with string output. Uses AES encryption.
|
5
5
|
|
6
6
|
Usage example
|
7
7
|
-------------
|
8
8
|
|
9
|
-
In order to encode or decode a message, you should know the **key** and **signature** ahead of time.
|
9
|
+
In order to encode or decode a message, you should know the **key** and **signature** ahead of time.
|
10
|
+
|
11
|
+
- The key is a 16-, 24-, or 32-character string, used as an AES encryption key.
|
12
|
+
- The signature is prepended to the message before encryption, and verified after decryption.
|
10
13
|
|
11
14
|
```ruby
|
12
15
|
require 'encrypted_text'
|
@@ -20,7 +23,7 @@ encoded = codec.encode("Hello, world!")
|
|
20
23
|
original_message = codec.decode(encoded)
|
21
24
|
```
|
22
25
|
|
23
|
-
You can also add a random
|
26
|
+
You can also add a random salt, so that repeated encodings of the same message produce different results.
|
24
27
|
|
25
28
|
```ruby
|
26
29
|
# Continued from previous example
|
@@ -34,6 +37,6 @@ b = codec.encode(message) # Should be a different result!
|
|
34
37
|
Motivation
|
35
38
|
----------
|
36
39
|
|
37
|
-
|
40
|
+
Among other things, this library is useful for generating tokens that seem opaque to the outside world, but actually encode real information.
|
38
41
|
|
39
|
-
|
42
|
+
For example, in situations where tokens are passed from a service to an outside party and then back again, the service needs some way of resolving tokens passed back to it. Oftentimes this means performing a lookup on a stored mapping (e.g. a database query) between the token and some kind of cleartext data that outside parties never see. But this comes with all the clumsiness of maintaining and interacting with a persistent data store. For some applications, it might be acceptable simply to encode data directly into the token itself, using a secret that only the originating service has access to. EncryptedText provides a simple API to accomplish this.
|
data/lib/encrypted_text/codec.rb
CHANGED
@@ -11,11 +11,10 @@ module EncryptedText
|
|
11
11
|
attr_reader :charset, :key, :salt_size
|
12
12
|
|
13
13
|
KEY_CHAR_SIZES = [16, 24, 32] # An AES key must be 8-bit char strings of these lengths
|
14
|
-
|
14
|
+
SALT_CHARSET = Array(32..126).map{ |i| i.chr } # Printable ASCII chars go from 32 to 126
|
15
15
|
|
16
16
|
def initialize(opts)
|
17
17
|
config = {
|
18
|
-
:charset => DEFAULT_CHARSET,
|
19
18
|
:signature => '',
|
20
19
|
:key => nil,
|
21
20
|
:salt_size => 0,
|
@@ -28,18 +27,9 @@ module EncryptedText
|
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
31
|
-
def charset=(charset)
|
32
|
-
@charset = charset
|
33
|
-
@reverse_charset = @charset.each.with_index.reduce({}) do |res, (c, i)|
|
34
|
-
res[c] = i
|
35
|
-
res
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
30
|
def key=(key)
|
31
|
+
@engine = FastAES.new(key)
|
40
32
|
@key = key
|
41
|
-
@engine = FastAES.new(@key)
|
42
|
-
@key
|
43
33
|
end
|
44
34
|
|
45
35
|
def salt_size=(s)
|
@@ -47,18 +37,9 @@ module EncryptedText
|
|
47
37
|
@salt_size = s
|
48
38
|
end
|
49
39
|
|
50
|
-
def base_encode(val, from_base)
|
51
|
-
val.b(from_base).to_a.map{ |id| @charset[id] }.join
|
52
|
-
end
|
53
|
-
|
54
|
-
def base_decode(val)
|
55
|
-
val.split.map{ |c| @reverse_charset.fetch(c) }.b(@charset.size).to_i
|
56
|
-
end
|
57
|
-
|
58
40
|
def encode(message)
|
59
|
-
|
60
|
-
|
61
|
-
encrypted = @engine.encrypt(signed)
|
41
|
+
signed_and_salted = @signature + random_salt + message
|
42
|
+
encrypted = @engine.encrypt(signed_and_salted)
|
62
43
|
hex_string = '1' + encrypted.to_hex_string.split(' ').join # Add "1" prefix in case hex_string has leading zeroes
|
63
44
|
encoded = Radix.convert(hex_string.upcase, 16, 62) # Radix requires allcaps
|
64
45
|
end
|
@@ -69,16 +50,20 @@ module EncryptedText
|
|
69
50
|
hex_string = hex_string[1..-1] if hex_string[0] == '1' # remove "1" prefix
|
70
51
|
hex_string = "0" + hex_string if (hex_string.size % 2) != 0 # Make sure we have an even number of hex digits
|
71
52
|
byte_string = hex_string.to_byte_string
|
72
|
-
decrypted = @engine.decrypt(
|
53
|
+
decrypted = @engine.decrypt(byte_string)
|
73
54
|
rescue #TODO: don't use generic rescue here
|
74
55
|
raise EncryptedText::Err::CannotDecrypt
|
75
56
|
end
|
76
57
|
|
77
58
|
# Ensure that the message is signed correctly
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
59
|
+
raise EncryptedText::Err::BadSignature unless decrypted.index(@signature) == 0
|
60
|
+
|
61
|
+
# Remove signature and salt
|
62
|
+
decrypted[(@signature.size + @salt_size)..-1]
|
63
|
+
end
|
64
|
+
|
65
|
+
def random_salt
|
66
|
+
(0...@salt_size).map{ SALT_CHARSET.sample }.join
|
82
67
|
end
|
83
68
|
|
84
69
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: encrypted_text
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fast-aes
|