From 0eafc34970a8e2d4e928eb25f309666c9b25496a Mon Sep 17 00:00:00 2001 From: gardners Date: Tue, 15 May 2012 20:04:41 +0930 Subject: [PATCH] BK encoding and decoding complete, but untested. --- commandline.c | 3 ++- dataformats.c | 16 +++++++++++++++ rhizome.c | 14 +++++++++---- rhizome.h | 7 ++++--- rhizome_bundle.c | 12 +++++++----- rhizome_crypto.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++-- serval.h | 1 + 7 files changed, 89 insertions(+), 15 deletions(-) diff --git a/commandline.c b/commandline.c index e7274690..4fcd07a0 100644 --- a/commandline.c +++ b/commandline.c @@ -1137,7 +1137,8 @@ int app_rhizome_extract_manifest(int argc, const char *const *argv, struct comma case 0: ret = 1; break; case 1: ret = 0; if (manifestpath[0]) { - if (rhizome_manifest_finalise(m, 1) == -1) +#warning why do we ask for the manifest to be signed here, when we are just extracting it? Anyway, it wont work while the author field is null. + if (rhizome_manifest_finalise(m, 1,NULL) == -1) ret = WHY("Could not overwrite manifest file."); else if (rhizome_write_manifest_file(m, manifestpath) == -1) ret = WHY("Could not overwrite manifest file."); diff --git a/dataformats.c b/dataformats.c index d5602856..ed31bd9b 100644 --- a/dataformats.c +++ b/dataformats.c @@ -136,6 +136,22 @@ int stowSid(unsigned char *packet, int ofs, const char *sid) return 0; } +int stowBytes(unsigned char *packet, const char *in,int count) +{ + int ofs=0; + if (strlen(in)!=(count*2)) + return WHY("Input string is wrong length"); + int i; + for(i = 0; i != count; ++i) { + if(hexvalue(in[i<<1])<0) return WHYF("Non-hex char at position %d",i<<1); + if(hexvalue(in[(i<<1)+1])<0) return WHYF("Non-hex char at position %d",(i<<1)+1); + packet[ofs] = hexvalue(in[i<<1]) << 4; + packet[ofs++] |= hexvalue(in[(i<<1)+1]); + } + return 0; +} + + int hexvalue(unsigned char c) { if (c>='0'&&c<='9') return c-'0'; diff --git a/rhizome.c b/rhizome.c index 02c3527d..e2e29c7a 100644 --- a/rhizome.c +++ b/rhizome.c @@ -220,7 +220,7 @@ int rhizome_add_manifest(rhizome_manifest *m_in, fprintf(stderr, "Found duplicate payload: name=\"%s\" version=%llu hexhash=%s -- not adding\n", name, dupm->version, dupm->fileHexHash); /* If the caller wants the duplicate manifest, it must be finalised, otherwise discarded. */ if (m_out) { - if (rhizome_manifest_finalise(dupm, 0)) + if (rhizome_manifest_finalise(dupm, 0,NULL)) return WHY("Failed to finalise manifest.\n"); *m_out = dupm; } @@ -250,7 +250,7 @@ int rhizome_add_manifest(rhizome_manifest *m_in, } /* Check if we know its private key */ rhizome_hex_to_bytes(id, m_in->cryptoSignPublic, crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES*2); - if (!rhizome_find_privatekey(m_in)) + if (!rhizome_extract_privatekey(m_in,author)) m_in->haveSecret=1; } else { /* The manifest had no ID (256 bit random string being a public key in the NaCl CryptoSign @@ -270,7 +270,13 @@ int rhizome_add_manifest(rhizome_manifest *m_in, The nice thing about this specification is that: privateKey = BK XOR sha512(RS##BID), so the same function can be used to encrypt and decrypt the BK field. */ - + int len=crypto_sign_edwards25519sha512batch_SECRETKEYBYTES; + unsigned char bkbytes[len]; + if (!rhizome_bk_xor(author,m_in->cryptoSignPublic, + m_in->cryptoSignPublic, + bkbytes)) { + rhizome_manifest_set(m_in,"BK",rhizome_bytes_to_hex(bkbytes,len)); + } } } @@ -282,7 +288,7 @@ int rhizome_add_manifest(rhizome_manifest *m_in, } /* Finish completing the manifest */ - if (rhizome_manifest_finalise(m_in, signP)) + if (rhizome_manifest_finalise(m_in, signP,author)) return WHY("Failed to finalise manifest.\n"); /* Okay, it is written, and can be put directly into the rhizome database now */ diff --git a/rhizome.h b/rhizome.h index 64923e0a..ed9015f3 100644 --- a/rhizome.h +++ b/rhizome.h @@ -173,7 +173,7 @@ int rhizome_str_is_manifest_id(const char *text); int rhizome_strn_is_file_hash(const char *text); int rhizome_str_is_file_hash(const char *text); int rhizome_write_manifest_file(rhizome_manifest *m, const char *filename); -int rhizome_manifest_sign(rhizome_manifest *m); +int rhizome_manifest_sign(rhizome_manifest *m,const char *authoring_sid); int rhizome_drop_stored_file(char *id,int maximum_priority); int rhizome_manifest_priority(char *id); rhizome_manifest *rhizome_read_manifest_file(const char *filename, int bufferPAndSize, int flags); @@ -201,11 +201,11 @@ int rhizome_add_manifest(rhizome_manifest *m_in, rhizome_manifest **m_out, const char *groups[], int ttl, int verifyP, int checkFileP, int signP, const char *author); -int rhizome_manifest_finalise(rhizome_manifest *m,int signP); +int rhizome_manifest_finalise(rhizome_manifest *m,int signP,const char *author); char *rhizome_bytes_to_hex(unsigned char *in,int byteCount); int rhizome_hex_to_bytes(const char *in,unsigned char *out,int hexChars); int rhizome_find_privatekey(rhizome_manifest *m); -rhizome_signature *rhizome_sign_hash(rhizome_manifest *m); +rhizome_signature *rhizome_sign_hash(rhizome_manifest *m,const char *author); int rhizome_server_free_http_request(rhizome_http_request *r); int rhizome_server_close_http_request(int i); int rhizome_server_http_send_bytes(int rn,rhizome_http_request *r); @@ -239,3 +239,4 @@ int rhizome_bk_xor(const char *author, unsigned char bid[crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES], unsigned char bkin[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES], unsigned char bkout[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES]); +int rhizome_extract_privatekey(rhizome_manifest *m,const char *authorHex); diff --git a/rhizome_bundle.c b/rhizome_bundle.c index b2a70b13..1ebeaca2 100644 --- a/rhizome_bundle.c +++ b/rhizome_bundle.c @@ -413,10 +413,12 @@ int rhizome_manifest_pack_variables(rhizome_manifest *m) return 0; } -/* Sign this manifest using our own private CryptoSign key */ -int rhizome_manifest_sign(rhizome_manifest *m) +/* Sign this manifest using our own private CryptoSign key. + We may have multiple identities at any given point, so tell + which one we should be using. */ +int rhizome_manifest_sign(rhizome_manifest *m,const char *author) { - rhizome_signature *sig=rhizome_sign_hash(m); + rhizome_signature *sig=rhizome_sign_hash(m,author); if (!sig) return WHY("rhizome_sign_hash() failed."); @@ -466,7 +468,7 @@ int rhizome_manifest_dump(rhizome_manifest *m,char *msg) return 0; } -int rhizome_manifest_finalise(rhizome_manifest *m,int signP) +int rhizome_manifest_finalise(rhizome_manifest *m,int signP,const char *author) { /* set fileHexHash */ if (!m->fileHashedP) { @@ -503,7 +505,7 @@ int rhizome_manifest_finalise(rhizome_manifest *m,int signP) rhizome_manifest_pack_variables(m); /* Sign it */ - if (signP) rhizome_manifest_sign(m); + if (signP) rhizome_manifest_sign(m,author); /* mark manifest as finalised */ m->finalised=1; diff --git a/rhizome_crypto.c b/rhizome_crypto.c index ad2b0016..8852f22d 100644 --- a/rhizome_crypto.c +++ b/rhizome_crypto.c @@ -123,13 +123,60 @@ int rhizome_bk_xor(const char *author, return 0; } -rhizome_signature *rhizome_sign_hash(rhizome_manifest *m) +/* See if the manifest has a BK entry, and if so, use it to obtain the + private key for the BID. Decoding BK's relies on the provision of + the appropriate SID. + + XXX Note that this function is not able to verify that the private key + is correct, as there is no exposed API in NaCl for calculating the + public key from a cryptosign private key. We thus have to trust that + the supplied SID is correct. + +*/ +int rhizome_extract_privatekey(rhizome_manifest *m,const char *authorHex) +{ + char *bk = rhizome_manifest_get(m, "bk", NULL, 0); + if (!bk) return WHY("Cannot obtain private key as manifest lacks BK field"); + + unsigned char bkBytes[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES]; + if (stowBytes(bkBytes,bk,crypto_sign_edwards25519sha512batch_SECRETKEYBYTES)) + return WHY("Failed to make packed version of BK. Is it a valid hex string of the correct length?"); + + if (rhizome_bk_xor(authorHex, + m->cryptoSignPublic, + bkBytes, + m->cryptoSignSecret)) + return WHY("rhizome_bk_xor() failed"); + + /* Verify validity of key. + XXX This is a pretty ugly way to do it, but NaCl offers no API to + do this cleanly. */ + { +#include "nacl-source/nacl-20110221/nacl-source/crypto_sign_edwards25519sha512batch_ref/ge25519.h" + unsigned char *sk=m->cryptoSignSecret; + unsigned char pk[crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES]; + sc25519 scsk; + ge25519 gepk; + + sc25519_from32bytes(&scsk,sk); + + ge25519_scalarmult_base(&gepk, &scsk); + ge25519_pack(pk, &gepk); + bzero(&scsk,sizeof(scsk)); + if (bcmp(pk,m->cryptoSignPublic, + crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES)) + return WHY("BID secret key decoded from BK was not valid"); + else return 0; + } +} + +rhizome_signature *rhizome_sign_hash(rhizome_manifest *m,const char *author) { unsigned char *hash=m->manifesthash; unsigned char *publicKeyBytes=m->cryptoSignPublic; unsigned char secretKeyBytes[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES]; - if (rhizome_find_privatekey(m)) + if (rhizome_extract_privatekey(m,author)) { WHY("Cannot find secret key to sign manifest data."); return NULL; diff --git a/serval.h b/serval.h index c76fdc5b..fdf740d1 100755 --- a/serval.h +++ b/serval.h @@ -397,6 +397,7 @@ int recvwithttl(int sock,unsigned char *buffer,int bufferlen,int *ttl, struct sockaddr *recvaddr,unsigned int *recvaddrlen); int validateSid(const char *sid); int stowSid(unsigned char *packet, int ofs, const char *sid); +int stowBytes(unsigned char *packet, const char *in,int count); int stowDid(unsigned char *packet,int *ofs,char *did); int isFieldZeroP(unsigned char *packet,int start,int count); void srandomdev();