bk2204 / daniel-ruby

An easy-to-use password generator

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

daniel

What is it?

daniel is a fast password generator based on using a single master password. When generating a password, it produces a small "reminder" containing all the information necessary to reproduce the password, but only in conjunction with the master password. Without the master password, the reminder is useless.

How does it work?

Simply run the script from the command line:

% daniel
Please enter your master password:

Enter a strong master password. This can actually be a passphrase: it can contain any text you like, as long as it’s in UTF-8. Be sure this is something you can remember, since your passwords cannot be recovered if you forget it.

Then daniel will print out a six-character checksum. This checksum is computed based on the master password, and it will likely be different if you accidentally mistype your master password. This helps prevent you from generating a lot of passwords based on a mistyped passphrase and then being unable to reproduce them.

daniel then prompts you for a code. This code is used to generate a unique password. One common technique is to use an abbreviated form of the domain name, so if you wanted to generate a password for GitHub, you could use “github.com” (without the quotes).

Finally, daniel produces the password and a reminder. If you run daniel with the reminder on the command line, it will print out the same password as before once you enter your master password.

% daniel
Please enter your master password:
# ok, checksum is 72eb36
Enter code: example.tld
Password is: nj&xzO@hz&QvuoGY
Reminder is: 72eb360a1000example.tld

% daniel 72eb360a1000example.tld
Please enter your master password:
# ok, checksum is 72eb36
Password is: nj&xzO@hz&QvuoGY

The master password in this case was “foobar”. Please use something more secure.

Can I adjust the set of characters that are generated?

Yes. The flags parameter can be adjusted on the command line with -f, or by entering !flags=value at the “Enter code:” prompt. When the flags are set to 0, all characters from hex 20 to hex 7E are included. The different bits mean:

Flag

Meaning

1

Exclude all digits

2

Exclude spaces

4

Exclude those characters on top of the digits on a US keyboard

8

Exclude other symbols

16

Exclude letters

The default is 2 (exclude spaces) because many websites don’t handle those characters properly. The flags parameter is encoded as part of the reminder, and changing the flags will cause a completely different password to be generated.

To generate an arbitrary byte sequence, such as a shared secret for HOTP or TOTP, set the flags to 128. The sequence is printed in hexadecimal, or URL-encoded in machine-readable format.

Can I adjust the length of the password?

Yes. The length can be adjusted using the -l parameter, or by entering !length=value at the “Enter code:” prompt. The length is encoded as part of the reminder, but it does not cause the generated password to be any different other than in length. That is, truncating a 16-character password to 8 characters is exactly the same as generating an 8-character password with the same parameters. The default length is 16.

What if a site forces me to change my password frequently?

There is a version field that can be incremented to produce a completely different password. Use -v or enter !version=value at the “Enter code:” prompt. The default version is 0, and values up to 232-1 are accepted. The version is encoded as part of the reminder.

This feature was written with the corporate and academic worlds in mind, but it can also be used if you absolutely need one of a certain set of characters in your password, but the default one that was generated does not contain such a character. Simply bump the version number until a satisfactory password is generated.

Do I need to protect the reminder?

No. You may store it completely publicly. Without the master password, it cannot be used to regenerate your password. Note, however, that if you choose to store reminders publicly, and they contain information about the site in question, you are disclosing to the public that you have an account on that site.

Can I use this to remember a password I generated with a different program?

Yes. You can use the -m flag to put daniel into existing password mode. Instead of generating a new password, it will prompt you (twice) for an existing password, and generate a reminder from that. These reminders are much longer than the standard kind, however.

You should not use the same code for more than one password, as this will leak information about your password.

Can I copy the password to the clipboard instead of printing it?

Yes. Install the clipboard gem and its dependencies and use the -p option. Note that on Linux, the xclip utility is required unless you are using a version of the clipboard gem newer than 1.0.5, as xsel support is broken in earlier versions.

Can I script daniel?

Yes. You can use the -r option to put daniel in machine-readable mode. Instead of the normal output, daniel will print a number of lines each beginning with a colon. If the line is a prompt, it will end with a question mark. If the line is an error, it will end with an exclamation point. Otherwise, after the message type, a single space and a URL-encoded value will be output. This ensures that all characters are represented properly and that a non-prompt line can never end in a question mark.

What characters are above the digits on a US keyboard?

The following: !@#$%^&*().

Why isn’t this a gem?

daniel can be loaded with Kernel#load, or with Kernel#require if you use the version in the lib directory (since it has an .rb extension). The tests use this technique.

It’s also designed to be a single, standalone script so that people can copy it wherever they might need it. I will probably make it a gem at some point, though.

Why is daniel written in Ruby?

Ruby provides all the necessary cryptographic primitives as part of the standard library. Other languages, such as Perl, do not.

What versions of Ruby are supported?

The code should run on MRI 1.8.7, 1.9.3, 2.0.0, 2.1, 2.2, 2.3, 2.4, and 2.5. 1.8 will require the io-console gem for interactive use; this is part of the standard library in 1.9.3.

JRuby 1.7 works fine with the jruby-openssl gem. Other versions haven’t been tested, but are expected to work. At least in theory, there’s no reason it shouldn’t function just fine on Rubinius as well.

Opal can be used, provided you copy or symlink the files from the core directory of the Stanford JavaScript Crypto Library (sjcl) into lib/daniel/opal. Due to a large portion of the Ruby standard library being unavailable in Opal, daniel can only be used as a library with it; no main program is available.

Having said that, only MRI 1.9.3, 2.0.0, 2.1, 2.2, and 2.3 are officially supported. I will probably notice if the tests fail on 1.8.7 and fix it myself. You’re welcome to send a pull request if it doesn’t work on your preferred flavor (although please stick to 1.8.7-equivalent or newer).

So what about the cryptography you’re using?

Glad you asked. Essentially, the master password is hashed with some static data using 1024 iterations of PBKDF-2 using HMAC-SHA256. No salt is used, since there is no place to store the salt. This produces the master secret.

The checksum is generated from the first three bytes, hex-encoded, of the SHA-256 hash of the master secret and some static data. This is done from the master secret and not the master password because it forces an attacker to go through the PBKDF-2 step in order to generate candidate matches.

Now things differ.

Version 0

The code, flags, password version, and some static data are hashed using PBKDF-2 again, this time with the master secret as the salt. This produces the initialization vector.

To generate the password, AES-256 in counter mode is used as a byte generator, with the master secret as the key and the first 16 bytes of the initialization vector, as, well, the initialization vector. If a generated byte is in the set of acceptable values, it is output; otherwise, it is discarded.

For existing password mode, the byte generator is run the same way, except that the first n bytes (where n is the existing password length), regardless of value, are XORed with the existing password to generate a mask, which is encoded in the reminder.

Version 1

The master secret is run through an additional, variable number of iterations of PBKDF2/HMAC-SHA256 (default of 1024), with an additional salt (if provided). This produces the master key.

The master key is used with HKDF-Expand (using SHA-256) to produce a 256-bit seed and 256-bit MAC key.

The flags, version, and code are serialized into a canonical JSON format, and hashed with SHA-256. An HMAC-DRBG instance using SHA-256 is created using the seed and the hash of the JSON parameters. 1024 bytes are generated at a time, and the password or mask is generated from these bytes, just as the AES output is used for version 0.

The data for a version 1 reminder is encoded as a JWT with a prefix and suffix. The MAC key is used to protect the contents of this JWT using the HS256 algorithm.

The version 1 algorithm was designed to improve on defects in version 0 (such as the lack of salt, a fixed number of iterations, and unprotected parameters). It also has the benefit that it can be easily implemented without support for cryptographic operations other than SHA-256 and HMAC, in case of export concerns.

Version 1 reminders also have the ability to use a checksum of all-zeros, which indicates that no checksum comparison is to be done. This prevents leaking any information about the master password, except by checking of the MAC.

About

An easy-to-use password generator

License:MIT License


Languages

Language:Ruby 96.5%Language:HTML 3.5%Language:CSS 0.0%