lenc 1.0.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.
@@ -0,0 +1,377 @@
1
+ require 'test/unit'
2
+
3
+ require_relative '../lib/lenc/tools.rb'
4
+ req('repo lencrypt')
5
+
6
+
7
+ #SINGLETEST = "test_200_recover_with_incorrect_password"
8
+ if defined? SINGLETEST
9
+ if main?(__FILE__)
10
+ ARGV.concat("-n #{SINGLETEST}".split)
11
+ end
12
+ end
13
+
14
+ class RepoTest < MyTestSuite
15
+
16
+ include LEnc
17
+
18
+ # Make a directory, if it doesn't already exist
19
+ def mkdir(name)
20
+ if !File.directory?(name)
21
+ Dir::mkdir(name)
22
+ end
23
+ end
24
+
25
+ def suite_setup
26
+ # pr("\n\n>>>> RepoTest setup\n\n")
27
+
28
+ # Make current directory = the one containing this script
29
+ main?(__FILE__)
30
+
31
+ @@testDir = "__temp_dirs__"
32
+ mkdir(@@testDir)
33
+
34
+ @@sourceDir = File.join(@@testDir,"__source__")
35
+ @@encryptDir = File.join(@@testDir,"__encrypted__")
36
+ @@recoverDir = File.join(@@testDir,"__recovered__")
37
+ @@repoFile = File.join(@@sourceDir,Repo::LENC_REPO_FILENAME)
38
+ @@key = "onefishtwofishredfishbluefish"
39
+ @@sampleFile = "demeter"
40
+
41
+ if !File.directory?(@@sourceDir)
42
+ create_source_tree()
43
+ end
44
+
45
+ clean()
46
+
47
+ # Construct a list of the source subdirectories, since some of them have
48
+ # unicode filenames and OSX changes them on us.
49
+ @@sourceDirs = []
50
+ getSourceDirList(@@sourceDirs, @@sourceDir)
51
+ end
52
+
53
+
54
+ def getSourceDirList(lst, dr)
55
+ dir_entries(dr).each do |f|
56
+ child = File.join(dr,f)
57
+ if File.directory? child
58
+ lst.push child
59
+ getSourceDirList(lst, child)
60
+ end
61
+ end
62
+ end
63
+
64
+
65
+ # Delete .lenc file from source directory,
66
+ # and delete the encryption and recovery directories
67
+ def clean
68
+ # pr("clean, repoFile=%s exists=%s\n",@@repoFile,File.file?(@@repoFile))
69
+ remove_file_or_dir(@@repoFile)
70
+ remove_file_or_dir(@@encryptDir)
71
+ remove_file_or_dir(@@recoverDir)
72
+ # remove_file_or_dir(bogusSourceFile())
73
+ end
74
+
75
+
76
+ def suite_teardown
77
+ # pr("\n\n<<<< RepoTest teardown\n\n")
78
+
79
+ if false
80
+ warn("always removing source dir")
81
+
82
+ if @@sourceDir.end_with?("__source__")
83
+ pr("removing...\n")
84
+ remove_file_or_dir(@@sourceDir)
85
+ end
86
+ end
87
+ end
88
+
89
+ def method_setup
90
+ # pr("\n\n\n")
91
+ end
92
+
93
+ def method_teardown
94
+ # pr("\n\n\n")
95
+ end
96
+
97
+
98
+
99
+ def makeFile(pth, lngth=3)
100
+ remove_file_or_dir(pth)
101
+
102
+ srand(1965)
103
+
104
+ File.open(pth, 'wb') do |f|
105
+ j = 0
106
+ while j < lngth
107
+ if (j+1) % 40 == 0
108
+ f.write("\n")
109
+ else
110
+ f.write((rand(26)+65).chr)
111
+ end
112
+ j += 1
113
+ end
114
+ end
115
+ end
116
+
117
+ def unicode(c)
118
+ s = [c].pack("U*")
119
+ s
120
+ end
121
+
122
+ def create_source_tree
123
+ # Create a set of directories and files within the repo's source directory.
124
+
125
+ # Specify a script as a sequence of names, each followed by
126
+ # | : file
127
+ # / : directory
128
+ # ^ : parent directory (name should be empty)
129
+
130
+ # Some names have unicode characters for test purposes.
131
+
132
+ scr =<<SCR
133
+
134
+ mars| sol| luna| aphrodite | apollo | ares | artemis | hades | demeter |
135
+ alpha/
136
+ earth| venus| symphony 1 | symphony 2 | hephaestus | hera | hermes | hestia |
137
+ delt#{unicode(0xe5)} /
138
+ jupiter| saturn| poseidon | zeus |
139
+ ^
140
+ ^
141
+ bet#{unicode(0xe1)} gamma|
142
+ uranus|
143
+ neptune|
144
+ pluto|
145
+ SCR
146
+
147
+ # Script of predetermined file lengths:
148
+ cs = RepoInternal::CHUNK_SIZE_ENCR
149
+ hs = RepoInternal::CHUNK_HEADER_SIZE
150
+ flens = [0, cs - 1, cs, cs + 1, cs + hs - 1, cs + hs, cs + hs + 1,
151
+ (2 * cs) - 1, 2 * cs, 2 * cs + 1, 2 * (cs + hs) - 1, 2 * (cs + hs), 2 * (cs + hs) + 1]
152
+ fNum = 0
153
+
154
+ srand(1983)
155
+
156
+ dr = @@sourceDir
157
+ mkdir(dr)
158
+
159
+ dirStack = []
160
+ k = 0
161
+ k0 = k
162
+ while k < scr.size
163
+ c = scr[k]
164
+ k += 1
165
+ next if !"|/^".index(c)
166
+
167
+ nm = scr[k0...k-1].strip
168
+
169
+ k0 = k
170
+
171
+ if c == '|'
172
+ # create a file; use our predetermined lengths, if we still have some;
173
+ # otherwise, choose a random file length
174
+ if fNum < flens.size
175
+ j = flens[fNum]
176
+ else
177
+ j = (rand() * rand() * 130000).to_i + 3
178
+ end
179
+ fNum += 1
180
+ makeFile(File.join(dr, nm), j)
181
+ elsif c == '/'
182
+ dirStack.push(dr)
183
+ dr = File.join(dr,nm)
184
+ mkdir(dr)
185
+ elsif c == '^'
186
+ dr = dirStack.pop
187
+ end
188
+ end
189
+
190
+ # Store some .lencignore files
191
+ dr = @@sourceDir
192
+ writeIgnore(dr, "s*")
193
+
194
+ dr = File.join(dr, "alpha")
195
+ writeIgnore(dr, "hera")
196
+
197
+ dr = File.join(dr, "delt#{unicode(0xe5)}")
198
+ writeIgnore(dr, "!s*")
199
+ end
200
+
201
+
202
+ def writeIgnore(dr, contents)
203
+ pth = File.join(dr,Repo::IGNOREFILENAME)
204
+ File.open(pth,'w') do |f|
205
+ f.write("# This is a .lencignore file\n#{contents}\n\n### end ###\n")
206
+ end
207
+ end
208
+
209
+ def ex(args)
210
+ if args.is_a? String
211
+ args = args.split
212
+ end
213
+ args.concat(["-w", @@sourceDir, "-q"])
214
+ LEncApp.new().run(args)
215
+ end
216
+
217
+ # def bogusSourceFile
218
+ # return File.join(@@sourceDir, "_#bogusfile.txt")
219
+ # end
220
+
221
+ def build_repo_obj(silent = true)
222
+ v = silent ? -1 : 0
223
+ rp = Repo.new(:verbosity => v)
224
+ rp
225
+ end
226
+
227
+ def create_repo
228
+ clean
229
+ rp = build_repo_obj
230
+ rp.create(@@sourceDir,@@key,@@encryptDir)
231
+ rp.close
232
+ rp
233
+ end
234
+
235
+ def update_repo(silent = true)
236
+ rp = build_repo_obj(silent)
237
+ rp.open(@@sourceDir)
238
+ rp.perform_update
239
+ rp.close
240
+ end
241
+
242
+ def do_recover
243
+ rp = build_repo_obj
244
+ rp.perform_recovery(@@key, @@encryptDir,@@recoverDir)
245
+ rp.close
246
+ end
247
+
248
+ # --------------- tests --------------------------
249
+
250
+
251
+
252
+ def test_050_AES_encryption
253
+ req 'aes'
254
+
255
+ f = RepoInternal::MyAES.new(true, @@key, "42")
256
+
257
+ originalText = ""
258
+ while originalText.size < 100000
259
+ 64.times do |i|
260
+ ch = ((i % 26) + 65).chr
261
+ originalText << ch * 17
262
+ end
263
+ end
264
+
265
+ enc = ""
266
+ s = originalText.size
267
+ n = 0
268
+ while n < s
269
+ c = [60,s-n].min
270
+ f.add(originalText[n...n+c])
271
+ n += c
272
+ enc << f.flush()
273
+ end
274
+
275
+ f.finish()
276
+ enc << f.flush
277
+
278
+ require 'digest/md5'
279
+
280
+ digest = Digest::MD5.hexdigest(enc)
281
+ assert(digest.to_s == '284740fbf3355951e9e76fb43fda985c')
282
+
283
+ f = RepoInternal::MyAES.new(false, @@key)
284
+ dec = ""
285
+ n = 0
286
+ s = enc.size
287
+ while n < s
288
+ c = [60,s-n].min
289
+ f.add(enc[n...n+c])
290
+ n += c
291
+ dec << f.flush
292
+ end
293
+
294
+ f.finish()
295
+ dec << f.flush
296
+ assert(originalText == dec)
297
+ end
298
+
299
+
300
+ # Create repo using Repo class
301
+ def test_100_create_repo
302
+ create_repo
303
+ assert(File.file?(@@repoFile))
304
+ end
305
+
306
+ # Create repo using lencrypt program
307
+ def test_101_create_repo
308
+ clean
309
+ a = "-i #{@@key} #{@@encryptDir}"
310
+ ex(a)
311
+ end
312
+
313
+ def test_101_update_repo_with_verify
314
+ clean
315
+ ex("-i #{@@key} #{@@encryptDir}")
316
+ rp = build_repo_obj
317
+ rp.open(@@sourceDir)
318
+ rp.perform_update(true)
319
+ rp.close
320
+ end
321
+
322
+ def test_110_open_repo_using_Repo_class
323
+ # (assumes repo exists at this point; preceding test creates it)
324
+ rp = build_repo_obj
325
+ rp.open(@@sourceDir)
326
+ end
327
+
328
+ def test_120_update_repo_using_Repo_class
329
+ update_repo
330
+ assert(File.directory?(@@encryptDir))
331
+ end
332
+
333
+ def test_121_update_repo_with_lencrypt_program
334
+ remove_file_or_dir(@@encryptDir)
335
+ ex("")
336
+ assert(File.directory?(@@encryptDir))
337
+ end
338
+
339
+ def test_125_recover_repository
340
+ remove_file_or_dir(@@recoverDir)
341
+ do_recover
342
+ assert(File.directory?(@@recoverDir))
343
+ end
344
+
345
+ def test_130_update_when_repository_not_found
346
+ assert_raise(RepoNotFoundException) do
347
+ clean
348
+ rp = build_repo_obj
349
+ rp.open(@@sourceDir)
350
+ end
351
+ end
352
+
353
+ def test_200_recover_with_incorrect_password
354
+ create_repo
355
+ ex("") # updates repo
356
+ assert_raise(DecryptionError) do
357
+ remove_file_or_dir(@@recoverDir)
358
+ rp = build_repo_obj()
359
+ rp.perform_recovery("thisisthewrongkey_______", @@encryptDir,@@recoverDir)
360
+ rp.close
361
+ end
362
+ end
363
+
364
+ # def test_300_source_contains_encrypted_filename
365
+ # create_repo
366
+ # update_repo
367
+ #
368
+ # makeFile(bogusSourceFile())
369
+ # assert_raise(UpdateException) do
370
+ # update_repo
371
+ # end
372
+ # remove_file_or_dir(bogusSourceFile())
373
+ # end
374
+
375
+
376
+
377
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lenc
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jeff Sember
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-03-19 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: "Encrypts a set of local files, and copies the encrypted versions to
14
+ a repository, \nwhich may be located within a free cloud service (Dropbox, Google
15
+ Drive, Microsoft SkyDrive). \nThe program uses the trusted AES 256-bit encryption
16
+ standard. \nAll files are encrypted on the user machine; \npasswords and unencrypted
17
+ files are never seen by the cloud service. \n"
18
+ email: jpsember@gmail.com
19
+ executables:
20
+ - lencrypt
21
+ extensions: []
22
+ extra_rdoc_files: []
23
+ files:
24
+ - lib/lenc.rb
25
+ - lib/lenc/aes.rb
26
+ - lib/lenc/config_file.rb
27
+ - lib/lenc/lencrypt.rb
28
+ - lib/lenc/repo.rb
29
+ - lib/lenc/tools.rb
30
+ - lib/lenc/trollop.rb
31
+ - bin/lencrypt
32
+ - CHANGELOG.txt
33
+ - README.txt
34
+ - test/test.rb
35
+ homepage: http://www.cs.ubc.ca/~jpsember/
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.0.2
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: Maintains an encrypted repository of a set of files for secure cloud storage.
59
+ test_files:
60
+ - test/test.rb
61
+ has_rdoc: