ccipher_box 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/.rspec +3 -0
- data/Gemfile +35 -0
- data/Gemfile.lock-java +89 -0
- data/Gemfile.lock-ruby +91 -0
- data/README.md +35 -0
- data/Rakefile +10 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/ccipher_box.gemspec +47 -0
- data/lib/ccipher_box/bin_struct.rb +167 -0
- data/lib/ccipher_box/binenc_constant.rb +38 -0
- data/lib/ccipher_box/decryption_engine.rb +74 -0
- data/lib/ccipher_box/enc_key_config.rb +78 -0
- data/lib/ccipher_box/encryption_engine.rb +77 -0
- data/lib/ccipher_box/keybox.rb +147 -0
- data/lib/ccipher_box/mem_key.rb +394 -0
- data/lib/ccipher_box/mem_vault.rb +93 -0
- data/lib/ccipher_box/secure_box.rb +299 -0
- data/lib/ccipher_box/secure_ring.rb +129 -0
- data/lib/ccipher_box/version.rb +5 -0
- data/lib/ccipher_box.rb +28 -0
- data/run_test.rb +27 -0
- metadata +148 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
module CcipherBox
|
5
|
+
#
|
6
|
+
# Meant to encrypt large data
|
7
|
+
#
|
8
|
+
class EncryptionEngine
|
9
|
+
include TR::CondUtils
|
10
|
+
|
11
|
+
def initialize(*args)
|
12
|
+
@keys = args
|
13
|
+
end
|
14
|
+
|
15
|
+
def init(output)
|
16
|
+
raise CcipherBox::Error, "Output is mandatory" if output.nil?
|
17
|
+
|
18
|
+
@output = output
|
19
|
+
@baseMat = SecureRandom.random_bytes(256/8)
|
20
|
+
@sk = CcipherFactory::SymKeyGenerator.derive(:aes, 256) do |ops|
|
21
|
+
case ops
|
22
|
+
when :password
|
23
|
+
@baseMat
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
@intOut = Tempfile.new
|
28
|
+
|
29
|
+
@cipher = CcipherFactory::SymKeyCipher.encryptor
|
30
|
+
@cipher.output(@intOut)
|
31
|
+
@cipher.key = @sk
|
32
|
+
@cipher.encrypt_init
|
33
|
+
end
|
34
|
+
|
35
|
+
def update(data)
|
36
|
+
@cipher.encrypt_update(data)
|
37
|
+
end
|
38
|
+
|
39
|
+
def final(&block)
|
40
|
+
header = @cipher.encrypt_final
|
41
|
+
|
42
|
+
st = BinStruct.instance.struct(:ccipherbox_cipher)
|
43
|
+
st.keyConfig = @sk.encoded
|
44
|
+
|
45
|
+
encBaseMat = []
|
46
|
+
@keys.each do |k|
|
47
|
+
#logger.debug "Encrypt with key #{k.name}"
|
48
|
+
encBaseMat << k.encrypt(@baseMat)
|
49
|
+
end
|
50
|
+
st.baseMaterial = encBaseMat
|
51
|
+
|
52
|
+
st.cipherConfig = header
|
53
|
+
aheader = st.encoded
|
54
|
+
|
55
|
+
@output.write(aheader)
|
56
|
+
|
57
|
+
@intOut.rewind
|
58
|
+
while not @intOut.eof?
|
59
|
+
@output.write(@intOut.read)
|
60
|
+
end
|
61
|
+
|
62
|
+
@intOut.close
|
63
|
+
@intOut.delete
|
64
|
+
|
65
|
+
aheader
|
66
|
+
end
|
67
|
+
|
68
|
+
def logger
|
69
|
+
if @logger.nil?
|
70
|
+
@logger = TeLogger::Tlogger.new
|
71
|
+
@logger.tag = :enc_eng
|
72
|
+
end
|
73
|
+
@logger
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
|
2
|
+
require 'ccipher_factory'
|
3
|
+
|
4
|
+
module CcipherBox
|
5
|
+
|
6
|
+
# Abstraction of deriving a key from a given base key (baseMat)
|
7
|
+
# and the Key Derivation Function (KDF).
|
8
|
+
# With the two inputs, a derive key would be provided via dkey() API
|
9
|
+
class Keybox
|
10
|
+
include TR::CondUtils
|
11
|
+
|
12
|
+
attr_accessor :outBitLength, :kdf, :baseMat
|
13
|
+
|
14
|
+
def initialize(kdfEngine = nil)
|
15
|
+
raise KeyboxException, "Instance of KDF engine (CcipherFactory::KDF::KDFEngine) required" if not_empty?(kdfEngine) and not kdfEngine.is_a?(CcipherFactory::KDF::KDFEngine)
|
16
|
+
|
17
|
+
@kdfEng = kdfEngine
|
18
|
+
if not @kdfEng.nil?
|
19
|
+
@kdfOut = MemBuf.new
|
20
|
+
@kdfEng.output(@kdfOut)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.from_encoded(bin)
|
25
|
+
|
26
|
+
raise KeyboxException, "Given binary is empty" if is_empty?(bin)
|
27
|
+
|
28
|
+
st = BinStruct.instance.struct_from_bin(bin)
|
29
|
+
kdfEng = CcipherFactory::KDF.from_encoded(st.kdfConfig)
|
30
|
+
Keybox.new(kdfEng)
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
def baseMat=(val)
|
35
|
+
|
36
|
+
case val
|
37
|
+
when CcipherFactory::SymKey
|
38
|
+
# taking the key value only will still can get
|
39
|
+
# derived key correctly even if the key type and size
|
40
|
+
# has changed. For example change from Blowfish to AES
|
41
|
+
# will not resulted in a different value
|
42
|
+
#
|
43
|
+
# Decided to take only the raw key value to allow
|
44
|
+
# flexibility at upper application to change from a
|
45
|
+
# symmetric algo to another, since the objective of this
|
46
|
+
# class is just to get a derived raw key, not SymKey object
|
47
|
+
@baseMat = val.key
|
48
|
+
|
49
|
+
# taking the encoded value however from symkey
|
50
|
+
# will make the base key sensitive to meta data changes,
|
51
|
+
# from key type, size, KDF config changes all will affect
|
52
|
+
# final result
|
53
|
+
#@baseMat = val.encoded
|
54
|
+
#when String
|
55
|
+
# test for String will means need a mechanism to test for Java::byte[]
|
56
|
+
# which is not yet there
|
57
|
+
# @baseMat = val
|
58
|
+
else
|
59
|
+
@baseMat = val
|
60
|
+
#raise KeyboxException, "Unsupported base material type '#{val}'"
|
61
|
+
end
|
62
|
+
|
63
|
+
@dkeyVal = nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def dkey
|
67
|
+
|
68
|
+
if @dkeyVal.nil?
|
69
|
+
|
70
|
+
raise KeyboxException, "BaseMat not given" if is_empty?(@baseMat)
|
71
|
+
|
72
|
+
kdfEng.derive_update(@baseMat)
|
73
|
+
|
74
|
+
@kdfConfig = kdfEng.derive_final
|
75
|
+
|
76
|
+
@dkeyVal = @kdfOut.bytes.clone
|
77
|
+
@kdfOut.dispose
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
@dkeyVal
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
def encoded
|
86
|
+
st = BinStruct.instance.struct(:keybox)
|
87
|
+
st.kdfConfig = @kdfConfig
|
88
|
+
st.encoded
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
def kdfEng
|
93
|
+
|
94
|
+
if @kdfEng.nil?
|
95
|
+
|
96
|
+
raise KeyboxException, "OutBitLength is not given" if is_empty?(@outBitLength)
|
97
|
+
|
98
|
+
if @kdf.nil?
|
99
|
+
|
100
|
+
# random KDF
|
101
|
+
rEng = [:scrypt, :hkdf, :pbkdf2].sample
|
102
|
+
logger.debug "Random KDF : #{rEng}"
|
103
|
+
@kdfEng = CcipherFactory::KDF.instance(rEng)
|
104
|
+
@kdfEng.outByteLength = @outBitLength/8
|
105
|
+
|
106
|
+
@kdfOut = MemBuf.new
|
107
|
+
@kdfEng.output(@kdfOut)
|
108
|
+
@kdfEng.derive_init
|
109
|
+
|
110
|
+
else
|
111
|
+
|
112
|
+
case @kdf
|
113
|
+
when :scrypt, :hkdf, :pbkdf2
|
114
|
+
logger.debug "Given KDF : #{@kdf}"
|
115
|
+
@kdfEng = CcipherFactory::KDF.instance(@kdf)
|
116
|
+
@kdfEng.outByteLength = @outBitLength/8
|
117
|
+
else
|
118
|
+
raise KeyboxException, "Unknown KDF engine '#{@kdf}' requested"
|
119
|
+
end
|
120
|
+
|
121
|
+
@kdfOut = MemBuf.new
|
122
|
+
@kdfEng.output(@kdfOut)
|
123
|
+
@kdfEng.derive_init
|
124
|
+
|
125
|
+
end # @kdf.nil?
|
126
|
+
|
127
|
+
end # kdfEng.nil?
|
128
|
+
|
129
|
+
@kdfEng
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.logger
|
134
|
+
if @logger.nil?
|
135
|
+
@logger = TeLogger::Tlogger.new
|
136
|
+
@logger.tag = :keybox
|
137
|
+
end
|
138
|
+
@logger
|
139
|
+
end
|
140
|
+
|
141
|
+
def logger
|
142
|
+
self.class.logger
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
@@ -0,0 +1,394 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module CcipherBox
|
4
|
+
|
5
|
+
#
|
6
|
+
# Actual data encryption key that is encrypted in memory
|
7
|
+
# This class represents a single encryption key
|
8
|
+
#
|
9
|
+
class MemKey
|
10
|
+
include TR::CondUtils
|
11
|
+
|
12
|
+
class MemKeyException < Exception; end
|
13
|
+
|
14
|
+
attr_accessor :name, :ring
|
15
|
+
|
16
|
+
def initialize(ring, key, name = nil)
|
17
|
+
@dataConv = Ccrypto::UtilFactory.instance(:data_conversion)
|
18
|
+
@dataComp = Ccrypto::UtilFactory.instance(:comparator)
|
19
|
+
self.ring = ring
|
20
|
+
self.key = key
|
21
|
+
self.name = name
|
22
|
+
|
23
|
+
@activateCount = 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def key=(val)
|
27
|
+
generateKeyID(val)
|
28
|
+
@key = mem_seal(val)
|
29
|
+
end
|
30
|
+
|
31
|
+
def keyID
|
32
|
+
@keyID
|
33
|
+
end
|
34
|
+
|
35
|
+
# keyID is stored as binary in the structure
|
36
|
+
# but was used as Hex value at application level
|
37
|
+
def self.to_KeyID(val)
|
38
|
+
Ccrypto::UtilFactory.instance(:data_conversion).to_hex(val)
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Encrypt by this key is generally consider key wrap
|
43
|
+
# therefore data is not expected to be very big.
|
44
|
+
#
|
45
|
+
# This is not really going to encrypt the actual data
|
46
|
+
# since there might have multiple key involved during
|
47
|
+
# data protection
|
48
|
+
#
|
49
|
+
def encrypt(data, &block)
|
50
|
+
|
51
|
+
if block
|
52
|
+
algo = block.call(:symkey_algo)
|
53
|
+
keysize = block.call(:symkey_length)
|
54
|
+
mode = block.call(:symkey_mode)
|
55
|
+
output = block.call(:output)
|
56
|
+
end
|
57
|
+
|
58
|
+
algo = :aes if is_empty?(algo)
|
59
|
+
keysize = 256 if is_empty?(keysize)
|
60
|
+
mode = :gcm if is_empty?(mode)
|
61
|
+
output = :binary if is_empty?(output)
|
62
|
+
|
63
|
+
key = mem_unseal(@key)
|
64
|
+
case key
|
65
|
+
when CcipherFactory::SymKey
|
66
|
+
sk = key
|
67
|
+
else
|
68
|
+
sk = CcipherFactory::SymKeyGenerator.derive(algo, keysize) do |k|
|
69
|
+
case k
|
70
|
+
when :password
|
71
|
+
key
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
@activateCount += 1
|
77
|
+
# refresh the in-memory encryption
|
78
|
+
if @activateCount > 5
|
79
|
+
logger.debug "Seal refresh during encrypt ops"
|
80
|
+
@key = mem_seal(@key)
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
membuf = MemBuf.new
|
85
|
+
enc = CcipherFactory::SymKeyCipher.att_encryptor
|
86
|
+
enc.key = sk
|
87
|
+
enc.mode = mode
|
88
|
+
|
89
|
+
enc.output(membuf)
|
90
|
+
enc.att_encrypt_init
|
91
|
+
enc.att_encrypt_update(data)
|
92
|
+
enc.att_encrypt_final
|
93
|
+
|
94
|
+
encOut = membuf.bytes.clone
|
95
|
+
membuf.dispose
|
96
|
+
|
97
|
+
st = BinStruct.instance.struct(:ccipherbox_keywrap)
|
98
|
+
st.keyid = @dataConv.from_hex(self.keyID)
|
99
|
+
sk.attach_mode
|
100
|
+
st.keyConfig = sk.encoded
|
101
|
+
st.cipher = encOut
|
102
|
+
res = st.encoded
|
103
|
+
|
104
|
+
case output
|
105
|
+
when :hex
|
106
|
+
@dataConv.to_hex(res)
|
107
|
+
when :b64
|
108
|
+
@dataConv.to_b64(res)
|
109
|
+
else
|
110
|
+
res
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
def decrypt(bin, &block)
|
116
|
+
|
117
|
+
st = BinStruct.instance.struct_from_bin(bin)
|
118
|
+
st.keyid = @dataConv.to_hex(st.keyid)
|
119
|
+
|
120
|
+
raise MemKeyException, "Given data to decrypt is not cipher envelope" if CBTag.value_constant(st.oid) != :ccipherbox_keywrap
|
121
|
+
raise MemKeyException, "Give cipher envelope is not meant for this key. Current key ID '#{self.keyID}' and key ID inside envelope '#{st.keyid}'" if not @dataComp.is_equals?(self.keyID, st.keyid)
|
122
|
+
|
123
|
+
case @key
|
124
|
+
when CcipherFactory::SymKey
|
125
|
+
sk = @key
|
126
|
+
else
|
127
|
+
sk = CcipherFactory::SymKey.from_encoded(st.keyConfig) do |k|
|
128
|
+
case k
|
129
|
+
when :password
|
130
|
+
mem_unseal(@key)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
@activateCount += 1
|
136
|
+
# refresh the in-memory protection
|
137
|
+
if @activateCount > 5
|
138
|
+
logger.debug "Seal refresh during decrypt ops"
|
139
|
+
@key = mem_seal(@key)
|
140
|
+
end
|
141
|
+
|
142
|
+
membuf = MemBuf.new
|
143
|
+
dec = CcipherFactory::SymKeyCipher.att_decryptor
|
144
|
+
dec.key = sk
|
145
|
+
|
146
|
+
dec.output(membuf)
|
147
|
+
dec.att_decrypt_init
|
148
|
+
dec.att_decrypt_update(st.cipher)
|
149
|
+
dec.att_decrypt_final
|
150
|
+
|
151
|
+
plain = membuf.bytes.clone
|
152
|
+
membuf.dispose
|
153
|
+
|
154
|
+
if block
|
155
|
+
output = block.call(:output)
|
156
|
+
end
|
157
|
+
output = :binary if is_empty?(output)
|
158
|
+
|
159
|
+
case output
|
160
|
+
when :hex
|
161
|
+
@dataConv.to_hex(plain)
|
162
|
+
when :b64
|
163
|
+
@dataConv.to_b64(plain)
|
164
|
+
else
|
165
|
+
plain
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
#def derive(algo = :script)
|
171
|
+
# kb = Keybox.new(algo)
|
172
|
+
# kb.baseMat = mem_unseal(@key)
|
173
|
+
# kb
|
174
|
+
#end
|
175
|
+
|
176
|
+
#def encoded
|
177
|
+
# st = BinStruct.instance.struct(:mem_key)
|
178
|
+
# st.value = mem_unseal(@key)
|
179
|
+
# st.encoded
|
180
|
+
#end
|
181
|
+
|
182
|
+
def plain_key
|
183
|
+
mem_unseal(@key)
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
# Encrypt the actual key resides in memory
|
188
|
+
def mem_seal(key)
|
189
|
+
|
190
|
+
supported = CcipherFactory::SymKeyGenerator.supported_symkey
|
191
|
+
symAlgo = supported.keys
|
192
|
+
# randomly select which algo to start for in memory protection
|
193
|
+
startIndx = rand(0..symAlgo.length-1)
|
194
|
+
loopCnt = 0
|
195
|
+
|
196
|
+
logger.debug "Total supported symkey algo : #{symAlgo.length}"
|
197
|
+
|
198
|
+
indx = startIndx
|
199
|
+
|
200
|
+
#case key
|
201
|
+
#when CcipherFactory::SoftSymKey
|
202
|
+
# logger.debug "Given key to seal is Soft SymKey"
|
203
|
+
# payload = key.key.key
|
204
|
+
#when CcipherFactory::DerivedSymKey
|
205
|
+
# logger.debug "Given key to seal is Derived SymKey"
|
206
|
+
# payload = key.key
|
207
|
+
#else
|
208
|
+
# logger.debug "Given key to seal is native key"
|
209
|
+
# payload = key
|
210
|
+
#end
|
211
|
+
|
212
|
+
case key
|
213
|
+
when CcipherFactory::SymKey
|
214
|
+
logger.debug "Given key to seal is SymKey #{key.class}"
|
215
|
+
payload = key.raw_key
|
216
|
+
else
|
217
|
+
logger.debug "Given key to seal is native key"
|
218
|
+
payload = key
|
219
|
+
end
|
220
|
+
|
221
|
+
loop do
|
222
|
+
|
223
|
+
algo = symAlgo[indx]
|
224
|
+
ks = supported[algo][:keysize][-1]
|
225
|
+
mode = supported[algo][:mode][-1]
|
226
|
+
|
227
|
+
logger.debug "Utilizing symkey at index : #{indx} - #{algo}/#{ks}/#{mode}"
|
228
|
+
sk = CcipherFactory::SymKeyGenerator.generate(algo, ks)
|
229
|
+
|
230
|
+
#logger.debug "Generated key #{loopCnt} : #{sk.inspect}"
|
231
|
+
|
232
|
+
enc = CcipherFactory::SymKeyCipher.att_encryptor
|
233
|
+
enc.key = sk
|
234
|
+
enc.mode = mode
|
235
|
+
|
236
|
+
membuf = MemBuf.new
|
237
|
+
enc.output(membuf)
|
238
|
+
|
239
|
+
enc.att_encrypt_init
|
240
|
+
enc.att_encrypt_update(payload)
|
241
|
+
enc.att_encrypt_final
|
242
|
+
|
243
|
+
sk.attach_mode
|
244
|
+
encRes = membuf.bytes.clone
|
245
|
+
membuf.dispose
|
246
|
+
|
247
|
+
#logger.debug "Encrypted #{loopCnt} : #{encRes.inspect}"
|
248
|
+
|
249
|
+
st = BinStruct.instance.struct(:mem_key_layer)
|
250
|
+
st.material = sk.encoded
|
251
|
+
st.payload = encRes
|
252
|
+
payload = st.encoded
|
253
|
+
|
254
|
+
indx = ((indx+1) % symAlgo.length)
|
255
|
+
|
256
|
+
loopCnt += 1
|
257
|
+
break if loopCnt >= symAlgo.length
|
258
|
+
|
259
|
+
end
|
260
|
+
|
261
|
+
kkey = CcipherFactory::SymKeyGenerator.derive(:aes, 256) do |k|
|
262
|
+
case k
|
263
|
+
when :password
|
264
|
+
case key
|
265
|
+
when CcipherFactory::SoftSymKey
|
266
|
+
# SymKey -> Ccrypto::SecretKey -> raw key
|
267
|
+
key.key.key
|
268
|
+
when CcipherFactory::DerivedSymKey
|
269
|
+
key.key
|
270
|
+
else
|
271
|
+
key
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
st = BinStruct.instance.struct(:mem_key_envp)
|
277
|
+
|
278
|
+
kcv = CcipherFactory::KCV.new
|
279
|
+
kcv.key = kkey
|
280
|
+
|
281
|
+
st.kcv = kcv.encoded
|
282
|
+
st.kcvconfig = kkey.encoded
|
283
|
+
st.layer = payload
|
284
|
+
st.encoded
|
285
|
+
|
286
|
+
end
|
287
|
+
|
288
|
+
# Decrypt the in-memory protected key for operational
|
289
|
+
def mem_unseal(env)
|
290
|
+
|
291
|
+
begin
|
292
|
+
|
293
|
+
sti = BinStruct.instance.struct_from_bin(env)
|
294
|
+
|
295
|
+
payload = sti.layer
|
296
|
+
|
297
|
+
loop do
|
298
|
+
|
299
|
+
st = BinStruct.instance.struct_from_bin(payload)
|
300
|
+
|
301
|
+
break if st.nil?
|
302
|
+
|
303
|
+
key = CcipherFactory::SymKey.from_encoded(st.material)
|
304
|
+
#logger.debug "Unseal found : #{key.inspect}"
|
305
|
+
|
306
|
+
encData = st.payload
|
307
|
+
|
308
|
+
dec = CcipherFactory::SymKeyCipher.att_decryptor
|
309
|
+
|
310
|
+
membuf = MemBuf.new
|
311
|
+
dec.output(membuf)
|
312
|
+
|
313
|
+
dec.key = key
|
314
|
+
dec.att_decrypt_init
|
315
|
+
dec.att_decrypt_update(encData)
|
316
|
+
dec.att_decrypt_final
|
317
|
+
|
318
|
+
payload = membuf.bytes.clone
|
319
|
+
membuf.dispose
|
320
|
+
|
321
|
+
#logger.debug "Decrypted payload : #{payload.inspect}"
|
322
|
+
|
323
|
+
end
|
324
|
+
rescue Binenc::BinencDecodingError => ex
|
325
|
+
rescue Binenc::BinencEngineException => ex
|
326
|
+
#STDERR.puts ex.message
|
327
|
+
end
|
328
|
+
|
329
|
+
#begin
|
330
|
+
# dkey = CcipherFactory::SymKey.from_encoded(payload)
|
331
|
+
#rescue Binenc::BinencDecodingError => ex
|
332
|
+
payload
|
333
|
+
#end
|
334
|
+
|
335
|
+
end
|
336
|
+
|
337
|
+
def generateKeyID(key)
|
338
|
+
|
339
|
+
if @keyID.nil?
|
340
|
+
|
341
|
+
if key.is_a?(CcipherFactory::SymKey)
|
342
|
+
sk = key
|
343
|
+
else
|
344
|
+
sk = CcipherFactory::SymKeyGenerator.derive(:aes, 256) do |k|
|
345
|
+
case k
|
346
|
+
when :password
|
347
|
+
key
|
348
|
+
when :kdf
|
349
|
+
:scrypt
|
350
|
+
when :kdf_scrypt_cost
|
351
|
+
65536
|
352
|
+
when :kdf_scrypt_parallel
|
353
|
+
1
|
354
|
+
when :kdf_scrypt_blocksize
|
355
|
+
8
|
356
|
+
when :kdf_scrypt_salt
|
357
|
+
@dataConv.from_hex("FEDCBA0123456789")
|
358
|
+
when :kdf_scrypt_digestAlgo
|
359
|
+
:sha3_256
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
kcv = CcipherFactory::KCV.new
|
365
|
+
kcv.key = sk
|
366
|
+
kcv.nonce = "8"*32
|
367
|
+
kcvBin = kcv.encoded do |k|
|
368
|
+
case k
|
369
|
+
when :kcv_cipher_iv
|
370
|
+
# given key (sk) is AES key with GCM mode (default if mode not given)
|
371
|
+
# therefore the IV size has to be 12
|
372
|
+
# Other algo this must be adjusted accordingly
|
373
|
+
"1A2B3C4D5E6F"
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
@keyID = @dataConv.to_hex(kcvBin)
|
378
|
+
end
|
379
|
+
|
380
|
+
@keyID
|
381
|
+
|
382
|
+
end
|
383
|
+
|
384
|
+
|
385
|
+
def logger
|
386
|
+
if @logger.nil?
|
387
|
+
@logger = TeLogger::Tlogger.new
|
388
|
+
@logger.tag = :mem_key
|
389
|
+
end
|
390
|
+
@logger
|
391
|
+
end
|
392
|
+
|
393
|
+
end
|
394
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
|
2
|
+
require_relative 'bin_struct'
|
3
|
+
|
4
|
+
require_relative 'mem_key'
|
5
|
+
|
6
|
+
module CcipherBox
|
7
|
+
|
8
|
+
# Collection of crypto keys in a vault to be used by application.
|
9
|
+
# Application can register a key that tie with a name here
|
10
|
+
# and later use the name to encrypt a data
|
11
|
+
# This only store keys that will be kept in memory
|
12
|
+
# Not meant to be persistance
|
13
|
+
class MemVault
|
14
|
+
include TR::CondUtils
|
15
|
+
|
16
|
+
class MemVaultException < Exception; end
|
17
|
+
|
18
|
+
def initialize(ringName)
|
19
|
+
@ringName = ringName
|
20
|
+
end
|
21
|
+
|
22
|
+
def register(name, key)
|
23
|
+
@dataConv = Ccrypto::UtilFactory.instance(:data_conversion)
|
24
|
+
vault[name] = MemKey.new(@ringName, key, name)
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def deregister(name)
|
29
|
+
vault.delete(name)
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def is_registered?(name)
|
34
|
+
vault.keys.include?(name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def encrypt(name, data, &block)
|
38
|
+
key = vault[name]
|
39
|
+
key.encrypt(data, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
def decrypt(cipher)
|
43
|
+
keyID = BinStruct.instance.struct_fields_from_bin(cipher, 2)[0]
|
44
|
+
keyID = MemKey.to_KeyID(keyID)
|
45
|
+
|
46
|
+
foundKey = nil
|
47
|
+
vault.values.each do |k|
|
48
|
+
if k.keyID == keyID
|
49
|
+
foundKey = k
|
50
|
+
break
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
if not_empty?(foundKey)
|
55
|
+
logger.debug "Found decryption key with label #{vault.invert[foundKey]}"
|
56
|
+
foundKey.decrypt(cipher)
|
57
|
+
else
|
58
|
+
raise KeyNotRegistered, "Encryption key for this cipher not registered (KeyID : #{keyID})"
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
def derive(name)
|
64
|
+
vault[name].derive
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_key(name)
|
68
|
+
vault[name]
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
# internal structure to bind the application given name
|
73
|
+
# to a key.
|
74
|
+
# This allow application to select which key to be used for
|
75
|
+
# data protection
|
76
|
+
def vault
|
77
|
+
if @vault.nil?
|
78
|
+
@vault = { }
|
79
|
+
end
|
80
|
+
@vault
|
81
|
+
end
|
82
|
+
|
83
|
+
def logger
|
84
|
+
if @logger.nil?
|
85
|
+
@logger = TeLogger::Tlogger.new
|
86
|
+
@logger.tag = :mem_vault
|
87
|
+
end
|
88
|
+
@logger
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|