=head1 PCP1 KEYS B keys are stored in a binary file, called B. It's by default located in B<~/.pcpvault> but you can of course specify another location using the B<-V> option. There are two kinds of keys: secret and public keys. In reality a secret key always includes its public key. Both types of keys can be exported to files and transfered to other people who can then import them. You should usually only do this with public keys though. There is a primary secret key which will always used for operations when no keyid has been specified. However, you may have as many secret keys in your vault as you like. Each key can be identified using its B which looks like this: 0xD49119E85266509F A public key exported from a secret key will have the same keyid as the secret key. If you just want to know details about a key or the vault, use the B<-t> option. =head1 ENCRYPTION There are 2 modes of encryption available in pcp1: =over =item B In this mode, which is the default, a public key as specified with B<-i> or B<-r> and your primary secret key will be used for encryption. Example command: pcp1 -e -i 0x2BD734B15CE2722D -I message.txt -O message.asc Here we didn't specify a recipient. Therefore the public key given with -i will be used directly. Another example: pcp1 -e -r Bobby -r McCoy -I message.txt -O message.asc =item B You can also encrypt a file symetrically. No public key material will be used in this mode. While this works, the security of it totally depends on the strength of the passphrase used for encryption. Example command: pcp1 -e -I message.txt -O cipher.z85 As you can see we didn't specify -i or -r and therefore pcp1 operates in self mode for encryption. It will ask you for a passphrase to protect the encryption key. =back =head1 SIGNATURES There are 3 modes for digital signatures available on pcp1: =over =item B In this mode, which is the default, an ED25519 signature will be calculated from a BLAKE2 hash of the input file content. Both the original file content plus the signature will be written to the output file. Example: pcp1 -g -I message.txt -O message.asc -g You will be asked for the passphrase to access your primary secret key. The output file will be a binary file. =item B While this mode does the very same calculations, the output slightly differs. The output file will be marked as a signature file, the signature itself will be appended with its own headers and Z85 encoded. Example: pcp1 -g -I message.txt -O message.asc -g -z You will be asked for the passphrase to access your primary secret key. The output file will be a text file. =item B In some cases you will need to have the signature separated from the original input file, e.g. to sign download files. You can generate detached signatures for such purposes. Still, the signature will be calculated the same way as in standard signatures but put out into a separate file. A detached signature file will always be Z85 encoded. Example: pcp1 -g -I message.txt -O -g --sigfile message.sig Verification by recipient: pcp -c -f message.sig -I message.txt =back =head1 SIGNED ENCRYPTION Beside pure encryption and signatures pcp1 also supports signed encryption. In this mode an input file will be signed your primary secret key from a BLAKE2 hash of the file contents and the recipients and then encrypted. The signature is encrypted as well. Example: pcp1 -e -g -r Bobby -I README.txt -O README.asc Please note the additional B<-g> parameter. The recipient can decrypt and verify the so created data like this: pcp1 -d -c -I README.asc -o README.txt Please note the additional B<-c> parameter. If decryption works, the output file will be written. If signature verification fails you will be informed, but the decrypted output will be left untouched. It is up to you how to react on an invalid signature. B Note: this behavior might change in the future. =head1 ALTERNATIVE COMMANDLINES You can save typing if you supply additional arguments to pcp after commandline options. Such arguments are treated as filenames or recipients, depending what options you already specified. Here is a list of commandlines and their possible alternatives: ORIGINAL ALTERNATIVE DESCRIPTION pcp -e -I message -r Bob pcp -e -r Bob message use 'message' as inputfile. pcp -e -I message Bob use 'Bob' as recipient, multiple recipients supported. pcp -d -I crypted pcp -d crypted use 'crypted' as inputfile. pcp -g -I message pcp -g message use 'message' as inputfile. pcp -g -I msg -O sig pcp -g -I msg sig use 'sig' as outputfile. pcp -p -O key.pcp pcp -p key.pcp use 'key.pcp' as outputfile. pcp -p -O key.pcp -r Bob pcp -p -O key.pcp Bob use 'Bob' as recipient. pcp -s -O key.pcp pcp -s key.pcp use 'key.pcp' as outputfile. pcp -s -O key.pcp -r Bob pcp -s -O key.pcp Bob use 'Bob' as recipient. pcp -P -I alice.pcp pcp -P alice.pcp use 'alice.pcp' as inputfile. pcp -S -I alice.pcp pcp -S alice.pcp use 'alice.pcp' as inputfile. =head1 ENVIRONMENT VARIABLES pcp respects the following environment variables: =over =item B Use an alternative vaultfile. The default is B<~/.pcpvault> and can be overridden with the B<-V> commandline option. If PCP_VAULT is set, this one will be used instead. =item B Enable debugging output, where supported. Same as B<-D>. =back =head1 EXIT STATUS Pcp may return one of several error codes if it encounters problems. =over =item 0 No problems occurred. =item 1 Generic error code. =back =head1 FILES =over =item B<~/.pcpvault> Default vault file where all keys are stored. =back =head1 EXPERIMENTAL STATUS Currently there are a couple of problems which are currently unsolved or in the process to be solved. =over =item B Pretty Curved Privacy is a store-and-forward system, it works on files and can't use any cool key exchange protocols therefore. For example there would be B which guarantees a secure key exchange. But CurveCP cannot be used offline. Users have to find other means to exchange keys. That's a pity since with Curve25519 you can't just publish your public key to some key server because in order to encrypt a message, both the recipient AND the sender need to have the public key of each other. It would be possible to publish public keys, and attach the senders public key to the encrypted message, but I'm not sure if such an aproach would be secure enough. =item B At the time of this writing the ECC algorithm Curve25519 is only rarely used, in most cases by experimental software (such as Pretty Curved Privacy). As far as I know there haven't been done the kind of exessive crypto analysis as with other ECC algorithms. While I, as the author of pcp1 totally trust D.J.Bernstein, this may not be the case for you. In short, I'd suggest not to use it on critical systems yet. =back =head1 INTERNALS =head2 VAULT FORMAT The vault file contains all public and secret keys. It's a portable binary file. The file starts with a header: +-------------------------------------------+ | Field Size Description | +-------------------------------------------+ | File ID | 1 | Vault Identifier 0xC4 | +-------------------------------------------+ | Version | 4 | Big endian, version | +-------------------------------------------+ | Checksum | 32 | SHA256 Checksum | +-------------------------------------------+ The checksum is a checksum of all keys. The header is followed by the keys. Each key is preceded by a key header which looks like this: +--------------------------------------------+ | Field Size Description | +--------------------------------------------+ | Type | 1 | Key type (S,P,M) | +--------------------------------------------+ | Size | 4 | Big endian, keysize | +--------------------------------------------+ | Version | 4 | Big endian, keyversion | +--------------------------------------------+ | Checksum | 32 | SHA256 Key Checksum | +--------------------------------------------+ Type can be one of: PCP_KEY_TYPE_MAINSECRET 0x01 PCP_KEY_TYPE_SECRET 0x02 PCP_KEY_TYPE_PUBLIC 0x03 The key header is followed by the actual key, see below. =head2 SECRET KEY FORMAT A secret key is a binary structure with the following format: +---------------------------------------------------------+ | Field Size Description | +-------------+--------+----------------------------------+ | Public | 32 | Curve25519 Public Key Part | +-------------|--------|----------------------------------+ | Secret | 32 | Curve25519 Secret Key Unencrypted| +-------------|--------|----------------------------------+ | ED25519 Pub | 32 | ED25519 Public Key Part | +-------------|--------|----------------------------------+ | ED25519 Sec | 64 | ED25519 Secret Key Unencrypted | +-------------|--------|----------------------------------+ | Nonce | 24 | Nonce for secret key encryption | +-------------|--------|----------------------------------+ | Encrypted | 48 | Encrypted Curve25519 Secret Key | +-------------|--------|----------------------------------+ | Owner | 255 | String, Name of Owner | +-------------|--------|----------------------------------+ | Mail | 255 | String, Email Address | +-------------|--------|----------------------------------+ | ID | 17 | String, Key ID | +-------------|--------|----------------------------------+ | Ctime | 4 | Creation time, sec since epoch | +-------------|--------|----------------------------------+ | Version | 4 | Key version | +-------------|--------|----------------------------------+ | Serial | 4 | Serial Number | +-------------|--------|----------------------------------+ | Type | 1 | Key Type | +-------------+--------+----------------------------------+ Some notes: The secret key fields will be filled with random data if the key is encrypted. The first byte of it will be set to 0 in that case. The key id is a computed JEN Hash of the secret and public key concatenated, put into hex, as a string. The key version is a static value, currently 0x2. If the key format changes in the future, this version number will be increased to distinguish old from new keys. Exported keys will be encoded in Z85 encoding. When such an exported key is imported, only the actual Z85 encoded data will be used. Header lines and lines starting with whitespace will be ignored. They are only there for convenience. Key generation works like this: =over =item * Generate a random seed (32 bytes). =item * Generate a ED25519 sigining keypair from that seed. =item * Generate a random seed (32 bytes). =item * Generate a Curve25519 encryption keypair from that seed. =back So, while both secrets are stored in the sam PCP key, they are otherwise unrelated. If one of them leaks, the other cannot be recalculated from it. Take a look at the function B for details. =head2 ENCRYPTED OUTPUT FORMAT Encrypted output will always written as binary files. No armoring supported yet. The encryption process works as this: =over =item generate a random symetric 32 byte key B =item encrypt it asymetrically for each recipient using a unique nonce (B) =item encrypt the input file 32k blockwise using the symetric key =back Symetric encryption works the very same with the recipient stuff left out. Formal format description, asymetric encrypted files: +---------------------------------------------------------+ | Field Size Description | +-------------+--------+----------------------------------+ | Type | 1 | Filetype, 5=ASYM, 23=SYM | +-------------|--------|----------------------------------+ | Len R | 4 | Number of recipients (*) | +-------------|--------|----------------------------------+ | Recipients | R*72 | C(recipient)|C(recipient)... (*) | +-------------|--------|----------------------------------+ | Encrypted | ~ | The actual encrypted data | +-------------|--------|----------------------------------+ Left out when doing symetric encryption. Recipient field format: +---------------------------------------------------------+ | Field Size Description | +-------------+--------+----------------------------------+ | Nonce | 24 | Random Nonce, one per R | +-------------|--------|----------------------------------+ | Cipher | 48 | S encrypted with PK or R | +-------------|--------|----------------------------------+ R is calculated using public key encryption using the senders secret key, the recipients public key and a random nonce. Pseudocode: R = foreach P: N | crypto_box(S, N, P, SK) L = len(R) T = 5 write (T | L | R) foreach I: write (N | crypto_secret_box(I, N, S)) where P is the public key of a recipient, SK is the senders secret key, R is the recipient list, L is the number of recipients, T is the filetype header, I is a block of input with a size of 32k, N is a nonce (new per block) and S the symmetric key. The encrypted output maybe Z85 encoded. In this case the Z85 encoding will be done blockwise with blocks of 16k bytes. The decoded content inside will be as described above. =head2 SIGNATURE FORMAT There are different signature formats. Standard binary NACL signatures have the following format: +---------------------------------------------------------+ | Field Size Description | +-------------+--------+----------------------------------+ | Content | ~ | Original file content | +-------------|--------|----------------------------------+ | \nnacl- | 6 | Offset separator | +-------------|--------|----------------------------------+ | Hash | 64 | BLAKE2 hash of the content | +-------------|--------|----------------------------------+ | Signature | 64 | ED25519 signature of BLAKE2 Hash | +-------------|--------|----------------------------------+ The actual signature is not a signature over the whole content of an input file but of a BLAKE2 hash of the content. Pseudo code: H = crypto_generichash(C) C | O | H | crypto_sign(H, S) where C is the message (content), H is the blake2 hash, O is the offset separator and S is the secret signing key of the sender. Armored signatures have the following format: ----- BEGIN ED25519 SIGNED MESSAGE ----- Hash: Blake2 MESSAGE ----- BEGIN ED25519 SIGNATURE ----- Version: PCP v0.2.0 195j%-^/G[cVo4dSk7hU@D>NT-1rBJ]VbJ678H4I!%@-)bzi>zOba5$KSgz7b@R]A0!kL$m MTQ-1DW(e1mma( followed by the binary encrypted signature described in B without the offset separator. However, not only the hash of the file content will be signed but the recipient list described in B as well. A valid recipient is therefore not able to re-encrypt the decrypted message, append the original signature and send it to other recipients. The signature would not match since the recipient list differs and so recipients know that the signature is forged. Formal file description of sign+encrypt format: +---------------------------------------------------------+ | Field Size Description | +-------------+--------+----------------------------------+ | Type | 1 | Filetype, 5=ASYM, 23=SYM | +-------------|--------|----------------------------------+ | Len R | 4 | Number of recipients (*) | +-------------|--------|----------------------------------+ | Recipients | R*72 | C(recipient)|C(recipient)... (*) | +-------------|--------|----------------------------------+ | Encrypted | ~ | The actual encrypted data | +-------------|--------|----------------------------------+ | Signature | ~ | Encrypted signature(*) | +-------------|--------|----------------------------------+ As usual the encrypted signature consists of a nonce and the actual cipher, which is computed symmetrically (see above) from the following clear signature. Before encryption the signature format is: +---------------------------------------------------------+ | Field Size Description | +-------------+--------+----------------------------------+ | Hash | 64 | BLAKE2 hash of content+R (*) | +-------------|--------|----------------------------------+ | Signature | 64 | ED25519 signature of BLAKE2 Hash | +-------------|--------|----------------------------------+ where R is: C(recipient)|C(recipient)... (see B). Pseudocode: N | crypto_secret_box( crypto_sign( crypto_generichash( M + R, SK ) ), N, S) where N is the nonce, M the message, R the recipient list, SK is the senders secret signing key and S the symmetric key. =head2 Z85 ENCODING B uses Z85 to encode exported keys and armored signatures. Comments in encoded files are surrounded by the tilde character. We're using the tilde because it's not part of the Z85 base charset. Sample: ~~~ Header ~~~ ~ Version: 1 ~ 246ge]+yn={}]Xi3*N3Xx34Y^0rz:r.5j v#6Sh/m3XKwy?VlA+h8ks]9:kVj{D[fd7]NA]T-(ne+xo!W5X5-gIUWqM ~~~ Footer ~~~ Multiple tildes can be used as long as their number is uneven. This is a proprietary PCP extension. =head3 Z85 BACKGROUND The Z85 encoding format is described here: B. It's part of ZeroMQ (B). Z85 is based on ASCII85 with a couple of modifications (portability, readability etc). To fulfil the requirements of the ZeroMQ Z85 functions, B does some additional preparations of raw input before actually doing the encoding, since the input for zmq_z85_encode() must be divisible by 4. Therefore we pad the input with zeroes and remove them after decoding. B. Z85 encoding and decoding can be used separately as well to work with files. Examples: Encode some file to Z85 encoding: pcp1 -z -I file -O file.z85 Reverse the process: pcp1 -Z -I file.z85 -O file =head2 PBP COMPATIBILITY PCP tries to be fully compatible with PBP (https://github.com/stef/pbp). Encrypted files and signatures - at least their binary versions - should be exchangable. However, this is a work in progress and might not work under all circumstances. Also there's currently no shared key format between pbp and pcp. However, it is possible to export and import pbp keys from/to pcp.