pluginaweek-encrypted_strings 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,59 @@
1
+ == master
2
+
3
+ == 0.3.2 / 2009-01-11
4
+
5
+ * Use Array#pack/String#unpack instead of Base64 to be compatible with Ruby 1.9+
6
+
7
+ == 0.3.1 / 2008-12-4
8
+
9
+ * Fix symmetric ciphers not working on Ruby 1.8.6 and below
10
+
11
+ == 0.3.0 / 2008-12-14
12
+
13
+ * Remove the PluginAWeek namespace
14
+
15
+ == 0.2.1 / 2008-12-04
16
+
17
+ * Fix class-level defaults not working when inherited
18
+
19
+ == 0.2.0 / 2008-12-01
20
+
21
+ * Remove AsymmetricEncryptor.default_algorithm, instead relying on SymmetricEncryptor.default_algorithm
22
+ * Rename NoKeyError to NoPasswordError
23
+ * Rename Encryptors to Ciphers
24
+ * Remove deprecated SymmetricEncryptor#key option
25
+ * Require that symmetric encryption be PKCS #5 compliant
26
+
27
+ == 0.1.1 / 2008-12-01
28
+
29
+ * Fix non-compliant PKCS #5 algorithm being used for symmetric encryption. Use :pkcs5_compliant => true for better security.
30
+ * Rename SymmetricEncryptor#key to #password
31
+ * Fix deprecation messages for Cipher#encrypt/decrypt
32
+
33
+ == 0.1.0 / 2008-07-06
34
+
35
+ * Remove dependency on active_support
36
+
37
+ == 0.0.5 / 2008-07-05
38
+
39
+ * Add automatic stringification of salts for SHA encryption
40
+ * Fix not resetting the encryptor after calling decrypt!
41
+
42
+ == 0.0.4 / 2008-05-05
43
+
44
+ * Updated documentation
45
+
46
+ == 0.0.3 / 2007-09-18
47
+
48
+ * Remove gem dependency on activesupport
49
+
50
+ == 0.0.2 / 2007-08-23
51
+
52
+ * Fix not allowing the decryption mode to be overriden if the string already has an encryptor
53
+ * Convert dos newlines to unix newlines
54
+
55
+ == 0.0.1 / 2007-08-05
56
+
57
+ * Official public release
58
+ * Add api documentation
59
+ * Refactor unit test names
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2005 Rick Olson, 2006-2009 Aaron Pfeifer
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,88 @@
1
+ = encrypted_strings
2
+
3
+ +encrypted_strings+ provides dead-simple string encryption/decryption syntax.
4
+
5
+ == Resources
6
+
7
+ API
8
+
9
+ * http://api.pluginaweek.org/encrypted_strings
10
+
11
+ Bugs
12
+
13
+ * http://pluginaweek.lighthouseapp.com/projects/13270-encrypted_strings
14
+
15
+ Development
16
+
17
+ * http://github.com/pluginaweek/encrypted_strings
18
+
19
+ Source
20
+
21
+ * git://github.com/pluginaweek/encrypted_strings.git
22
+
23
+ == Description
24
+
25
+ Encrypting and decrypting data is not exactly the most straightforward and DRY
26
+ way. encrypted_strings improves the syntax and reduces the complexity, adding
27
+ straightforward support for encrypting values using SHA-1, Symmetric, and
28
+ Asymmetric ciphers.
29
+
30
+ == Usage
31
+
32
+ === SHA Encryption
33
+
34
+ >> password = 'shhhh'
35
+ => "shhhh"
36
+ >> encrypted_password = password.encrypt
37
+ => "66c85d26dadde7e1db27e15a0776c921e27143bd"
38
+ >> encrypted_password.class
39
+ => String
40
+ >> encrypted_password.cipher
41
+ => #<EncryptedStrings::ShaCipher:0x2b9238889460 @salt="salt">
42
+ >> encrypted_password == 'shhhh'
43
+ => true
44
+ >> encrypted_password.decrypt
45
+ NotImplementedError: Decryption is not supported using a(n) EncryptedStrings::ShaCipher
46
+ from ./script/../config/../config/../vendor/plugins/encrypted_strings/lib/encrypted_strings/cipher.rb:13:in `decrypt'
47
+ from ./script/../config/../config/../vendor/plugins/encrypted_strings/lib/encrypted_strings/extensions/string.rb:52:in `decrypt'
48
+ from (irb):40
49
+
50
+ When encrypt is called, it creates a +cipher+ instance which is used for
51
+ future encryption and decryption of the string. The default cipher uses
52
+ SHA-1 encryption. For ciphers that do not support decryption, equality with
53
+ other strings is tested by encrypting the other string and checking whether the
54
+ resulting encrypted value is the same.
55
+
56
+ === Symmetric Encryption
57
+
58
+ >> password = 'shhhh'
59
+ => "shhhh"
60
+ >> crypted_password = password.encrypt(:symmetric, :password => 'secret_key')
61
+ => "qSg8vOo6QfU=\n"
62
+ >> crypted_password.class
63
+ => String
64
+ >> crypted_password == 'shhhh'
65
+ => true
66
+ >> password = crypted_password.decrypt
67
+ => "shhhh"
68
+
69
+ === Asymmetric encryption
70
+
71
+ >> password = 'shhhh'
72
+ => "shhhh"
73
+ >> crypted_password = password.encrypt(:asymmetric, :public_key_file => './public.key', :private_key_file => './private.key')
74
+ => "NEwVzcikYUKfS8HTc9L9eg/dMxBCLZ/nFr7J1aQYjkl3I2MPUD0lmjr/saC6\nTJEPwOl60Ki24H8TUwnGtZy14A==\n"
75
+ >> crypted_password.class
76
+ => String
77
+ >> crypted_password == 'shhhh'
78
+ => true
79
+ >> password = crypted_password.decrypt
80
+ => "shhhh"
81
+
82
+ == Dependencies
83
+
84
+ None.
85
+
86
+ == References
87
+
88
+ * Rick Olson - sentry[http://github.com/technoweenie/sentry]
@@ -0,0 +1,96 @@
1
+ require 'rake/testtask'
2
+ require 'rake/rdoctask'
3
+ require 'rake/gempackagetask'
4
+ require 'rake/contrib/sshpublisher'
5
+
6
+ spec = Gem::Specification.new do |s|
7
+ s.name = 'encrypted_strings'
8
+ s.version = '0.3.2'
9
+ s.platform = Gem::Platform::RUBY
10
+ s.summary = 'Dead-simple string encryption/decryption syntax'
11
+ s.description = s.summary
12
+
13
+ s.files = FileList['{lib,test}/**/*'] + %w(CHANGELOG.rdoc init.rb LICENSE Rakefile README.rdoc)
14
+ s.require_path = 'lib'
15
+ s.has_rdoc = true
16
+ s.test_files = Dir['test/**/*_test.rb']
17
+
18
+ s.author = 'Aaron Pfeifer'
19
+ s.email = 'aaron@pluginaweek.org'
20
+ s.homepage = 'http://www.pluginaweek.org'
21
+ s.rubyforge_project = 'pluginaweek'
22
+ end
23
+
24
+ desc 'Default: run all tests.'
25
+ task :default => :test
26
+
27
+ desc "Test the #{spec.name} plugin."
28
+ Rake::TestTask.new(:test) do |t|
29
+ t.libs << 'lib'
30
+ t.test_files = spec.test_files
31
+ t.verbose = true
32
+ end
33
+
34
+ begin
35
+ require 'rcov/rcovtask'
36
+ namespace :test do
37
+ desc "Test the #{spec.name} plugin with Rcov."
38
+ Rcov::RcovTask.new(:rcov) do |t|
39
+ t.libs << 'lib'
40
+ t.test_files = spec.test_files
41
+ t.rcov_opts << '--exclude="^(?!lib/)"'
42
+ t.verbose = true
43
+ end
44
+ end
45
+ rescue LoadError
46
+ end
47
+
48
+ desc "Generate documentation for the #{spec.name} plugin."
49
+ Rake::RDocTask.new(:rdoc) do |rdoc|
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = spec.name
52
+ rdoc.template = '../rdoc_template.rb'
53
+ rdoc.options << '--line-numbers'
54
+ rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG.rdoc', 'LICENSE', 'lib/**/*.rb')
55
+ end
56
+
57
+ desc 'Generate a gemspec file.'
58
+ task :gemspec do
59
+ File.open("#{spec.name}.gemspec", 'w') do |f|
60
+ f.write spec.to_ruby
61
+ end
62
+ end
63
+
64
+ Rake::GemPackageTask.new(spec) do |p|
65
+ p.gem_spec = spec
66
+ p.need_tar = true
67
+ p.need_zip = true
68
+ end
69
+
70
+ desc 'Publish the beta gem.'
71
+ task :pgem => [:package] do
72
+ Rake::SshFilePublisher.new('aaron@pluginaweek.org', '/home/aaron/gems.pluginaweek.org/public/gems', 'pkg', "#{spec.name}-#{spec.version}.gem").upload
73
+ end
74
+
75
+ desc 'Publish the API documentation.'
76
+ task :pdoc => [:rdoc] do
77
+ Rake::SshDirPublisher.new('aaron@pluginaweek.org', "/home/aaron/api.pluginaweek.org/public/#{spec.name}", 'rdoc').upload
78
+ end
79
+
80
+ desc 'Publish the API docs and gem'
81
+ task :publish => [:pgem, :pdoc, :release]
82
+
83
+ desc 'Publish the release files to RubyForge.'
84
+ task :release => [:gem, :package] do
85
+ require 'rubyforge'
86
+
87
+ ruby_forge = RubyForge.new.configure
88
+ ruby_forge.login
89
+
90
+ %w(gem tgz zip).each do |ext|
91
+ file = "pkg/#{spec.name}-#{spec.version}.#{ext}"
92
+ puts "Releasing #{File.basename(file)}..."
93
+
94
+ ruby_forge.add_release(spec.rubyforge_project, spec.name, spec.version, file)
95
+ end
96
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'encrypted_strings'
@@ -0,0 +1,7 @@
1
+ require 'openssl'
2
+
3
+ require 'encrypted_strings/extensions/string'
4
+ require 'encrypted_strings/cipher'
5
+ require 'encrypted_strings/symmetric_cipher'
6
+ require 'encrypted_strings/asymmetric_cipher'
7
+ require 'encrypted_strings/sha_cipher'
@@ -0,0 +1,185 @@
1
+ module EncryptedStrings
2
+ # Indicates no public key was found
3
+ class NoPublicKeyError < StandardError
4
+ end
5
+
6
+ # Indicates no private key was found
7
+ class NoPrivateKeyError < StandardError
8
+ end
9
+
10
+ # Encryption in which the keys used to encrypt/decrypt come in pairs. Also
11
+ # known as public key encryption. Anything that's encrypted using the
12
+ # public key can only be decrypted with the same algorithm and a matching
13
+ # private key. Any message that is encrypted with the private key can only
14
+ # be decrypted with the matching public key.
15
+ #
16
+ # Source: http://support.microsoft.com/kb/246071
17
+ #
18
+ # == Encrypting
19
+ #
20
+ # To encrypt a string using an asymmetric cipher, the location of the
21
+ # public key file must be specified. You can define the default for this
22
+ # value like so:
23
+ #
24
+ # EncryptedStrings::AsymmetricCipher.default_public_key_file = './public.key'
25
+ #
26
+ # If these configuration options are not passed in to #encrypt, then the
27
+ # default values will be used. You can override the default values like so:
28
+ #
29
+ # password = 'shhhh'
30
+ # password.encrypt(:asymmetric, :public_key_file => './encrypted_public.key') # => "INy95irZ8AlHmvc6ZAF/ARsTpbqPIB/4bEAKKOebjsayB7NYWtIzpswvzxqf\nNJ5yyuvxfMODrcg7RimEMFkFlg==\n"
31
+ #
32
+ # An exception will be raised if either the public key file could not be
33
+ # found or the key could not decrypt the public key file.
34
+ #
35
+ # == Decrypting
36
+ #
37
+ # To decrypt a string using an asymmetric cipher, the location of the
38
+ # private key file must be specified. If this file is itself encrypted, you
39
+ # must also specify the algorithm and password used to seed the symmetric
40
+ # algorithm that will decrypt the plublic key file. You can define defaults
41
+ # for these values like so:
42
+ #
43
+ # EncryptedStrings::AsymmetricCipher.default_private_key_file = './private.key'
44
+ # EncryptedStrings::SymmetricCipher.default_algorithm = 'DES-EDE3-CBC'
45
+ # EncryptedStrings::SymmetricCipher.default_password = 'secret'
46
+ #
47
+ # If these configuration options are not passed in to #decrypt, then the
48
+ # default values will be used. You can override the default values like so:
49
+ #
50
+ # password = "INy95irZ8AlHmvc6ZAF/ARsTpbqPIB/4bEAKKOebjsayB7NYWtIzpswvzxqf\nNJ5yyuvxfMODrcg7RimEMFkFlg==\n"
51
+ # password.decrypt(:asymmetric, :public_key_file => './encrypted_public.key', :password => 'secret') # => "shhhh"
52
+ #
53
+ # An exception will be raised if either the private key file could not be
54
+ # found or the password could not decrypt the private key file.
55
+ class AsymmetricCipher < Cipher
56
+ class << self
57
+ # The default private key to use during encryption. Default is nil.
58
+ attr_accessor :default_private_key_file
59
+
60
+ # The default public key to use during encryption. Default is nil.
61
+ attr_accessor :default_public_key_file
62
+ end
63
+
64
+ # Private key used for decrypting data
65
+ attr_reader :private_key_file
66
+
67
+ # Public key used for encrypting data
68
+ attr_reader :public_key_file
69
+
70
+ # The algorithm to use if the key files are encrypted themselves
71
+ attr_accessor :algorithm
72
+
73
+ # The password used during symmetric decryption of the key files
74
+ attr_accessor :password
75
+
76
+ # Creates a new cipher that uses an asymmetric encryption strategy.
77
+ #
78
+ # Configuration options:
79
+ # * <tt>:private_key_file</tt> - Encrypted private key file
80
+ # * <tt>:public_key_file</tt> - Public key file
81
+ # * <tt>:password</tt> - The password to use in the symmetric cipher
82
+ # * <tt>:algorithm</tt> - Algorithm to use symmetrically encrypted strings
83
+ def initialize(options = {})
84
+ invalid_options = options.keys - [:private_key_file, :public_key_file, :algorithm, :password]
85
+ raise ArgumentError, "Unknown key(s): #{invalid_options.join(", ")}" unless invalid_options.empty?
86
+
87
+ options = {
88
+ :private_key_file => AsymmetricCipher.default_private_key_file,
89
+ :public_key_file => AsymmetricCipher.default_public_key_file
90
+ }.merge(options)
91
+
92
+ @public_key = @private_key = nil
93
+
94
+ self.private_key_file = options[:private_key_file]
95
+ self.public_key_file = options[:public_key_file]
96
+ raise ArgumentError, 'At least one key file must be specified (:private_key_file or :public_key_file)' unless private_key_file || public_key_file
97
+
98
+ self.algorithm = options[:algorithm]
99
+ self.password = options[:password]
100
+
101
+ super()
102
+ end
103
+
104
+ # Encrypts the given data. If no public key file has been specified, then
105
+ # a NoPublicKeyError will be raised.
106
+ def encrypt(data)
107
+ raise NoPublicKeyError, "Public key file: #{public_key_file}" unless public?
108
+
109
+ encrypted_data = public_rsa.public_encrypt(data)
110
+ [encrypted_data].pack('m')
111
+ end
112
+
113
+ # Decrypts the given data. If no private key file has been specified, then
114
+ # a NoPrivateKeyError will be raised.
115
+ def decrypt(data)
116
+ raise NoPrivateKeyError, "Private key file: #{private_key_file}" unless private?
117
+
118
+ decrypted_data = data.unpack('m')[0]
119
+ private_rsa.private_decrypt(decrypted_data)
120
+ end
121
+
122
+ # Sets the location of the private key and loads it
123
+ def private_key_file=(file)
124
+ @private_key_file = file and load_private_key
125
+ end
126
+
127
+ # Sets the location of the public key and loads it
128
+ def public_key_file=(file)
129
+ @public_key_file = file and load_public_key
130
+ end
131
+
132
+ # Does this cipher have a public key available?
133
+ def public?
134
+ return true if @public_key
135
+
136
+ load_public_key
137
+ !@public_key.nil?
138
+ end
139
+
140
+ # Does this cipher have a private key available?
141
+ def private?
142
+ return true if @private_key
143
+
144
+ load_private_key
145
+ !@private_key.nil?
146
+ end
147
+
148
+ private
149
+ # Loads the private key from the configured file
150
+ def load_private_key
151
+ @private_rsa = nil
152
+
153
+ if private_key_file && File.file?(private_key_file)
154
+ @private_key = File.read(private_key_file)
155
+ end
156
+ end
157
+
158
+ # Loads the public key from the configured file
159
+ def load_public_key
160
+ @public_rsa = nil
161
+
162
+ if public_key_file && File.file?(public_key_file)
163
+ @public_key = File.read(public_key_file)
164
+ end
165
+ end
166
+
167
+ # Retrieves the private RSA from the private key
168
+ def private_rsa
169
+ if password
170
+ options = {:password => password}
171
+ options[:algorithm] = algorithm if algorithm
172
+
173
+ private_key = @private_key.decrypt(:symmetric, options)
174
+ OpenSSL::PKey::RSA.new(private_key)
175
+ else
176
+ @private_rsa ||= OpenSSL::PKey::RSA.new(@private_key)
177
+ end
178
+ end
179
+
180
+ # Retrieves the public RSA
181
+ def public_rsa
182
+ @public_rsa ||= OpenSSL::PKey::RSA.new(@public_key)
183
+ end
184
+ end
185
+ end