CCR(1)
๐ CCR(1) โ the Codecrypt manual ๐
hi bestie!! welcome to the manual page for ccr, aka Codecrypt ๐ (yes that's what the "ccr" is short for, iykyk). sit down, grab a strawberry, we're gonna go through literally every single thing this page says, no skipping. periodt.
โจ NAME โจ
ccr โ The post-quantum cryptography encryption and signing tool ๐
๐ SYNOPSIS ๐
ccr [OPTION]...
that's it. that's the whole vibe. options only, no positional args, she's flexible like that ๐
๐ฆ DESCRIPTION ๐ฆ
ccr (short of Codecrypt) is a general purpose encryption/decryption signing/verification tool that uses only quantum-computer-resistant algorithms. like, the whole point. quantum computers can't touch this, no cap ๐ฅ
๐ธ General options: ๐ธ
-h,--helpโ shows a simple help with the option listing. baby's first flag ๐ผ-V,--versionโ displays only version information. just the version, nothing else, she's minimal ๐-T,--testโ okay so this one exists purely as a convenience for hackers ๐งโ๐ป in this case,ccrinitializes itself, calls atest()function from source filesrc/main.cpp(which is meant to be filled by testing stuff beforehand) and then terminates. in distribution packages, it will probably do nothing. so like... don't expect drama from this one ๐-R,--in <file>โ redirects standard input to be read from file instead of from stdin. you can still specify-to force reading from stdin, so you're never trapped ๐ซถ-o,--out <file>โ redirects standard output to be written to file. you can specify-to force writing to stdout. same energy, other direction โจ-E,--err <file>โ redirects the standard error output to file. you can specify-to force writing to stderr. important: error output does not carry any data, but it does provide useful error messages and metadata about what's happening โ e.g. the identity of the message signer, or details about why decryption or verification fails. so it's the little narrator voice in the corner ๐-a,--armorโ wherever you'd be expecting input or output of data in codecrypt communication format, use ascii-armoring. because Codecrypt otherwise usually generates raw binary data, and those are very hard to pass through e-mail or similar text communication channels. armor is what makes it survive the group chat ๐ญ-y,--yesโ assumes the user knows what he is doing, and answers"yes"to all questions. bold move, she's trusting you fr fr ๐
๐ 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 the message content if the verification succeeded. no valid signature, no message, that's the deal ๐-e,--encryptโ produce an encrypted message from input ๐-d,--decryptโ decrypt the message from input ๐
note bestie: 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". one command, two jobs, main character energy ๐
๐ 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. locked to exactly one person ๐-u,--user <keyspec>โ specify a private key to use for signing the message. if this option is empty, it is defaulted from theCCR_USERenvironment variable ๐ซถ-C,--cleartextโ when working with signatures, produce/expect a cleartext signature. the basic property of a 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. readable and signed, we love a multitasker โจ-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 the program's input (potentially using the"-R"option). signature in one hand, file in the other ๐-S,--symmetric <file>โ use symmetric cryptography.- when doing a
"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. like a vibe check but for bytes ๐ - when doing a
"generate","encrypt"or"decrypt"operation: do not encrypt asymmetrically, but instead generate or use a file with a key for the specified symmetric cipher. use"-g help"to see available symmetric primitives. for symmetric encryption to work, you need at least one stream cipher (marked withC) and at least one hash function (marked withH, used to protect against malleability), separated by comma. additionally, the user can specify the"longblock"or"shortblock"keyword to manipulate the size of the internal encryption block structure (longer blocks consume more RAM, but the ciphertext doesn't grow very much); or the"longkey"flag, which creates a 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, because why not, stack 'em ๐ - the purpose of the
--symmetricoption 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 you're 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. big file stays home, tiny file goes on tour ๐งณโจ
- when doing a
๐ 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 the key is meant for or who it belongs to. public keys also have an algorithm identifier to specify how to work with them, and sometimes also have a private key attached 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. like @-mentioning your key bestie ๐ - using a name โ the key specification consists of a string, and a key is then matched if its name contains the specified string. matching is case-insensitive, she's chill like that ๐ธ
and now the options, bestie:
-g,--gen-key <algorithm>โ generate a keypair for usage with the specified algorithm. use"-g help"to get a list of all algorithms available. the listing also contains flags"S"and"E", meaning that the algorithm can be used for signatures or encryption, or"H"and"C"for usage with symmetric hashes and ciphers. in the 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 โ so no ambiguous guesses, she needs a definitive answer โจ-N,--name <keyname>โ specify that the affected keys (those being imported, generated, exported or renamed) should be newly renamed to keyname. glow-up for keys ๐-F,--filter <keyspec>โ when listing, importing or exporting keys, only process keys that match keyspec. the bouncer at the club ๐ช-k,--listโ list available public keys ๐-K,--list-secretโ list available private keys (in keypairs). secret list, for secret girlies ๐คซ-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. window shopping, not buying ๐๏ธ-f,--fingerprintโ when printing keys, format full KeyIDs. note that full KeyIDs can be used in a similar way as fingerprints known from other crypto tools. it's giving ID verification ๐ชช-p,--exportโ export public keys in keyring format ๐ค-P,--export-secretโ export private keys. (do this carefully!) literally, the manpage put it in parentheses, take the hint bestie ๐ญ-x,--delete <keyspec>โ remove matching keys from the public keyring ๐๏ธ-X,--delete-secret <keyspec>โ remove matching keys from the 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-wis not specified, asking for the password interactively (i.e."-w @") will be assumed. it'll just ask you, no biggie ๐ซถ
๐ 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 the 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 the 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. slay, now you can script around it ๐ฏ
๐งฌ ALGORITHMS ๐งฌ
Okay bestie, so Codecrypt has a bunch of different โalgorithmsโ for signatures and encryption. Wanna see the whole menu? Run ccr -g help and itโll spill the tea on whatโs supported. ๐
The FMTSeq-named schemes are the Merkle-tree signature algorithms. When you see a name like FMTSEQxxx-HASH1-HASH2, that means the scheme gives you attack complexity (aka โbit securityโ) around 2^xxx, HASH1 is used as the message digest algorithm, and HASH2 is used for construction of the Merkle tree. ๐ณ
McEliece-based encryption schemes are formed from a McEliece trapdoor running on quasi-dyadic Goppa codes (the MCEQD- algorithms) and on quasi-cyclis medium-density parity-check (the 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 the 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. Periodt. ๐
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, according 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 versions1.3.1and older! A: KeyID algorithm changed after that version. If you want, you can manually rewrite the messagesencodeenvelopes to contain new recipient/signer KeyIDs and new message identificators, things should work perfectly after that. ๐
Q: I canโt read/verify messages from versions1.7.4and older! A: There was a mistake with no security implications inCubehashimplementation. Same advice as in previous case applies. ๐งฉ
Q: Some signatures from version1.5and older fail to verify! A: There was a slight mistake in padding of messages shorter than signature hash function size (64bytes in the256-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 themsg_padfunction insrc/algos_sig.hso that theload_key()function is called on empty vector instead ofout. ๐ ๏ธ
Q: MyCubehash-based FMTSeq key produces invalid signatures after version1.7.5! A:Cubehashwas corrected to obey standards in1.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--symmetricoption. See theCAVEATSsection 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 ๐
okay bestie, here's the whole vibe. these commands roughly show off what using ccr from the command line actually looks like:
ccr -g help
ccr -g sig --name "John Doe" # your signature key
ccr -g enc --name "John Doe" # your encryption key
that's the starter pack, fr. ccr -g help is your little menu of generators, and then you make yourself a signature key and an encryption key, both tagged with your name. two keys, one you ๐
now go look at what you just made:
ccr -K #watch the generated keys
ccr -k
-K shows the public halves, -k shows the secret halves. watch them. they're yours now ๐ซถ
want your friends to be able to encrypt stuff to you? export your public keys so they can have them:
ccr -p -a -o my_pubkeys.asc -F Doe # export your pubkeys for friends
-p = publish, -a = ascii-armored (so it's cute text you can paste anywhere), -o my_pubkeys.asc = where it lands, and -F Doe filters down to the ones matching Doe.
and then the other direction โ clocking what people sent you:
#see what people sent us
ccr -ina < friends_pubkeys.asc
-i import, -n no-lock, -a armored input, straight from stdin. chef's kiss.
importing Frank, but making his name nicer than whatever he put in there:
#import Frank's key and rename it
ccr -ia -R friends_pubkeys.asc --name "Friendly Frank"
-i import, -a armored, -R = rename to the --name you give it. glow-up achieved โจ
and now the actual love letter moment:
#send a nice message to Frank (you can also specify him by @12345 keyid)
ccr -se -r Frank < Document.doc > Message_to_frank.ccr
-s sign, -e encrypt, -r Frank picks the recipient โ and yeah, you can point at him with his @12345 keyid instead of his name if you want to be precise. Document.doc goes in, Message_to_frank.ccr comes out.
and when he replies:
#receive a reply
ccr -dv -o Decrypted_verified_reply.doc <Reply_from_frank.ccr
-d decrypt, -v verify, -o writes it to Decrypted_verified_reply.doc. note there's no space between < and the filename there, and it works just fine ๐ฆ
renaming somebody else's key (no notes, just vibes):
#rename other's keys
ccr -m Frank -N "Unfriendly Frank"
-m Frank = the match, -N = the new name. she's Unfriendly now.
and then, since we keep a clean house:
#and delete pukeys of everyone who's Unfriendly
ccr -x Unfri
-x deletes everything matching that string. yes, the original comment says "pukeys". we don't fix it, we respect it ๐
making a hashfile out of something absolutely enormous:
#create hashfile from a large file
ccr -sS hashfile.ccr < big_data.iso
-s sign, -S symmetric mode (so, no keypair needed), and big_data.iso streams in from stdin.
and checking it later, same data, same hashfile:
#verify the hashfile
ccr -vS hashfile.ccr < the_same_big_data.iso
-v verify, -S symmetric again. if it matches you're golden ๐
symmetric key time, for the big stuff:
#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
first line: generate a symmetric key using sha256,chacha20, ascii-armored (-a), saved as symkey.asc. second line: encrypt (-e) symmetrically (-S) with symkey.asc, reading big_data.iso (-R), writing big_data_encrypted.iso (-o).
and getting it back:
#decrypt a large file
ccr -daS symkey.asc <big_data_encrypted.iso >big_data.iso
decrypt, armored, symmetric, in through stdin, out through stdout. no cap, it's that easy.
protect every private key you own with a password:
#password-protect all your private keys
ccr -L
-L = lock it all up ๐
or protect one symmetric key using another symmetric key:
#protect a symmetric key using another symmetric key
ccr -L -S symkey1 -w symkey2
-S symkey1 is the thing getting locked, -w symkey2 is the key doing the locking.
and if you're feeling fancy, lock it with a custom cipher instead:
#password-protect symkey2 with a custom cipher
ccr -L -S symkey2 -w @xsynd,cube512
that @xsynd,cube512 is your hand-picked cipher. main character energy ๐
๐ DISCLAIMER ๐
The cryptography in here is relatively new. For this reason, codecrypt eats data. Use it with caution.
likeโฆ genuinely. read that twice. it's new, it's hungry, and it will eat your data. Use it with caution. ๐
๐ AUTHORS ๐
Codecrypt was written by Mirek Kratochvil in 2013-2017. legend behaviour, honestly ๐ซถ
and that's the whole page bestie!! this was ccr, section 1 of your manual, dated 2017-10-23 โ that's the version and the date stamped on the bottom, and now you know everything she knows ๐
โจ bye ily, go encrypt responsibly ๐ธ
๐ฆ where this page comes from
- debian bookworm: codecrypt 1.8-1+b1 ยท LGPL-3.0-or-later
- debian trixie: codecrypt 1.8-1+b2 ยท LGPL-3.0-or-later
- ubuntu jammy: codecrypt 1.8-1build2 ยท LGPL-3.0-or-later
- ubuntu noble: codecrypt 1.8-1build3 ยท LGPL-3.0-or-later
- ubuntu resolute: codecrypt 1.8-1build4 ยท LGPL-3.0-or-later
- ubuntu stonking: codecrypt 1.8-2 ยท LGPL-3.0-or-later
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms