safedb 0.01.0001

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.yardopts +3 -0
  4. data/Gemfile +10 -0
  5. data/LICENSE +21 -0
  6. data/README.md +793 -0
  7. data/Rakefile +16 -0
  8. data/bin/safe +5 -0
  9. data/lib/configs/README.md +58 -0
  10. data/lib/extension/array.rb +162 -0
  11. data/lib/extension/dir.rb +35 -0
  12. data/lib/extension/file.rb +123 -0
  13. data/lib/extension/hash.rb +33 -0
  14. data/lib/extension/string.rb +572 -0
  15. data/lib/factbase/facts.safedb.net.ini +38 -0
  16. data/lib/interprete.rb +462 -0
  17. data/lib/keytools/PRODUCE_RAND_SEQ_USING_DEV_URANDOM.txt +0 -0
  18. data/lib/keytools/kdf.api.rb +243 -0
  19. data/lib/keytools/kdf.bcrypt.rb +265 -0
  20. data/lib/keytools/kdf.pbkdf2.rb +262 -0
  21. data/lib/keytools/kdf.scrypt.rb +190 -0
  22. data/lib/keytools/key.64.rb +326 -0
  23. data/lib/keytools/key.algo.rb +109 -0
  24. data/lib/keytools/key.api.rb +1391 -0
  25. data/lib/keytools/key.db.rb +330 -0
  26. data/lib/keytools/key.docs.rb +195 -0
  27. data/lib/keytools/key.error.rb +110 -0
  28. data/lib/keytools/key.id.rb +271 -0
  29. data/lib/keytools/key.ident.rb +243 -0
  30. data/lib/keytools/key.iv.rb +107 -0
  31. data/lib/keytools/key.local.rb +259 -0
  32. data/lib/keytools/key.now.rb +402 -0
  33. data/lib/keytools/key.pair.rb +259 -0
  34. data/lib/keytools/key.pass.rb +120 -0
  35. data/lib/keytools/key.rb +585 -0
  36. data/lib/logging/gem.logging.rb +132 -0
  37. data/lib/modules/README.md +43 -0
  38. data/lib/modules/cryptology/aes-256.rb +154 -0
  39. data/lib/modules/cryptology/amalgam.rb +70 -0
  40. data/lib/modules/cryptology/blowfish.rb +130 -0
  41. data/lib/modules/cryptology/cipher.rb +207 -0
  42. data/lib/modules/cryptology/collect.rb +138 -0
  43. data/lib/modules/cryptology/crypt.io.rb +225 -0
  44. data/lib/modules/cryptology/engineer.rb +99 -0
  45. data/lib/modules/mappers/dictionary.rb +288 -0
  46. data/lib/modules/storage/coldstore.rb +186 -0
  47. data/lib/modules/storage/git.store.rb +399 -0
  48. data/lib/session/fact.finder.rb +334 -0
  49. data/lib/session/require.gem.rb +112 -0
  50. data/lib/session/time.stamp.rb +340 -0
  51. data/lib/session/user.home.rb +49 -0
  52. data/lib/usecase/cmd.rb +487 -0
  53. data/lib/usecase/config/README.md +57 -0
  54. data/lib/usecase/docker/README.md +146 -0
  55. data/lib/usecase/docker/docker.rb +49 -0
  56. data/lib/usecase/edit/README.md +43 -0
  57. data/lib/usecase/edit/delete.rb +46 -0
  58. data/lib/usecase/export.rb +40 -0
  59. data/lib/usecase/files/README.md +37 -0
  60. data/lib/usecase/files/eject.rb +56 -0
  61. data/lib/usecase/files/file_me.rb +78 -0
  62. data/lib/usecase/files/read.rb +169 -0
  63. data/lib/usecase/files/write.rb +89 -0
  64. data/lib/usecase/goto.rb +57 -0
  65. data/lib/usecase/id.rb +36 -0
  66. data/lib/usecase/import.rb +157 -0
  67. data/lib/usecase/init.rb +63 -0
  68. data/lib/usecase/jenkins/README.md +146 -0
  69. data/lib/usecase/jenkins/jenkins.rb +208 -0
  70. data/lib/usecase/login.rb +71 -0
  71. data/lib/usecase/logout.rb +28 -0
  72. data/lib/usecase/open.rb +71 -0
  73. data/lib/usecase/print.rb +40 -0
  74. data/lib/usecase/put.rb +81 -0
  75. data/lib/usecase/set.rb +44 -0
  76. data/lib/usecase/show.rb +138 -0
  77. data/lib/usecase/terraform/README.md +91 -0
  78. data/lib/usecase/terraform/terraform.rb +121 -0
  79. data/lib/usecase/token.rb +35 -0
  80. data/lib/usecase/update/README.md +55 -0
  81. data/lib/usecase/update/rename.rb +180 -0
  82. data/lib/usecase/use.rb +41 -0
  83. data/lib/usecase/verse.rb +20 -0
  84. data/lib/usecase/view.rb +71 -0
  85. data/lib/usecase/vpn/README.md +150 -0
  86. data/lib/usecase/vpn/vpn.ini +31 -0
  87. data/lib/usecase/vpn/vpn.rb +54 -0
  88. data/lib/version.rb +3 -0
  89. data/safedb.gemspec +34 -0
  90. metadata +193 -0
@@ -0,0 +1,132 @@
1
+ require "logger"
2
+ require "session/user.home"
3
+
4
+ # [MIXIN] magic is deployed to hand out DevOps quality logging
5
+ # features to any class that includes the logging module.
6
+ #
7
+ # When logging facilities are not ready we need to log just to
8
+ # stdout but when they are we need to use them.
9
+ #
10
+ # mixin power enables one class to give the logfile path and all
11
+ # classes will suddenly retrieve a another logger and use that.
12
+ #
13
+ # include Logging
14
+ # def doImportant
15
+ # log.warn(x) "unhappy about doing this"
16
+ # do_anyway
17
+ # log.debug(x) "all good it was okay"
18
+ # end
19
+ #
20
+ # So what are Mixins?
21
+ #
22
+ # Refer to the below link for excellent coverage of mixins.
23
+ # @see http://ruby-doc.com/docs/ProgrammingRuby/html/tut_modules.html
24
+ #
25
+ module OpenLogger
26
+
27
+ @@gem_name = "safedb.net"
28
+ @@gem_base = File.join OpenSession::Home.dir, ".#{@@gem_name}"
29
+ FileUtils.mkdir_p @@gem_base unless File.exists? @@gem_base
30
+ @@log_path = File.join @@gem_base, "safedb.net-cli.log"
31
+
32
+
33
+ # Classes that include (MIXIN) this logging module will
34
+ # have access to this logger method.
35
+ #
36
+ # [memoization] is implemented here for performance and
37
+ # will only initiate a logger under 2 circumstances
38
+ #
39
+ # [1] - the first call (returns a STDOUT logger)
40
+ # [2] - the call after the logfile path is set
41
+ # (returns a more sophisticated logger)
42
+ def log
43
+
44
+ @@log_class ||= get_logger
45
+
46
+ end
47
+
48
+
49
+ # This Ruby behavioural snippet allows the logger to print 3 crucial
50
+ # pieces of information for the troubleshooter (detective) so that they
51
+ # may ascertain
52
+ #
53
+ # - the [module] the logging call came from
54
+ # - the [method] the logging call came from
55
+ # - line number origins of the logging call
56
+ #
57
+ # To use this method you can make calls like this
58
+ #
59
+ # - log.info(x) { "Log many things about where I am now." }
60
+ # - log.warn(x) { "Log many things about where I am now." }
61
+ #
62
+ def x
63
+
64
+ module_name = File.basename caller_locations(1,1).first.absolute_path, ".rb"
65
+ method_name = caller_locations(1,1).first.base_label
66
+ line_number = caller_locations(1,1).first.lineno
67
+
68
+ "#{module_name} | #{method_name} | (line #{line_number}) "
69
+
70
+ end
71
+
72
+
73
+ # This method returns an initialized logger.
74
+ #
75
+ # The logger returned may write to
76
+ #
77
+ # - a simple file
78
+ # - a service like fluentd
79
+ # - a message queue
80
+ # - a nosql database
81
+ # - all of the above
82
+ #
83
+ # Not that [memoization] should be used so that this method
84
+ # gets called ideally just once although in practise it may
85
+ # turn out to be a handful of times.
86
+ #
87
+ # @return [Logger] return an initialized logger object
88
+ def get_logger
89
+
90
+ file_logger = Logger.new @@log_path
91
+ original_formatter = Logger::Formatter.new
92
+
93
+ file_logger.formatter = proc { |severity, datetime, progname, msg|
94
+ original_formatter.call( severity, datetime, progname, msg.dump.chomp.strip )
95
+ }
96
+
97
+ return file_logger
98
+
99
+ end
100
+
101
+
102
+ # Overtly long file paths in the log files sometimes hamper readability
103
+ # and this method improves the situation by returning just the two
104
+ # immediate ancestors of the file (or folder) path.
105
+ #
106
+ # @example A really long input like
107
+ # <tt>/home/joe/project/degrees/math/2020</tt>
108
+ # is reduced to
109
+ # <tt>degrees/math/2020</tt>
110
+ #
111
+ # So this method returns the name of the grandparent folder then parent folder
112
+ # and then the most significant file (or folder) name.
113
+ #
114
+ # When this is not possible due to the filepath being colisively near the
115
+ # filesystem's root, it returns the parameter name.
116
+ #
117
+ # @param object_path [String] overtly long path that will be made more readable
118
+ # @return [String] the (separated) three most significant path name segments
119
+ def nickname object_path
120
+
121
+ object_name = File.basename object_path
122
+ parent_folder = File.dirname object_path
123
+ parent_name = File.basename parent_folder
124
+ granny_folder = File.dirname parent_folder
125
+ granny_name = File.basename granny_folder
126
+
127
+ return [granny_name,parent_name,object_name].join("/")
128
+
129
+ end
130
+
131
+
132
+ end
@@ -0,0 +1,43 @@
1
+
2
+
3
+ In order for data to be secured for storage or transmission, it must be transformed in such a manner that it would be difficult for an unauthorized individual to be able to discover its true meaning. To do this, certain mathematical equations are used, which are very difficult to solve unless certain strict criteria are met. The level of difficulty of solving a given equation is known as its intractability. These types of equations form the basis of cryptography.
4
+
5
+ Some of the most important are:
6
+
7
+ == The Discrete Logarithm Problem
8
+
9
+ The best way to describe this problem is first to show how its inverse concept works. The following applies to Galois fields (groups). Assume we have a prime number P (a number that is not divisible except by 1 and itself, P). This P is a large prime number of over 300 digits. Let us now assume we have two other integers, a and b. Now say we want to find the value of N, so that value is found by the following formula:
10
+
11
+ N = ab mod P, where 0 <= N <= (P · 1)
12
+
13
+ (meaning a to the power b mod P)
14
+ (learn to do powers in markdown)!
15
+
16
+
17
+ This is known as discrete exponentiation and is quite simple to compute. However, the opposite is true when we invert it. If we are given P, a, and N and are required to find b so that the equation is valid, then we face a tremendous level of difficulty.
18
+
19
+
20
+ This problem forms the basis for a number of public key infrastructure algorithms, such as Diffie-Hellman and EIGamal. This problem has been studied for many years and cryptography based on it has withstood many forms of attacks.
21
+
22
+ == The Integer Factorization Problem
23
+
24
+ This is simple in concept. Say that one takes two prime numbers, P2 and P1, which are both "large" (a relative term, the definition of which continues to move forward as computing power increases). We then multiply these two primes to produce the product, N. The difficulty arises when, being given N, we try and find the original P1 and P2. The Rivest-Shamir-Adleman public key infrastructure encryption protocol is one of many based on this problem. To simplify matters to a great degree, the N product is the public key and the P1 and P2 numbers are, together, the private key.
25
+
26
+ This problem is one of the most fundamental of all mathematical concepts. It has been studied intensely for the past 20 years and the consensus seems to be that there is some unproven or undiscovered law of mathematics that forbids any shortcuts. That said, the mere fact that it is being studied intensely leads many others to worry that, somehow, a breakthrough may be discovered.
27
+
28
+ == The Elliptic Curve Discrete Logarithm Problem
29
+
30
+ This is a new cryptographic protocol based upon a reasonably well-known mathematical problem. The properties of elliptic curves have been well known for centuries, but it is only recently that their application to the field of cryptography has been undertaken.
31
+
32
+ First, imagine a huge piece of paper on which is printed a series of vertical and horizontal lines. Each line represents an integer with the vertical lines forming x class components and horizontal lines forming the y class components. The intersection of a horizontal and vertical line gives a set of coordinates (x,y). In the highly simplified example below, we have an elliptic curve that is defined by the equation:
33
+
34
+ y2 + y = x3 · x2 (this is way too small for use in a real life application, but it will illustrate the general idea)
35
+
36
+ For the above, given a definable operator, we can determine any third point on the curve given any two other points. This definable operator forms a "group" of finite length. To add two points on an elliptic curve, we first need to understand that any straight line that passes through this curve intersects it at precisely three points. Now, say we define two of these points as u and v: we can then draw a straight line through two of these points to find another intersecting point, at w. We can then draw a vertical line through w to find the final intersecting point at x. Now, we can see that u + v = x. This rule works, when we define another imaginary point, the Origin, or O, which exists at (theoretically) extreme points on the curve. As strange as this problem may seem, it does permit for an effective encryption system, but it does have its detractors.
37
+
38
+ On the positive side, the problem appears to be quite intractable, requiring a shorter key length (thus allowing for quicker processing time) for equivalent security levels as compared to the Integer Factorization Problem and the Discrete Logarithm Problem. On the negative side, critics contend that this problem, since it has only recently begun to be implemented in cryptography, has not had the intense scrutiny of many years that is required to give it a sufficient level of trust as being secure.
39
+
40
+ This leads us to more general problem of cryptology than of the intractability of the various mathematical concepts, which is that the more time, effort, and resources that can be devoted to studying a problem, then the greater the possibility that a solution, or at least a weakness, will be found.
41
+
42
+
43
+
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/ruby
2
+ # coding: utf-8
3
+
4
+ module SafeDb
5
+
6
+ module ToolBelt
7
+
8
+
9
+ # Aes256 is a symmetric encryption cipher which inherits extends the
10
+ # {SafeDb::Cipher} base class in order to implement plug and play
11
+ # symmetric encryption.
12
+ #
13
+ # == Aes256 Symmetric Encrypt/Decrypt
14
+ #
15
+ # To facilitate decryption - this cipher produces a key/value pair
16
+ # dictionary which will be stored along with the ciphertext itself.
17
+ # The dictionary includes
18
+ #
19
+ # - <b>symmetric.cipher</b> - the algorithm used to encrypt and decrypt
20
+ # - <b>encryption.key</b> - hex encoded key for encrypting and decrypting
21
+ # - <b>initialize.vector</b> - the initialization vector known as a IV (four)
22
+ #
23
+ # == Aes256 Implemented Methods
24
+ #
25
+ # This cipher brings the cryptographic mathematics and implementation algorithms
26
+ # for the 256Bit Advanced Encryption Standard. No serious practical (nor theoretical)
27
+ # challenge has ever been mounted against this algorithm (or this implementation).
28
+ #
29
+ # This class implements the below methods
30
+ #
31
+ # - <b>do_symmetric_encryption(plain_text)</b> - resulting in ciphertext
32
+ # - <b>do_symmetric_decryption(ciphertext, encryption_dictionary)</b> &raquo; plaintext
33
+ #
34
+ # and it also sets the <b>@dictionary</b> hash (map) of pertinent
35
+ # key/value pairs including the +encryption algorithm+ and +encryption key+.
36
+ #
37
+ # That's It. Cipher children can rely on the {SafeDb::Cipher} parent to
38
+ # do the nitty gritty of file-handling plus managing stores and paths.
39
+
40
+ class Aes256
41
+
42
+ # Use the AES 256 bit block cipher and a robust strong random key plus
43
+ # initialization vector (IV) to symmetrically encrypt the plain text.
44
+ #
45
+ # <b>Cryptographic Properties</b>
46
+ #
47
+ # This encrypt event populates key/value pairs to the hash (dictionary) instance
48
+ # given in the parameter.
49
+ #
50
+ # A crypt properties dictionary acts as <b>output from every encryption event</b>
51
+ # and <b>input to every decryption event</b>. The most common properties include
52
+ #
53
+ # - the symmetric key used for the encryption and decryption
54
+ # - the iv (initialization vector) that adds another dimension of strength
55
+ # - authorization data that thwarts switch attacks by tying context to content
56
+ # - the cipher algorithm, its implementation and its encryption strength
57
+ # - the digest of the original message for validation purposes
58
+ #
59
+ # @param e_properties [Hash]
60
+ # instantiated hash map in which the encrryption properties will
61
+ # be stuffed.
62
+ #
63
+ # @param plain_text [String] the plain (or base64 encoded) text to encrypt
64
+ # @return [String] the symmetrically encrypted cipher text
65
+ def self.do_encrypt e_properties, plain_text
66
+
67
+ crypt_cipher = OpenSSL::Cipher::AES256.new(:CBC)
68
+ crypt_cipher.encrypt
69
+ plain_text_digest = Digest::SHA256.digest plain_text
70
+
71
+ e_properties[CryptIO::DICT_CIPHER_NAME] = crypt_cipher.class.name
72
+ e_properties[CryptIO::DICT_CRYPT_KEY] = Base64.urlsafe_encode64 crypt_cipher.random_key
73
+ e_properties[CryptIO::DICT_CRYPT_IV] = Base64.urlsafe_encode64 crypt_cipher.random_iv
74
+ e_properties[CryptIO::DICT_TEXT_DIGEST] = Base64.urlsafe_encode64 plain_text_digest
75
+
76
+ return crypt_cipher.update( plain_text ) + crypt_cipher.final
77
+
78
+ end
79
+
80
+
81
+ # Use the AES 256 bit block cipher together with the encryption key,
82
+ # initialization vector (iv) and other data found within the decryption
83
+ # properties dictionary to symmetrically decrypt the cipher text.
84
+ #
85
+ # This encrypt event in {self.do_encrypt} populated the property dictionary
86
+ # that was presumably serialized, stored, retrieved then deserialized and
87
+ # (at last) presented in the first parameter.
88
+ #
89
+ # <b>Cryptographic Properties</b>
90
+ #
91
+ # A crypt properties dictionary is the <b>output from every encryption event</b>
92
+ # and <b>input to every decryption event</b>. The most common properties include
93
+ #
94
+ # - the symmetric key used for the encryption and decryption
95
+ # - the iv (initialization vector) that adds another dimension of strength
96
+ # - authorization data that thwarts switch attacks by tying context to content
97
+ # - the cipher algorithm, its implementation and its encryption strength
98
+ # - the digest of the original message for validation purposes
99
+ #
100
+ # @param d_properties [Hash]
101
+ # the crypt properties dictionary is the <b>output from every encryption event</b>
102
+ # and (as in this case) <b>input to every decryption event</b>.
103
+ #
104
+ # @param cipher_text [String]
105
+ # the (already decoded) cipher text for decryption by this method using the
106
+ # encryption properties setup during the past encrypt event.
107
+ #
108
+ # @return [String]
109
+ # the plain text message originally given to be encrypted. If the message digest
110
+ # is provided within the decryption properties dictionary a sanity check will
111
+ # occur.
112
+ #
113
+ # @raise [RuntimeError]
114
+ # if decryption fails or the recalculated message digest fails an equivalence test.
115
+ def self.do_decrypt d_properties, cipher_text
116
+
117
+ decode_cipher = OpenSSL::Cipher::AES256.new(:CBC)
118
+ decode_cipher.decrypt
119
+
120
+ decode_cipher.key = Base64.urlsafe_decode64( d_properties[CryptIO::DICT_CRYPT_KEY] )
121
+ decode_cipher.iv = Base64.urlsafe_decode64( d_properties[CryptIO::DICT_CRYPT_IV] )
122
+
123
+ plain_text = decode_cipher.update( cipher_text ) + decode_cipher.final
124
+ assert_digest_equivalence( d_properties[CryptIO::DICT_TEXT_DIGEST], plain_text )
125
+
126
+ return plain_text
127
+
128
+ end
129
+
130
+
131
+ private
132
+
133
+
134
+ def self.assert_digest_equivalence( digest_b4_encryption, plain_text_message )
135
+
136
+ plain_text_digest = Base64.urlsafe_encode64( Digest::SHA256.digest( plain_text_message ) )
137
+ return if digest_b4_encryption.eql? plain_text_digest
138
+
139
+ msg1 = "\nEquivalence check of original and decrypted plain text digests failed.\n"
140
+ msg2 = "Digest before encryption => #{digest_b4_encryption}\n"
141
+ msg3 = "Digest after decryption => #{plain_text_digest}\n"
142
+ error_message = msg1 + msg2 + msg3
143
+ raise RuntimeError, error_message
144
+
145
+ end
146
+
147
+
148
+ end
149
+
150
+
151
+ end
152
+
153
+
154
+ end
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module SafeDb
4
+
5
+ module ToolBelt
6
+
7
+
8
+ # This class knows how to amalgamate passwords, keys and string data in
9
+ # a manner that is the cryptographical equivalent of synergy.
10
+ #
11
+ # The amalgamated keys are synergially (cryptographically) greater than
12
+ # the sum of their parts.
13
+ class Amalgam
14
+
15
+ # Amalgamate the two parameter passwords in a manner that is the
16
+ # cryptographical equivalent of synergy. The amalgamated keys are
17
+ # synergially greater than the sum of their parts.
18
+ #
19
+ # -- Get a viable machine password taking into account the human
20
+ # -- password length and the specified mix_ratio.
21
+ #
22
+ #
23
+ # @param human_password [String] the password originating from a human
24
+ # @param machine_key [String] a machine engineered ascii password (key)
25
+ # @mixparam machine_key [String] a machine engineered ascii password (key)
26
+ #
27
+ # @return [String] the union of the two parameter passwords
28
+ #
29
+ # @raise [ArgumentError] when the size of the two passwords and the
30
+ # mix ratio do not conform to the constraint imposed by the below
31
+ # equation which must hold true.
32
+ # <tt>machine password length = human password length * mix_ratio - 1</tt>
33
+ #
34
+ def self.passwords human_password, machine_password, mix_ratio
35
+
36
+ size_error_msg = "Human pass length times mix_ratio must equal machine pass length."
37
+ lengths_are_perfect = human_password.length * mix_ratio == machine_password.length
38
+ raise ArgumentError.new size_error_msg unless lengths_are_perfect
39
+
40
+ machine_passwd_chunk = 0
41
+ amalgam_passwd_index = 0
42
+ amalgamated_password = ""
43
+
44
+ human_password.each_char do |passwd_char|
45
+
46
+ amalgamated_password[amalgam_passwd_index] = passwd_char
47
+ amalgam_passwd_index += 1
48
+
49
+ for i in 0..(mix_ratio-1) do
50
+ machine_pass_index = machine_passwd_chunk * mix_ratio + i
51
+ amalgamated_password[amalgam_passwd_index] = machine_password[machine_pass_index]
52
+ amalgam_passwd_index += 1
53
+ end
54
+
55
+ machine_passwd_chunk += 1
56
+
57
+ end
58
+
59
+ return amalgamated_password
60
+
61
+ end
62
+
63
+
64
+ end
65
+
66
+
67
+ end
68
+
69
+
70
+ end
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/ruby
2
+ # coding: utf-8
3
+
4
+ module SafeDb
5
+
6
+ module ToolBelt
7
+
8
+ # Blowfish is a symmetric encryption cipher which inherits extends the
9
+ # {SafeDb::Cipher} base class in order to implement plug and play
10
+ # symmetric encryption.
11
+ #
12
+ # Blowfish is still uncrackable - however its successor (TwoFish) has
13
+ # been reinforced to counter the growth of super-computer brute force
14
+ # resources.
15
+ class Blowfish
16
+
17
+ # The blowfish cipher id constant is used to +initialize+
18
+ # an {OpenSSL::Cipher} class instance.
19
+ BLOWFISH_CIPHER_ID = "BF-ECB"
20
+
21
+
22
+ # Blowfish constrains the length of +incoming plain text+ forcing it
23
+ # to be a multiple of eight (8).
24
+ BLOWFISH_BLOCK_LEN = 8
25
+
26
+
27
+ # Encrypt the (plain) text parameter using the symmetric encryption key
28
+ # specified in the second parameter and return the base64 encoded
29
+ # representation of the cipher text.
30
+ #
31
+ # Blowfish is a block cipher meaning it needs both the key and the plain
32
+ # text inputted to conform to a divisible block length.
33
+ #
34
+ # Don't worry about this block length requirement as this encrption method
35
+ # takes care of it and its sister method {self.decryptor} will also perform
36
+ # the correct reversal activities to give you back the original plain text.
37
+ #
38
+ # {Base64.urlsafe_encode64} facilitates the ciphertext encoding returning text that
39
+ # is safe to write to a file.
40
+ #
41
+ # @param plain_text [String]
42
+ # This parameter should be the non-nil text to encrypt using Blowfish.
43
+ # Before encryption the text will be padded using a text string from
44
+ # the {SafeDb::Cipher::TEXT_PADDER} constant until it results in
45
+ # a string with the required block length.
46
+ #
47
+ # @param encryption_key [String]
48
+ # send a long strong unencoded key which does not have to be a multiple of
49
+ # eight even though the algorithm demands it. Before the encryption this key
50
+ # will be passed through a digest using behaviour from {Digest::SHA256.digest}
51
+ #
52
+ # This behaviour returns a key whose length is a multiple of eight.
53
+ #
54
+ # @return [String] base64 representation of blowfish crypted ciphertext
55
+ #
56
+ # @raise [OpenSSL::Cipher::CipherError]
57
+ # An (encryption) <tt>key length too short</tt> error is raised for short keys.
58
+ def self.encryptor plain_text, encryption_key
59
+
60
+ shortkey_msg = "The #{encryption_key.length} character encryption key is too short."
61
+ raise ArgumentError, shortkey_msg unless encryption_key.length > 8
62
+ log.info(x) { "os blowfish request to encrypt plain text with provided key." }
63
+
64
+ block_txt = plain_text
65
+ block_txt += CryptIO::TEXT_PADDER until block_txt.bytesize % BLOWFISH_BLOCK_LEN == 0
66
+ raw_stretched_key = Digest::SHA256.digest(encryption_key)
67
+
68
+ blowfish_encryptor = OpenSSL::Cipher.new(BLOWFISH_CIPHER_ID).encrypt
69
+ blowfish_encryptor.key = raw_stretched_key
70
+ return blowfish_encryptor.update(block_txt) << blowfish_encryptor.final
71
+
72
+ end
73
+
74
+
75
+ # Decrypt the cipher text parameter using the symmetric decryption key
76
+ # specified in the second parameter. The cipher text is expected to have
77
+ # already been decoded if necessary.
78
+ #
79
+ # Its okay to use a bespoke encryptor - just ensure you encode the result
80
+ # and override the padding constant.
81
+ #
82
+ # Blowfish is a block cipher meaning it needs both the key and the plain
83
+ # text inputted to conform to a divisible block length.
84
+ #
85
+ # Don't worry about this block length requirement as this decrption method
86
+ # takes care of the reversing the activities carried out by {self.encryptor}.
87
+ #
88
+ # @param cipher_text [String]
89
+ # This incoming cipher text should already be encoded but it
90
+ # will <b>chomped and stripped upon receipt</b> followed by
91
+ # decryption using the Blowfish algorithm.
92
+ #
93
+ # @param decryption_key [String]
94
+ # Send the same key that was used during the encryption phase. The encryption
95
+ # phase passed the key through the {Digest::SHA256.digest} digest so here
96
+ # the decryption does the exact same thing.
97
+ #
98
+ # The digest processing guarantees a symmetric key whose length conforms to
99
+ # the multiple of eight block length requirement.
100
+ #
101
+ # @return [String]
102
+ # After decoding and decryption the plain text string will still be padded,
103
+ # +but not with spaces+. The unlikely to occur padding string constant used
104
+ # is the {SafeDb::Cipher::TEXT_PADDER}.
105
+ #
106
+ # If the plaintext ended with spaces these would be preserved. After padder
107
+ # removal any trailing spaces will be preserved in the returned plain text.
108
+ #
109
+ def self.decryptor cipher_text, decryption_key
110
+
111
+ digested_key = Digest::SHA256.digest decryption_key
112
+
113
+ decrypt_tool = OpenSSL::Cipher.new(BLOWFISH_CIPHER_ID).decrypt
114
+ decrypt_tool.key = digested_key
115
+
116
+ padded_plaintxt = decrypt_tool.update(cipher_text) << decrypt_tool.final
117
+ pad_begin_index = padded_plaintxt.index CryptIO::TEXT_PADDER
118
+ return padded_plaintxt if pad_begin_index.nil?
119
+ return padded_plaintxt[ 0 .. (pad_begin_index-1) ]
120
+
121
+ end
122
+
123
+
124
+ end
125
+
126
+
127
+ end
128
+
129
+
130
+ end