25

I am searching for an algorithm for file encryption/decryption which satisfies the following requirements:

  • Algorithm must be reliable
  • Algorithm should be fast for rather big files
  • Private key can be generated by some parameter (for example, password)
  • Generated private key must be compatible with public key (public key is generated only once and stored in database)

Is there any Ruby implementation of suggested algorithms?

Wayne Conrad
  • 103,207
  • 26
  • 155
  • 191
tiktak
  • 1,801
  • 2
  • 26
  • 46

4 Answers4

38

Note Well: As emboss mentions in the comments, this answer is a poor fit for an actual system. Firstly, file encryption should not be carried out using this method (The lib provides AES, for example.). Secondly, this answer does not address any of the wider issues that will also affect how you engineer your solution.

The original source also goes into more details.

Ruby can use openssl to do this:

#!/usr/bin/env ruby

# ENCRYPT

require 'openssl'
require 'base64'

public_key_file = 'public.pem';
string = 'Hello World!';

public_key = OpenSSL::PKey::RSA.new(File.read(public_key_file))
encrypted_string = Base64.encode64(public_key.public_encrypt(string))

And decrypt:

#!/usr/bin/env ruby

# DECRYPT

require 'openssl'
require 'base64'

private_key_file = 'private.pem';
password = 'boost facile'

encrypted_string = %Q{
...
}

private_key = OpenSSL::PKey::RSA.new(File.read(private_key_file),password)
string = private_key.private_decrypt(Base64.decode64(encrypted_string))

from here

brice
  • 24,329
  • 7
  • 79
  • 95
  • 2
    I'm no Rubyist actually, but those are pretty good batteries. I wonder how hard the equivalent would be in python... – brice Mar 27 '12 at 14:49
  • 3
    Just want to add that files should be ecnrypted with, for example, AES-256, but its key should be sended with rsa. – tiktak Mar 27 '12 at 19:17
  • 4
    I'm sorry, but this is really bad advice. The OP talks about file encryption/decryption and you should never use RSA for that. – emboss Mar 28 '12 at 02:23
  • @emboss: See tiktak's previous comment. You're absolutely right - In wanting to answer the question, I didn't really stop to consider the wider issues. I'll try to amend my post to show this. – brice Mar 28 '12 at 09:16
  • @brice: Great! No harm done, just didn't want people to be mislead :) – emboss Mar 28 '12 at 11:44
  • When read .cer file, I got OpenSSL::PKey::RSA instance of public key, I unable to set it as aes key like `cipher.key = KEY` where KEY is OpenSSL::PKey::RSA instance. Is it right way to do it? http://stackoverflow.com/q/40760184/4477305 – CodecPM Nov 26 '16 at 07:05
12

I'm afraid you are mixing two concepts here, authentication/authorization and confidentiality, trying to cover both aspects in one single step, and that won't work. You should never encrypt "real data" with asymmetric algorithms. a) they are way too slow for that, b) there are subtle issues that, if not done right, will severely weaken the security of your solution.

A good rule of thumb is that the only thing you should end up encrypting with private asymmetric keys is symmetric keys used by a much faster symmetric algorithm. But in almost all cases you shouldn't even be doing that, because in 90% of the cases what you actually want is TLS (SSL) in those cases - I tried to explain why here a while ago.

In your case, I assume the requirements are:

  • confidentiality of the data that is to be stored in the database: the general public shouldn't be able to read it (or even access it)

  • a selected few (probably just one person) should be able to access and read that data

The first goal is generally achieved by using symmetric encryption. The second goal is, albeit related, realized by quite different means. You want the user accessing the file to be authenticated (i.e. establish the identity) and on top of that you also want them to be authorized (i.e. check whether the established identity has the right to do what they intend to). This is where asymmetric cryptography may enter the stage, but not necessarily. Since your question is tagged with Rails I assume we are talking about a Rails application. You typically already have some means to authenticate and authorize users there (most likely involving the afore-mentioned TLS), you may simply reuse them in order to establish a symmetric key for actual file encryption/decryption. Password-based encryption would fit for this purpose, if you want to avoid asymmetric crypto at all. Things get even more complicated if you also want to ensure integrity of the already confidential data, that is, you want to give a kind of guarantee to the authenticated and authorized user in the sense that what they finally access has not been altered in any way in the meantime.

Developing a solution for this will be no trivial task and depend to a large extent on your given requirements, so I'm afraid there's no "golden way" that suits everyone. I would suggest to do some research, get a clearer picture of what you are trying to achieve and how, then try to get additional advice on subjects that you still feel uncertain/uncomfortable with.

Community
  • 1
  • 1
emboss
  • 38,880
  • 7
  • 101
  • 108
  • 1
    Thanks for answer! I solved the question with transfering and storing data in the following way: 1) generate symmetric encryption key (sym-key) 2) encrypt files with sym-key 3) encrypt sym-key with public asym-key 4) send files and encrypted sym-key 5) decrypt user private encrypted asym-key with user's secret token 6) decrypt received sym-key with private asym-key 7) decrypt files with decrypted sym-key. Think it's rather normal. – tiktak Mar 28 '12 at 17:01
  • 2
    That's the right direction! But it's still vulnerable to replay attacks. Instead of sending a key wrapped by an asymmetric key, couldn't you use TLS instead? I've found that in almost all cases where you transport data from A to B you should be using TLS instead of asymmetric crypto - TLS protects you against the things that would most likely break a custom protocol. – emboss Mar 29 '12 at 11:43
2

Symmetric Encryption is definitely fast and has excellent support for streaming of very large files.

SymmetricEncryption::Writer.open('my_file.enc') do |file|
  file.write "Hello World\n"
  file.write "Keep this secret"
end

Symmetric Encryption is designed for encrypting data and large files within an organization.

When it comes to sharing files with other organizations then the best option is PGP. For streaming of very large files with PGP consider: IOStreams

IOStreams.writer('hello.pgp', recipient: 'receiver@example.org') do |writer|
  writer.write('Hello World')
  writer.write('and some more')
end

Look at the file iostreams/lib/io_streams/pgp.rb for more PGP examples. It also supports PGP key management directly from Ruby.

Reid
  • 41
  • 1
  • 5
0

I made a gem to help with this. It's called cryptosystem. Simply configure the path and password to your private key as well as the path to your public key, and it does the rest.

Encrypting is as simple as:

rsa = Cryptosystem::RSA.new
rsa.encrypt('secret') # => "JxpuhTpEqRtMLmaSfaq/X6XONkBnMe..."

And decrypting:

encrypted_value = rsa.encrypt('secret') # => "Y8DWJc2/+7TIxdLEolV99XI2sclHuK..."
rsa.decrypt(encrypted_value) # => "secret"

You can check it out on GitHub or RubyGems.