NAME
ccr - The post-quantum cryptography encryption and signing tool
SYNOPSIS
ccr [OPTION]...
DESCRIPTION
ccr (short of Codecrypt) is a general purpose encryption/decryption signing/verification tool that uses only quantum-computer-resistant algorithms.
General
options:
-h, --help
Show a simple help with option listing.
-V, --version
Display only version information.
-T, --test
This option exists as a convenience for hackers - in this case, ccr initializes itself, calls a test() function from source file src/main.cpp (that is meant to be filled by testing stuff beforehand) and terminates. In distribution packages, it will probably do nothing.
-R, --in <file>
Redirect standard input to be read from file instead from stdin. You can still specify "-" to force reading from stdin.
-o, --out <file>
Redirect standard output to be written to file. You can specify "-" to force writing to stdout.
-E, --err <file>
Redirect the standard error output to file. You can specify "-" to force writing to stderr. Error output does not carry any data, but provides useful error messages and metadata about what is happening, e.g. the identity of message signer or details about why decryption or verification fails.
-a, --armor
Where expecting input or output of data in codecrypt communication format, use ascii-armoring.
Codecrypt otherwise usually generates raw binary data, that are very hard to pass through e-mail or similar text communication channels.
-y, --yes
Assume the user knows what he is doing, and answer "yes" to all questions.
Actions:
-s, --sign
Produce a signed message from input.
-v, --verify
Take a signed message from input, verify whether the signature is valid, and output message content if the verification succeeded.
-e, --encrypt
Produce an encrypted message from input.
-d, --decrypt
Decrypt the message from input.
Note that the actions for signature/encryption and decryption/verification can be easily combined into one command, simply by specifying both options usually as "-se" or "-dv".
Action
options:
-r, --recipient <keyspec>
Specify that the message for encryption should be encrypted so that only the owner of a private key paired with public key specified by keyspec can decrypt it.
-u, --user <keyspec>
Specify a private key to use for signing the message. If this option is empty, it is defaulted from CCR_USER environment variable.
-C, --cleartext
When working with signatures, produce/expect a cleartext signature. The basic property of cleartext signature is that the message it contains is easily readable by users, therefore it is a very popular method to e.g. sign e-mails.
-b, --detach-sign <file>
On signing, produce a detached signature and save it to file. When verifying, read the detached signature from file. Note that files that is being signed or verified must be put into program’s input (potentially using "-R" option.
-S, --symmetric <file>
Use symmetric cryptography.
When doing "sign" or "verify" operation, do not sign asymmetrically, but instead generate file with cryptographic hashes that can later be used to verify if the contents of input was changed.
When doing "generate", "encrypt" or "decrypt" operation, do not encrypt asymmetrically, but instead generate or use a file with a key for specified symmetric cipher. Use "-g help" to see available symmetric primitives. For symmetric encryption to work, at least one stream cipher (marked with C) and at least one hash function (marked with H, used to protect against malleability) separated by comma need to be selected. Additionally, user can specify "longblock" or "shortblock" keyword to manipulate size of internal encryption block structure (longer blocks consume more RAM, but the ciphertext doesn’t grow very much); or the "longkey" flag which creates larger symmetric key to provide more key material to the ciphers (which can help to protect against low-quality random numbers, but is generally unnecessary and even considered to be a bad practice). It is also possible to combine more stream ciphers and hash functions.
Purpose of the --symmetric option is that symmetric cryptography is a lot faster than asymmetric, and symmetric primitives usually work also on very large files and data streams, as they don’t need to be fully copied into allocated memory for this purpose. Thus, if working with a large file, process it symmetrically first, then sign/encrypt the (tiny) symmetric file asymmetrically and send it along with the (possibly encrypted) large file.
Key
management:
In Codecrypt, each public key has a KeyID, which is
basically a hash of its representation that is used to
identify the key globally. Each public key is stored along
with a key name, which is a convenience tool for users who
can store arbitrary information about e.g. what is the key
meant for or who it belongs to. Public keys also have an
algorithm identifier to specify how to work with them, and
sometimes also attached a private key to form a secret
"keypair".
Keys can be specified using several methods:
Using KeyID -- the key specification starts with @ and continues with several first characters of the KeyID that identify a single key with that prefix.
Using a name --
key specification consists of a string, a key is then
matched if its name contains the specified string. Matching
is case-insensitive.
-g, --gen-key <algorithm>
Generate a keypair for usage with specified algorithm. Use "-g help" to get list of all algorithms available. Listing also contains flags "S" and "E", meaning that algorithm can be used for signatures or encryption, or "H" and "C" for usage with symmetric hashes and ciphers. In asymmetric case (where the algorithm names are long) the supplied algorithm name does not need to be a full name, but must match only one available algorithm.
-N, --name <keyname>
Specify that affected keys (those being imported, generated, exported or renamed) should be newly renamed to keyname.
-F, --filter <keyspec>
When listing, importing or exporting keys, only process keys that match keyspec.
-k, --list
List available public keys.
-K, --list-secret
List available private keys (in keypairs).
-i, --import
Import public keys.
-I, --import-secret
Import private keypairs.
-n, --no-action
On import, do not really import the keys, but only print what keys and names will be imported. This is useful for preventing accepting unwanted private or public keys.
-f, --fingerprint
When printing keys, format full KeyIDs. Note that full KeyIDs can be used in similar way as fingerprints known from other crypto tools.
-p, --export
Export public keys in keyring format.
-P, --export-secret
Export private keys. (Do this carefully!)
-x, --delete <keyspec>
Remove matching keys from public keyring.
-X, --delete-secret <keyspec>
Remove matching keys from private keypairs.
-m, --rename <keyspec>
Rename matching public keys. Use "-N" to specify a new name.
-M, --rename-secret <keyspec>
Rename matching private keys.
-w, --with-lock <file>
When loading the secret part of the keyring, decrypt the file using the specified shared key. If that file looks encrypted and -w is not specified, asking for the password interactively (i.e. "-w @") will be assumed.
FILES
Codecrypt stores user data in a directory specified by environment variable CCR_DIR, which defaults to "$HOME/.ccr". It contains the files "pubkeys" and "secrets" which are sencode keyring representations of user’s public and private keyring.
Backups of user data (i.e. for each file the last state that was loaded successfully) are, on each change, written to files "pubkeys~" and "secrets~".
When Codecrypt is running, it locks the ".ccr" directory using a lockfile "lock" and applying flock(2) to it.
For seeding the random number generator, Codecrypt uses data from "/dev/random" for generating keys and "/dev/urandom" for everything else, e.g. nonces or envelopes. Both cases can be overridden at once by specifying some other filename in environment variable CCR_RANDOM_SEED.
RETURN VALUE
ccr returns exit status 0 if there was no error and all cryptography went fine, or 1 on generic errors. If the error was that a missing hash algorithm or a public or private key was needed to complete the operation, 2 is returned. If signature or hash verification fails (e.g. the signature is bad or likely forged), the program returns 3.
ALGORITHMS
Program offers several "algorithms" that can be used for signatures and encryption. Use "ccr -g help" to get a list of supported algorithms.
FMTSeq-named schemes are the Merkle-tree signature algorithms. The name FMTSEQxxx-HASH1-HASH2 means, that the scheme provides attack complexity ("bit security") around 2^xxx, HASH1 is used as a message digest algorithm, and HASH2 is used for construction of Merkle tree.
McEliece-based encryption schemes are formed from McEliece trapdoor running on quasi-dyadic Goppa codes (the MCEQD- algorithms) and on quasi-cyclis medium-density parity-check (QCMDPC- ones) with Fujisaki-Okamoto encryption padding for CCA2. Algorithm name MCEQDxxxFO-HASH-CIPHER means that the trapdoor is designed to provide attack complexity around 2^xxx, and HASH and CIPHER are the hash and symmetric cipher functions that are used in Fujisaki-Okamoto padding scheme.
As of November 2015, users are advised to deploy the 2^128-secure variants of the algorithms -- running 2^128 operations would require around 10^22 years of CPU time (of a pretty fast CPU), which is considered more than sufficient for any reasonable setup and using stronger algorithms seems just completely unnecessary.
Note that using stronger algorithm variants does not come with any serious performance drawback and protects the user from non-fatal attacks that decrease the security of the scheme only by a small amount -- compare getting an attack speedup of 2^20 on a scheme with 2^80 bit security (which is fatal) with getting the same speedup on a scheme with 2^128 security (where the resulting 2^108 is still strong).
For comparison with existing schemes, 2^128 security level is very roughly equivalent to that of classical RSA with 3072bit modulus (which is, accordingly to the best results available in June 2013 for general public, reported to provide roughly 2^112 attack complexity).
For another comparison, a very good idea about the unbelievably insane amount of energy that is actually needed for brute-forcing 2^256 operations can be obtained from Wikipedia, which estimates the size of whole observable universe (!) to around 2^270 atoms.
All algorithms are believed to be resistant to quantum-computer-specific attacks, except for the generic case of Grover search which (in a very idealized case and very roughly) halves the bit security (although the attack remains exponential). Users who are aware of large quantum computers being built are advised to use 2^192 or 2^256 bit security keys.
PASSWORD-DERIVED SYMMETRIC KEYS AND PASSWORD-PROTECTED SECRETS
Symmetric keys can be specified using a filename, or expanded from a password (which is convenient e.g. for protecting private keys): If the filename for -S starts with "@", program will first check the rest of the filename to find a symmetric cipher algorithm specification, as in -g. If nothing is specified, it will check CCR_SYMMETRIC_ALGORITHM environment variable, and if that is still unspecified, it will default to "SYM,SHORTBLOCK". The reason for defaulting the short blocks is that the functionality focuses on tiny keys.
After the symmetric algorithm is chosen, program will try to get the password from environment variable CCR_SYMMETRIC_PASSWORD. If that variable is not set, it will ask the user for the password interactively.
The password will be expanded to internally form a symmetric key for the specified algorithm, which will in turn be used for the requested action.
Symmetric and private keys may be encrypted by a password or a symmetric key. Parameter -w accepts the same arguments as -S, with the exception that the resulting loaded or internally generated symmetric key will be used to encrypt or decrypt symmetric and private keys when required:
Actions -L and -U can be used to lock, resp. unlock private keys (specific keys to be modified can be selected using --filter) or symmetric keys (if used together with -S). Action -g can be modified by -L in the same way.
The environment variables used for automatically-specifying the password in this case are separate from the previous ones: CCR_KEYRING_PASSWORD and CCR_KEYRING_ALGORITHM for locking/unlocking private keys, respectively CCR_SYMKEY_PASSWORD and CCR_SYMKEY_ALGORITHM for specifying symmetric key used to unlock other symmetric keys (even the ones that are themselves used for locking other keys).
WARNINGS AND CAVEATS
General
advice
Codecrypt does not do much to prevent damage from mistakes
of the user. Be especially careful when managing your
keyring, be aware that some operations can rename or delete
more keys at once. Used cryptography is relatively new,
therefore be sure to verify current state of cryptanalysis
before you put your data at risk.
Current
state of cryptanalysis
In a fashion similar to aforementioned ’new
cryptography’, the original algebraic variant of
quasi-dyadic McEliece that is still in codecrypt (MCEQD*
algorithms, kept for compatibility purposes) has been broken
by an algebraic attack. Security is greatly reduced. Use the
QC-MDPC variant which dodges similar attacks.
Large
files
Codecrypt is not very good for working directly with large
files. Because of the message format and code clarity, whole
input files and messages are usually loaded into memory
before getting signed/encrypted. Fixing the problem requires
some deep structural changes in Codecrypt that would break
most of the achieved internal simplicity, therefore the fix
is probably not going to happen. You can easily workaround
the whole problem using symmetric ciphers (for encryption of
large files) or hashfiles (for signatures of large files).
See the --symmetric option.
FMTSeq
signatures
FMTSeq signatures are constructed from one-time signature
scheme, for this reason the private key changes after each
signature, basically by increasing some counter. IF THE
PRIVATE KEY IS USED MORE THAN ONCE TO SIGN WITH THE SAME
COUNTER AND THE SIGNATURES GET PUBLISHED, SECURITY OF THE
SCHEME IS SEVERELY DAMAGED. Never use the same key on two
places at once. If you backup the private keys, be sure to
backup it everytime after a signature is made.
If something goes wrong and you really need to use the key that has been, for example, recovered from a backup, you can still "skip" the counter by producing and discarding some dummy signatures (ccr -s </dev/null >/dev/null). If you plan to do that for some real purpose, for your own safety be sure to understand inner workings of FMTSeq, especially how the Diffie-Lamport signature scheme degrades after publishing more than one signature.
FMTSeq can only produce a limited amount of signatures (but still a pretty large number). When the remaining signature count starts to get low, Codecrypt will print warning messages. In that case, users are advised to generate and certify new keys.
Working with
keys
Try to always use the "-n" option before you
actually import keys -- blind import of keys can bring
serious inconsistencies into your key naming scheme.
In a distant universe after much computation, KeyIDs can collide. If you find someone who has a colliding KeyID, kiss him and generate another key.
Own sources
of random seed
Using CCR_RANDOM_SEED is slightly counterintuitive and
dangerous, use it only for debugging.
If your system does not have /dev/(u)random, make a port by choosing a safe value in the source code instead of specifying the seed each time you invoke Codecrypt.
If the seed source of your system can not be trusted, fix the system instead.
Password-derived symmetric keys
Passwords are weak and, if times did not change and humanoids are still humanoids, you are prone to $5 wrench attacks.
Combination of -L and -S options can be exploited to output a password-expanded key to a file. Doing that for any real purpose is a bad idea.
Troubleshooting/FAQ
Q: I can’t read/verify messages from versions 1.3.1 and older!
A: KeyID algorithm changed after that version. If you want, you can manually rewrite the message sencode envelopes to contain new recipient/signer KeyIDs and new message identificators, things should work perfectly after that.
Q: I can’t read/verify messages from versions 1.7.4 and older!
A: There was a mistake with no security implications in Cubehash implementation. Same advice as in previous case applies.
Q: Some signatures from version 1.5 and older fail to verify!
A: There was a slight mistake in padding of messages shorter than signature hash function size (64 bytes in the 256-bit-secure signature types) with no security implications. It was decided not to provide backward compatibility for this minor use-case. If you really need to verify such signatures, edit the msg_pad function in src/algos_sig.h so that the ’load_key()’ function is called on empty vector instead of ’out’.
Q: My Cubehash-based FMTSeq key produces invalid signatures after version 1.7.5!
A: Cubehash was corrected to obey standards in 1.7.5. It is possible to generate a new public key that would work with your private key, but the general advice is just to generate a new key.
Q: I want to sign/encrypt a large file but it took all my RAM and takes ages!
A: Use --symmetric option. See the ’CAVEATS’ section for more details.
Q: How much ’broken’ is the original quasi-dyadic McEliece?
A: The private key of proposed dyadic variant by Misoczki and Barreto can be derived from the public key with standard computer equipment pretty quickly.
EXAMPLE
Following commands roughly demonstrate command line usage of ccr:
ccr -g help
ccr -g sig --name "John Doe" # your signature key
ccr -g enc --name "John Doe" # your encryption
key
ccr -K #watch
the generated keys
ccr -k
ccr -p -a -o my_pubkeys.asc -F Doe # export your pubkeys for friends
#see what
people sent us
ccr -ina < friends_pubkeys.asc
#import
Frank’s key and rename it
ccr -ia -R friends_pubkeys.asc --name "Friendly
Frank"
#send a nice
message to Frank (you can also specify him by @12345 keyid)
ccr -se -r Frank < Document.doc >
Message_to_frank.ccr
#receive a
reply
ccr -dv -o Decrypted_verified_reply.doc
<Reply_from_frank.ccr
#rename
other’s keys
ccr -m Frank -N "Unfriendly Frank"
#and delete
pukeys of everyone who’s Unfriendly
ccr -x Unfri
#create
hashfile from a large file
ccr -sS hashfile.ccr < big_data.iso
#verify the
hashfile
ccr -vS hashfile.ccr < the_same_big_data.iso
#create
(ascii-armored) symmetric key and encrypt a large file
ccr -g sha256,chacha20 -aS symkey.asc
ccr -eaS symkey.asc -R big_data.iso -o
big_data_encrypted.iso
#decrypt a
large file
ccr -daS symkey.asc <big_data_encrypted.iso
>big_data.iso
#password-protect
all your private keys
ccr -L
#protect a
symmetric key using another symmetric key
ccr -L -S symkey1 -w symkey2
#password-protect
symkey2 with a custom cipher
ccr -L -S symkey2 -w @xsynd,cube512
DISCLAIMER
Used cryptography is relatively new. For this reason, codecrypt eats data. Use it with caution.
AUTHORS
Codecrypt was written by Mirek Kratochvil in 2013-2017.