There are many implementations of password managers/safes out there. But lots of them are black boxes, either because they are not open source, or because they have to much features and it gets complicated to understand the source (which is most likely not written in a happy programming language). You don’t know, what really happens with your passwords. So…

Do it yourself!
Do it with Ruby!
Do it in less than 250 lines ;)

Although this tutorial is for people who want to learn how to use Ruby, you should be familiar with the Ruby basics.

The article is divided into four/five phases, each with a code snippet and some explanations about some lines that might not be perspicuous at first glance.

Phase 0: What is it about?

What should be the purpose of the program? These are my thoughts

It should be a little command line utility, called pws

It should store many passwords for you, and protect them with a master password

It should encrypt the password store

It should be easy to use and especially be useful for every-day-use

It should stay simple!

Phase I: Encryption

Let’s dive into it with the most exciting part: Encryption (because it’s an important part). A quick search on the net reveals how to. Let’s modernize and refactor it into a handy, small module:

require'openssl'require'fileutils'class PasswordSafeVERSION='0.0.2'.freezedef initialize(filename=File.expand_path('~/.pws'))@pwfile=filename@pwdata="example data"@pwhash=Encryptor.hash'password'access_saferead_safeendprivate# Tries to load and decrypt the password safe from the pwfiledef read_safepwdata_encrypted=File.read@pwfile@pwdata=Encryptor.decryptpwdata_encrypted,@pwhashend# Tries to encrypt and save the password safe into the pwfiledef write_safepwdata_encrypted=Encryptor.encrypt@pwdata,@pwhashFile.open(@pwfile,'w'){|f|f.writepwdata_encrypted}end# Checks if the file is accessible or create a new onedef access_safeif!File.file?@pwfileputs"No password safe detected, creating one at #@pwfile"FileUtils.touch@pwfilewrite_safeendendclass <<Encryptor=Module.newCIPHER='AES256'def decrypt(data,pwhash)crypt:decrypt,data,pwhashenddef encrypt(data,pwhash)crypt:encrypt,data,pwhashenddef hash(plaintext)OpenSSL::Digest::SHA512.new(plaintext).digestendprivate# Encrypts or decrypts the data with the password hash as key# NOTE: encryption exceptions do not get caught!def crypt(decrypt_or_encrypt,data,pwhash)c=OpenSSL::Cipher.newCIPHERc.senddecrypt_or_encrypt.to_symc.key=pwhashc.update(data)<<c.finalendendendif__FILE__==$0# test whether it works :)pws=PasswordSafe.new'p2test'print'Enter data to encrypt: 'pws.instance_variable_set:@pwdata,gets.choppws.send:write_safeputs"In safe: "+(File.readpws.instance_variable_get:@pwfile).inspectpws=PasswordSafe.new'p2test'pws.send:read_safeputs"Read from safe: "+pws.instance_variable_get(:@pwdata)end# J-_-L

def initialize( filename = File.expand_path('~/.pws') )

A new password safe is associated with a password file

pwdata_encrypted = File.read @pwfile

Reads the file into a string

File.open( @pwfile, 'w' ){ |f| f.write pwdata_encrypted }

Writes the string into a file

FileUtils.touch @pwfile

Creates an empty file just like the unix tool

pws.instance_variable_set :@pwdata, gets.chop

This is an example of the flexibility of Ruby: Access to all private variables

Also note: The Encryptor module is now within the PasswordSafe scope.

Phase III: Data structure & public api

This phase completes the basic functionality:

The passwords get saved in a hash of the Entry data structure and this hash gets saved in a file using the Marshal class for serializing

When retrieving a password, it’s copied to the clipboard

Furthermore, the zucker gem is used to write some pieces of code more cleanly

pws :)

drew | November 01, 2010

If you are using ruby 1.8.7 or later you no longer need to require fileutils.

chris | November 01, 2010

Surely this could have been done without opening the eigenclass? It's hardly simple ruby code.

Rob Gleeson | November 02, 2010

unnecessarily complex -- especially how you open the singleton class. I think you're trying to be fancy at the cost of confusing your supposed target audience.

The best code is understandable code, and I think you went out of your way to complicate the code in your examples.

J-_-L | November 02, 2010

@drew: Thanks for this hint<br/>@chris and Rob Gleeson: If I didn't open the eigenclass, I would have to prefix every method in the module with <code>self.</code> - it's common behaviour to open the eigenclass instead. I've just written it a different way to avoid the double nesting.

Jarmo Pertman | November 02, 2010

Agreed that all above was overly complicated. Using openssl, which is very poorly documented in Ruby is a complex step to do itself. I'd use Digest[1] and Crypt[2] instead for that task.

Also, asking for the password you could have used Highline [3] #ask instead of all that manual coding.

One good thing about Ruby is that "there's probably a gem for that" :)

And i'm pretty sure that the syntax "module Encryptor; class << self" is used a lot more than the syntax showed by you.

J-_-L | November 02, 2010

Crypt is indeed better documented, but OpenSSL works fine as well (although it's true, the OpenSSL api is not very intuitive). I had taken a look at HighLine, but I didn't like the api, so I went with the two "manual" lines of code.

Of course, the <code>module Enryptor; class << self</code> variant is used more often, but would it have made sense in this case? It adds an unneeded level of nesting. Whether you open the eigenclass with <code>class << self</code> or with <code>class << Encryptor</code> is not a big difference in my view.

Nevertheless, thanks for the feedback ;)

nimai | November 03, 2010

I like it. Always good to read through other peoples code. I learnt a lot, regardless of what rob and chris have said. I don't think it's unnecessarily complex.

seancribbs | November 03, 2010

The easier pattern for "singleton" modules is simply to make the first line be 'extend self'. Then you need not have that eigenclass confusion, nor create an anonymous module.

module Encryptor; extend self; # etc

Dave Sailer | March 19, 2011

"Since version 23, Emacs includes a package called EasyPG (an interface to GnuPG: https://epg.sourceforge.jp/) which makes this seamless - just make sure that you have GnuPG (https://www.gnupg.org/) installed.

"The only thing you need to do is adding the .gpg -extension to your files, and EasyPG will automatically encrypt/decrypt them when writing/reading.

"To create an encrypted file, simply visit (C-x C-f) a file with a name like myfile.txt.gpg; emacs opens this just like any file. When you want to save the file, emacs will ask you for a password, and with this same password, you can open it again."

I'm on Ubuntu 10.04, with emacs23, and found that everything was already installed. All I had to do was use it.