opensecret 0.0.962 → 0.0.988

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +16 -10
  3. data/bin/opensecret +3 -4
  4. data/bin/ops +5 -0
  5. data/lib/extension/string.rb +114 -0
  6. data/lib/factbase/facts.opensecret.io.ini +9 -21
  7. data/lib/interprete/begin.rb +232 -0
  8. data/lib/interprete/cmd.rb +621 -0
  9. data/lib/{plugins/usecases/unlock.rb → interprete/export.rb} +25 -70
  10. data/lib/interprete/init.rb +205 -0
  11. data/lib/interprete/key.rb +119 -0
  12. data/lib/interprete/open.rb +148 -0
  13. data/lib/{plugins/usecases → interprete}/put.rb +19 -6
  14. data/lib/{plugins/usecases → interprete}/safe.rb +2 -1
  15. data/lib/{plugins/usecases/lock.rb → interprete/seal.rb} +24 -34
  16. data/lib/interprete/set.rb +46 -0
  17. data/lib/interprete/use.rb +43 -0
  18. data/lib/interpreter.rb +165 -0
  19. data/lib/keytools/binary.map.rb +245 -0
  20. data/lib/keytools/digester.rb +245 -0
  21. data/lib/keytools/doc.conversion.to.ones.and.zeroes.ruby +179 -0
  22. data/lib/keytools/doc.rsa.radix.binary-mapping.ruby +190 -0
  23. data/lib/keytools/doc.star.schema.strategy.txt +77 -0
  24. data/lib/keytools/doc.using.pbkdf2.kdf.ruby +95 -0
  25. data/lib/keytools/doc.using.pbkdf2.pkcs.ruby +266 -0
  26. data/lib/keytools/kdf.bcrypt.rb +180 -0
  27. data/lib/keytools/kdf.pbkdf2.rb +164 -0
  28. data/lib/keytools/key.data.rb +227 -0
  29. data/lib/keytools/key.derivation.rb +341 -0
  30. data/lib/keytools/key.module.rb +140 -0
  31. data/lib/keytools/key.rb +481 -0
  32. data/lib/logging/gem.logging.rb +1 -2
  33. data/lib/modules/cryptology.md +43 -0
  34. data/lib/{plugins/ciphers → modules/cryptology}/aes-256.rb +6 -0
  35. data/lib/{crypto → modules/cryptology}/amalgam.rb +6 -0
  36. data/lib/modules/cryptology/blowfish.rb +130 -0
  37. data/lib/modules/cryptology/cipher.rb +207 -0
  38. data/lib/modules/cryptology/collect.rb +118 -0
  39. data/lib/{plugins → modules/cryptology}/crypt.io.rb +5 -0
  40. data/lib/{crypto → modules/cryptology}/engineer.rb +7 -1
  41. data/lib/{crypto → modules/cryptology}/open.bcrypt.rb +0 -0
  42. data/lib/modules/mappers/collateral.rb +282 -0
  43. data/lib/modules/mappers/dictionary.rb +288 -0
  44. data/lib/modules/mappers/envelope.rb +127 -0
  45. data/lib/modules/mappers/settings.rb +170 -0
  46. data/lib/modules/storage/coldstore.rb +186 -0
  47. data/lib/{opensecret/plugins.io/git/git.flow.rb → modules/storage/git.store.rb} +11 -0
  48. data/lib/notepad/scratch.pad.rb +17 -0
  49. data/lib/session/fact.finder.rb +13 -0
  50. data/lib/session/require.gem.rb +5 -0
  51. data/lib/store-commands.txt +180 -0
  52. data/lib/version.rb +1 -1
  53. data/opensecret.gemspec +5 -6
  54. metadata +74 -29
  55. data/lib/crypto/blowfish.rb +0 -85
  56. data/lib/crypto/collect.rb +0 -140
  57. data/lib/crypto/verify.rb +0 -33
  58. data/lib/opensecret.rb +0 -236
  59. data/lib/plugins/cipher.rb +0 -203
  60. data/lib/plugins/ciphers/blowfish.rb +0 -126
  61. data/lib/plugins/coldstore.rb +0 -181
  62. data/lib/plugins/envelope.rb +0 -116
  63. data/lib/plugins/secrets.uc.rb +0 -94
  64. data/lib/plugins/usecase.rb +0 -239
  65. data/lib/plugins/usecases/init.rb +0 -145
  66. data/lib/plugins/usecases/open.rb +0 -108
  67. data/lib/session/attributes.rb +0 -279
  68. data/lib/session/dictionary.rb +0 -191
  69. data/lib/session/file.path.rb +0 -53
  70. data/lib/session/session.rb +0 -80
@@ -0,0 +1,179 @@
1
+ # coding: utf-8
2
+
3
+ # =====> Look you convert to ones and zeroes like this - see below too.
4
+ # =====> Look you convert to ones and zeroes like this - see below too.
5
+ # =====> Look you convert to ones and zeroes like this - see below too.
6
+ # =====> Look you convert to ones and zeroes like this - see below too.
7
+ # =====> Look you convert to ones and zeroes like this - see below too.
8
+ # =====> Look you convert to ones and zeroes like this - see below too.
9
+ # =====> Look you convert to ones and zeroes like this - see below too.
10
+ # =====> Look you convert to ones and zeroes like this - see below too.
11
+ # =====> Look you convert to ones and zeroes like this - see below too.
12
+ # =====> Look you convert to ones and zeroes like this - see below too.
13
+ # =====> Look you convert to ones and zeroes like this - see below too.
14
+ # =====> Look you convert to ones and zeroes like this - see below too.
15
+
16
+ Conversion from String to binary
17
+ Easiest way, using unpack and tell Ruby that it is binary
18
+ "Hello".unpack("B*")
19
+ => ["0100100001100101011011000110110001101111"]
20
+
21
+
22
+ # =====> Look you convert to ones and zeroes like this - see below too.
23
+ # =====> Look you convert to ones and zeroes like this - see below too.
24
+ # =====> Look you convert to ones and zeroes like this - see below too.
25
+ # =====> Look you convert to ones and zeroes like this - see below too.
26
+ # =====> Look you convert to ones and zeroes like this - see below too.
27
+ # =====> Look you convert to ones and zeroes like this - see below too.
28
+ # =====> Look you convert to ones and zeroes like this - see below too.
29
+ # =====> Look you convert to ones and zeroes like this - see below too.
30
+ # =====> Look you convert to ones and zeroes like this - see below too.
31
+ # =====> Look you convert to ones and zeroes like this - see below too.
32
+ # =====> Look you convert to ones and zeroes like this - see below too.
33
+ # =====> Look you convert to ones and zeroes like this - see below too.
34
+ # =====> Look you convert to ones and zeroes like this - see below too.
35
+ # =====> Look you convert to ones and zeroes like this - see below too.
36
+ # =====> Look you convert to ones and zeroes like this - see below too.
37
+ # =====> Look you convert to ones and zeroes like this - see below too.
38
+ # =====> Look you convert to ones and zeroes like this - see below too.
39
+ # =====> Look you convert to ones and zeroes like this - see below too.
40
+ # =====> Look you convert to ones and zeroes like this - see below too.
41
+ # =====> Look you convert to ones and zeroes like this - see below too.
42
+ # =====> Look you convert to ones and zeroes like this - see below too.
43
+ # =====> Look you convert to ones and zeroes like this - see below too.
44
+ # =====> Look you convert to ones and zeroes like this - see below too.
45
+ # =====> Look you convert to ones and zeroes like this - see below too.
46
+ # =====> Look you convert to ones and zeroes like this - see below too.
47
+ # =====> Look you convert to ones and zeroes like this - see below too.
48
+ # =====> Look you convert to ones and zeroes like this - see below too.
49
+ # =====> Look you convert to ones and zeroes like this - see below too.
50
+ # =====> Look you convert to ones and zeroes like this - see below too.
51
+ # =====> Look you convert to ones and zeroes like this - see below too.
52
+ # =====> Look you convert to ones and zeroes like this - see below too.
53
+ # =====> Look you convert to ones and zeroes like this - see below too.
54
+
55
+
56
+ -100.to_s(2) # => "-1100100"
57
+ -100.to_s(2) # => "-1100100"
58
+ -100.to_s(2) # => "-1100100"
59
+ -100.to_s(2) # => "-1100100"
60
+ -100.to_s(2) # => "-1100100"
61
+ -100.to_s(2) # => "-1100100"
62
+ -100.to_s(2) # => "-1100100"
63
+ -100.to_s(2) # => "-1100100"
64
+
65
+
66
+
67
+ #### -----> See important padding article
68
+ #### -----> See important padding article
69
+ #### -----> See important padding article
70
+ #### -----> See important padding article
71
+ #### -----> See important padding article
72
+ #### -----> See important padding article
73
+
74
+ ## --> https://stackoverflow.com/questions/4080988/why-does-base64-encoding-require-padding-if-the-input-length-is-not-divisible-by?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
75
+
76
+
77
+
78
+
79
+ 2.6. Converting Between Numeric Bases
80
+ Problem
81
+ You want to convert numbers from one base to another.
82
+
83
+ Solution
84
+ You can convert specific binary, octal, or hexadecimal numbers to decimal by representing them with the 0b, 0o, or 0x prefixes:
85
+
86
+ 0b100 # => 4
87
+ 0o100 # => 64
88
+ 0x100 # => 256
89
+ You can also convert between decimal numbers and string representations of those numbers in any base from 2 to 36. Simply pass the base into String#to_i or Integer#to_s.
90
+
91
+ Here are some conversions between string representations of numbers in various bases, and the corresponding decimal numbers:
92
+
93
+ "1045".to_i(10) # => 1045
94
+ "-1001001".to_i(2) # => -73
95
+ "abc".to_i(16) # => 2748
96
+ "abc".to_i(20) # => 4232
97
+ "number".to_i(36) # => 1442151747
98
+ "zz1z".to_i(36) # => 1678391
99
+ "abcdef".to_i(16) # => 11259375
100
+ "AbCdEf".to_i(16) # => 11259375
101
+ Here are some reverse conversions of decimal numbers to the strings that represent those numbers in various bases:
102
+
103
+ 42.to_s(10) # => "42"
104
+ -100.to_s(2) # => "-1100100"
105
+ 255.to_s(16) # => "ff"
106
+ 1442151747.to_s(36) # => "number"
107
+ Some invalid conversions:
108
+
109
+ "6".to_i(2) # => 0
110
+ "0".to_i(1) # ArgumentError: illegal radix 1
111
+ 40.to_s(37) # ArgumentError: illegal radix 37
112
+ Discussion
113
+ String#to_i can parse and Integer#to_s can create a string representation in every common integer base: from binary (the familiar base 2, which uses only the digits 0 and 1) to hexatridecimal (base 36). Hexatridecimal uses the digits 0–9 and the letters a–z; it's sometimes used to generate alphanumeric
114
+
115
+
116
+
117
+
118
+
119
+
120
+ Convert String to Binary in Ruby
121
+ As for the sake of today 11/11/11,
122
+ Everything is in binary mode.
123
+ Why not do a conversion between String and binary :)
124
+
125
+ Conversion from String to binary
126
+ Easiest way, using unpack and tell Ruby that it is binary
127
+ "Hello".unpack("B*")
128
+ => ["0100100001100101011011000110110001101111"]
129
+
130
+ You can specify length of each binary by replace * with total length of the word (default binary has 8 bit per character)
131
+ "Hello".unpack("B40")
132
+ => ["0100100001100101011011000110110001101111"]
133
+
134
+ The output is in array format, removing an array can be done by adding [0] to select the first element from array.
135
+ "Hello".unpack("B*")[0]
136
+ => "0100100001100101011011000110110001101111"
137
+
138
+ Other method is to break down the string into characters first and get ASCII number of each character, then convert them to binary.
139
+ Here is a way for breaking a String into ASCII character code.
140
+ ‎"Hello".unpack("C*")
141
+ => [72, 101, 108, 108, 111]
142
+
143
+ Then using print formatting with %b to convert each ASCII code (int) to binary
144
+ "Hello".unpack("C*").each{|c| print "%08b" % c}
145
+
146
+ Another way to do using split('')
147
+ "Hello".split('').each{|c| print "%08b" % c[0] }
148
+ => 0100100001100101011011000110110001101111
149
+
150
+ Or you could use scan(/./)
151
+ "Hello".scan(/./).each{|c| print "%08b" % c[0] }
152
+ => 0100100001100101011011000110110001101111
153
+
154
+ Actually there is another method for converting number into binary, it is using ".to_str(2)" but this method doesn't put leading-zeros in the result, as you can see:
155
+ "Hello".scan(/./).each{|c| print "%08s " % c[0].to_s(2) }
156
+ => 1001000 1100101 1101100 1101100 1101111
157
+
158
+ Conversion from binary back to String
159
+ Same as above, we can use the same method to convert binary back to String
160
+ a="0100100001100101011011000110110001101111"
161
+ [a].pack("B*")
162
+ => "Hello"
163
+
164
+ Or split it by 8 digit each, then convert each 8 digit to int , then to character
165
+ a="0100100001100101011011000110110001101111"
166
+ (0..a.length).step(8).each {|i| print a[i,8].to_i(2).chr}
167
+ => Hello
168
+
169
+
170
+
171
+ P.S.
172
+ After reading .pack and .unpack function API, I found that Ruby has a built-in Base64 encoder/decoder.
173
+ To use it just use pack() or unpack() with "m" directive
174
+ Base64 Encoding
175
+ ["Hello"].pack("m*").chomp
176
+ => "SGVsbG8="
177
+ Base64 Decoding
178
+ "SGVsbG8=".unpack("m*")[0]
179
+ => "Hello"
@@ -0,0 +1,190 @@
1
+
2
+ For Starters....
3
+ I am often torn when programming between using libraries and following the DIY approach. On one hand you can accomplish a lot in a short time by including libraries that have the functionality you need and just bridging the gaps, but I am often left with the feeling of some loss-of-control and bloat. Obviously some library usage is inevitable, but I do like to take a minimalist approach to including external libraries because the management burden of updating libraries, the effort to make various libraries play together and because moving library-heavy applications between platforms can be... interesting. Most of all I like the learning that takes place when building it yourself. It was for this reason that I decided to see if I could effectively utilize the OpenSSL library that is typically part of a Ruby installation to create my own higher-level encryption/decryption class. Before we dive in I would like to layout the details of the application.
4
+
5
+ Password Management App
6
+
7
+ I have for years maintained a PGP encrypted file for my account passwords. I had the desire to centralize this and make it more web accessible. In order to do this I wanted assurance that the data was not only encrypted on the wire via SSL, but also at rest. I looked at various Ruby PGP/GPG libraries, but all of the ones I surveyed were wrappers around the GPG binary itself which didn't make it very web host friendly ( I planned on hosting it on Heroku with a Couchdb backend on Cloudant). That was when I decided to look at OpenSSL for file encryption since it is typically part of a Ruby installation and was available on Heroku. I also had the need for public-key encryption so a password store could be shared between two or more people (I share some accounts with my partner).
8
+
9
+ Take One... RSA
10
+ I thought I could simply use RSA encryption to meet all my needs and at first it worked quite well. Creating keys was straight forward and encryption/decryption worked well. One caveat is that the string passed to the FileEncryptor#encrypt_string method cannot be larger than the key size + PKCS padding size (11 bytes). So for a 128 byte (1024 bit) key the string should only be 117 bytes (see String#size).
11
+
12
+
13
+ require 'openssl'
14
+
15
+ class Encryptor
16
+
17
+ def initialize(key_pass, key_size = 1024, key_name = 'rsakey.sec', cipher = OpenSSL::Cipher.new('aes-256-cbc'))
18
+ @key_size = key_size
19
+ @cipher = cipher
20
+ @key_name = key_name
21
+
22
+ if( File.exists?(@key_name) )
23
+ @rsakey = OpenSSL::PKey::RSA.new(File.read(@key_name), key_pass)
24
+ else
25
+ @rsakey = OpenSSL::PKey::RSA.generate(@key_size)
26
+ File.open(@key_name,'w+') do |priv|
27
+ priv.write(@rsakey.to_pem(@cipher, key_pass))
28
+ end
29
+ end
30
+ end
31
+
32
+ def encrypt_string(txt)
33
+ begin
34
+ @rsakey.public_encrypt(txt)
35
+ rescue OpenSSL::PKey::RSAError => e
36
+ if e.message == 'data too large for key size'
37
+ STDERR.puts 'Your string is too large to encrypt'
38
+ else
39
+ raise
40
+ end
41
+ end
42
+ end
43
+
44
+ def decrypt_string(etxt)
45
+ @rsakey.private_decrypt(etxt)
46
+ end
47
+ end
48
+
49
+
50
+
51
+
52
+ ## -- See YAML storage of key (excellent).
53
+ ## -- See YAML storage of key (excellent).
54
+ ## -- See YAML storage of key (excellent).
55
+ ## -- See YAML storage of key (excellent).
56
+ ## -- See YAML storage of key (excellent).
57
+ ## -- See YAML storage of key (excellent).
58
+ ## -- See YAML storage of key (excellent).
59
+ ## -- See YAML storage of key (excellent).
60
+ ## -- See YAML storage of key (excellent).
61
+ ## -- See YAML storage of key (excellent).
62
+ ## -- See YAML storage of key (excellent).
63
+ ## -- See YAML storage of key (excellent).
64
+ ## -- See YAML storage of key (excellent).
65
+ ## -- See YAML storage of key (excellent).
66
+ ## -- See YAML storage of key (excellent).
67
+ ## -- See YAML storage of key (excellent).
68
+
69
+
70
+
71
+ This seemed to work quite well until I remembered that I needed to have the encrypted data be readable by multiple parties. I then had to change my approach and decided to use a symmetric AES key that is then shared between the multiple parties and each person encrypts the key with their RSA public key.
72
+
73
+ Take Two... RSA + AES
74
+ In order to accomplish secure use of the AES key we start out the same way as the previous solution by creating a RSA key. It will only be used to secure AES keys that we use to protect certain data stores. So if I have a data store I want to share with my brother I encrypt the data store with an AES key then I encrypt that key with my public RSA key and my brother's public RSA key. Now both he and I can access anything in that store and the AES key is still secure from prying eyes. Here is an overview of the steps taken before I post the code.
75
+ Create a RSA key-pair
76
+ Create an AES key to encrypt the data store
77
+ Encrypt the AES key with your RSA public key
78
+ To give access to the data store encrypt the AES key with the person's public RSA key send them back the cipher-text.
79
+
80
+ And here is the class I wrote to make this work:
81
+
82
+
83
+ require 'openssl'
84
+ require 'yaml'
85
+
86
+ class Encryptor
87
+
88
+ def initialize(key_pass, key_size = 2048, key_name = 'rsakey.sec', cipher = OpenSSL::Cipher.new('aes-256-cbc'))
89
+ @key_size = key_size
90
+ @cipher = cipher
91
+ @key_name = key_name
92
+
93
+ if( File.exists?(@key_name) )
94
+ @rsakey = OpenSSL::PKey::RSA.new(File.read(@key_name), key_pass)
95
+ else
96
+ @rsakey = OpenSSL::PKey::RSA.generate(@key_size)
97
+ File.open(@key_name,'w+') do |priv|
98
+ priv.write(@rsakey.to_pem(@cipher, key_pass))
99
+ end
100
+ end
101
+ end
102
+
103
+ def rsa_encrypt(txt, pub_key=nil)
104
+ begin
105
+ pub_key.nil? ? @rsakey.public_encrypt(txt) : OpenSSL::PKey::RSA.new(pub_key).public_encrypt(txt)
106
+ rescue OpenSSL::PKey::RSAError => e
107
+ if e.message == 'data too large for key size'
108
+ STDERR.puts 'Your string is too large to encrypt'
109
+ else
110
+ raise
111
+ end
112
+ end
113
+ end
114
+
115
+ def rsa_decrypt(etxt)
116
+ @rsakey.private_decrypt(etxt)
117
+ end
118
+
119
+ def aes_encrypt(txt, aes_file)
120
+ key = get_aes_key(aes_file)
121
+ cif = OpenSSL::Cipher.new('AES-256-CBC')
122
+ cif.encrypt
123
+ cif.key = key[:key]
124
+ cif.iv = key[:iv] = cif.random_iv
125
+ save_aes_key(aes_file, key)
126
+ etxt = ''
127
+ etxt << cif.update(txt)
128
+ etxt << cif.final
129
+ etxt
130
+ end
131
+
132
+ def aes_decrypt(etxt, aes_file)
133
+ key = get_aes_key(aes_file)
134
+ cif = OpenSSL::Cipher.new('AES-256-CBC')
135
+ cif.decrypt
136
+ cif.key = key[:key]
137
+ cif.iv = key[:iv]
138
+ txt = ''
139
+ txt << cif.update(etxt)
140
+ txt << cif.final
141
+ txt
142
+ end
143
+
144
+ def gen_aes_key(file)
145
+ cif = OpenSSL::Cipher.new('AES-256-CBC')
146
+ key = {key: cif.random_key}
147
+ save_aes_key(file, key)
148
+ key
149
+ end
150
+
151
+ def save_aes_key(file,key_iv)
152
+ File.open(file,'w+') do |f|
153
+ f.write(rsa_encrypt(YAML.dump(key_iv)))
154
+ end
155
+ end
156
+
157
+ def get_aes_key(file)
158
+ YAML.load(rsa_decrypt(File.read(file)))
159
+ end
160
+
161
+ def give_aes_key(aes_file, rsa_pub)
162
+ aes = get_aes_key(aes_file)
163
+ rsa_encrypt(YAML.dump(aes), rsa_pub)
164
+ end
165
+
166
+ end
167
+
168
+
169
+
170
+ Below is a demonstration of the use of this class to accomplish the needs I had for my password protector application. I am aware that this class needs some refactoring and it's a bit annoying to have to pass the AES key file to the methods, but logically it is working the way I had hoped.
171
+
172
+
173
+
174
+ fe = Encryptor.new('mysecret')
175
+
176
+ aesfile = 'aeskey.sec'
177
+
178
+ fe.gen_aes_key(aesfile)
179
+
180
+ etxt = fe.aes_encrypt('this is a test', aesfile)
181
+
182
+ txt = fe.aes_decrypt(etxt, aesfile)
183
+
184
+ pub_key = < Assume I got someone's public RSA Key somehow >
185
+
186
+ fe.give_aes_key(aesfile, pub_key)
187
+
188
+ Like I mentioned, this code needs to be cleaned up a bit, but it gives me all of the functionality I need to build my application and it doesn't require any external libraries except OpenSSL and YAML which are typically standard in any Ruby installation.
189
+
190
+ Hopefully someone finds this post useful and if you have any additions, corrections, criticisms please post them below. Feedback is always welcome.
@@ -0,0 +1,77 @@
1
+
2
+
3
+ ### @@@@@@@@@@@@@@@@@@@@@@@@@@
4
+ ### Star Schema Strategy
5
+ ### @@@@@@@@@@@@@@@@@@@@@@@@@@
6
+
7
+ - We move away from a single private key to one per sealed envelope.
8
+
9
+ There are 2 huge 72 character keys ( NOT base64 characters but UTF-7 (or 8) possible characters )
10
+
11
+ (note - in common mistakes article put the fact that random keys are generated
12
+ from tools like securerandom that do not cover the full range f possible
13
+ chars hence sharpely narrowing the search space for an attacker.
14
+ )
15
+
16
+ Write test program to prove that EVERY ONE of THE 128 CHARACTERS COUNT.
17
+ How ----> Create 71 characters that are all AAAAAAA...
18
+ ====> Rotate round each of the 128 chars as the 72nd character
19
+ ----> Check that bcrypt generates 128 different outcomes for each of the 128 chars.
20
+
21
+
22
+ ==> Use get random bytes to get 72 random bytes (not secure random which halves (if not worse) the search space).
23
+
24
+
25
+ When password entered we read the salt and retrieve the key and unlock the STRONG 256 BIT key (found by getting 32 random bytes then mapping to 32 bytes with say SHA512 digest) crypt for index file.
26
+
27
+ We then grab this crypt key (32 bytes long or 64 bytes - the longest a symmetric crypt key can be) - test this out with AES256.
28
+
29
+ The crypt key unlocks the index file.
30
+
31
+ We then grab the session ID - then hash that say through Digest.SHA512 - and use the resulting key to decrypt the ENVironment VARIABLE.
32
+ This reveals a 512 (or 256) bit SESSION crypt key which creates a copy of the (in-memory) index file and then writes it with a new name
33
+ that is the alpha-number session ID hash. We encrypt the index file with the new key.
34
+
35
+ Still in SAME CALL we prepare the NEXT (future) SEAL password. We create a 256 bit key and then derive a new bcrypt salt and out comes the 186bit key (which we hash and use to lock the 256 bit key just created and we save the salt in the configs and save the future SEAL password crypt in the configs.
36
+ The crux move is we use the session key to also lock the seal password for when session ends.
37
+
38
+ NOW WE THROW AWAY THE PASSWORD THE BEAUTY OF THIS METHOD IS THAT WE NEVER KEEP THE PASSWORD ANYWHERE ENCRYPTED OR OTHERWISE - WE TRHOW IT AWAY WE WONT NEED IT AGAIN UNTIL THE NEXT SESSION.
39
+
40
+
41
+ Now we continue with the other open, put, add type calls. They all now accesses the copied session index file and it is changed as appropriate.
42
+
43
+
44
+ Finally when the SEAL time comes we use session key to unlock and retrieve the NEXT time (seal) key. We lock index file with this key.
45
+
46
+ In clean up we throw away all our session bits and bobs.
47
+
48
+
49
+ We are ready for "next time" - when the password is entered we derive the key again and can unlock the last saved index file!! Cool plan or what??
50
+
51
+
52
+ REDIS Store + more
53
+
54
+ This plan allows a seamless migration to keeping the index not in a file (risks failure)
55
+ but in a REDIS or etcd or PostgreSQL or other key-value stores.
56
+
57
+
58
+
59
+ ### @@@@@@@@@@@@@@@@@@@@@@@@@@
60
+ ### Star Schema for Each Envelope Details
61
+ ### @@@@@@@@@@@@@@@@@@@@@@@@@@
62
+
63
+ - path off session base
64
+ - path to private key
65
+ - (inner encrypted private key lock)
66
+ - path to keyfile
67
+ - path to crypt file
68
+ - outer path
69
+ - inner path
70
+ - sealed already?
71
+ - is reopen or no?
72
+ - last accessed time
73
+ - who by user@hostname
74
+ - on what ppi (shell) id@mac address
75
+ - top level count
76
+
77
+
@@ -0,0 +1,95 @@
1
+ # coding: utf-8
2
+
3
+ # OpenSSL::PKCS5.pbkdf2_hmac has been renamed to OpenSSL::KDF.pbkdf2_hmac.
4
+ # This method is provided for backwards compatibility.
5
+
6
+ def pbkdf2_hmac(pass, salt, iter, keylen, digest)
7
+
8
+ OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter,
9
+ length: keylen, hash: digest)
10
+
11
+ end
12
+
13
+
14
+ ##########################################################################################
15
+ ##########################################################################################
16
+ ##########################################################################################
17
+ ##########################################################################################
18
+ ##########################################################################################
19
+
20
+
21
+ OpenSSL::KDF
22
+ Provides functionality of various KDFs (key derivation function).
23
+
24
+ KDF is typically used for securely deriving arbitrary length symmetric keys to be used with an OpenSSL::Cipher from passwords. Another use case is for storing passwords: Due to the ability to tweak the effort of computation by increasing the iteration count, computation can be slowed down artificially in order to render possible attacks infeasible.
25
+
26
+ Currently, OpenSSL::KDF provides implementations for the following KDF:
27
+
28
+ PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in combination with HMAC
29
+
30
+ scrypt
31
+
32
+ HKDF
33
+
34
+ ############################
35
+ #### Parameters
36
+ ############################
37
+
38
+ pass = the passphrase
39
+
40
+ salt = The salt. Salts prevent attacks based on dictionaries of common passwords and attacks based on rainbow tables. It is a public value that can be safely stored along with the password (e.g. if the derived value is used for password storage).
41
+
42
+ iterations = The iteration count. This provides the ability to tune the algorithm. It is better to use the highest count possible for the maximum resistance to brute-force attacks.
43
+
44
+ length = The desired length of the derived key in octets.
45
+
46
+ hash = The hash algorithm used with HMAC for the PRF. May be a String representing the algorithm name, or an instance of OpenSSL::Digest.
47
+
48
+
49
+ ############################
50
+ #### Examples
51
+ ############################
52
+
53
+ Generating a 128 bit key for a Cipher (e.g. AES)¶ ↑
54
+ pass = "secret"
55
+ salt = OpenSSL::Random.random_bytes(16)
56
+ iter = 20_000
57
+ key_len = 16
58
+ key = OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter,
59
+ length: key_len, hash: "sha1")
60
+
61
+ ############################
62
+ #### Storing Passwords
63
+ ############################
64
+
65
+ pass = "secret"
66
+ # store this with the generated value
67
+ salt = OpenSSL::Random.random_bytes(16)
68
+ iter = 20_000
69
+ hash = OpenSSL::Digest::SHA256.new
70
+ len = hash.digest_length
71
+ # the final value to be stored
72
+ value = OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter,
73
+ length: len, hash: hash)
74
+
75
+ ############################
76
+ #### Important Note on Checking Passwords
77
+ #### Thwart Timing Attacks by taking the Same Amount of Time to Check Failures and Successes
78
+ ############################
79
+
80
+ When comparing passwords provided by the user with previously stored values, a common mistake made is comparing the two values using "==". Typically, "==" short-circuits on evaluation, and is therefore vulnerable to timing attacks. The proper way is to use a method that always takes the same amount of time when comparing two values, thus not leaking any information to potential attackers. To compare two values, the following could be used:
81
+
82
+ def eql_time_cmp(a, b)
83
+ unless a.length == b.length
84
+ return false
85
+ end
86
+ cmp = b.bytes
87
+ result = 0
88
+ a.bytes.each_with_index {|c,i|
89
+ result |= c ^ cmp[i]
90
+ }
91
+ result == 0
92
+ end
93
+ Please note that the premature return in case of differing lengths typically does not leak valuable information - when using PBKDF2, the length of the values to be compared is of fixed size.
94
+
95
+