mirror of
https://codeberg.org/scip/pcp.git
synced 2025-12-17 12:00:56 +01:00
620 lines
22 KiB
Plaintext
620 lines
22 KiB
Plaintext
=head1 NAME
|
|
|
|
Pretty Curved Privacy - File encryption using eliptic curve cryptography.
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
|
|
|
|
Usage: pcp1 [options]
|
|
|
|
General Options:
|
|
-V --vault <vaultfile> Specify an alternate vault file.
|
|
The deault vault is ~/.pcpvault.
|
|
-O --outfile <file> Output file. If not specified, stdout
|
|
will be used.
|
|
-I --infile <file> Input file. If not specified, stdin
|
|
will be used.
|
|
-i --keyid <id> Specify a key id to import/export.
|
|
-r --recipient <string> Specify a recpipient, used for public
|
|
key export and encryption.
|
|
-t --text Print textual representation of some
|
|
item. Specify -V to get info about a
|
|
vault, -i to get info about a key id
|
|
installed in the vault or -I in which
|
|
case it determines itself what kind of
|
|
file it is.
|
|
-h --help Print this help message.
|
|
-v --version Print program version.
|
|
-D --debug Enable debug output.
|
|
|
|
Keymanagement Options:
|
|
-k --keygen Generate a CURVE25519 secret key. If
|
|
the generated key is the first one in
|
|
your vault, it will become the primary
|
|
secret key. If an output file (-O) has
|
|
been specified, don't store the generated
|
|
key to the vault but export it to the
|
|
file instead. You will be asked for
|
|
an owner, mail and a passphrase. If you
|
|
leave the passphrase empty, the key will
|
|
be stored unencrypted.
|
|
-l --listkeys List all keys currently stored in your
|
|
vault. Only the key id's and some info
|
|
about the keys will be printed, not the
|
|
actual keys.
|
|
-R --remove-key Remove a key from the vault. Requires
|
|
option -i <keyid>.
|
|
-s --export-secret Export a secret key. If your vault only
|
|
contains one secret key, this one will
|
|
be exported. If a key id have been
|
|
specified (-i), this one will be used.
|
|
If there are more than one secret keys
|
|
in the vault and no key id has been
|
|
given, export the primary secret key.
|
|
Use -O to export to a file.
|
|
-p --export-public Export a public key. If no key id have
|
|
been specified, the public part of your
|
|
primary secret key will be exported.
|
|
Use -O to export to a file.
|
|
-S --import-secret Import a secret key. Use -I to import
|
|
from a file.
|
|
-P --import-public Import a public key. Use -I to import
|
|
from a file.
|
|
-y --export-yaml Export all keys stored in your vault
|
|
as YAML formatted text. Use -O to put
|
|
the export into a file.
|
|
Encryption Options:
|
|
-e --encrypt Encrypt a message. Read from stdin or
|
|
specified via -I. If a keyid (-i) has been
|
|
given, use that public key for encryption.
|
|
If a recipient (-r) has been given, use
|
|
a derived public key. If none of -i or
|
|
-r has been given, use the primary
|
|
secret key and the public part of it
|
|
for encrytion (self-encryption mode).
|
|
-d --decrypt Decrypt a message. Read from stdin or
|
|
specified via -I. Output to stdout or
|
|
written to the file specified via -O.
|
|
The primary secret key will be used for
|
|
decryption, if there is no primary and
|
|
just one secret key in the vault, this
|
|
one will be used. Otherwise you'll have
|
|
to specify the keyid (-i) of the key.
|
|
|
|
Signature Options:
|
|
-g --sign Create a signature of file specified with
|
|
-I (or from stdin) using your primary
|
|
secret key. If -r has been given, a derived
|
|
secret key will be used for signing.
|
|
|
|
-c --check-signature <file> Verify a signature in file <file> against
|
|
the file specified with -I (or stdin).
|
|
The public key required for this must
|
|
exist in your vault file.
|
|
|
|
Encoding Options:
|
|
-z --z85-encode Encode something to Z85 encoding. Use
|
|
-I and -O respectively, otherwise it
|
|
stdin/stdout.
|
|
-Z --z85-decode Decode something from Z85 encoding. Use
|
|
-I and -O respectively, otherwise it
|
|
stdin/stdout
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
B<Pretty Curved Privacy> (pcp1) is a commandline utility which can
|
|
be used to encrypt files. B<pcp1> uses eliptc curve cryptography
|
|
for encryption (CURVE25519 by Dan J. Bernstein). While CURVE25519
|
|
is no worldwide accepted standard it hasn't been compromised by
|
|
the NSA - which might be better, depending on your point of view.
|
|
|
|
B<Caution>: since CURVE25519 is no accepted standard, B<pcp1> has
|
|
to be considered as experimental software. In fact, I wrote it just
|
|
to learn about the curve and see how it works.
|
|
|
|
Beside some differences it works like B<GNUPG>. So, if you already
|
|
know how to use gpg, you'll feel almost home.
|
|
|
|
=head1 QUICKSTART
|
|
|
|
Lets say, Alicia and Bobby want to exchange encrypted messages.
|
|
Here's what the've got to do.
|
|
|
|
First, both have create a secret key:
|
|
|
|
Alicia Bobby
|
|
pcp1 -k pcp1 -k
|
|
|
|
After entering their name, email address and a passphrase to protect
|
|
the key, it will be stored in their B<vault file> (by default ~/.pcpvault).
|
|
|
|
Now, both of them have to export the public key, which has to be
|
|
imported by the other one. With B<pcp> you can export the public
|
|
part of your primary key, but the better solution is to export
|
|
a derived public key especially for the recipient:
|
|
|
|
Alicia Bobby
|
|
pcp1 -p -r Bobby -O alicia.pub pcp1 -p -r Alicia -O bobby.pub
|
|
|
|
They've to exchange the public key somehow (which is not my
|
|
problem at the moment, use ssh, encrypted mail, whatever). Once exchanged,
|
|
they have to import it:
|
|
|
|
|
|
Alicia Bobby
|
|
pcp1 -P -I bobby.pub pcp1 -P -I alicia.pub
|
|
|
|
They will see a response as this when done:
|
|
|
|
key 0x29A323A2C295D391 added to .pcpvault.
|
|
|
|
Now, Alicia finally writes the secret message, encrypts it and
|
|
sends it to Bobby, who in turn decrypts it:
|
|
|
|
Alicia Bobby
|
|
echo "Love you, honey" > letter
|
|
pcp1 -e -i 0x29A323A2C295D391 -I letter -O letter.z85
|
|
cat letter.z85 | mail bobby@foo.bar
|
|
|
|
pcp1 -d -I letter.z85 | less
|
|
|
|
And that's it.
|
|
|
|
Please note the big difference to B<GPG> though: both Alicia
|
|
AND Bobby have to enter the passphrase for their secret key!
|
|
That's the way CURVE25519 works: you encrypt a message using
|
|
your secret key and the recipients public key and the recipient
|
|
does the opposite, he uses his secret key and your public key
|
|
to actually decrypt the message.
|
|
|
|
Oh - and if you're wondering why I named them Alicia and Bobby:
|
|
I was just sick of Alice and Bob. We're running NSA-free, so we're
|
|
using other sample names as well.
|
|
|
|
# -*-perl-*-
|
|
|
|
=head1 PCP1 KEYS
|
|
|
|
B<pcp1> keys are stored in a binary file, called B<the vault>.
|
|
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<keyid> which looks like this:
|
|
|
|
0xD49119E85266509F
|
|
|
|
A public key exported from a secret key will have the same keyid
|
|
as the secret key. When using for encryption, the keyid will be
|
|
added to the message so that the receiver knows who was the
|
|
sender of the message (B<This might change in the future. As of
|
|
this writing I'm not sure if this was a good idea>).
|
|
|
|
If you just want to know details about a key or the vault, use the
|
|
B<-t> option.
|
|
|
|
=head2 Derived Public Keys
|
|
|
|
In the real world you would not use your primary key to encrypt
|
|
messages, because this would require to send the public key part
|
|
to your recipient in one way or another. The much better and more
|
|
secure way is to use a B<Derived Public Key>:
|
|
|
|
Such a key will be dynamically generated from a hash of your
|
|
primary secret key and the recipient (an email address, name or key id).
|
|
The public part of this dynamic key will be exported and sent to
|
|
the recipient. A public key generated this way will only be usable
|
|
by the recipient (and yourself) and each recipient will have a different
|
|
public key from you (and vice versa).
|
|
|
|
=head1 ENCRYPTION
|
|
|
|
There are 3 modi for encryption available in pcp1:
|
|
|
|
=over
|
|
|
|
=item B<Standard public key encryption>
|
|
|
|
In this mode, which is the default, a public key as specified
|
|
with B<-i> and the primary secret key will be used for encryption.
|
|
The public key in question maybe a derived public key, which
|
|
is transparent for the sender however.
|
|
|
|
If you don't use derived keys, you will have to transfer
|
|
the public key part of your primary keypair to the recipient,
|
|
which is considered insecure if the transfer channel itself
|
|
uses untrusted transports or if the transferred public key
|
|
ends up on a public system (a shared server, a workstation
|
|
at your employer or the like). You should avoid this encryption
|
|
mode in such cases and use derived keys instead.
|
|
|
|
Example command:
|
|
|
|
pcp1 -e -i 0x2BD734B15CE2722D -I message.txt -O cipher.z85
|
|
|
|
Here we didn't specify a recipient. Therefore the public
|
|
key given with -i will be used directly.
|
|
|
|
=item B<Derived public key encryption>
|
|
|
|
Derived keys will be generated dynamically at runtime
|
|
(see B<Derived Public Keys> above). Therefore an exported
|
|
derived public key is unique for the sender AND recipient.
|
|
|
|
This mode can be considered the most secure. If such a key
|
|
gets lost (or into the wrong hands), only this specific
|
|
communication channel will be compromised.
|
|
|
|
Example command:
|
|
|
|
pcp1 -e -r bobby@local -I message.txt -O cipher.z85
|
|
|
|
We specified a recipient. pcp1 searches the vault for a
|
|
matching public key and generates a derived keypair for
|
|
encryption. You need to have a public key installed from
|
|
the recipient anyway, it won't work without one. You may
|
|
also specify a key id (-i) as well to make sure, the right
|
|
key will be used for derivation.
|
|
|
|
=item B<Self encryption mode>
|
|
|
|
Pretty Curved Privacy doesn't provide symetric file encryption.
|
|
However there are cases when you need to encrypt a file just
|
|
for yourself. In such a case the file will be encrypted using
|
|
the public key part of your primary secret key and the secret
|
|
key itself (thanks to the wonders of ECC this works like a charm).
|
|
|
|
The file can be decrypted using the primary key pair.
|
|
|
|
While this works, the security of it totally depends on the
|
|
strength of your password, especially if the primary secret
|
|
used for this kind of encryption is stored in a vault on the
|
|
same system.
|
|
|
|
Example command:
|
|
|
|
pcp1 -e -I message.txt -O cipher.z85
|
|
|
|
As you can see we didn't specify -i or -r and therefore pcp1
|
|
tries to use the primary keypair for encryption.
|
|
|
|
=back
|
|
|
|
|
|
=head1 VULNERABILITIES
|
|
|
|
Currently there are a couple of problems which are not
|
|
addressed. These are usually protocol problems, which are
|
|
not caused by pcp1.
|
|
|
|
=over
|
|
|
|
=item B<No secure native key exchange for store-and-forward systems>
|
|
|
|
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<CurveCP> 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<Curve25519 not widely adopted>
|
|
|
|
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 keypair from that seed.
|
|
|
|
=item *
|
|
|
|
Take the first 32 bytes of the generated ED25519 secret
|
|
and generate a SHA512 hash from it.
|
|
|
|
=item *
|
|
|
|
Clamp bytes 0 and 31 which turns it into a Curve25519 secret.
|
|
|
|
=item *
|
|
|
|
Do scalar multiplication from that secret to retrieve
|
|
the matching public key.
|
|
|
|
=back
|
|
|
|
Take a look at the function B<pcp_keypairs()> for details.
|
|
|
|
=head2 ENCRYPTED OUTPUT FORMAT
|
|
|
|
Encrypted output will always be Z85 encoded and has the following
|
|
format:
|
|
|
|
+---------------------------------------------------------+
|
|
| Field Size Description |
|
|
+-------------+--------+----------------------------------+
|
|
| Hash | 32 | Hash of the sender key id |
|
|
+-------------|--------|----------------------------------+
|
|
| Encrypted | ~ | The actual encrypted data |
|
|
+-------------|--------|----------------------------------+
|
|
|
|
=head2 SIGNATURE FORMAT
|
|
|
|
Signatures will always be Z85 encoded and have the following
|
|
format:
|
|
|
|
+---------------------------------------------------------+
|
|
| Field Size Description |
|
|
+-------------+--------+----------------------------------+
|
|
| Key ID | 17 | Signers key id
|
|
+-------------|--------|----------------------------------+
|
|
| Ctime | 4 | Creation time, sec since epoch |
|
|
+-------------|--------|----------------------------------+
|
|
| Version | 4 | Signature version |
|
|
+-------------|--------|----------------------------------+
|
|
| Signature | 96 | ED25519 signature of SHA256 Hash |
|
|
+-------------|--------|----------------------------------+
|
|
|
|
The actual signature is not a signature over the whole content
|
|
of an input file but of a SHA256 hash of the content.
|
|
|
|
=head2 Z85 ENCODING
|
|
|
|
B<pcp1> uses Z85 to encode exported keys and encrypted messages.
|
|
Therefore it includes a Z85 utility mode:
|
|
|
|
B<pcp1> can be used to encode and decode strings to Z85 encoding.
|
|
|
|
The option B<-z> encodes B<to> Z85, the option B<-Z> does the opposite
|
|
and decodes B<from> Z85.
|
|
|
|
If no input file have been specified using B<-I>, B<pcp1> expects the
|
|
input to come from B<STDIN>, otherwise it reads the contents
|
|
of B<file>.
|
|
|
|
Encoded or decoded output will be written to B<STDOUT> unless an
|
|
output file has been specified using the option B<-O>.
|
|
|
|
=head3 Z85 EXAMPLES
|
|
|
|
To encode a given file to Z85 and write the output to another:
|
|
|
|
pcp1 -z myfile.bin > myfile.z85
|
|
|
|
To decode the file created above and restore the original:
|
|
|
|
pcp1 -Z -d myfile.z85 > myfile.bin
|
|
|
|
To encode something from stdin to Z85:
|
|
|
|
ps axuw | pcp1 -z > pslist.z85
|
|
|
|
To decode the above and print to stdout:
|
|
|
|
pcp1 -Z -d pslist.z85
|
|
|
|
=head3 Z85 BACKGROUND
|
|
|
|
The Z85 encoding format is described here: B<http://rfc.zeromq.org/spec:32>.
|
|
It's part of ZeroMQ (B<http://zeromq.org>). Z85 is based on ASCII85 with
|
|
a couple of modifications (portability, readability etc).
|
|
|
|
To fulfil the requirements of the ZeroMQ Z85 functions, B<pcp1>
|
|
does some additional preparations of raw input before actually doing the
|
|
encoding, since the input for zmq_z85_encode() must be divisible by 4:
|
|
|
|
Expand the input so that the resulting size is divisible by 4.
|
|
|
|
Fill the added bytes with zeroes.
|
|
|
|
Prepend the input with a one byte value which holds the number of zeroes
|
|
added in the previous step.
|
|
|
|
Example:
|
|
|
|
Raw input:
|
|
|
|
hello\0
|
|
|
|
Here, the input size is 6, which is insufficient, therefore it has to be expanded
|
|
to be 8. After the process the input looks like this:
|
|
|
|
1hello\0\0
|
|
|
|
So, we padded the input with 1 zero (makes 7 bytes) and preprended it with the
|
|
value 1 (the number of zeros added): makes 8 bytes total.
|
|
|
|
After decoding Z85 input the process will be reversed.
|
|
|
|
B<Trying to use another tool to decode an Z85 encoded string produced
|
|
by z85, might not work therefore, unless the tool takes the padding scheme
|
|
outlined above into account>.
|
|
|
|
|
|
=head1 COPYRIGHT
|
|
|
|
Copyright (c) 2013 by T.Linden <tom AT cpan DOT org>
|
|
|
|
=head1 ADDITIONAL COPYRIGHTS
|
|
|
|
=over
|
|
|
|
=item B<ZeroMQ Z85 encoding routine>
|
|
|
|
Copyright (c) 2007-2013 iMatix Corporation
|
|
Copyright (c) 2009-2011 250bpm s.r.o.
|
|
Copyright (c) 2010-2011 Miru Limited
|
|
Copyright (c) 2011 VMware, Inc.
|
|
Copyright (c) 2012 Spotify AB
|
|
|
|
=item B<Tarsnap readpass helpers>
|
|
|
|
Copyright 2009 Colin Percival
|
|
|
|
=item B<jen_hash() hash algorithm>
|
|
|
|
Bob Jenkins, Public Domain.
|
|
|
|
=item B<UTHASH hashing macros>
|
|
|
|
Copyright (c) 2003-2013, Troy D. Hanson
|
|
|
|
=item B<Random art image from OpenSSH keygen>
|
|
|
|
Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
|
|
|
Comitted by Alexander von Gernler in rev 1.7.
|
|
|
|
=back
|
|
|
|
Every incorporated source code is opensource and licensed
|
|
under the B<GPL> as well.
|
|
|
|
=head1 AUTHORS
|
|
|
|
I<T.Linden <tom AT cpan DOT org>>
|
|
|
|
=head1 LICENSE
|
|
|
|
Licensed under the GNU GENERAL PUBLIC LICENSE version 3.
|
|
|
|
=head1 HOME
|
|
|
|
The homepage of Pretty Curved Privacy can be found on
|
|
http://www.daemon.de/PrettyCurvedPrivacy. The source is
|
|
on Github: https://github.com/TLINDEN/pcp
|
|
|
|
=cut
|