Crypto
February 28, 2015I’ve been playing around with Public-key cryptography or asymmetric cryptography. With revaltions from Eric Snowden on programs like PRISM, I feel that encryption is more important than ever.
From Wikipedia
Public-key cryptography is a class of cryptographic algorithms which requires two separate keys, one of which is secret (or private) and one of which is public. Although different, the two parts of this key pair are mathematically linked. The public key is used to encrypt plaintext or to verify a digital signature; whereas the private key is used to decrypt ciphertext or to create a digital signature.
There are two main uses for public key crypto.
Public key encryption. A message is encrypted with a recipient’s public key. The message can only be unencrypted by the holder of the private key.
Digital Signature. A message is signed with a the senders private key to generate a cryptographic hash. Using the public key, one can verify the message was indeed sent with the coresponding private key and can ensure the message has not been altered.
Keys
First, let’s generate some keys. From the private key we will also generate the public key. Remember the private and public key are mathematically linked. This is important.
[1] pry(main)> require "openssl"
=> true
[2] pry(main)> private_key = OpenSSL::PKey::RSA.new(2048)
=> #<OpenSSL::PKey::RSA:0x007ff03b379c30>
[3] pry(main)> public_key = private_key.public_key
=> #<OpenSSL::PKey::RSA:0x007ff03c3330b8> Great. Now we have a key pair. We can write these keys to disk if we like.
## write the private key to disk.
File.open("~/.ssh/private_key", "w+") do |f|
f.write private_key.to_pem
end
# write the public key to disk.
File.open("~/.ssh/public_key.pem", "w+") do |f|
f.write public_key.to_pem
end We can read the key in from key like so.
key = OpenSSL::PKey::RSA.new(File.read("~/.ssh/private_key")) Public key enctryption
We’ll be encrypting a message with the public key. So it can only be unenctrypted by the owner of the private key.
## Use the public key to encrypt a message
[4] pry(main)> encrypted_data = public_key.public_encrypt("Some private data is here.")
=> "Ò"lûú¢Ì;Ârú\ÛZY4ãiÛµ´<츫"aáàbì®À!È©ÞBe^ÌeÜÜXÖ"bUJ°Bí}÷IýôQ§HÅaá¤kxô6A% ëë: Ñ¢ÿ¤$½PRéÓ\r>5ÙèYde`à½å\öÔmÍJ*¦õS9ÒMÕ 7Îð¹<¯e®`W;HZëØÿÞmò*\tL2â`KÈ)OÚ¯k4Ð\rNó%}êMhe߯åª$V¾~LvÇ´o¡3âÞât!]-ȯãÕý`TÙÍsÿ®(<½¹" This will result in some unreadable binary data. Next we’ll decrypt this data with the private key.
## Use the private key to decrypt
[5] pry(main)> private_key.private_decrypt(enc)
=> "Some private data is here." Nice!
The public key can encrypt but cannot decrypt the message. This enctryption only works in one direction. Only the private key can decrypt that message. You can also encrypt messages with a private key. Those messages can be unenctrypted with the public key and the private key.
Asymmetric public/private key encryption is slow and victim to attack in cases where it is used without padding or directly to encrypt larger chunks of data. Typical use cases for RSA encryption involve “wrapping” a symmetric key with the public key of the recipient who would “unwrap” that symmetric key again using their private key.
NOTE - The enctrypted messages are in binary format. If we want to encode the data for transmission accoss the net, we’ll want to use something like base64.
[6] pry(main)> require "base64"
=> true
[7] pry(main)> enc_string = Base64.encode64(encrypted)
=> "iRBt6WHFYP2sn2Qv+qs16js/EJqBGaTWyxUH7iI/aj3UEw1oUHHbrFs/705W\nP+8dJ77p5gAaBpS/spCYLu/strU3uN06DTOh3neTcyDQrpIL5Zqs0Gl6/76m\nOQFGi18khnwWPAyW4+uVcZiQmZU9M0tlWywwNlkVoKAwkFlwkYF07YZazfCY\nMrAoQ6nusfjqjfU7HQeQKSCnMrBkzInsqan0PUm+UuGCMbxpQMdPA1de2nHB\neMs7OR7Pd5q5T93z240Iacjtwo/CV3Tcr1EyrfCcx05Jp4FKi9DPJf33asPx\noJ7J2XNa3QXqEbisMGT/b+6QZDm/LbfZXKuCIDYOjA==\n" This works for small messages but if you try and encrpt a string larget than your key… you’ll hit an errors. You could break up the string into smaller chunks and encrypt each chunk individually. But this is not secure. This is what cypher block chaining is for. Below is an example.
cipher = OpenSSL::Cipher.new 'AES-128-CBC'
cipher.encrypt
iv = cipher.random_iv
pwd = 'tRiSsmiTp'
salt = OpenSSL::Random.random_bytes 16
iter = 20000
key_len = cipher.key_len
digest = OpenSSL::Digest::SHA256.new
key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest)
cipher.key = key
File.open("enc-text.txt",'w') do |enc|
File.open("./plain.txt") do |f|
loop do
r = f.read(4096)
break unless r
enc << cipher.update(r)
end
enc << cipher.final
end
end Digital Signature
Asymmetric digital signatures is a great way to verify integrity and authenticity of data. Create a keypair, send the public key to your receivers, and use this method to create a digital signature. By combining the data and the public key, you can verify that the signature was created by the owner of the private key.
require "openssl"
data = "A small brown fox."
digest = OpenSSL::Digest::SHA256.new
# To list available digests:
#OpenSSL::Digest.constants
signature = private_key.sign(digest, data)
public_key.verify(digest, signature, data)
# => true
public_key.verify(digest, signature, data + "altered")
# => false
public_key.verify(digest, "altered" + signature, data)
# => false More
Using openssl library directly we can encrypt a file.
openssl aes-256-cbc -a -e -in source-file.txt -out enc-file.txt -k private_key And to decrypt the file.
openssl aes-256-cbc -d -a -in enc-file.txt -out unenc-file.txt -k private_key ssh config
February 21, 2015I’m in and out of servers all day. One thing I’ve found helpful is a ssh config file. Create a file and place it ~/.ssh/config. You can add as many entries as you like.
Host s3-rsync
HostName ec2-54-203-43-190.us-west-2.compute.amazonaws.com
User ec2-user
IdentityFile "~/.ssh/private-key-location" Host: A friendly name/handle which you’ll use.
HostName: The remote server address you’ll be connecting to.
User: The user you want to connect as.
IdentityFile: The private key to authenticate with.
Once its all setup you can connect by typing: ssh s3-rsync
This is the same as: ssh -i ~/.ssh/bs2-deploy ec2-user@ec2-54-203-43-190.us-west-2.compute.amazonaws.com.
Standard rails create action
February 11, 2015Rails has taught me some really good best practices. Let’s look at a default rails create action
def create
@post = Post.new(post_params)
respond_to do |format|
if @post.save
format.html { redirect_to @post, notice: 'Post was successfully created.' }
else
format.html { render :new }
end
end
end I try not to deviate too much from this and nor should you. If @post.save returns true. return a 201 status code. If @post.save returns false re-render the :new action. So you can let the user fix the form.
Often I will see things like this.
def create
if params[:something]
@post = Post.create(post_params)
else
@post = Post.create(other_params)
end
redirect_to posts_path
end At first glance this looks clean. But if you look closer. There is a subtle problem here. If the post object fails validation and fails to create, The action redirects to the index action where all new instaces are creating. The @post object has lost any knowlege of the params and it will not get to oportunity to display the errors from the object. You’ll have to resort to things like flash[:notice] = "@post.errors.full_messages.join()"… ugh.
Active record gives us a nice interface for displaying errors on an object.
class Post < ActiveRecord::Base
validates :title, presence: true
end irb(main):001:0> p = Post.new
=> #<Post id: nil, title: nil, body: nil, created_at: nil, updated_at: nil>
irb(main):002:0> p.valid?
=> false
irb(main):003:0> p.errors
=> #<ActiveModel::Errors:0x007fe0ca9e4b68 @base=#<Post id: nil, title: nil, body: nil, created_at: nil, updated_at: nil>,
@messages={:title=>["can't be blank"]}>
irb(main):004:0> When you call @post.save OR @post.valid? errors are added to the @post object so they can be displayed within the form.
Digging even deeper… Check out ActiveModel::Model. It will give you this same object interface without needing database backed model. Powerful stuff.
angularjs
February 11, 2015Lately I’ve been writing a lot of angularjs. At my work, we had a great debeate.. which client side framework should we use. Ultimately, we choose angular. I’m happy we did. Angularjs is awesome. I would have been just as happy to settle with ember. Two way binding is a game changer.
Rails is great, BUT, I feel that, in any rails app, you end up creating interfaces that are a reflection of your database. Adding a client side framework, you’re free to create interfaces that are decoupled from your backend.
Message of the Day
February 07, 2015Lately I’ve been doing a lot of server administration. It can be a lot of fun automating systems. One thing I’ve found super valuable is to setup a “message of the day” file. This will display immediately after login and can be found in /etc/motd. I like to put notes/documentation here. For example, I’ll put in how to restart redis, how to tag a deploy, or the path to the app.