rubyment 0.5.25438564 → 0.5.25471659
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rubyment.rb +416 -12
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 048e8eae5ac557122a9a5e74a3019c29768cf1c5
|
4
|
+
data.tar.gz: 7ad419465aab2718f75be44c706f435a326313ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 218c7e8b2b10503986b12b7a0d0b0411f4dfb9c910614b8535e9608241884bbe57efbd0cb558347c057d4bf3580a6dd6e1fcc719ed0d8288bd84f86eda17deba
|
7
|
+
data.tar.gz: 398b1b171d911c3f79e9040e05e10429f34265690b3749acd44ec32aaa757ce380dfd6ff768c872599d6a8bff2af1804a7ed6ad5ee600b0382bdbc138a994aa8
|
data/lib/rubyment.rb
CHANGED
@@ -67,8 +67,9 @@ class Rubyment
|
|
67
67
|
:home_dir => Dir.home,
|
68
68
|
:system_user => ENV['USER'] || ENV['USERNAME'],
|
69
69
|
:system_user_is_super => ENV['USER'] == "root", # changed plan: platform indenpend.
|
70
|
-
:static_separator_key => "
|
71
|
-
:static_end_key => "
|
70
|
+
:static_separator_key => "strings_having_this" + "_string_not_guaranteed_to_work",
|
71
|
+
:static_end_key => "strings_havinng_this_string" + "_also_not_guaranteed_to_work",
|
72
|
+
:static_separator_key_per_execution => "strings_having_this" + "_string_not_guaranteed_to_work" + (Proc.new {}).to_s + Time.now.to_s,
|
72
73
|
}
|
73
74
|
@memory.update memory.to_h
|
74
75
|
invoke @memory[:invoke].to_a
|
@@ -138,6 +139,11 @@ class Rubyment
|
|
138
139
|
end
|
139
140
|
|
140
141
|
|
142
|
+
# returns a string having the current backtrace, for debugging.
|
143
|
+
def backtrace
|
144
|
+
Thread.current.backtrace.join("\n")
|
145
|
+
end
|
146
|
+
|
141
147
|
# returns a Class object out of class_name (or itself if it is already
|
142
148
|
# a class)
|
143
149
|
def to_class args=ARGV
|
@@ -236,6 +242,24 @@ class Rubyment
|
|
236
242
|
end
|
237
243
|
|
238
244
|
|
245
|
+
# returns the contents of file.
|
246
|
+
# file can be a url, if 'open-uri' is available.
|
247
|
+
# can throw exceptions
|
248
|
+
def file_or_url_contents file
|
249
|
+
contents = nil
|
250
|
+
stderr = @memory[:stderr]
|
251
|
+
(require 'open-uri') && open_uri = true
|
252
|
+
require 'fileutils'
|
253
|
+
file = file.to_s
|
254
|
+
file_is_filename = true
|
255
|
+
open_uri && (
|
256
|
+
contents = open(file).read
|
257
|
+
) || (
|
258
|
+
contents = File.read
|
259
|
+
)
|
260
|
+
contents
|
261
|
+
end
|
262
|
+
|
239
263
|
# returns the contents of file (or empty, or a default
|
240
264
|
# if a second parameter is given).
|
241
265
|
# if file is a nonexisting filepath, or by any reason
|
@@ -278,6 +302,8 @@ class Rubyment
|
|
278
302
|
|
279
303
|
|
280
304
|
# opens an echoing prompt, if arg1 is nil or empty
|
305
|
+
# not prepared to work with binary input (which can contain \0)
|
306
|
+
# closed for extensions
|
281
307
|
# args:
|
282
308
|
# [ arg1 (String or nil)]
|
283
309
|
def input_single_line args=ARGV
|
@@ -289,6 +315,8 @@ class Rubyment
|
|
289
315
|
|
290
316
|
|
291
317
|
# opens a non-echoing prompt, if arg1 is nil or empty
|
318
|
+
# not prepared to work with binary input (which can contain \0)
|
319
|
+
# closed for extensions
|
292
320
|
# args:
|
293
321
|
# [ arg1 (String or nil)]
|
294
322
|
def input_single_line_non_echo args=ARGV
|
@@ -301,6 +329,8 @@ class Rubyment
|
|
301
329
|
|
302
330
|
|
303
331
|
# opens an echoing multiline prompt, if arg1 is nil or empty
|
332
|
+
# not prepared to work with binary input (which can contain \0)
|
333
|
+
# closed for extensions
|
304
334
|
# args:
|
305
335
|
# [ arg1 (String or nil)]
|
306
336
|
def input_multi_line args=ARGV
|
@@ -312,6 +342,8 @@ class Rubyment
|
|
312
342
|
|
313
343
|
|
314
344
|
# opens a non-echoing multiline prompt, if arg1 is nil or empty
|
345
|
+
# not prepared to work with binary input (which can contain \0)
|
346
|
+
# closed for extensions
|
315
347
|
# args:
|
316
348
|
# [ arg1 (String or nil)]
|
317
349
|
def input_multi_line_non_echo args=ARGV
|
@@ -323,6 +355,62 @@ class Rubyment
|
|
323
355
|
end
|
324
356
|
|
325
357
|
|
358
|
+
# opens an echoing prompt, if arg1 is nil or empty
|
359
|
+
# better prepared to work with binary input
|
360
|
+
# args:
|
361
|
+
# [ arg1 (String or nil)]
|
362
|
+
def binary_input_single_line args=ARGV
|
363
|
+
stderr = @memory[:stderr]
|
364
|
+
stdin = @memory[:stdin]
|
365
|
+
stderr.print "single line:"
|
366
|
+
static_separator_key_per_execution = @memory[:static_separator_key_per_execution]
|
367
|
+
args.shift.to_s.b.split(static_separator_key_per_execution).first || stdin.gets.chomp
|
368
|
+
end
|
369
|
+
|
370
|
+
|
371
|
+
# opens a non-echoing prompt, if arg1 is nil or empty
|
372
|
+
# better prepared to work with binary input (which can contain \0)
|
373
|
+
# args:
|
374
|
+
# [ arg1 (String or nil)]
|
375
|
+
def binary_input_single_line_non_echo args=ARGV
|
376
|
+
stderr = @memory[:stderr]
|
377
|
+
stdin = @memory[:stdin]
|
378
|
+
static_separator_key_per_execution = @memory[:static_separator_key_per_execution]
|
379
|
+
require "io/console"
|
380
|
+
stderr.print "non echo single line:"
|
381
|
+
args.shift.to_s.b.split(static_separator_key_per_execution).first || stdin.noecho{ stdin.gets}.chomp
|
382
|
+
end
|
383
|
+
|
384
|
+
|
385
|
+
# opens an echoing multiline prompt, if arg1 is nil or empty
|
386
|
+
# better prepared to work with binary input
|
387
|
+
# args:
|
388
|
+
# [ arg1 (String or nil)]
|
389
|
+
def binary_input_multi_line args=ARGV
|
390
|
+
stderr = @memory[:stderr]
|
391
|
+
stdin = @memory[:stdin]
|
392
|
+
static_separator_key_per_execution = @memory[:static_separator_key_per_execution]
|
393
|
+
stderr.print "multiline[enter + control-D to stop]:"
|
394
|
+
args.shift.to_s.b.split(static_separator_key_per_execution).first || stdin.readlines.join
|
395
|
+
end
|
396
|
+
|
397
|
+
|
398
|
+
# opens a non-echoing multiline prompt, if arg1 is nil or empty
|
399
|
+
# better prepared to work with binary input (which can contain \0)
|
400
|
+
# args:
|
401
|
+
# [ arg1 (String or nil)]
|
402
|
+
def binary_input_multi_line_non_echo args=ARGV
|
403
|
+
stderr = @memory[:stderr]
|
404
|
+
stdin = @memory[:stdin]
|
405
|
+
static_separator_key_per_execution = @memory[:static_separator_key_per_execution]
|
406
|
+
require "io/console"
|
407
|
+
# puts backtrace
|
408
|
+
# p args.map {|e| e.to_s[0..15] }
|
409
|
+
stderr.print "multiline[enter + control-D to stop]:"
|
410
|
+
args.shift.to_s.b.split(static_separator_key_per_execution).first || stdin.noecho{ stdin.readlines}.join.chomp
|
411
|
+
end
|
412
|
+
|
413
|
+
|
326
414
|
def input_shift_or_empty_string args=ARGV, default = ''
|
327
415
|
args.shift || default
|
328
416
|
end
|
@@ -440,6 +528,7 @@ class Rubyment
|
|
440
528
|
# +ending+:: [nil] deprecated
|
441
529
|
# +base64_salt+:: [String, nil] #generate_pbkdf2_key salt encoded with Base64
|
442
530
|
# +base64_iter+:: [String, nil] #generate_pbkdf2_key iterations encoded with Base64
|
531
|
+
# +data_not_base64+:: [true, false, nil] don't return base64 data -- the same +data_not_base64+ given for enc should be used.
|
443
532
|
#
|
444
533
|
# @return [String] decoded data
|
445
534
|
def dec args=ARGV
|
@@ -447,7 +536,7 @@ class Rubyment
|
|
447
536
|
require 'base64'
|
448
537
|
memory = @memory
|
449
538
|
static_end_key = memory[:static_end_key]
|
450
|
-
password, base64_iv, base64_encrypted, ending, base64_salt, base64_iter = args
|
539
|
+
password, base64_iv, base64_encrypted, ending, base64_salt, base64_iter, data_not_base64 = args
|
451
540
|
salt = Base64.decode64 base64_salt
|
452
541
|
iter = Base64.decode64 base64_iter
|
453
542
|
ending = ending.to_s.split("\0").first || static_end_key
|
@@ -461,7 +550,8 @@ class Rubyment
|
|
461
550
|
|
462
551
|
decipher.key = key || (Digest::SHA256.hexdigest password)
|
463
552
|
decipher.iv = Base64.decode64 base64_iv
|
464
|
-
|
553
|
+
base64_plain = decipher.update(Base64.decode64 base64_encrypted) + decipher.final
|
554
|
+
plain = data_not_base64 && (Base64.decode64 base64_plain) || base64_plain
|
465
555
|
# split is not the ideal, if ever ending is duplicated it won't
|
466
556
|
# work. also may be innefficient.
|
467
557
|
(plain.split ending).first
|
@@ -550,6 +640,8 @@ class Rubyment
|
|
550
640
|
|
551
641
|
# encode data into aes-128-cbc cipher protected by a key generated
|
552
642
|
# by #generate_pbkdf2_key, using given +password+, +salt+, +iter+
|
643
|
+
# By default, may not work with binary data. Set +data_not_base64+ to
|
644
|
+
# true (or give data already as base64) to make it work.
|
553
645
|
#
|
554
646
|
# @param [Array] args, an +Array+ whose elements are expected to be:
|
555
647
|
# +password+:: [String, nil] password to be used to encryption.
|
@@ -557,6 +649,7 @@ class Rubyment
|
|
557
649
|
# +ending+:: [nil] deprecated
|
558
650
|
# +salt+:: [String, nil] #generate_pbkdf2_key salt argument
|
559
651
|
# +iter+:: [String, nil] #generate_pbkdf2_key iterations argument
|
652
|
+
# +data_not_base64+:: [true, false, nil] data not yet in base64
|
560
653
|
#
|
561
654
|
# @return @param [Array] an +Array+ whose elements are expected to be:
|
562
655
|
# +base64_encrypted+:: [String, nil] ciphered data (without metadata) encoded with Base64
|
@@ -570,7 +663,7 @@ class Rubyment
|
|
570
663
|
require 'base64'
|
571
664
|
memory = @memory
|
572
665
|
static_end_key = memory[:static_end_key]
|
573
|
-
password, data, ending, salt, iter = args
|
666
|
+
password, data, ending, salt, iter, data_not_base64 = args
|
574
667
|
ending ||= static_end_key
|
575
668
|
key, password, salt, iter = (
|
576
669
|
generate_pbkdf2_key [password, salt, iter]
|
@@ -581,7 +674,8 @@ class Rubyment
|
|
581
674
|
|
582
675
|
cipher.key = key || (Digest::SHA256.hexdigest password)
|
583
676
|
iv = cipher.random_iv
|
584
|
-
|
677
|
+
base64_data = data_not_base64 && (Base64.encode64 data) || data
|
678
|
+
encrypted = cipher.update(base64_data + ending) + cipher.final
|
585
679
|
|
586
680
|
base64_iv = Base64.encode64 iv
|
587
681
|
base64_encrypted = Base64.encode64 encrypted
|
@@ -776,15 +870,16 @@ class Rubyment
|
|
776
870
|
# echo) from @memory[:stdin], which defaults to STDIN
|
777
871
|
# * +password+ [String, nil] password to be used to encryption.
|
778
872
|
# If empty or nil, read (without echo) from @memory[:stdin], which defaults to STDIN
|
873
|
+
# +data_not_base64+:: [true, false, nil] don't return base64 data -- the same +data_not_base64+ given for enc should be used.
|
779
874
|
#
|
780
875
|
# @return [TrueClass, FalseClass] depending on whether test succeeds.
|
781
876
|
def dec_interactive args=ARGV
|
782
877
|
stderr = @memory[:stderr]
|
783
|
-
iv, encrypted, base64_salt, base64_iter, password = args
|
878
|
+
iv, encrypted, base64_salt, base64_iter, password, data_not_base64 = args
|
784
879
|
stderr.print "[password]"
|
785
880
|
password = (input_single_line_non_echo [password])
|
786
881
|
stderr.puts
|
787
|
-
dec [password, iv, encrypted, nil, base64_salt, base64_iter]
|
882
|
+
dec [password, iv, encrypted, nil, base64_salt, base64_iter, data_not_base64]
|
788
883
|
end
|
789
884
|
|
790
885
|
|
@@ -839,7 +934,7 @@ class Rubyment
|
|
839
934
|
stderr.puts "# programmatically:"
|
840
935
|
stderr.puts "dec " + dec_args.to_s
|
841
936
|
stderr.puts "# shell: "
|
842
|
-
stderr.puts "
|
937
|
+
stderr.puts "#{$0} invoke_double p dec " + (output_array_to_shell dec_args).to_s
|
843
938
|
data_plain = dec [password, base64_iv, base64_encrypted, nil, base64_salt, base64_iter]
|
844
939
|
judgement =
|
845
940
|
[
|
@@ -848,18 +943,60 @@ class Rubyment
|
|
848
943
|
end
|
849
944
|
|
850
945
|
|
946
|
+
# output encrypted data (and data required to
|
947
|
+
# decrypt) into encrypted_base64_filename
|
948
|
+
def output_enc_file args=ARGV
|
949
|
+
stderr = @memory[:stderr]
|
950
|
+
require 'json'
|
951
|
+
require 'base64'
|
952
|
+
base64_iv, base64_encrypted, base64_salt, base64_iter, encrypted_base64_filename = args
|
953
|
+
metadata = {
|
954
|
+
"metadata" => "Metadata",
|
955
|
+
"base64_iv" => base64_iv,
|
956
|
+
"base64_encrypted" => base64_encrypted,
|
957
|
+
"base64_salt" => base64_salt,
|
958
|
+
"base64_iter" => base64_iter,
|
959
|
+
}
|
960
|
+
base64_json_serialized_data = Base64.encode64 JSON.pretty_generate metadata
|
961
|
+
File.write encrypted_base64_filename, base64_json_serialized_data
|
962
|
+
stderr.puts "# File written: \n# #{encrypted_base64_filename}"
|
963
|
+
end
|
964
|
+
|
965
|
+
|
966
|
+
# output encrypted data (and data required to
|
967
|
+
# decrypt) into encrypted_base64_filename
|
968
|
+
def output_dec_file args=ARGV
|
969
|
+
stderr = @memory[:stderr]
|
970
|
+
require 'json'
|
971
|
+
require 'base64'
|
972
|
+
enc_filename_or_url, out_filename, password, data_is_base64 = args
|
973
|
+
base64_json_serialized_data = file_or_url_contents enc_filename_or_url
|
974
|
+
|
975
|
+
metadata = JSON.parse Base64.decode64 base64_json_serialized_data
|
976
|
+
base64_iv = metadata["base64_iv"]
|
977
|
+
base64_encrypted = metadata["base64_encrypted"]
|
978
|
+
base64_salt = metadata["base64_salt"]
|
979
|
+
base64_iter = metadata["base64_iter"]
|
980
|
+
base64_key = metadata["base64_key" ]
|
981
|
+
ending = nil
|
982
|
+
pw_plain = binary_dec [password, base64_iv, base64_encrypted, ending, base64_salt, base64_iter, data_is_base64]
|
983
|
+
File.write out_filename, pw_plain
|
984
|
+
stderr.puts "# File written: \n# #{out_filename}"
|
985
|
+
end
|
986
|
+
|
987
|
+
|
851
988
|
# test for enc and dec_interactive.
|
852
989
|
# good idea is to use this function once with the desired
|
853
990
|
# data, password, and use the stderr output
|
854
991
|
def test__enc_dec_interactive args=ARGV
|
855
992
|
stderr = @memory[:stderr]
|
856
|
-
data, password = args
|
993
|
+
data, password, encrypted_base64_filename, data_not_base64 = args
|
857
994
|
stderr.print "[data]"
|
858
995
|
data = input_multi_line_non_echo [data]
|
859
996
|
stderr.print "[password]"
|
860
997
|
password = input_single_line_non_echo [password]
|
861
998
|
stderr.puts
|
862
|
-
base64_encrypted, base64_iv, base64_salt, base64_iter, base64_key = enc [password, data]
|
999
|
+
base64_encrypted, base64_iv, base64_salt, base64_iter, base64_key = enc [password, data, nil, nil, nil, data_not_base64 ]
|
863
1000
|
# the output is supposed to be safe to store,
|
864
1001
|
# so password is not placed in from dec_interactive_args:
|
865
1002
|
dec_interactive_args = [base64_iv, base64_encrypted, base64_salt, base64_iter]
|
@@ -869,7 +1006,8 @@ class Rubyment
|
|
869
1006
|
stderr.puts "#{$0} invoke_double puts dec_interactive " + (output_array_to_shell dec_interactive_args).to_s
|
870
1007
|
stderr.puts "#or shell var:"
|
871
1008
|
stderr.puts "my_secret=$(#{$0} invoke_double puts dec_interactive " + (output_array_to_shell dec_interactive_args).to_s + ")\necho $my_secret\nunset mysecret"
|
872
|
-
|
1009
|
+
encrypted_base64_filename && output_enc_file(dec_interactive_args + [encrypted_base64_filename])
|
1010
|
+
data_plain = dec_interactive(dec_interactive_args + [password, data_not_base64])
|
873
1011
|
judgement =
|
874
1012
|
[
|
875
1013
|
[data, data_plain, "data"]
|
@@ -877,6 +1015,272 @@ class Rubyment
|
|
877
1015
|
end
|
878
1016
|
|
879
1017
|
|
1018
|
+
# similar to
|
1019
|
+
# test__enc_dec_interactive,
|
1020
|
+
# just that the data is ready from a file instead
|
1021
|
+
# note that there is an extra argument between
|
1022
|
+
# the args, the enc_out_filename.
|
1023
|
+
def test__enc_dec_file_interactive args=ARGV
|
1024
|
+
stderr = @memory[:stderr]
|
1025
|
+
filename_or_url, enc_out_filename, password, data_not_base64 = args
|
1026
|
+
stderr.print "[filename_or_url]"
|
1027
|
+
filename_or_url = input_multi_line_non_echo [filename_or_url]
|
1028
|
+
stderr.print "[output_filename_encrypted_data]"
|
1029
|
+
enc_out_filename = input_multi_line_non_echo [enc_out_filename ]
|
1030
|
+
data = file_or_url_contents filename_or_url
|
1031
|
+
test__enc_dec_interactive [ data, password, enc_out_filename, data_not_base64 ]
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
|
1035
|
+
# basically the reverse of test__enc_dec_file_interactive
|
1036
|
+
# planned improvements: still outputs to stdout
|
1037
|
+
def test__dec_file_interactive args=ARGV
|
1038
|
+
stderr = @memory[:stderr]
|
1039
|
+
enc_filename_or_url, out_filename, password, data_not_base64 = args
|
1040
|
+
stderr.print "[enc_filename_or_url]"
|
1041
|
+
enc_filename_or_url = input_multi_line_non_echo [enc_filename_or_url]
|
1042
|
+
stderr.print "[output_filename_plain_data]"
|
1043
|
+
out_filename = input_multi_line_non_echo [out_filename ]
|
1044
|
+
stderr.print "[password]"
|
1045
|
+
password = input_single_line_non_echo [password]
|
1046
|
+
data = file_or_url_contents enc_filename_or_url
|
1047
|
+
require 'json'
|
1048
|
+
require 'base64'
|
1049
|
+
base64_json_serialized_data = data
|
1050
|
+
metadata = JSON.parse Base64.decode64 base64_json_serialized_data
|
1051
|
+
base64_iv = metadata["base64_iv"]
|
1052
|
+
base64_encrypted = metadata["base64_encrypted"]
|
1053
|
+
base64_salt = metadata["base64_salt"]
|
1054
|
+
base64_iter = metadata["base64_iter"]
|
1055
|
+
base64_key = metadata["base64_key" ]
|
1056
|
+
ending = nil
|
1057
|
+
pw_plain = dec [password, base64_iv, base64_encrypted, ending, base64_salt, base64_iter, data_not_base64]
|
1058
|
+
shell_dec_output [pw_plain]
|
1059
|
+
end
|
1060
|
+
|
1061
|
+
|
1062
|
+
# encode data into aes-128-cbc cipher protected by a key generated
|
1063
|
+
# by #generate_pbkdf2_key, using given +password+, +salt+, +iter+
|
1064
|
+
# By default, must work with binary data. Set +data_is_base64+ to
|
1065
|
+
# true (or give data already as base64) to achieve the original
|
1066
|
+
# behavior of enc(), and avoid one encoding operation on data.
|
1067
|
+
#
|
1068
|
+
# @param [Array] args, an +Array+ whose elements are expected to be:
|
1069
|
+
# +password+:: [String, nil] password to be used to encryption.
|
1070
|
+
# +data+:: [String, nil] data to be encoded data
|
1071
|
+
# +ending+:: [nil] deprecated
|
1072
|
+
# +salt+:: [String, nil] #generate_pbkdf2_key salt argument
|
1073
|
+
# +iter+:: [String, nil] #generate_pbkdf2_key iterations argument
|
1074
|
+
# +data_is_base64+:: [true, false, nil] data already in base64
|
1075
|
+
#
|
1076
|
+
#
|
1077
|
+
# @return @param [Array] an +Array+ whose elements are expected to be:
|
1078
|
+
# +base64_encrypted+:: [String, nil] ciphered data (without metadata) encoded with Base64
|
1079
|
+
# +base64_iv+:: [String] initialization vectors encoded with Base64
|
1080
|
+
# +base64_salt+:: [String] #generate_pbkdf2_key salt encoded with Base64
|
1081
|
+
# +base64_iter+:: [String] #generate_pbkdf2_key iterations encoded with Base64
|
1082
|
+
# +base64_key+:: [String] #generate_pbkdf2_key return value
|
1083
|
+
#
|
1084
|
+
def binary_enc args=ARGV
|
1085
|
+
require 'openssl'
|
1086
|
+
require 'base64'
|
1087
|
+
memory = @memory
|
1088
|
+
static_end_key = memory[:static_end_key] + "_binary"
|
1089
|
+
password, data, ending, salt, iter, data_is_base64 = args
|
1090
|
+
ending ||= static_end_key
|
1091
|
+
key, password, salt, iter = (
|
1092
|
+
generate_pbkdf2_key [password, salt, iter]
|
1093
|
+
)|| [nil, password, salt, iter]
|
1094
|
+
|
1095
|
+
cipher = OpenSSL::Cipher.new('aes-128-cbc')
|
1096
|
+
cipher.encrypt
|
1097
|
+
|
1098
|
+
cipher.key = key || (Digest::SHA256.hexdigest password)
|
1099
|
+
iv = cipher.random_iv
|
1100
|
+
base64_data = data_is_base64 && (Base64.encode64 data) || data
|
1101
|
+
encrypted = cipher.update(base64_data + ending) + cipher.final
|
1102
|
+
|
1103
|
+
base64_iv = Base64.encode64 iv
|
1104
|
+
base64_encrypted = Base64.encode64 encrypted
|
1105
|
+
base64_salt = Base64.encode64 salt.to_s
|
1106
|
+
base64_iter = Base64.encode64 iter.to_s
|
1107
|
+
base64_key = Base64.encode64 key.to_s
|
1108
|
+
|
1109
|
+
[base64_encrypted, base64_iv, base64_salt, base64_iter, base64_key]
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
|
1113
|
+
# decipher the data encoded by binary_enc
|
1114
|
+
#
|
1115
|
+
# @param [Array] args, an +Array+ whose elements are expected to be:
|
1116
|
+
# +password+:: [String, nil] password to be used to encryption.
|
1117
|
+
# +base64_iv+:: [String, nil] initialization vectors encoded with Base64
|
1118
|
+
# +base64_encrypted+:: [String, nil] ciphered data (without metadata) encoded with Base64
|
1119
|
+
# +ending+:: [nil] deprecated
|
1120
|
+
# +base64_salt+:: [String, nil] #generate_pbkdf2_key salt encoded with Base64
|
1121
|
+
# +base64_iter+:: [String, nil] #generate_pbkdf2_key iterations encoded with Base64
|
1122
|
+
# +data_is_base64+:: [true, false, nil] return base64 data -- the same +data_is_base64+ given for enc should be used.
|
1123
|
+
#
|
1124
|
+
# @return [String] decoded data
|
1125
|
+
def binary_dec args=ARGV
|
1126
|
+
require 'openssl'
|
1127
|
+
require 'base64'
|
1128
|
+
memory = @memory
|
1129
|
+
static_end_key = memory[:static_end_key] + "_binary"
|
1130
|
+
password, base64_iv, base64_encrypted, ending, base64_salt, base64_iter, data_is_base64 = args
|
1131
|
+
salt = Base64.decode64 base64_salt
|
1132
|
+
iter = Base64.decode64 base64_iter
|
1133
|
+
# FIXME: don't split on \0
|
1134
|
+
ending = ending.to_s.split("\0").first || static_end_key
|
1135
|
+
key, password, salt, iter = (
|
1136
|
+
generate_pbkdf2_key [password, salt, iter]
|
1137
|
+
)|| [nil, password, salt, iter]
|
1138
|
+
|
1139
|
+
decipher = OpenSSL::Cipher.new('aes-128-cbc')
|
1140
|
+
decipher.decrypt
|
1141
|
+
decipher.padding = 0
|
1142
|
+
|
1143
|
+
decipher.key = key || (Digest::SHA256.hexdigest password)
|
1144
|
+
decipher.iv = Base64.decode64 base64_iv
|
1145
|
+
base64_plain = decipher.update(Base64.decode64 base64_encrypted) + decipher.final
|
1146
|
+
plain = data_is_base64 && (Base64.decode64 base64_plain) || base64_plain
|
1147
|
+
# split is not the ideal, if ever ending is duplicated it won't
|
1148
|
+
# work. also may be innefficient.
|
1149
|
+
(plain.split ending).first
|
1150
|
+
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
|
1154
|
+
# an alternative interface to binary_dec -- reads password if
|
1155
|
+
# nil or empty.
|
1156
|
+
#
|
1157
|
+
# @param [Array] args Defaults to +ARGV+. Elements:
|
1158
|
+
# * +data+ [String, nil] data to be encrypted, If empty or nil, read (without
|
1159
|
+
# echo) from @memory[:stdin], which defaults to STDIN
|
1160
|
+
# * +password+ [String, nil] password to be used to encryption.
|
1161
|
+
# If empty or nil, read (without echo) from @memory[:stdin], which defaults to STDIN
|
1162
|
+
# +data_is_base64+:: [true, false, nil] return base64 data -- the same +data_is_base64+ given for enc should be used.
|
1163
|
+
#
|
1164
|
+
# @return [TrueClass, FalseClass] depending on whether test succeeds.
|
1165
|
+
def binary_dec_interactive args=ARGV
|
1166
|
+
stderr = @memory[:stderr]
|
1167
|
+
iv, encrypted, base64_salt, base64_iter, password, data_is_base64 = args
|
1168
|
+
stderr.print "[password]"
|
1169
|
+
password = (input_single_line_non_echo [password])
|
1170
|
+
stderr.puts
|
1171
|
+
binary_dec [password, iv, encrypted, nil, base64_salt, base64_iter, data_is_base64]
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
|
1175
|
+
# test for binary_enc and binary_dec.
|
1176
|
+
# "" and nil are expected to be treated
|
1177
|
+
# as the same.
|
1178
|
+
def test__binary_enc_dec_nil args=ARGV
|
1179
|
+
nil_case = binary_dec [nil, "ltUQIxgRAeUNXPNTTps8FQ==\n", "xyeqxw/TzkyXtOxpDqAl58SNAvXPyNZ89B5JGtwDkcbjo0vObgPsh5FrgZJs\nHPjofsyXnljnTrHpDoQeDVezo9wBZ74NU+TSi/GssX605oE=\n", nil, "TU4o3IKiFWki3rZ3lMchLQ==\n", "MjAwMDA=\n"]
|
1180
|
+
empty = binary_dec ["", "ltUQIxgRAeUNXPNTTps8FQ==\n", "xyeqxw/TzkyXtOxpDqAl58SNAvXPyNZ89B5JGtwDkcbjo0vObgPsh5FrgZJs\nHPjofsyXnljnTrHpDoQeDVezo9wBZ74NU+TSi/GssX605oE=\n", "", "TU4o3IKiFWki3rZ3lMchLQ==\n", "MjAwMDA=\n"]
|
1181
|
+
judgement =
|
1182
|
+
[
|
1183
|
+
[nil_case, empty, "empty_nil_equality"]
|
1184
|
+
].map(&method("expect_equal")).all?
|
1185
|
+
end
|
1186
|
+
|
1187
|
+
|
1188
|
+
# test for binary_enc and binary_dec.
|
1189
|
+
#
|
1190
|
+
# @param [Array] args, an +Array+ whose elements are expected to be:
|
1191
|
+
# +data+:: [String, nil] data to be encrypted.
|
1192
|
+
# If empty or nil, read (without echo) from @memory[:stdin], which defaults to STDIN
|
1193
|
+
# +password+:: [String, nil] password to be used to encryption.
|
1194
|
+
# If empty or nil, read (without echo) from @memory[:stdin], which defaults to STDIN
|
1195
|
+
#
|
1196
|
+
# @return [TrueClass, FalseClass] depending on whether test succeeds.
|
1197
|
+
def test__binary_enc_dec args=ARGV
|
1198
|
+
stderr = @memory[:stderr]
|
1199
|
+
data, password = args
|
1200
|
+
stderr.print "[data]"
|
1201
|
+
data = binary_input_multi_line_non_echo [data]
|
1202
|
+
stderr.print "[password]"
|
1203
|
+
password = binary_input_single_line_non_echo [password]
|
1204
|
+
base64_encrypted, base64_iv, base64_salt, base64_iter, base64_key = binary_enc [password, data]
|
1205
|
+
dec_args = [password, base64_iv, base64_encrypted, nil, base64_salt, base64_iter]
|
1206
|
+
stderr.puts "# WARNING: secrets, including password are printed here. Storing them may be a major security incident."
|
1207
|
+
stderr.puts "# programmatically:"
|
1208
|
+
stderr.puts "binary_dec " + dec_args.to_s
|
1209
|
+
stderr.puts "# shell: "
|
1210
|
+
stderr.puts "#{$0} invoke_double p binary_dec " + (output_array_to_shell dec_args).to_s
|
1211
|
+
data_plain = binary_dec [password, base64_iv, base64_encrypted, nil, base64_salt, base64_iter]
|
1212
|
+
judgement =
|
1213
|
+
[
|
1214
|
+
[data, data_plain, "data"]
|
1215
|
+
].map(&method("expect_equal")).all?
|
1216
|
+
end
|
1217
|
+
|
1218
|
+
|
1219
|
+
# test for binary_enc and binary_dec_interactive.
|
1220
|
+
# good idea is to use this function once with the desired
|
1221
|
+
# data, password, and use the stderr output
|
1222
|
+
def test__binary_enc_dec_interactive args=ARGV
|
1223
|
+
stderr = @memory[:stderr]
|
1224
|
+
data, password, encrypted_base64_filename, data_is_base64 = args
|
1225
|
+
stderr.print "[data]"
|
1226
|
+
data = binary_input_multi_line_non_echo [data]
|
1227
|
+
stderr.print "[password]"
|
1228
|
+
password = binary_input_single_line_non_echo [password]
|
1229
|
+
stderr.puts
|
1230
|
+
base64_encrypted, base64_iv, base64_salt, base64_iter, base64_key = binary_enc [password, data, nil, nil, nil, data_is_base64 ]
|
1231
|
+
# the output is supposed to be safe to store,
|
1232
|
+
# so password is not placed in from binary_dec_interactive_args:
|
1233
|
+
dec_interactive_args = [base64_iv, base64_encrypted, base64_salt, base64_iter]
|
1234
|
+
stderr.puts "# programmatically:"
|
1235
|
+
stderr.puts "dec_interactive " + dec_interactive_args.to_s
|
1236
|
+
stderr.puts "# shell: "
|
1237
|
+
stderr.puts "#{$0} invoke_double puts binary_dec_interactive " + (output_array_to_shell dec_interactive_args).to_s
|
1238
|
+
stderr.puts "#or shell var:"
|
1239
|
+
stderr.puts "my_secret=$(#{$0} invoke_double puts binary_dec_interactive " + (output_array_to_shell dec_interactive_args).to_s + ")\necho $my_secret\nunset mysecret"
|
1240
|
+
encrypted_base64_filename && output_enc_file(dec_interactive_args + [encrypted_base64_filename])
|
1241
|
+
data_plain = binary_dec_interactive(dec_interactive_args + [password, data_is_base64])
|
1242
|
+
judgement =
|
1243
|
+
[
|
1244
|
+
[data.size, data_plain.size, "data.size"],
|
1245
|
+
[data, data_plain, "data"],
|
1246
|
+
].map(&method("expect_equal")).all?
|
1247
|
+
end
|
1248
|
+
|
1249
|
+
|
1250
|
+
# similar to
|
1251
|
+
# test__binary_enc_dec_interactive,
|
1252
|
+
# just that the data is ready from a file instead
|
1253
|
+
# note that there is an extra argument between
|
1254
|
+
# the args, the enc_out_filename.
|
1255
|
+
def test__binary_enc_dec_file_interactive args=ARGV
|
1256
|
+
stderr = @memory[:stderr]
|
1257
|
+
filename_or_url, enc_out_filename, password, data_is_base64 = args
|
1258
|
+
stderr.print "[filename_or_url]"
|
1259
|
+
filename_or_url = binary_input_multi_line_non_echo [filename_or_url]
|
1260
|
+
stderr.print "[output_filename_encrypted_data]"
|
1261
|
+
enc_out_filename = binary_input_multi_line_non_echo [enc_out_filename ]
|
1262
|
+
data = file_or_url_contents filename_or_url
|
1263
|
+
test__binary_enc_dec_interactive [ data, password, enc_out_filename, data_is_base64 ]
|
1264
|
+
end
|
1265
|
+
|
1266
|
+
|
1267
|
+
# basically the reverse of test__binary_enc_dec_file_interactive
|
1268
|
+
# planned improvements: still outputs to stdout
|
1269
|
+
def test__binary_dec_file_interactive args=ARGV
|
1270
|
+
stderr = @memory[:stderr]
|
1271
|
+
stdout = @memory[:stdout]
|
1272
|
+
enc_filename_or_url, out_filename, password, data_is_base64 = args
|
1273
|
+
stderr.print "[enc_filename_or_url]"
|
1274
|
+
enc_filename_or_url = binary_input_multi_line_non_echo [enc_filename_or_url]
|
1275
|
+
stderr.print "[output_filename_plain_data]"
|
1276
|
+
out_filename = binary_input_multi_line_non_echo [out_filename ]
|
1277
|
+
stderr.print "[password]"
|
1278
|
+
password = binary_input_single_line_non_echo [password]
|
1279
|
+
|
1280
|
+
output_dec_file [enc_filename_or_url, out_filename, password, data_is_base64]
|
1281
|
+
end
|
1282
|
+
|
1283
|
+
|
880
1284
|
# gem_spec
|
881
1285
|
# args (Array like the one returned by rubyment_gem_defaults)
|
882
1286
|
# returns: a gem spec string accordingly to args
|