Skip to content

Latest commit

 

History

History
561 lines (423 loc) · 22 KB

README.rdoc

File metadata and controls

561 lines (423 loc) · 22 KB
Author

Stanislav Fomichev ([email protected])

Copyright

© 2012 by Stanislav Fomichev

License

MIT

Overview

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.

Install

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.

Use

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.

Features

  • 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.

Guts

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:

Form bookmarklet

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);})();

Chrome extension

TODO: add details here

Database format

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.

Is it possible to import database from other password managers?

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).

Is is possible to export database to other password managers?

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.

Extending / Adding new web form (includes)

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

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 read cryptobox.json from the Dropbox.

TODO: make more meaningful example and comment it here or directly in the example

Configuration

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.

Embed include into 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 }

Used components

Ruby

On Ruby side standard bindings to OpenSSL are used to manage database.

The following components are required only for development

  • ExecJS

    Used to compile Handlebars templates to JS

    therubyracer gem is required for cross platform Javascript engine (V8)

  • Sprockets

    Compile CSS and JS

  • Ruby-YUI Compressor

    Compress CSS and JS

    This GEM required Java Runtime!

  • Cucumber

    Test Rub and JS parts

  • Aruba Cucumber extension for console application testing

  • Capybara

    Ruby browser simulator for tests

  • Poltergeist

    PhantomJS driver for Capybara

  • PhantomJS

    Headless WebKit with JavaScript API

Chrome extension

  • Iconic - CC BY-SA 3.0

    src/chrome/icon.png

JavaScript

Decrypt data without cryptobox

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.

Give me the key!

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

Decrypt my data

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.

Development

TODO: describe here what libs used and where

Update templates

  • rake handlebars TODO

  • rake sprockets TODO

  • rake build Executes both ‘rake handlebars` and `rake sprockets` which is usually the right thing to do.

Todo

Documentation

  • 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

Include

  • fix form include for appleid.apple.com

  • mark habrahabr.com as broken (requires captcha)

Ruby

  • 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

Bookmarklets

  • 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

Common JS

  • 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

Desktop HTML

  • Check login with token

  • Consider using random.org for generating passwords

Chrome extension

  • Fix autolock

  • Align locked page with desktop version (left justify form elements)

  • Add key binding to show popup (using popover class)

Version with Dropbox support

  • 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

Firefox extension

  • Implement desktop Firefox plugin

  • Implement mobile Firefox plugin (only with dropbox integration)