Record Protobuf
This commit is contained in:
parent
3aa0d89cb3
commit
897d257b3b
2 changed files with 206 additions and 65 deletions
|
@ -3,14 +3,19 @@
|
||||||
struct Libp2pRecord {
|
struct Libp2pRecord {
|
||||||
// the key that references this record
|
// the key that references this record
|
||||||
char* key;
|
char* key;
|
||||||
|
size_t key_size;
|
||||||
// the actual value this record is storing
|
// the actual value this record is storing
|
||||||
unsigned char* value;
|
unsigned char* value;
|
||||||
|
size_t value_size;
|
||||||
// hash of the author's public key
|
// hash of the author's public key
|
||||||
char* author;
|
char* author;
|
||||||
|
size_t author_size;
|
||||||
// a PKI signature for the key + value + author
|
// a PKI signature for the key + value + author
|
||||||
unsigned char* signature;
|
unsigned char* signature;
|
||||||
|
size_t signature_size;
|
||||||
// time the record was received, set by receiver
|
// time the record was received, set by receiver
|
||||||
char* time_received;
|
char* time_received;
|
||||||
|
size_t time_received_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,6 +52,7 @@ int libp2p_record_protobuf_decode(const unsigned char* in, size_t in_size, struc
|
||||||
* @param key the key in the Libp2pRecord
|
* @param key the key in the Libp2pRecord
|
||||||
* @param value the value in the Libp2pRecord
|
* @param value the value in the Libp2pRecord
|
||||||
* @param vlen the length of value
|
* @param vlen the length of value
|
||||||
* @param sign ??
|
* @param sign true if you want to sign the record
|
||||||
|
* @returns 0 on success, -1 on error
|
||||||
*/
|
*/
|
||||||
int libp2p_record_make_put_record (char** record, size_t *rec_size, struct RsaPrivateKey* sk, char* key, char* value, size_t vlen, int sign);
|
int libp2p_record_make_put_record (char** record, size_t *rec_size, const struct RsaPrivateKey* sk, const char* key, const char* value, size_t vlen, int sign);
|
||||||
|
|
261
record/record.c
261
record/record.c
|
@ -2,72 +2,207 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "libp2p/crypto/rsa.h"
|
#include "libp2p/crypto/rsa.h"
|
||||||
|
#include "libp2p/crypto/sha256.h"
|
||||||
#include "libp2p/record/record.h"
|
#include "libp2p/record/record.h"
|
||||||
#include "protobuf.h"
|
#include "protobuf.h"
|
||||||
#include "mh/hashes.h"
|
#include "mh/hashes.h"
|
||||||
#include "mh/multihash.h"
|
#include "mh/multihash.h"
|
||||||
|
|
||||||
#define RECORD_BUFSIZE 6048
|
/**
|
||||||
|
* Convert a Libp2pRecord into protobuf format
|
||||||
// libp2p_record_make_put_record creates and signs a dht record for the given key/value pair
|
* @param in the Libp2pRecord to convert
|
||||||
int libp2p_record_make_put_record (char** record, size_t *rec_size, struct RsaPrivateKey* sk, char* key, char* value, size_t vlen, int sign)
|
* @param buffer where to store the protobuf
|
||||||
{
|
* @param max_buffer_size the size of the allocated buffer
|
||||||
char *pkh, *p;
|
* @param bytes_written the size written into buffer
|
||||||
int pkh_len;
|
* @returns true(1) on success, otherwise false(0)
|
||||||
size_t len = 0, l;
|
*/
|
||||||
|
int libp2p_record_protobuf_encode(const struct Libp2pRecord* in, unsigned char* buffer, size_t max_buffer_size, size_t* bytes_written) {
|
||||||
*record = NULL; *rec_size = 0;
|
// data & data_size
|
||||||
p = malloc(RECORD_BUFSIZE);
|
size_t bytes_used = 0;
|
||||||
|
*bytes_written = 0;
|
||||||
if (p) {
|
int retVal = 0;
|
||||||
memset (p, '\0', len);
|
// field 1
|
||||||
if (!protobuf_encode_string (1, WIRETYPE_LENGTH_DELIMITED, key, p, RECORD_BUFSIZE, &l)) {
|
retVal = protobuf_encode_length_delimited(1, WIRETYPE_LENGTH_DELIMITED, in->key, in->key_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
|
||||||
free (p);
|
if (retVal == 0)
|
||||||
return -1;
|
return 0;
|
||||||
}
|
*bytes_written += bytes_used;
|
||||||
len += l;
|
// field 2
|
||||||
if (!protobuf_encode_length_delimited (2, WIRETYPE_LENGTH_DELIMITED, value, vlen, p+len, RECORD_BUFSIZE-len, &l)) {
|
retVal = protobuf_encode_length_delimited(2, WIRETYPE_LENGTH_DELIMITED, in->value, in->value_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
|
||||||
free (p);
|
if (retVal == 0)
|
||||||
return -1;
|
return 0;
|
||||||
}
|
*bytes_written += bytes_used;
|
||||||
len += l;
|
// field 3
|
||||||
pkh_len = mh_new_length(MH_H_SHA2_256, sk->public_key_length);
|
retVal = protobuf_encode_length_delimited(3, WIRETYPE_LENGTH_DELIMITED, in->author, in->author_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
|
||||||
pkh = malloc(pkh_len);
|
if (retVal == 0)
|
||||||
if (!pkh) {
|
return 0;
|
||||||
free (p);
|
*bytes_written += bytes_used;
|
||||||
return -1;
|
// field 4
|
||||||
}
|
retVal = protobuf_encode_length_delimited(4, WIRETYPE_LENGTH_DELIMITED, in->signature, in->signature_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
|
||||||
if (mh_new(pkh, MH_H_SHA2_256, sk->public_key_der, sk->public_key_length)) {
|
if (retVal == 0)
|
||||||
free (pkh);
|
return 0;
|
||||||
free (p);
|
*bytes_written += bytes_used;
|
||||||
return -1;
|
// field 5
|
||||||
}
|
retVal = protobuf_encode_length_delimited(5, WIRETYPE_LENGTH_DELIMITED, in->time_received, in->time_received_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
|
||||||
if (!protobuf_encode_length_delimited (3, WIRETYPE_LENGTH_DELIMITED, pkh, pkh_len, p+len, RECORD_BUFSIZE-len, &l)) {
|
if (retVal == 0)
|
||||||
free (pkh);
|
return 0;
|
||||||
free (p);
|
*bytes_written += bytes_used;
|
||||||
return -1;
|
return 1;
|
||||||
}
|
}
|
||||||
free (pkh);
|
|
||||||
len += l;
|
/**
|
||||||
if (sign) {
|
* Generates an estimate of the buffer size needed to encode the struct
|
||||||
char *sign_buf;
|
* @param in the Libp2pRecord that you want to encode
|
||||||
size_t sign_length;
|
* @returns the approximate number of bytes required
|
||||||
if (!libp2p_crypto_rsa_sign (sk, (unsigned char*) p, len, (unsigned char**)sign_buf, &sign_length) ||
|
*/
|
||||||
!protobuf_encode_string (4, WIRETYPE_LENGTH_DELIMITED, sign_buf, p+len, RECORD_BUFSIZE-len, &l)) {
|
size_t libp2p_record_protobuf_encode_size(const struct Libp2pRecord* in) {
|
||||||
free(sign_buf);
|
size_t retVal = 11 + in->key_size;
|
||||||
free (p);
|
retVal += 11 + in->value_size;
|
||||||
return -1;
|
retVal += 11 + in->author_size;
|
||||||
}
|
retVal += 11 + in->signature_size;
|
||||||
free(sign_buf);
|
retVal += 11 + in->time_received_size;
|
||||||
len += l;
|
return retVal;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
*record = realloc(p, len); // Reduces memory used for just what is needed.
|
/**
|
||||||
if (*record) {
|
* Convert a protobuf byte array into a Libp2pRecord
|
||||||
*rec_size = len;
|
* @param in the byte array
|
||||||
} else {
|
* @param in_size the size of the byte array
|
||||||
free (p);
|
* @param out a pointer to the new Libp2pRecord
|
||||||
return -1;
|
* @returns true(1) on success, otherwise false(0)
|
||||||
}
|
*/
|
||||||
return 0; // sucess.
|
int libp2p_record_protobuf_decode(const unsigned char* in, size_t in_size, struct Libp2pRecord** out) {
|
||||||
|
size_t pos = 0;
|
||||||
|
int retVal = 0;
|
||||||
|
|
||||||
|
if ( (*out = (struct Libp2pRecord*)malloc(sizeof(struct Libp2pRecord))) == NULL)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
while(pos < in_size) {
|
||||||
|
size_t bytes_read = 0;
|
||||||
|
int field_no;
|
||||||
|
enum WireType field_type;
|
||||||
|
if (protobuf_decode_field_and_type(&in[pos], in_size, &field_no, &field_type, &bytes_read) == 0) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
pos += bytes_read;
|
||||||
|
switch(field_no) {
|
||||||
|
case (1): // key
|
||||||
|
if (protobuf_decode_length_delimited(&in[pos], in_size - pos, (char**)&((*out)->key),&((*out)->key_size), &bytes_read) == 0)
|
||||||
|
goto exit;
|
||||||
|
pos += bytes_read;
|
||||||
|
break;
|
||||||
|
case (2): // value
|
||||||
|
if (protobuf_decode_length_delimited(&in[pos], in_size - pos, (char**)&((*out)->value), &((*out)->value_size), &bytes_read) == 0)
|
||||||
|
goto exit;
|
||||||
|
pos += bytes_read;
|
||||||
|
break;
|
||||||
|
case (3): // author
|
||||||
|
if (protobuf_decode_length_delimited(&in[pos], in_size - pos, (char**)&((*out)->author), &((*out)->author_size), &bytes_read) == 0)
|
||||||
|
goto exit;
|
||||||
|
pos += bytes_read;
|
||||||
|
break;
|
||||||
|
case (4): // signature
|
||||||
|
if (protobuf_decode_length_delimited(&in[pos], in_size - pos, (char**)&((*out)->signature), &((*out)->signature_size), &bytes_read) == 0)
|
||||||
|
goto exit;
|
||||||
|
pos += bytes_read;
|
||||||
|
break;
|
||||||
|
case (5): // time
|
||||||
|
if (protobuf_decode_length_delimited(&in[pos], in_size - pos, (char**)&((*out)->time_received), &((*out)->time_received_size), &bytes_read) == 0)
|
||||||
|
goto exit;
|
||||||
|
pos += bytes_read;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
retVal = 1;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (retVal == 0) {
|
||||||
|
free(*out);
|
||||||
|
*out = NULL;
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method does all the hard stuff in one step. It fills a Libp2pRecord struct, and converts it into a protobuf
|
||||||
|
* @param record a pointer to the protobuf results
|
||||||
|
* @param rec_size the number of bytes used in the area pointed to by record
|
||||||
|
* @param sk the private key used to sign
|
||||||
|
* @param key the key in the Libp2pRecord
|
||||||
|
* @param value the value in the Libp2pRecord
|
||||||
|
* @param vlen the length of value
|
||||||
|
* @param sign true(1) if you want to sign the data
|
||||||
|
* @returns 0 on success, otherwise -1
|
||||||
|
*/
|
||||||
|
int libp2p_record_make_put_record (char** record_buf, size_t *rec_size, const struct RsaPrivateKey* sk, const char* key, const char* value, size_t vlen, int sign)
|
||||||
|
{
|
||||||
|
int retVal = -1;
|
||||||
|
size_t bytes_size = 0;
|
||||||
|
unsigned char* bytes = NULL;
|
||||||
|
unsigned char* sign_buf = NULL;
|
||||||
|
unsigned char hash[32];
|
||||||
|
|
||||||
|
// build the struct
|
||||||
|
struct Libp2pRecord record;
|
||||||
|
record.key = (char*)key;
|
||||||
|
record.key_size = strlen(key);
|
||||||
|
record.value = (char*)value;
|
||||||
|
record.value_size = vlen;
|
||||||
|
|
||||||
|
// clear the rest of the fields
|
||||||
|
record.signature = NULL;
|
||||||
|
record.signature_size = 0;
|
||||||
|
//TODO: what should we put in the time field?
|
||||||
|
record.time_received = NULL;
|
||||||
|
record.time_received_size = 0;
|
||||||
|
|
||||||
|
// build a hash of the author's public key
|
||||||
|
libp2p_crypto_hashing_sha256(sk->public_key_der, sk->public_key_length, &hash[0]);
|
||||||
|
record.author = &hash[0];
|
||||||
|
record.author_size = 32;
|
||||||
|
|
||||||
|
bytes_size = record.key_size + record.value_size + record.author_size;
|
||||||
|
bytes = malloc(bytes_size);
|
||||||
|
if (bytes == NULL)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
// build the signature
|
||||||
|
if (sign) {
|
||||||
|
memcpy(&bytes[0], record.key, record.key_size);
|
||||||
|
memcpy(&bytes[record.key_size], record.value, record.value_size);
|
||||||
|
memcpy(&bytes[record.key_size + record.value_size], record.author, record.author_size);
|
||||||
|
size_t sign_length = 0;
|
||||||
|
if (!libp2p_crypto_rsa_sign ((struct RsaPrivateKey*)sk, bytes, bytes_size, &sign_buf, &sign_length))
|
||||||
|
goto exit;
|
||||||
|
record.signature = bytes;
|
||||||
|
record.signature_size = bytes_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now protobuf the struct
|
||||||
|
size_t protobuf_size = libp2p_record_protobuf_encode_size(&record);
|
||||||
|
*record_buf = malloc(protobuf_size);
|
||||||
|
if (*record_buf == NULL)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
if (!libp2p_record_protobuf_encode(&record, *record_buf, protobuf_size, &protobuf_size))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
// we're done here. Cleanup time.
|
||||||
|
retVal = 0;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
|
||||||
|
if (bytes != NULL)
|
||||||
|
free(bytes);
|
||||||
|
if (sign_buf != NULL)
|
||||||
|
free(sign_buf);
|
||||||
|
if (retVal == 0) {
|
||||||
|
free(*record_buf);
|
||||||
|
*record_buf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue