Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Simply encrypt and decrypt Strings in Ruby.
require 'openssl'
class String
def encrypt(key)
cipher = OpenSSL::Cipher.new('DES-EDE3-CBC').encrypt
cipher.key = Digest::SHA1.hexdigest key
s = cipher.update(self) + cipher.final
s.unpack('H*')[0].upcase
end
def decrypt(key)
cipher = OpenSSL::Cipher.new('DES-EDE3-CBC').decrypt
cipher.key = Digest::SHA1.hexdigest key
s = [self].pack("H*").unpack("C*").pack("c*")
cipher.update(s) + cipher.final
end
end
puts plain = 'confidential' # confidential
puts key = 'secret' # secret
puts cipher = plain.encrypt(key) # 5C6D4C5FAFFCF09F271E01C5A132BE89
puts cipher.decrypt('guess') # raises OpenSSL::Cipher::CipherError
puts cipher.decrypt(key) # confidential
@leduytung

This comment has been minimized.

Copy link

leduytung commented Jul 24, 2017

Nice :) , 2017 and still works

@xiaohui-zhangxh

This comment has been minimized.

Copy link

xiaohui-zhangxh commented Aug 13, 2017

Very helpful, thanks

@bater

This comment has been minimized.

Copy link

bater commented Sep 1, 2017

I got key must be 24 bytes message at this line:

cipher.key = Digest::SHA1.hexdigest key

so I change to like this

key = cipher.random_key
cipher.key = key

It will always fit.

Reference http://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html

@grammakov

This comment has been minimized.

Copy link

grammakov commented Apr 5, 2018

To avoid deprecation messages change

cipher = OpenSSL::Cipher::Cipher.new('DES-EDE3-CBC').decrypt

to

cipher = OpenSSL::Cipher.new('DES-EDE3-CBC').decrypt
@TiredOfProgramming

This comment has been minimized.

Copy link

TiredOfProgramming commented May 15, 2018

Doesn't work for me. Getting no implicit conversion of Object into String (TypeError) on line s = [self].pack("H*").unpack("C*").pack("c*")

@wteuber

This comment has been minimized.

Copy link
Owner Author

wteuber commented Aug 23, 2018

@TiredOfProgramming
The provided code monkey-patches the class String and works only there. If you want to use it another class (e.g. Object), you need to define the string to encrypt or decrypt separately, e.g.

require 'openssl'

def encrypt(plain_text, key)
  cipher = OpenSSL::Cipher.new('DES-EDE3-CBC').encrypt
  cipher.key = Digest::SHA1.hexdigest key
  s = cipher.update(plain_text) + cipher.final

  s.unpack('H*')[0].upcase
end

def decrypt(cipher_text, key)
  cipher = OpenSSL::Cipher.new('DES-EDE3-CBC').decrypt
  cipher.key = Digest::SHA1.hexdigest key
  s = [cipher_text].pack("H*").unpack("C*").pack("c*")

  cipher.update(s) + cipher.final
end

puts plain = 'confidential'            # confidential
puts key = 'secret'                    # secret
puts cipher = encrypt(plain, key)      # 5C6D4C5FAFFCF09F271E01C5A132BE89

puts decrypt(cipher, 'guess')          # raises OpenSSL::Cipher::CipherError
puts decrypt(cipher, key)              # confidential

I hope you find that helpful.

@mikosullivan

This comment has been minimized.

Copy link

mikosullivan commented Nov 11, 2019

When I try to set encrypter.key I always get this error message: key must be 24 bytes. Here's my complete script:
#!/usr/bin/ruby -w
require 'openssl'
key = 'my-secret-key'
cipher = OpenSSL::Cipher.new('DES-EDE3-CBC')
encrypter = cipher.encrypt
encrypter.key = Digest::SHA1.hexdigest(key)

I'm running ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux-gnu]. The OS is Ubuntu 18.04.3 LTS.

I should also mention that this script works fine on an Ubuntu 17 machine with Ruby version ruby 2.3.3p222 (2016-11-21) [x86_64-linux-gnu]. The OS is Ubuntu 17.10.

Any help is appreciated.

@wteuber

This comment has been minimized.

Copy link
Owner Author

wteuber commented Nov 13, 2019

@mikosullivan key is used in different context. In this gist, key is a cipher "password". You a trying to set the "encryption key". Consider using your key as cipher password and generate a secure random key. Check out Ruby's documentation for encrypt and key and the section Choosing a key.

If you absolutely need to use passwords as encryption keys, you should use Password-Based Key Derivation Function 2 (PBKDF2) by generating the key with the help of the functionality provided by OpenSSL::PKCS5.pbkdf2_hmac_sha1 or OpenSSL::PKCS5.pbkdf2_hmac.

Although there is #pkcs5_keyivgen, its use is deprecated and it should only be used in legacy applications because it does not use the newer PKCS#5 v2 algorithms.

I suggest, you don't you a password, but generate a secure (random) key. Store it somewhere safe, e.g. base64-encoded.

require 'openssl'
key = 'my-secret-key'
cipher = OpenSSL::Cipher.new('DES-EDE3-CBC')
encrypter = cipher.encrypt
encrypter.key_len
# => 24
encrypter.key = encrypter.random_key
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.