Cryptobox - Passwords storage solution <img src=“https://travis-ci.org/fomichev/cryptobox.png”/>¶ ↑
- Author
-
Stanislav Fomichev (s@fomichev.me)
- Copyright
-
© 2012 by Stanislav Fomichev
- License
-
MIT
Cryptobox is a bunch of Ruby scripts that help you manage passwords and other sensitive data. The idea is simple: there is some encrypted file (cryptobox/cryptobox.yaml
) where the sensitive information is stored. To edit it you use special executable (cryptobox edit
) which will open editor and let you update passwords/bookmarks/notes/etc. When the editor is closed, cryptobox edit
will create beautiful and easy to navigate HTML page with all your sensitive information (encrypted). This HTML page will also contain Javascript code which can decrypt attached encrypted data on the fly when you provide the correct password.
Your sensitive information is never exposed; it’s never stored on the disk in the plain text and exists in the HTML page only in the encrypted form.
To get an idea of what the result HTML looks like, you may download and run either desktop or mobile version of the application. These applications were generated from the following YAML file and as an example of what it looks like when it’s stored on the disk download cryptobox.yaml.
There’s no gem distribution so far, thus the only possible solution is to make a git clone. So to install cryptobox, make a git clone of this repository and add <path to your clone>/bin
directory to the PATH environment variable.
You may also build gem yourself using the following command:
$ rake gem
And then install it with:
$ gem install pkg/cryptobox-*.gem
Please note, that the required version of Ruby is 1.9! 1.8 will not work because of the threading model (and who knows what the other issues are). You can get Ruby for Windows from ruby-lang.org; on Max OS X you can use brew to get Ruby; and on Linux system use whatever package manager is installed on your system to install it.
To create new database (creates empty cryptobox/cryptobox.yaml
) execute the following command:
$ cryptobox create
Upon database creation, PBKDB2 salt and AES IV will be generated. That guarantees that even two databases with the same content will be encrypted to different cipher text.
To edit your database (it will also update html page at cryptobox/html/cryptobox.html
and at cryptobox/html/m.cryptobox.html
) use this command:
$ cryptobox edit
Whenever you edit cryptobox database, the backup file (under cryptobox/backup
) is created with the previous version of your database. So if some unexpected error happens, you can always restore your previous database contents.
In order to change password (every couple of months) execute:
$ cryptobox passwd
As in cryptobox edit
command, backup file will be created (or updated) whenever you change the password.
-
Secure storage of sensitive information;
-
Desktop and mobile HTML pages for ease of use;
-
One-click login for sites without authenticity tokens (read more below);
-
More-than-one-click login for sites with authenticity tokens (that still saves you from manually copy-pasting your passwords);
-
Really small amount of code. You can get through it probably within an hour or two (to ensure that your data is safe);
-
Works on every platform with modern browser (everywhere);
-
Chrome extension or browser bookmarklet to login to currently displayed page.
All information is stored in the cryptobox/cryptobox.yaml
file, encrypted via AES; key length is 128 bits (by default) and it is derived from your master password (recommend way to generate it - Diceware) using PBKDF2.
When cryptobox edit
generates HTML, it asks your password, decrypts cryptobox/cryptbox.yaml
file and merges it with JSON patterns from include/
directory (more on this later), encrypts it using AES cipher and puts this information into HTML page. Later on, when you open it in the browser, it will ask your password and decrypt attached database on the fly. So, your sensitive information is never exposed in plain text.
The steps cryptobox edit
does to generate HTML are:
-
Reads
cryptobox/cryptobox.yaml
and decrypts it in memory; -
For each type of entry in this file, reads appropriate JSON file from
include/
and merges it with entry’s variables (username, password, etc); -
Merges all JSON entries into one string and encrypts it with AES;
-
Embeds this encrypted data into pre-baked HTML page (look at
src/html/
for more details); -
Embeds JavaScript and CSS (along with images) into HTML page and stores it under
cryptobox/html
directory (cryptobox.html
- is a desktop version;m.cryptobox.html
- is a mobile one); -
Does the same embedding for chrome extension and form bookmarklet.
TODO: describe how cryptobox edit
uses pipes to run editor and what it does instead on Windows:
-
cryptobox edit –no-pipe
Some sites use authenticity token which they place into the HTML you get; the login form along with username and password fields contains hidden field with authenticity token. So it’s no longer possible to use one-click login feature with such sites (where one-click login feature is simple post request with known username and password). But there is a solution!
There is a bookmarklet that you can run on a login page; it will parse the form data and will let you copy it in JSON format. Then, when you press ‘Log in’ button for token based sites, you’ll be asked for this data. After you paste it and press ‘OK’ you’ll be automatically logged in (using provided authenticity token and your username/password).
When you’re adding such form to the web forms storage (include/webform
), you should set token field value to __token__
; that will lead to a pop-up dialog box on login asking you to provide the form data (you may have multiple tokens within forms).
TODO: Describe how to get this bookmarklet; also describe login bookmarklet.
javascript:(function(){s=document.createElement('SCRIPT'); s.type='text/javascript';s.src='https://<BOOKMARKLET_PATH>'; document.getElementsByTagName('head')[0].appendChild(s);})();
TODO: add details here
YAML format is used for database. More information with examples can be found at the appropriate page.
Your sensitive information is stored in the form of entries; there may be a number of entries, each describing particular web form, bookmark, secure note or other information.
Entry has the following structure (fields in square brackets are optional):
<entry type>: - <entry name>: [tag: <tag>] [visible: false] <variable1>: <value1> <variableN>: <valueN> <multiline>: <line1> <line2> - <another entry with different name but the same type>: [tag: <tag>] [visible: false] <variable1>: <value1> <variableN>: <valueN> <multiline>: <line1> <line2>
You don’t need to quote anything (unless you have spaces or tabs at the beginning or at the end of your password/username); just put variable name on the left side of a colon and variable value on the right side of a colon without any quotes.
Entry type is a relative path to a file inside the include/
directory. And the first component in this path (until the first / of end of string) will form a tab in the HTML page. So, for example, if you have webform/google.com
and webform/yahoo.com
, there will be a webform
page (or Sites
because of predefined translations) in the HTML document containing two entries. If you have several note
entries, they will be located on anther tab. Be aware that you can’t have two entries with the same entry type
and entry name
!
Each file in the include/
directory is a JSON file which describes the format and layout of the entry. Variables from the entry will be substituted with <%= @vars[:NAME] %>
inside the JSON file and will form particular web form/bookmark/etc. There is some special handling for the webform
entries, where it’s expected to have form fields information in <%= @vars[:name] %>
and <%= @vars[:pass] %>
variables. For the other entries, there will be probably only text
(and mtext
for mobile version if special handling required) variable that will somehow format other variables from the entry.
Entry name has special meaning for webform
entry type: it should contain your username. For the other entry types, entry name is just the caption of the entry.
Tag variable will let you ‘merge’ several entries into a block (they will be placed close to each other on the HTML page). You don’t have to use tag variable, it’s usage is optional (and intended to help you with the clutter).
You can use visible: false
to remove some entries from the final HTML page (this is handy for the entries you want to keep and be able to access at some point but don’t want it to clutter your HTML). For Chrome extension visible
attribute controls whether web form will appear in the unmatched section (so it will hide it from the list but will still allow you to login to hidden sites that you know).
Comments are started with # and continue till the end of the line.
No, there is probably no easy way to automate it (taking into account the number of existing formats); you have to create (or use pre-created) JSON form layout in the include/webform
directory (via provided bookmarklet) and then add entry with your username/password to cryptobox/cryptobox.yaml
manually.
I’m not telling its impossible; I just see no need to implement it myself. The best way to import some existing data is too create a custom script (and contribute it back :-) ) which parses CSV (or some similar plaintext format which your current tool exports to), generate appropriate YAML and feed it directly to cryptobox edit --stdin
. The only thing you lose is the ability to use one-click login feature of the desktop HTML because there no data about forms fields (but you can always add missing form data manually later).
No, there are no reasons to switch from cryptobox :-) But if you have strong reasons, you can always implement cryptobox/cryptobox.yaml
parser yourself; the format is YAML, so probably all languages have some support of it and cryptobox edit
tool have useful --stdout
argument which you can use to pipe your plain text database to other tools safely.
I think it’s pretty straightforward. You can use aforesaid form
bookmarklet on your target site. The only caveat is that it can have multiple forms on one page, so watch out and select the one you need (don’t copy leading [ and trailing ], JSON data should start with { and end with }). Afterwards, look through the JSON and place <%= @vars[:name] %>
and <%= @vars[:pass] %>
into appropriate form fields (look for the other web forms’ JSON data in include/webform
, it will become clear from the example what to do). Better yet, you can fill in the form in the browser with the mentioned values and run the bookmarklet; this way, you don’t need to dig into the JSON and find out were to put these marks, they will already be in place.
Database example is located in sample/cryptobox.yml
file with the following sample generated data:
-
sample/cryptobox/bookmarklet/form.js
- form bookmarklet; -
sample/cryptobox/html/cryptobox.html
- desktop HTML application; -
sample/cryptobox/html/m.cryptobox.html
- mobile HTML application; -
sample/cryptobox/dropbox/html/*.html
- desktop and mobile HTML applications which can readcryptobox.json
from the Dropbox.
TODO: make more meaningful example and comment it here or directly in the example
You can configure cryptobox via configuration file called .cryptoboxrc
. When you run any of the cryptobox commands, it first searches for the .cryptoboxrc
file in the current directory, then it tries to find this file in your home directory, and if it didn’t find any configuration, it will use the default one. You can also pass configuration file path to the tools via -c
command line option.
Configuration file is simple YAML file with the following possible variables:
-
path.root
: root path to the installed cryptobox application
(default should work for anybody);
-
path.home
: path to the home directory of the user where (defaults
to actual user home, e.g. $HOME); cryptobox edit
will create its temporary files for communication with editor;
-
path.cryptobox
: path to the root database directory (default
<current directory>/cryptobox);
-
path.dropbox
: where to store applications that support dropbox
(default <path.cryptobox>/dropbox);
-
path.yml
: where to store cryptobox.yaml (default
<path.cryptobox>/cryptobox.json);
-
path.json
: where to store cryptobox.json (default
<path.cryptobox/cryptobox.json) ;
-
path.back
: where to store backups (default <path.cryptobox>/backup); -
ui.editor
: full path to your editor of choice; please note that this
command needs to start editor in the foreground; for example, for vim
it is -f option (default depends on the platform);
-
ui.lang
: selected language; currently supported are en and ru
default en);
-
ui.lock_timeout_minutes
: HTML application auto lock timeout in
minutes (default 5);
-
ui.default_password_length
: default password length in ‘generate
password’ dialog (default 16);
-
cryptobox.date_format
: date format that is used to generate date
in the HTML application (default %H:%M %d.%m.%Y);
-
cryptobox.keep_backups
: whether to keep (indefinite) backups or
not (default true);
All options are optional. Here’s probably a good example .cryptoboxrc
to put in your home directory:
path: cryptobox: ~/cryptobox
This way you can run cryptobox
command from any directory and it will still be able to find the database.
cat include.json | ruby -p -e '$_.sub!(/\n/, "").strip!' > processed.json
Put ‘include’ key in your database, e.g:
include: 'webform/xyz.com': { here goes JSON } 'webform/qwe.com': { here goes another JSON }
On Ruby side standard bindings to OpenSSL are used to manage database.
-
Used to compile Handlebars templates to JS
therubyracer gem is required for cross platform Javascript engine (V8)
-
Compile CSS and JS
-
Compress CSS and JS
This GEM required Java Runtime!
-
Test Rub and JS parts
-
Aruba Cucumber extension for console application testing
-
Ruby browser simulator for tests
-
PhantomJS driver for Capybara
-
Headless WebKit with JavaScript API
-
Iconic - CC BY-SA 3.0
src/chrome/icon.png
-
CryptoJS 3.0.2 - New BSD License
src/extern/CryptoJS
-
Random Seed 2.0 - BSD
src/extern/seedrandom
-
jQuery 1.8.3 - MIT
src/extern/jquery
-
Twitter Bootstrap 2.2.2 - Apache License, Version 2.0
src/extern/bootstrap
-
Handlebars 1.0.rc.1 - MIT
src/extern/handlebars
-
jQuery Mobile 1.2.0 - MIT
src/extern/jquery-mobile
-
Clippy 7329b72360 - MIT
src/extern/clippy
Even if you don’t have cryptobox available, you may still fairly easy decrypt your data.
Lets suppose, you have the following data encrypted:
webform/dropbox.com: - your_username: pass: your_password
With the following contents of cryptobox
file:
--- pbkdf2_salt: O4ERPqXt+Ro= pbkdf2_iter: 2000 aes_iv: V6WEGmrqOG21yc0h/uLqfg== aes_keylen: 128 format_version: 6 version: '0.8' timestamp: '2012-10-24T13:41:00+04:00' ciphertext: TfO1PfIJ/HTk6b71lyTgQvGARccaHeM0kRUYqlrz10Map4tx9dHP9ir9pPF/qMpnX0mkmf6urdbnfSESbB6kNA==
Now, let’s try to decrypt it (instructions are provided for Linux)!
Before you proceed, I want to warn you that the following commands are not safe! You will pass your AES key to the openssl
utility via command line (and will also store your plain text password in the file). So make it if you really need to get your data no matter what consequences may be. The following text is used just to demonstrate that your data could be easily decrypted using standard tools.
You have to take out the value of pbkdf2_salt field of config and convert it to hex encoding (ensure that file has UNIX line endings):
$ grep pbkdf2_salt cryptobox | cut -d: -f2 | tr -d ' ' | base64 -d | xxd -ps 3b81113ea5edf91a
Next, go and download a Perl script which implements PBKDF2 using OpenSSL:
$ wget http://www.ict.griffith.edu.au/anthony/software/pbkdf2.pl
Store your password in pwd
file and execute Perl script:
$ cat pwd hi $ perl pbkdf2.pl 3b81113ea5edf91a $(grep pbkdf2_iter cryptobox | cut -d: -f2) < pwd > result $ cat result 0cdfd225b34aee20877b969f38cc5f9191b7affc3d7a1d1d64dfc517d15c7937b323478b4c4a4bc8091150a12c9e8d9f
And because we are interested only if first 32 bytes (in case of AES 256), we need to cut the rest (the number 64 in the following command is 32 * 2 because each byte in hex encoding is represented by two characters)
$ cat result | cut -b1-64 > secret $ cat secret 0cdfd225b34aee20877b969f38cc5f9191b7affc3d7a1d1d64dfc517d15c7937
Now, we have a key, the only thing we need to do is to convert initialization vector (aes_iv) to hex, extract ciphertext from cryptobox and call openssl, let’s do it:
$ grep aes_iv cryptobox | cut -d: -f2 | tr -d ' ' | base64 -d | xxd -ps > iv $ cat iv 57a5841a6aea386db5c9cd21fee2ea7e $ grep ciphertext cryptobox | cut -d: -f2 | tr -d ' ' | tr -d "\n" > ciphertext $ cat ciphertext TfO1PfIJ/HTk6b71lyTgQvGARccaHeM0kRUYqlrz10Map4tx9dHP9ir9pPF/qMpnX0mkmf6urdbnfSESbB6kNA== $ openssl enc -base64 -A -d -aes-$(grep aes_keylen cryptobox | cut -d: -f2 | tr -d ' ')-cbc -K $(cat secret) -iv $(cat iv) -in ciphertext -out plaintext $ cat plaintext webform/dropbox.com: - your_username: pass: your_password
Congratulations, plaintext contains decrypted content of your cryptobox. Now, it’s better to remove all temporary files and clean bash
history.
TODO: describe here what libs used and where
-
rake handlebars TODO
-
rake sprockets TODO
-
rake build Executes both ‘rake handlebars` and `rake sprockets` which is usually the right thing to do.
-
describe the following features
-
broken web forms (do they still work? recheck!)
-
cryptobox.json
-
how to integrate include into yaml
-
in vim to read database :r !cryptobox edit –stdout (enter password and press enter)
to save database :w !cryptobox edit --stdin
-
cryptobox cat
-
web form aliases
-
cryptobox edit –no-pipe
-
-
revise README.rdoc and add other missing information
-
mention somewhere: supported fields for web form entry are: user, pass, secret, note
-
add comments to include/ JSON
-
new pbkdf2 salt and aes iv is generated whenever database is saved
-
fix form include for appleid.apple.com
-
mark habrahabr.com as broken (requires captcha)
-
use different default editors on different platforms
-
add some validation for DB and include/
-
ssh-agent/gnome-keyring daemon so we may hook up to the existing browsers/tools
-
new pbkdf2 salt and aes iv is generated whenever database is saved, make it configurable option
-
TEST FORM BOOKMARKLET (may not work because of the latest changes)
-
add CSS to bookmarklets popover so they look the same on all sites
-
fix form bookmarklet for deviantart.com
-
add format_version check (useful for dropbox)
-
keep passwords in memory encrypted (with some temporary key), decrypt as soon as user needs them; may prevent leaking when swapping or doing memory dump
-
rename div- to something more meaningful
-
Check login with token
-
Consider using random.org for generating passwords
-
Fix autolock
-
Align locked page with desktop version (left justify form elements)
-
Add key binding to show popup (using popover class)
-
Prepack dropbox.js instead of relying on cdn
-
Fix, test and cleanup Dropbox support
-
Try to open Dropbox authorization popup and also provide a link
-
Add documentation
-
Implement desktop Firefox plugin
-
Implement mobile Firefox plugin (only with dropbox integration)