finally got pbp key export/import to work. in order to make it happen, pbp needs to be patched (see pbp issue#10 for details!) to enable padding.

This commit is contained in:
git@daemon.de
2014-02-06 16:30:50 +01:00
parent d1d169b1fc
commit 7d715ba880
6 changed files with 173 additions and 32 deletions

View File

@@ -108,8 +108,10 @@ struct _pcp_pubkey_t {
/* keys.mp+keys.cp+keys.sp+keys.name */ /* keys.mp+keys.cp+keys.sp+keys.name */
struct _pbp_pubkey_t { struct _pbp_pubkey_t {
byte sigpub[crypto_sign_PUBLICKEYBYTES]; byte sigpub[crypto_sign_PUBLICKEYBYTES];
byte pub[crypto_box_PUBLICKEYBYTES];
byte edpub[crypto_sign_PUBLICKEYBYTES]; byte edpub[crypto_sign_PUBLICKEYBYTES];
byte pub[crypto_box_PUBLICKEYBYTES];
char iso_ctime[32];
char iso_expire[32];
char name[1024]; char name[1024];
}; };

View File

@@ -36,7 +36,7 @@ static void prep_base85(void)
int decode_85(char *dst, const char *buffer, int len) int decode_85(char *dst, const char *buffer, int len)
{ {
prep_base85(); prep_base85();
int pos = 0;
say1("len: %d\n", len); say1("len: %d\n", len);
say2("decode 85 <%.*s>\n", len / 4 * 5, buffer); say2("decode 85 <%.*s>\n", len / 4 * 5, buffer);
while (len) { while (len) {
@@ -47,13 +47,13 @@ int decode_85(char *dst, const char *buffer, int len)
ch = *buffer++; ch = *buffer++;
de = de85[ch]; de = de85[ch];
if (--de < 0) if (--de < 0)
return error("invalid base85 alphabet <%c>\n", ch); return error("invalid base85 alphabet <%02x> de: %d\n", ch, de);
acc = acc * 85 + de; acc = acc * 85 + de;
} while (--cnt); } while (--cnt);
ch = *buffer++; ch = *buffer++;
de = de85[ch]; de = de85[ch];
if (--de < 0) if (--de < 0 && ch != '\0')
return error("invalid base85 alphabet <%c>\n", ch); return error("invalid base85 alphabet <%02x> left\n", ch);
/* Detect overflow. */ /* Detect overflow. */
@@ -63,8 +63,7 @@ int decode_85(char *dst, const char *buffer, int len)
acc += de; acc += de;
/* say1(" %08x\n", acc); */ /* say1(" %08x\n", acc); */
say1("%.5s", buffer-5); say1("%.5s", buffer-5);
say2("=> %08x (len: %d)\n", acc, len); say2(" => %08x (len: %d)\n", acc, len);
cnt = (len < 4) ? len : 4; cnt = (len < 4) ? len : 4;
len -= cnt; len -= cnt;
do { do {

View File

@@ -60,9 +60,17 @@ void _xorbuf(unsigned char *iv, unsigned char *buf, size_t xlen) {
/* print some binary data to stderr */ /* print some binary data to stderr */
void _dump(char *n, unsigned char *d, size_t s) { void _dump(char *n, unsigned char *d, size_t s) {
fprintf(stderr, "%s (%ld): ", n, s); int l = strlen(n) + 9;
fprintf(stderr, "%s (%04ld): ", n, s);
size_t i; size_t i;
for (i=0; i<s; ++i) int c;
for (i=0; i<s; ++i) {
fprintf(stderr, "%02x", d[i]); fprintf(stderr, "%02x", d[i]);
if(i % 36 == 35 && i > 0) {
fprintf(stderr, "\n");
for(c=0; c<l; ++c)
fprintf(stderr, " ");
}
}
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }

View File

@@ -360,9 +360,9 @@ Verification by recipient:
=head1 SIGNED ENCRYPTION =head1 SIGNED ENCRYPTION
Beside pure encryption and signatures pcp1 also supports signed Beside pure encryption and signatures pcp1 also supports signed
encryption. In this mode an input file will be encrypted and encryption. In this mode an input file will be signed your primary
a signature using your primary secret key from a BLAKE2 hash of secret key from a BLAKE2 hash of the file contents and the recipients
the file contents will be appended to it. and then encrypted. The signature is encrypted as well.
Example: Example:
@@ -600,6 +600,20 @@ Recipient field format:
R is calculated using public key encryption using the senders R is calculated using public key encryption using the senders
secret key, the recipients public key and a random nonce. 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.
=head2 SIGNATURE FORMAT =head2 SIGNATURE FORMAT
There are different signature formats. Standard binary NACL There are different signature formats. Standard binary NACL
@@ -620,6 +634,15 @@ signatures have the following format:
The actual signature is not a signature over the whole content The actual signature is not a signature over the whole content
of an input file but of a BLAKE2 hash of the 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: Armored signatures have the following format:
----- BEGIN ED25519 SIGNED MESSAGE ----- ----- BEGIN ED25519 SIGNED MESSAGE -----
@@ -642,8 +665,54 @@ contents as the binary signature outlined above (hash+sig).
Signed encrypted files are in binary form only. The first part is Signed encrypted files are in binary form only. The first part is
the standard encrypted file as described in B<ENCRYPTED OUTPUT FORMAT> the standard encrypted file as described in B<ENCRYPTED OUTPUT FORMAT>
followed by the binary signature described in B<SIGNATURE FORMAT> without followed by the binary encrypted signature described in B<SIGNATURE FORMAT>
the offset separator. without the offset separator.
However, not only the hash of the file content will be signed but the
recipient list described in B<ENCRYPTED OUTPUT FORMAT> 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<ENCRYPTED OUTPUT FORMAT>).
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 =head2 Z85 ENCODING

View File

@@ -376,9 +376,11 @@ int pcp_importsecret (vault_t *vault, FILE *in) {
int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat) { int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat) {
pcp_pubkey_t *pub = NULL; pcp_pubkey_t *pub = NULL;
if(pbpcompat == 1) { if(pbpcompat == 1) {
char *date = NULL;
char *parts = NULL; char *parts = NULL;
int pnum; int pnum;
pbp_pubkey_t *b = ucmalloc(sizeof(pbp_pubkey_t)); pbp_pubkey_t *b = ucmalloc(sizeof(pbp_pubkey_t));
pcp_pubkey_t *tmp = ucmalloc(sizeof(pcp_pubkey_t));
pub = ucmalloc(sizeof(pcp_pubkey_t)); pub = ucmalloc(sizeof(pcp_pubkey_t));
unsigned char *buf = ucmalloc(2048); unsigned char *buf = ucmalloc(2048);
unsigned char *bin = ucmalloc(2048); unsigned char *bin = ucmalloc(2048);
@@ -396,7 +398,8 @@ int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat) {
nlen -= 1; nlen -= 1;
} }
} }
klen = (nlen / 5) * 4;
klen = nlen /5 * 4; /*((nlen + (5 - (nlen % 5))) / 5) * 4;*/
if(decode_85((char *)bin, (char *)buf, klen) != 0) if(decode_85((char *)bin, (char *)buf, klen) != 0)
goto errimp1; goto errimp1;
@@ -407,6 +410,9 @@ int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat) {
goto errimp1; goto errimp1;
} }
if(debug)
_dump("sig", bin, nlen);
/* unpad result, if any */ /* unpad result, if any */
for(i=klen; i>0; --i) { for(i=klen; i>0; --i) {
if(bin[i] != '\0' && i < klen) { if(bin[i] != '\0' && i < klen) {
@@ -418,6 +424,19 @@ int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat) {
/* use first part as sig and verify */ /* use first part as sig and verify */
memcpy(b, &bin[crypto_sign_BYTES], klen - crypto_sign_BYTES); memcpy(b, &bin[crypto_sign_BYTES], klen - crypto_sign_BYTES);
if(debug)
_dump("sig", bin, klen);
/* parse the date */
date = ucmalloc(19);
memcpy(date, b->iso_ctime, 18);
date[19] = '\0';
struct tm c;
if(strptime(date, "%Y-%m-%dT%H:%M:%S", &c) == NULL) {
fatal("Failed to parse creation time in PBP public key file (<%s>)\n", date);
goto errimp2;
}
/* parse the name */ /* parse the name */
parts = strtok (b->name, "<>"); parts = strtok (b->name, "<>");
pnum = 0; pnum = 0;
@@ -433,22 +452,35 @@ int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat) {
if(strlen(b->name) == 0) { if(strlen(b->name) == 0) {
char *owner = pcp_getstdin("Enter the name of the key owner"); char *owner = pcp_getstdin("Enter the name of the key owner");
memcpy(b->name, owner, strlen(owner) + 1); memcpy(pub->owner, owner, strlen(owner) + 1);
free(owner); free(owner);
} }
/* fill in the fields */ /* fill in the fields */
pub->ctime = (long)time(0); /* pbp exports no ctime */ pub->ctime = (long)mktime(&c);
pub->type = PCP_KEY_TYPE_PUBLIC; pub->type = PCP_KEY_TYPE_PUBLIC;
pub->version = PCP_KEY_VERSION; pub->version = PCP_KEY_VERSION;
pub->serial = arc4random(); pub->serial = arc4random();
memcpy(pub->id, pcp_getpubkeyid(pub), 17);
memcpy(pub->pub, b->pub, crypto_box_PUBLICKEYBYTES); memcpy(pub->pub, b->pub, crypto_box_PUBLICKEYBYTES);
memcpy(pub->edpub, b->edpub, crypto_sign_PUBLICKEYBYTES); memcpy(pub->edpub, b->edpub, crypto_sign_PUBLICKEYBYTES);
memcpy(pub->id, pcp_getpubkeyid(pub), 17);
/* edpub used for signing, might differ */
memcpy(tmp->edpub, b->sigpub, crypto_sign_PUBLICKEYBYTES);
if(debug) {
_dump(" mp", tmp->edpub, crypto_sign_PUBLICKEYBYTES);
_dump(" cp", pub->pub, crypto_sign_PUBLICKEYBYTES);
_dump(" sp", pub->edpub, crypto_sign_PUBLICKEYBYTES);
_dump("name", (unsigned char *)pub->owner, strlen(pub->owner));
_dump(" sig", bin, klen);
fprintf(stderr, "<%s>\n", (unsigned char *)pub->owner);
pcp_dumppubkey(pub);
}
unsigned char *sig = pcp_ed_verify(bin, klen, tmp);
free(tmp);
fprintf(stderr, "edpub: "); pcpprint_bin(stderr, pub->edpub, crypto_sign_PUBLICKEYBYTES); fprintf(stderr, "\n");
fprintf(stderr, " sig: "); pcpprint_bin(stderr, bin, klen); fprintf(stderr, "\n");
unsigned char *sig = pcp_ed_verify(bin, klen, pub);
if(sig == NULL) if(sig == NULL)
goto errimp1; goto errimp1;
@@ -458,6 +490,8 @@ int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat) {
free(bin); free(bin);
goto kimp; goto kimp;
errimp2:
free(date);
errimp1: errimp1:
free(bin); free(bin);

View File

@@ -233,23 +233,52 @@ void pcppubkey_print(pcp_pubkey_t *key, FILE* out, int pbpcompat) {
secret = pcpkey_decrypt(secret, passphrase); secret = pcpkey_decrypt(secret, passphrase);
if(secret != NULL) { if(secret != NULL) {
size_t pbplen = crypto_sign_PUBLICKEYBYTES+crypto_box_PUBLICKEYBYTES+crypto_sign_PUBLICKEYBYTES+strlen(key->owner); size_t pbplen = crypto_sign_PUBLICKEYBYTES+crypto_box_PUBLICKEYBYTES+crypto_sign_PUBLICKEYBYTES+strlen(key->owner)+64;
/* we need to do the padding here, since pbp verifies the sig including the pad */
/*
int pad = pbplen % 4;
if(pad > 0) {
pad = 4 - pad;
pbplen += pad;
}
*/
unsigned char *blob = ucmalloc(pbplen); unsigned char *blob = ucmalloc(pbplen);
fprintf(stderr, "edpub: "); pcpprint_bin(stderr, key->edpub, crypto_sign_PUBLICKEYBYTES); fprintf(stderr, "\n"); if(debug) {
fprintf(stderr, " pub: "); pcpprint_bin(stderr, key->pub, crypto_box_PUBLICKEYBYTES); fprintf(stderr, "\n"); _dump(" mp", secret->edpub, crypto_sign_PUBLICKEYBYTES);
fprintf(stderr, "edpub: "); pcpprint_bin(stderr, key->edpub, crypto_sign_PUBLICKEYBYTES); fprintf(stderr, "\n"); _dump(" cp", key->pub, crypto_sign_PUBLICKEYBYTES);
_dump(" sp", key->edpub, crypto_sign_PUBLICKEYBYTES);
_dump("name", (unsigned char *)key->owner, strlen(key->owner));
}
memcpy(blob, key->edpub, crypto_sign_PUBLICKEYBYTES); /* pkt = keys.sign(keys.mp+keys.sp+keys.cp+dates+keys.name, master=True) */
memcpy(&blob[crypto_sign_PUBLICKEYBYTES], key->pub, crypto_box_PUBLICKEYBYTES); memcpy(blob, secret->edpub, crypto_sign_PUBLICKEYBYTES);
memcpy(&blob[crypto_sign_PUBLICKEYBYTES+crypto_box_PUBLICKEYBYTES], key->edpub, crypto_sign_PUBLICKEYBYTES); memcpy(&blob[crypto_sign_PUBLICKEYBYTES], key->edpub, crypto_sign_PUBLICKEYBYTES);
memcpy(&blob[crypto_sign_PUBLICKEYBYTES+crypto_box_PUBLICKEYBYTES+crypto_sign_PUBLICKEYBYTES], memcpy(&blob[crypto_sign_PUBLICKEYBYTES*2], key->pub, crypto_box_PUBLICKEYBYTES);
key->owner, strlen(key->owner));
struct tm *v;
time_t vt = t + 31536000;
v = localtime(&vt);
char *date = ucmalloc(65);
sprintf(date, "%04d-%02d-%02dT%02d:%02d:%02d.000000 %04d-%02d-%02dT%02d:%02d:%02d.000000 ",
c->tm_year+1900-1, c->tm_mon+1, c->tm_mday, // wtf? why -1?
c->tm_hour, c->tm_min, c->tm_sec,
v->tm_year+1900-1, v->tm_mon+1, v->tm_mday,
v->tm_hour, v->tm_min, v->tm_sec);
memcpy(&blob[crypto_sign_PUBLICKEYBYTES+crypto_box_PUBLICKEYBYTES*2], date, 64);
memcpy(&blob[crypto_sign_PUBLICKEYBYTES+crypto_box_PUBLICKEYBYTES*2+64], key->owner, strlen(key->owner));
unsigned char *sig = pcp_ed_sign(blob, pbplen, secret); unsigned char *sig = pcp_ed_sign(blob, pbplen, secret);
fprintf(stderr, " sig: "); pcpprint_bin(stderr, sig, pbplen+crypto_sign_BYTES); fprintf(stderr, "\n");
fprintf(stderr, "siglen: %d, inlen: %ld\n", crypto_sign_BYTES, pbplen); if(debug)
_dump(" sig", sig, crypto_sign_BYTES+pbplen);
if(sig != NULL) { if(sig != NULL) {
size_t siglen = pbplen + crypto_sign_BYTES; size_t siglen = pbplen + crypto_sign_BYTES;
size_t blen = ((siglen / 4) * 5) + siglen; size_t blen = ((siglen / 4) * 5) + siglen;