Created
February 24, 2012 09:31
-
-
Save marcbowes/1899731 to your computer and use it in GitHub Desktop.
Envelope encryption in Ruby using OpenSSL
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Explanation at http://stackoverflow.com/questions/5212213/ruby-equivalent-of-php-openssl-seal/9428217#9428217 | |
# Implementation | |
class EnvelopeEncryption | |
require "openssl" | |
# This method takes in plaintext and produces ciphertext and an | |
# encrypted key which can be used to decrypt the ciphertext after it | |
# itself has been decrypted. | |
def encrypt(plaintext, rsa_key) | |
# Generate a random symmetric key (K1) and use it to generate | |
# ciphertext (CT) from our plaintext (PT) | |
aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC") | |
aes.encrypt | |
# generate a random IV | |
iv = aes.random_iv | |
# generate the session key | |
session_key = aes.random_key | |
# encrypt the payload with session key | |
ciphertext = aes.update(plaintext) + aes.final | |
# Key wrapping: at this point we (A) have CT and K1. The only way | |
# to decrypt the CT back to PT is via K1. To securely transfer K1 | |
# to our receiver (B), we encrypt it with the provided (public) key | |
# encrypt the session key with the public key | |
encrypted_session_key = rsa_key.public_encrypt(session_key) | |
[ciphertext, iv, encrypted_session_key] | |
end | |
def decrypt(ciphertext, iv, encrypted_session_key, rsa_key) | |
# Reversing #encrypt, we need to unwrap the envelope key (K1) | |
session_key = rsa_key.private_decrypt(encrypted_session_key) | |
# Now to get the plaintext | |
aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC") | |
aes.decrypt | |
aes.iv = iv | |
aes.key = session_key | |
aes.update(ciphertext) + aes.final | |
end | |
end | |
# Test with RSpec | |
describe EnvelopeEncryption do | |
let(:rsa_key) { OpenSSL::PKey::RSA.new(2048) } | |
it "encrypts and decrypts" do | |
plaintext = "I am the walrus" | |
e = EnvelopeEncryption.new | |
ciphertext, iv, key = e.encrypt(plaintext, rsa_key) | |
e.decrypt(ciphertext, iv, key, rsa_key).should eq(plaintext) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment