Now correctly generating the Peer ID from a public key

This commit is contained in:
John Jones 2017-02-02 18:27:57 -05:00
parent 6b24f06855
commit 94566ade69
8 changed files with 119 additions and 71 deletions

View file

@ -29,6 +29,39 @@ void libp2p_crypto_public_key_free(struct PublicKey* in) {
} }
} }
/***
* Calculates an approximate required size of a buffer for protobuf encoding a public key
* @param in the public key to examine
* @returns the size in bytes
*/
size_t libp2p_crypto_public_key_protobuf_encode_size(struct PublicKey* in) {
return 11 + 11 + in->data_size;
}
/***
* Encode a PublicKey into a protobuf
* @param in the struct PublicKey
* @param buffer where to put the results
* @param max_buffer_length the size of the buffer
* @param bytes_written how many bytes were used in the buffer
* @returns true(1) on success, otherwise false(0)
*/
int libp2p_crypto_public_key_protobuf_encode(struct PublicKey* in, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written) {
// data & data_size
size_t bytes_used = 0;
*bytes_written = 0;
int retVal = 0;
// key type (RSA vs ...)
retVal = protobuf_encode_varint(1, WIRETYPE_VARINT, in->type, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used);
*bytes_written += bytes_used;
// public key
retVal = protobuf_encode_length_delimited(2, WIRETYPE_LENGTH_DELIMITED, in->data, in->data_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used);
if (retVal == 0)
return 0;
*bytes_written += bytes_used;
return 1;
}
/** /**
* Unmarshal a public key from a protobuf * Unmarshal a public key from a protobuf
* @param buffer the protobuf * @param buffer the protobuf
@ -153,8 +186,15 @@ exit:
* @returns true(1) on success, otherwise false(0) * @returns true(1) on success, otherwise false(0)
*/ */
int libp2p_crypto_public_key_to_peer_id(struct PublicKey* public_key, char** peer_id) { int libp2p_crypto_public_key_to_peer_id(struct PublicKey* public_key, char** peer_id) {
size_t protobuf_len = libp2p_crypto_public_key_protobuf_encode_size(public_key);
unsigned char protobuf[protobuf_len];
libp2p_crypto_public_key_protobuf_encode(public_key, protobuf, protobuf_len, &protobuf_len);
unsigned char hashed[32]; unsigned char hashed[32];
libp2p_crypto_hashing_sha256(public_key->data, public_key->data_size, hashed); //libp2p_crypto_hashing_sha256(public_key->data, public_key->data_size, hashed);
libp2p_crypto_hashing_sha256(protobuf, protobuf_len, hashed);
size_t final_id_size = 100; size_t final_id_size = 100;
unsigned char final_id[final_id_size]; unsigned char final_id[final_id_size];
memset(final_id, 0, final_id_size); memset(final_id, 0, final_id_size);

View file

@ -5,6 +5,7 @@
#include "mh/hashes.h" #include "mh/hashes.h"
#include "libp2p/crypto/encoding/base58.h" #include "libp2p/crypto/encoding/base58.h"
#include "libp2p/crypto/sha256.h" #include "libp2p/crypto/sha256.h"
//#include "libp2p/crypto/key.h"
/** /**
* base58 encode a string NOTE: this also puts the prefix 'Qm' in front as the ID is a multihash * base58 encode a string NOTE: this also puts the prefix 'Qm' in front as the ID is a multihash
@ -38,20 +39,11 @@ int PrettyID(unsigned char * pointyaddr, size_t* rezbuflen,unsigned char * ID_BU
/**** /****
* Make a SHA256 hash of what is usually the DER formatted private key. * Make a SHA256 hash of what is usually the DER formatted private key.
* @param result where to store the result. Should be 32 chars long * @param result where to store the result. Should be 32 chars long
* @param texttohash the text to hash * @param texttohash the text to hash. A DER formatted public key
* @param text_size the size of the text * @param text_size the size of the text
*/ */
void ID_FromPK_non_null_terminated(char * result,unsigned char * texttohash, size_t text_size) void ID_FromPK_non_null_terminated(char * result,unsigned char * texttohash, size_t text_size)
{ {
/* old way
unsigned char hash[32];
bzero(hash,32);
SHA256_CTX ctx;
sha256_init(&ctx);
sha256_update(&ctx,texttohash,text_size);
sha256_final(&ctx,hash);
a_store_hash(result,hash);
*/
libp2p_crypto_hashing_sha256(texttohash, text_size, (unsigned char*)result); libp2p_crypto_hashing_sha256(texttohash, text_size, (unsigned char*)result);
} }

View file

@ -113,25 +113,7 @@ int libp2p_net_multistream_connect(const char* hostname, int port) {
if (num_bytes <= 0) if (num_bytes <= 0)
goto exit; goto exit;
// that should be successful, now we are in the loop, and it is waiting for a protocol buffer to use, so send it again // we are now in the loop, so we can switch to another protocol (i.e. /secio/1.0.0)
protocol_buffer = "/secio/1.0.0\n";
num_bytes = libp2p_net_multistream_send(socket, (const unsigned char*)protocol_buffer, strlen(protocol_buffer));
if (num_bytes <= 0)
goto exit;
// we should get it back again, handshake should be complete.
free(results);
results = NULL;
return_result = libp2p_net_multistream_receive(socket, &results, &results_size);
if (return_result == 0 || results_size < 1 || (results[0] == 'n' && results[1] == 'a')) {
// it failed, ask for a list
protocol_buffer = "ls";
num_bytes = libp2p_net_multistream_send(socket, (const unsigned char*)protocol_buffer, strlen(protocol_buffer));
if (num_bytes <= 0)
goto exit;
free(results);
results = NULL;
return_result = libp2p_net_multistream_receive(socket, &results, &results_size);
}
retVal = socket; retVal = socket;
exit: exit:

View file

@ -103,7 +103,7 @@ int libp2p_secio_propose_protobuf_decode(unsigned char* buffer, size_t buffer_le
size_t pos = 0; size_t pos = 0;
int retVal = 0; int retVal = 0;
if (libp2p_secio_propose_new(out) == 0) if ( (*out = libp2p_secio_propose_new()) == NULL)
goto exit; goto exit;
while(pos < buffer_length) { while(pos < buffer_length) {

View file

@ -1,4 +1,5 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> // for debugging, can remove
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
@ -58,6 +59,45 @@ int libp2p_secio_handshake(struct SecureSession* session, struct RsaPrivateKey*
struct Propose* propose_in = NULL; struct Propose* propose_in = NULL;
struct PublicKey* public_key = NULL; struct PublicKey* public_key = NULL;
// connect to host
session->socket_descriptor = libp2p_net_multistream_connect(session->host, session->port);
if (session->socket_descriptor == -1)
goto exit;
const unsigned char* protocol = (unsigned char*)"/secio/1.0.0\n";
bytes_written = libp2p_net_multistream_send(session->socket_descriptor, protocol, strlen((char*)protocol));
if (bytes_written <= 0)
goto exit;
// we should get back the protocol to signify it was accepted, as well as the protobuf of the Propose struct
bytes_written = libp2p_net_multistream_receive(session->socket_descriptor, (char**)&results, &results_size);
if (bytes_written < 1 || strstr((char*)results, "secio") == NULL)
goto exit;
// skip to the protobuf section
protobuf = (unsigned char*)strchr((char*)results, '\n');
if (protobuf == NULL)
goto exit;
protobuf++;
protobuf_size = results_size - (protobuf - results);
if (!libp2p_secio_propose_protobuf_decode(protobuf, protobuf_size, &propose_in))
goto exit;
// clear results
free(results);
results = NULL;
results_size = 0;
// hash the protobuf of the public key
// get public key
if (!libp2p_crypto_public_key_protobuf_decode(propose_in->public_key, propose_in->public_key_size, &public_key))
goto exit;
// generate their peer id
char* remote_peer_id;
libp2p_crypto_public_key_to_peer_id(public_key, &remote_peer_id);
// generate 16 byte nonce // generate 16 byte nonce
char nonceOut[16]; char nonceOut[16];
if (!libp2p_secio_generate_nonce(&nonceOut[0], 16)) { if (!libp2p_secio_generate_nonce(&nonceOut[0], 16)) {
@ -67,6 +107,10 @@ int libp2p_secio_handshake(struct SecureSession* session, struct RsaPrivateKey*
propose_out = libp2p_secio_propose_new(); propose_out = libp2p_secio_propose_new();
libp2p_secio_propose_set_property((void**)&propose_out->rand, &propose_out->rand_size, nonceOut, 16); libp2p_secio_propose_set_property((void**)&propose_out->rand, &propose_out->rand_size, nonceOut, 16);
// TODO: the Peer ID looks funny. I don't think it is right.
// we have their information, now we need to gather ours.
// will need: // will need:
// TODO: public key // TODO: public key
// supported exchanges // supported exchanges
@ -75,37 +119,6 @@ int libp2p_secio_handshake(struct SecureSession* session, struct RsaPrivateKey*
libp2p_secio_propose_set_property((void**)&propose_out->ciphers, &propose_out->ciphers_size, SupportedCiphers, strlen(SupportedCiphers)); libp2p_secio_propose_set_property((void**)&propose_out->ciphers, &propose_out->ciphers_size, SupportedCiphers, strlen(SupportedCiphers));
// supported hashes // supported hashes
libp2p_secio_propose_set_property((void**)&propose_out->hashes, &propose_out->exchanges_size, SupportedHashes, strlen(SupportedHashes)); libp2p_secio_propose_set_property((void**)&propose_out->hashes, &propose_out->exchanges_size, SupportedHashes, strlen(SupportedHashes));
// send request (protobuf, then send)
protobuf_size = libp2p_secio_propose_protobuf_encode_size(propose_out);
protobuf = (unsigned char*) malloc(protobuf_size);
if (protobuf == NULL)
goto exit;
if (!libp2p_secio_propose_protobuf_encode(propose_out, protobuf, protobuf_size, &protobuf_size))
goto exit;
// connect to host
session->socket_descriptor = libp2p_net_multistream_connect(session->host, session->port);
bytes_written = libp2p_net_multistream_send(session->socket_descriptor, protobuf, protobuf_size);
if (bytes_written <= 0)
goto exit;
// receive response (turn back into a Propose struct)
bytes_written = libp2p_net_multistream_receive(session->socket_descriptor, (char**)&results, &results_size);
if (bytes_written == 65535)
goto exit;
if (!libp2p_secio_propose_protobuf_decode(results, results_size, &propose_in))
goto exit;
// get public key
if (!libp2p_crypto_public_key_protobuf_decode(propose_in->public_key, propose_in->public_key_size, &public_key))
goto exit;
// generate their peer id
char* remote_peer_id;
libp2p_crypto_public_key_to_peer_id(public_key, &remote_peer_id);
// negotiate encryption parameters NOTE: SelectBest must match, otherwise this won't work // negotiate encryption parameters NOTE: SelectBest must match, otherwise this won't work
// curve // curve
// cipher // cipher

View file

@ -15,8 +15,7 @@ int test_protobuf_private_key() {
char* orig_peer_id = "QmbTyKkUuv6yaSpTuCFq1Ft6Q3g4wTtFJk1BLGMPRdAEP8"; char* orig_peer_id = "QmbTyKkUuv6yaSpTuCFq1Ft6Q3g4wTtFJk1BLGMPRdAEP8";
size_t orig_peer_id_size = strlen(orig_peer_id); size_t orig_peer_id_size = strlen(orig_peer_id);
unsigned char hashed[32]; unsigned char hashed[32];
size_t final_id_size = 1600; unsigned char *final_id;
unsigned char final_id[final_id_size];
// 1) take the private key and turn it back into bytes (decode base 64) // 1) take the private key and turn it back into bytes (decode base 64)
@ -40,16 +39,18 @@ int test_protobuf_private_key() {
goto exit; goto exit;
// 3) grab the public key, hash it, then base58 it // 3) grab the public key, hash it, then base58 it
ID_FromPK_non_null_terminated((char*)hashed, (unsigned char*)rsa_private_key.public_key_der, rsa_private_key.public_key_length); struct PublicKey public_key;
memset(final_id, 0, final_id_size); public_key.type = KEYTYPE_RSA;
if (!PrettyID(final_id, &final_id_size, hashed, 32)) public_key.data_size = rsa_private_key.public_key_length;
public_key.data = rsa_private_key.public_key_der;
if (!libp2p_crypto_public_key_to_peer_id(&public_key, (char**)&final_id ))
goto exit; goto exit;
// 4) compare results // 4) compare results
if (orig_peer_id_size != final_id_size) if (orig_peer_id_size != strlen((char*)final_id))
goto exit; goto exit;
if (strncmp(orig_peer_id, (char*)final_id, final_id_size) != 0) if (strncmp(orig_peer_id, (char*)final_id, strlen(final_id)) != 0)
goto exit; goto exit;
retVal = 1; retVal = 1;

View file

@ -11,6 +11,22 @@ int test_multistream_connect() {
char* response; char* response;
size_t response_size; size_t response_size;
socket_fd = libp2p_net_multistream_connect("www.jmjatlanta.com", 4001);
if (socket_fd < 0)
goto exit;
retVal = 1;
exit:
return retVal > 0;
}
int test_multistream_get_list() {
int retVal = 0, socket_fd = -1;
char* response;
size_t response_size;
socket_fd = libp2p_net_multistream_connect("www.jmjatlanta.com", 4001); socket_fd = libp2p_net_multistream_connect("www.jmjatlanta.com", 4001);
if (socket_fd < 0) if (socket_fd < 0)
goto exit; goto exit;
@ -26,6 +42,8 @@ int test_multistream_connect() {
if (retVal <= 0) if (retVal <= 0)
goto exit; goto exit;
fprintf(stdout, "Response from multistream ls: %s", response);
retVal = 1; retVal = 1;
exit: exit:

View file

@ -30,7 +30,8 @@ const char* names[] = {
"test_crypto_encoding_base32_encode", "test_crypto_encoding_base32_encode",
"test_protobuf_private_key", "test_protobuf_private_key",
"test_secio_handshake", "test_secio_handshake",
"test_multistream_connect" "test_multistream_connect",
"test_multistream_get_list"
}; };
int (*funcs[])(void) = { int (*funcs[])(void) = {
@ -55,7 +56,8 @@ int (*funcs[])(void) = {
test_crypto_encoding_base32_encode, test_crypto_encoding_base32_encode,
test_protobuf_private_key, test_protobuf_private_key,
test_secio_handshake, test_secio_handshake,
test_multistream_connect test_multistream_connect,
test_multistream_get_list
}; };
int testit(const char* name, int (*func)(void)) { int testit(const char* name, int (*func)(void)) {