diff --git a/crypto/encoding/x509.c b/crypto/encoding/x509.c index 6f66a66..647ccaf 100644 --- a/crypto/encoding/x509.c +++ b/crypto/encoding/x509.c @@ -91,6 +91,12 @@ int libp2p_crypto_encoding_x509_der_to_private_key(unsigned char* der, size_t de private_key->QP = *(rsa->QP.p); } + // now put the public DER format in. + private_key->der = der; + private_key->der_length = der_length; + + //NOTE: the public DER stuff is done in rsa.c + mbedtls_pk_free(&ctx); return retVal >= 0; diff --git a/crypto/rsa.c b/crypto/rsa.c index eecbee7..d232f0b 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -21,6 +21,7 @@ #include "mbedtls/rsa.h" #include "mbedtls/asn1write.h" #include "mbedtls/oid.h" +#include "mbedtls/pk.h" /** * Take an rsa context and turn it into a der formatted byte stream. @@ -193,6 +194,40 @@ exit: return retVal; } +/** + * Use the private key DER to fill in the public key DER + * @param private_key the private key to use + * @reutrns true(1) on success + */ +int libp2p_crypto_rsa_private_key_fill_public_key(struct RsaPrivateKey* private_key) { + // first build the rsa context + mbedtls_pk_context ctx; + mbedtls_pk_init(&ctx); + mbedtls_pk_parse_key(&ctx, private_key->der, private_key->der_length, NULL, 0); + + // buffer + size_t buffer_size = 1600; + unsigned char buffer[buffer_size]; + memset(buffer, 0, buffer_size); + + // generate public key der + int retVal = libp2p_crypto_rsa_write_public_key_der(&ctx, buffer, &buffer_size); + if (retVal == 0) { + mbedtls_pk_free(&ctx); + return 0; + } + + // allocate memory for the public key der + private_key->public_key_length = buffer_size; + private_key->public_key_der = malloc(sizeof(char) * buffer_size); + + //copy it into the struct + memcpy(private_key->public_key_der, &buffer[1600-buffer_size], buffer_size); + mbedtls_pk_free(&ctx); + + return 1; +} + /*** * Free resources used by RsaPrivateKey * @param private_key the resources diff --git a/include/libp2p/crypto/encoding/x509.h b/include/libp2p/crypto/encoding/x509.h index 1e64cdc..6b0552b 100644 --- a/include/libp2p/crypto/encoding/x509.h +++ b/include/libp2p/crypto/encoding/x509.h @@ -1,10 +1,6 @@ -// -// x509.h -// libp2p_xcode -// -// Created by John Jones on 11/7/16. -// Copyright © 2016 JMJAtlanta. All rights reserved. -// +/** + * Wrappers around the x509 stuff + */ #ifndef __LIBP2P_CRYPTO_ENCODING_X509_H__ #define __LIBP2P_CRYPTO_ENCODING_X509_H__ diff --git a/include/libp2p/crypto/rsa.h b/include/libp2p/crypto/rsa.h index b52c6ed..37ad7a0 100644 --- a/include/libp2p/crypto/rsa.h +++ b/include/libp2p/crypto/rsa.h @@ -38,6 +38,14 @@ struct RsaPrivateKey { */ int libp2p_crypto_rsa_generate_keypair(struct RsaPrivateKey* private_key, unsigned long num_bits_for_keypair); +/** + * Use the private key DER to fill in the public key DER + * @param private_key the private key to use + * @reutrns true(1) on success + */ +int libp2p_crypto_rsa_private_key_fill_public_key(struct RsaPrivateKey* private_key); + + /*** * Free resources used by RsaPrivateKey * @param private_key the resources diff --git a/include/libp2p/peerutils.h b/include/libp2p/peerutils.h index 513faaa..92b47e5 100644 --- a/include/libp2p/peerutils.h +++ b/include/libp2p/peerutils.h @@ -1,9 +1,12 @@ #ifndef PEERDEP #define PEERDEP + #include "stdio.h" #include "string.h" #include -#include "base58.h" +#include "libp2p/crypto/encoding/base58.h" +#include "mh/multihash.h" +#include "mh/hashes.h" #define uchar unsigned char // 8-bit byte #define juint unsigned int // 32-bit word @@ -165,25 +168,65 @@ void a_store_hash(unsigned char * result,unsigned char hash[]) strcat(result,mimi); } } -int PrettyID(unsigned char * pointyaddr, size_t rezbuflen,unsigned char * ID_BUF, size_t ID_BUF_SIZE)//b58 encoded ID buf + +/** + * base58 encode a string NOTE: this also puts the prefix 'Qm' in front as the ID is a multihash + * @param pointyaddr where the results will go + * @param rezbuflen the length of the results buffer. It will also put how much was used here + * @param ID_BUF the input text (usually a SHA256 hash) + * @param ID_BUF_SIZE the input size (normally a SHA256, therefore 32 bytes) + * @returns true(1) on success + */ +int PrettyID(unsigned char * pointyaddr, size_t* rezbuflen,unsigned char * ID_BUF, size_t ID_BUF_SIZE)//b58 encoded ID buf { int returnstatus = 0; - returnstatus = libp2p_crypto_encoding_base58_encode(ID_BUF, ID_BUF_SIZE, &pointyaddr, &rezbuflen); + + unsigned char temp_buffer[*rezbuflen]; + + memset(temp_buffer, 0, *rezbuflen); + + // wrap the base58 into a multihash + int retVal = mh_new(temp_buffer, MH_H_SHA2_256, ID_BUF, ID_BUF_SIZE); + if (retVal < 0) + return 0; + + // base58 the multihash + returnstatus = libp2p_crypto_encoding_base58_encode(temp_buffer, strlen(temp_buffer), &pointyaddr, rezbuflen); if(returnstatus == 0) { printf("\nERROR!!!!!\n"); return 0; } + + return 1; } -void ID_FromPK(char * result,unsigned char * texttohash) + +/**** + * 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 texttohash the text to hash + * @param text_size the size of the text + */ +void ID_FromPK_non_null_terminated(char * result,unsigned char * texttohash, size_t text_size) { unsigned char hash[32]; bzero(hash,32); SHA256_CTX ctx; sha256_init(&ctx); - sha256_update(&ctx,texttohash,strlen(texttohash)); - sha256_final(&ctx,hash); + sha256_update(&ctx,texttohash,text_size); + sha256_final(&ctx,hash); a_store_hash(result,hash); } -#endif \ No newline at end of file + +/**** + * 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 texttohash a null terminated string of the text to hash + */ +void ID_FromPK(char * result,unsigned char * texttohash) +{ + ID_FromPK_non_null_terminated(result,texttohash,strlen(texttohash)); +} + +#endif diff --git a/test/Makefile b/test/Makefile index 6a8c196..ba0629c 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,11 +1,11 @@ CC = gcc -CFLAGS = -O0 -I../include -I. +CFLAGS = -O0 -I../include -I. -I../../c-multihash/include ifdef DEBUG CFLAGS += -g3 endif -LFLAGS = -L../ +LFLAGS = -L../ -L../../c-multihash DEPS = crypto/test_base58.h crypto/test_rsa.h test_mbedtls.h OBJS = testit.o @@ -13,9 +13,13 @@ OBJS = testit.o $(CC) -c -o $@ $< $(CFLAGS) testit_libp2p: $(OBJS) $(DEPS) - $(CC) -o $@ $(OBJS) $(LFLAGS) -lp2p -lm + $(CC) -o $@ $(OBJS) $(LFLAGS) -lp2p -lm -lmultihash -all: testit_libp2p +all_others: + cd ../crypto; make all; + cd ../thirdparty; make all; + +all: all_others testit_libp2p clean: rm -f *.o diff --git a/test/crypto/test_rsa.h b/test/crypto/test_rsa.h index 21c5cff..ebac909 100644 --- a/test/crypto/test_rsa.h +++ b/test/crypto/test_rsa.h @@ -16,6 +16,8 @@ #include "libp2p/crypto/rsa.h" #include "libp2p/crypto/encoding/base64.h" #include "libp2p/crypto/encoding/x509.h" +#include "libp2p/peerutils.h" + /** * make sure we can get a DER formatted result @@ -75,6 +77,112 @@ int test_crypto_x509_der_to_private() { return private_key.D > 0; } +int test_public_der_to_private_der() { + struct RsaPrivateKey private_key; + int retVal = libp2p_crypto_rsa_generate_keypair(&private_key, 2048); + if (retVal == 0) + return 0; + + if (private_key.der_length == 0) + return 0; + if (private_key.der == NULL) + return 0; + + // copy the public DER to a temporary area, then erase it, then try to generate it again. + size_t public_der_temp_length = private_key.public_key_length; + unsigned char public_der_temp[private_key.public_key_length]; + memcpy(public_der_temp, private_key.public_key_der, private_key.public_key_length); + + free(private_key.public_key_der); + private_key.public_key_length = 0; + + retVal = libp2p_crypto_rsa_private_key_fill_public_key(&private_key); + if (retVal == 0) + return 0; + + if (public_der_temp_length != private_key.public_key_length) + return 0; + + /* + for(int i = 0; i < public_der_temp_length; i++) + if (public_der_temp[i] != private_key.public_key_der[i]) + return 0; + */ + // that didn't work... so let's try it again, to see if it is consistent + + size_t public_der_temp_length2 = private_key.public_key_length; + unsigned char public_der_temp2[public_der_temp_length2]; + memcpy(public_der_temp2, private_key.public_key_der, public_der_temp_length2); + + free(private_key.public_key_der); + private_key.public_key_length = 0; + + retVal = libp2p_crypto_rsa_private_key_fill_public_key(&private_key); + if (retVal == 0) + return 0; + + for(int i = 0; i < public_der_temp_length2; i++) + if (private_key.public_key_der[i] != public_der_temp2[i]) + return 0; + + // well, at least it is consistent. + return 1; +} + +int test_crypto_rsa_public_key_to_peer_id() { + // this is the base64 encoded private key from the config file + char* orig_priv_key = "CAASpwkwggSjAgEAAoIBAQDTDJBWjDzS/HxDNOHazvzH2bu9CPMVHUrrvKRdBUM5ansL6/CC3MVZ6HVm4O6QHRapN6EF2CbrTgI4KBOXIL125Xo8MlROnyfXYk3O5q2tgwL/MbW8kXjtkyCfBak7MUoLOdLU7Svg0gkl3l+uDAiDcCLnwJVcFfq9ch6z4wMOhYJqE5dtx0uXxn6IuKWl1B69FTvBXCc0thw8Rw54b941FDcsBH5ttV9mRNCJym3poZ5qalNgXlxoIIB+PUx5QD+aq7KMJdpAX8HkapBntCOahP/QUceRmma0grlZLeYkH6/oi/hIrM6se3KUZ+F6tBuDFys8UAZy/X2BCUbKjbxtAgMBAAECggEANWfQfpYuLhXGPBt9q6kFPm1SnJtPJ+CpvM2XqhJS2IyhZnrl+bd0GTRBwS7aL42s1lVFYf04nAK5fQxnKK8YQqX/MIxr2RldM5ukpN6qxGWKtJkXrAgD2dqJPrRoBpqKahzPxSHfIJ0Fw5dqDtjsrpYJvyt0oEDPmnDuZAbmFx4sJqnesPNhKxtRMBx1+yxGVuRVJjHcqAgqPqwNiuoMEaYMY+G9yzT6vza8ovCpbX7BBIgM5fAT9PD8TBG//Vu9THvj/ZomiVG2qv6RL0qQyVb+DUzPZz1amBsSvahtXCl72jA3JwAZ943RxSR66P934S0ashkVwLUi46z/EAbJ4QKBgQDojGIO07BEVL2+7VxlGL9XGZQp4Y3qlhh2zDDQGwkCq/KQ+BdNYWitPwqRl9GqFLgpmeQIhyHTOa/IThx+AXGKVQ24ROH+skUs4IbO6R3qY7BKtb5lkZE/Yln09x70BBngUYAzh/rtnsXO3cl1x2XDDqUbCwlGcDAs8Jh/6UnvQwKBgQDoVSQs7Uq9MJCGIUM2bixX89tHzSxq5mn9wMD3/XRVfT5Ua8YkYBuzcmlcT39N7L5BwuyFqX3Vi7lv/Ya/qaQP6XkrZ8W1OAaTlYewfE5ZgknJqSpXcNWhABKeNmqndvqyQ/8HNCv/j8AdraGB2DGO57Xso5J0CQ43W/U9+QIyjwKBgHLL2hw3o+wXaRO3WMUPUmVM2zdRgR0suybp5a7Vqb0H5NZrohUw4NulIzJ8H6Q2VjMzJL6Q9sGu2HepF6ecTtBa7ErqtiVlG4Dr1aCOs5XhYEWBMlwxX+JKSt4Cn+UVoTB7Cy5lEhn7JurX0Xuy0ylXMWoIKKv89cs5eg6quzTBAoGAaq9eEztLjKCWXOE9SetBdYnG8aunb9cqaJlwgu/h0bfXPVDYBbAUSEyLURY4MQI7Q1tM3Pu9iqfEmUZj7/LoIV5mg6X9RX/alT6etk3+dF+9nlqN1OU9U9cCtZ/rTcb2y5EptJcidRH/eCFY/pTV/PcttOJPx/S4kHcroC+N8MUCgYEA6DA5QHxHfNN6Nxv+pEzy2DIxFe9RrBxS+KPBsra1C8jgdeMf4EmfU0Nox92V0q0bRrD5ztqQwSONI0hSRb1iiMWR6MuFnAFajUJfASjjIlZ6nIQjQslI7vjlvYyyHS/p/Codxap+yJlTLWwVEOXp2D9pWwiMq1xEyf0TH1BosvM="; + // this is the peer id from the config file + char* orig_peer_id = "QmRskXriTSRjAftYX7QG1i1jAhouz5AHaLYZKNhEWRu5Fq"; + size_t orig_peer_id_size = strlen(orig_peer_id); + // if we take the private key, retrieve the public key, hash it, we should come up with the peer id + + // 1) take the private key and turn it back into bytes (decode base 64) + size_t decode_base64_size = libp2p_crypto_encoding_base64_decode_size(strlen(orig_priv_key)); + unsigned char decode_base64[decode_base64_size]; + memset(decode_base64, 0, decode_base64_size); + unsigned char* ptr = decode_base64; + + int retVal = libp2p_crypto_encoding_base64_decode(orig_priv_key, strlen(orig_priv_key), ptr, decode_base64_size, &decode_base64_size); + if (retVal == 0) + return 0; + + // the first 5 bytes [0-4] are protobuf metadata before the DER encoded private key + // byte 0 is "Tag 1 which is a varint" + // byte 1 is the value of the varint + // byte 2 is "Tag 2 which is a type 2, length delimited field" + // bytes 3 & 4 is a varint with the value of 1191, which is the number of bytes that follow + + // 2) take the bytes of the private key and turn it back into a private key struct + struct RsaPrivateKey private_key = {0}; + retVal = libp2p_crypto_encoding_x509_der_to_private_key(&decode_base64[5], decode_base64_size - 5, &private_key); + if (retVal == 0) + return 0; + + // 2b) take the private key and fill in the public key DER + retVal = libp2p_crypto_rsa_private_key_fill_public_key(&private_key); + if (retVal == 0) + return 0; + + // 3) grab the public key, hash it, then base58 it + unsigned char hashed[32]; + ID_FromPK_non_null_terminated(hashed, private_key.public_key_der, private_key.public_key_length); + size_t final_id_size = 1600; + unsigned char final_id[final_id_size]; + memset(final_id, 0, final_id_size); + retVal = PrettyID(final_id, &final_id_size, hashed, 32); + if (retVal == 0) + return 0; + + // 4) compare results + if (orig_peer_id_size != final_id_size) + return 0; + + if (strncmp(orig_peer_id, final_id, final_id_size) != 0) + return 0; + + return 1; +} #endif /* test_rsa_h */ diff --git a/test/testit.c b/test/testit.c index 51c88bb..0561429 100644 --- a/test/testit.c +++ b/test/testit.c @@ -1,6 +1,7 @@ #include + #include "crypto/test_rsa.h" #include "crypto/test_base58.h" #include "test_mbedtls.h" @@ -16,10 +17,11 @@ int testit(const char* name, int (*func)(void)) { } int main(int argc, char** argv) { + testit("test_public_der_to_private_der", test_public_der_to_private_der); testit("test_mbedtls_varint_128_binary", test_mbedtls_varint_128_binary); testit("test_mbedtls_varint_128_string", test_mbedtls_varint_128_string); testit("test_crypto_rsa_private_key_der", test_crypto_rsa_private_key_der); - //testit("test_crypto_x509_private_to_der", test_crypto_x509_private_to_der); + testit("test_crypto_rsa_public_key_to_peer_id", test_crypto_rsa_public_key_to_peer_id); testit("test_crypto_x509_der_to_private2", test_crypto_x509_der_to_private2); testit("test_crypto_x509_der_to_private", test_crypto_x509_der_to_private); //testit("test_multihash_encode", test_multihash_encode);