aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoakim Bech <joakim.bech@linaro.org>2016-06-28 09:59:30 +0200
committerJoakim Bech <joakim.bech@linaro.org>2016-07-18 10:51:09 +0200
commit0cda4151e89184daae8268a81846689320404e3c (patch)
tree1f0db44b70b792bf43b55ac237617fbbfe0f9dcd
parent098fcce812426e3172a8471e371e6cf461e53306 (diff)
downloadtinycrypt-0cda4151e89184daae8268a81846689320404e3c.tar.gz
Adding ability to generate NIST p-256 key pair
Added functions that can both read and write raw keys from disk. The keys will be converted to the format used in TinyCrypt (i.e., little-endian words). For a quick sanity check, a test using the Nordic test key has also been added. In the future one would like to have the ability to directly read *.pem files or something similar. Signed-off-by: Joakim Bech <joakim.bech@linaro.org>
-rw-r--r--CMakeLists.txt14
-rw-r--r--source/main.c396
-rw-r--r--source/signtest.c78
3 files changed, 465 insertions, 23 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 40a588e..9b61c67 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -21,13 +21,25 @@ include_directories(include
set(TINYCRYPT-SRC source/ecc_dsa.c
source/ecc.c
+ source/ecc_dh.c
source/sha256.c
source/utils.c
- source/main.c)
+ source/signtest.c)
# add_library(tee SHARED ${LIBTEE-SRC})
# add_definitions(-DBINARY_PREFIX="TEES")
+add_definitions(-std=c99)
add_executable(ecc_test ${TINYCRYPT-SRC})
#target_link_libraries(tee-supplicant tee)
+set(TCSIGN-SRC source/ecc.c
+ source/ecc_dh.c
+ source/sha256.c
+ source/utils.c
+ source/main.c)
+
+add_executable(tcsign ${TCSIGN-SRC})
+set_directory_properties(PROPERTIES
+ ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/nordic_test_key.pri"
+ ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/nordic_test_key.pub")
diff --git a/source/main.c b/source/main.c
index 12dae49..88f1c6f 100644
--- a/source/main.c
+++ b/source/main.c
@@ -1,42 +1,394 @@
+#include <assert.h>
+#include <getopt.h>
+#include <err.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
+#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <ecc.h>
-#include <sha256.h>
+#include <ecc_dsa.h>
+#include <ecc_dh.h>
#include <utils.h>
-static const char *str = "abc";
+#define MAX_KEYNAME_LEN 256
-void hash_str(const uint8_t *str, uint8_t *digest, uint32_t size)
+enum arg_params {
+ CREATE_KEY_PAIR,
+ SIGN_FILE,
+ VERIFY_FILE,
+ MAX_SIZE
+};
+
+static bool param[MAX_SIZE];
+
+static void hex_print(const char *str, uint8_t *d, uint32_t size)
+{
+ int i;
+ printf("String \"%s\" : ", str);
+ for (i = 0; i < size; i++)
+ printf("%02x", d[i]);
+ printf("\n");
+}
+
+void debug_fill_buffer(uint8_t *buf, uint32_t len)
+{
+ int i;
+ for (i = 0; i < len; i++)
+ buf[i] = i;
+}
+
+/*
+ * Writes a "native" key as a raw key to file.
+ *
+ * @param fname_priv name of the file
+ * @priv key in "native format"
+ * @keysize the size of the key
+ *
+ * @return TC_SUCCESS when OK, otherwise TC_FAIL
+ */
+static uint32_t fs_write_private_key(char *fname_priv, uint32_t *priv,
+ size_t keysize)
{
- struct tc_sha256_state_struct s;
+ FILE *f;
+ size_t n;
+ uint8_t d[NUM_ECC_BYTES];
+ uint32_t ret = TC_SUCCESS;
- memset(&s, 0, sizeof(struct tc_sha256_state_struct));
+ if (!fname_priv || !priv || keysize == 0) {
+ ret = TC_FAIL;
+ goto err;
+ }
- printf("Running ecc_test using Tinycrypt\n");
- if (tc_sha256_init(&s) != TC_SUCCESS)
- perror("SHA256 init failed\n");
+ f = fopen(fname_priv, "w");
+ if (!f) {
+ fprintf(stderr, "Cannot open: %s", fname_priv);
+ ret = TC_FAIL;
+ goto err;
+ }
- if (tc_sha256_update(&s, "abc", 3) != TC_SUCCESS)
- perror("SHA256 update failed\n");
+ memset(d, 0, sizeof(d));
+ ecc_native2bytes(d, priv);
- if (tc_sha256_final(digest, &s) != TC_SUCCESS)
- perror("SHA256 final failed\n");
+ n = fwrite(d, 1, keysize, f);
+ if (n != keysize)
+ ret = TC_FAIL;
+ fclose(f);
+err:
+ return ret;
}
-void hash_print(const char *str, uint8_t *digest, uint32_t size)
+static uint32_t fs_read_private_key(char *fname_priv, uint32_t *priv,
+ size_t keysize)
{
- int i;
- printf("Hash of \"%s\" = ", str);
- for (i = 0; i < size; i++)
- printf("%02x", digest[i]);
- printf("\n");
+ FILE *f;
+ size_t n;
+ uint8_t d[NUM_ECC_BYTES];
+
+ if (!fname_priv || !priv || keysize == 0)
+ return TC_FAIL;
+
+ f = fopen(fname_priv, "r");
+ if (!f) {
+ fprintf(stderr, "Cannot open: %s", fname_priv);
+ return TC_FAIL;
+ }
+
+ memset(d, 0, sizeof(d));
+
+ n = fread(d, 1, keysize, f);
+ fclose(f);
+
+ if (n != keysize)
+ return TC_FAIL;
+
+ ecc_bytes2native(priv, d);
+ return TC_SUCCESS;
}
-int main(int argc, char argv[])
+static uint32_t fs_write_public_key(char *fname_pub, EccPoint *pub, size_t keysize)
{
- uint8_t d[TC_SHA256_DIGEST_SIZE] = { 0 };
- hash_str(str, d, sizeof(d));
- hash_print(str, d, sizeof(d));
+ FILE *f;
+ size_t n;
+ uint8_t q[NUM_ECC_BYTES];
+ uint32_t ret = TC_SUCCESS;
+
+ if (!fname_pub || !pub || keysize == 0)
+ return TC_FAIL;
+
+ f = fopen(fname_pub, "w");
+ if (!f) {
+ fprintf(stderr, "Cannot open: %s", fname_pub);
+ return TC_FAIL;
+ }
+
+ memset(q, 0, sizeof(q));
+ ecc_native2bytes(q, pub->x);
+
+ n = fwrite(q, 1, (keysize / 2), f);
+ if (n != (keysize / 2)) {
+ ret = TC_FAIL;
+ goto err;
+ }
+
+ ecc_native2bytes(q, pub->y);
+
+ n = fwrite(q, 1, (keysize / 2), f);
+ if (n != (keysize / 2)) {
+ ret = TC_FAIL;
+ goto err;
+ }
+err:
+ if (f)
+ fclose(f);
+
+ return ret;
+}
+
+static uint32_t fs_read_public_key(char *fname_pub, EccPoint *pub, size_t keysize)
+{
+ FILE *f;
+ size_t n;
+ uint8_t q[NUM_ECC_BYTES];
+
+ if (!fname_pub || !pub || keysize == 0)
+ return TC_FAIL;
+
+ f = fopen(fname_pub, "r");
+ if (!f) {
+ fprintf(stderr, "Cannot open: %s", fname_pub);
+ return TC_FAIL;
+ }
+
+ memset(q, 0, sizeof(q));
+
+ n = fread(q, 1, (keysize / 2), f);
+ if (n != (keysize / 2)) {
+ fclose(f);
+ return TC_FAIL;
+ }
+
+ ecc_bytes2native(pub->x, q);
+
+ n = fread(q, 1, (keysize / 2), f);
+ if (n != (keysize / 2)) {
+ fclose(f);
+ return TC_FAIL;
+ }
+
+ ecc_bytes2native(pub->y, q);
+
+ fclose(f);
+ return TC_SUCCESS;
+}
+
+static void read_keys(void)
+{
+ uint32_t private_key[NUM_ECC_DIGITS];
+ char *privname = "foo2.pri";
+ EccPoint public_key;
+ char *pubname = "foo2.pub";
+
+ if (fs_read_private_key(privname, private_key, sizeof(private_key)) != TC_SUCCESS) {
+ fprintf(stderr, "Failed reading private key: %s from disk\n", privname);
+ }
+
+ if (fs_read_public_key(pubname, &public_key, sizeof(public_key)) != TC_SUCCESS) {
+ fprintf(stderr, "Failed reading public_key key: %s from disk\n", pubname);
+ }
+ return;
+}
+
+static void write_keys(void)
+{
+ uint32_t private_key[NUM_ECC_DIGITS];
+ char *privname = "foo2.pri";
+ EccPoint public_key;
+ char *pubname = "foo2.pub";
+
+ debug_fill_buffer((uint8_t *)private_key, sizeof(private_key));
+ if (fs_write_private_key(privname, private_key, sizeof(private_key)) != TC_SUCCESS) {
+ fprintf(stderr, "Failed writing private key: %s to disk\n", privname);
+ }
+
+ debug_fill_buffer((uint8_t *)&public_key, sizeof(public_key));
+ if (fs_write_public_key(pubname, &public_key, sizeof(public_key)) != TC_SUCCESS) {
+ fprintf(stderr, "Failed writing public_key key: %s to disk\n", pubname);
+ }
+ return;
+}
+
+/*
+ * $ openssl ec -in ~/devel/nRF5x_tools/pc-nrfutil/nordicsemi/dfu/tests/key.pem -text -noout
+ * read EC key
+ * Private-Key: (256 bit)
+ * priv:
+ * 3d:96:50:10:9e:ff:89:0b:86:5e:5e:90:9f:8e:f0:
+ * fb:69:ad:c6:a1:50:d1:44:dd:12:26:e6:1b:50:cc:
+ * 37:9d
+ * pub:
+ * 04:65:8d:a2:ed:db:98:1f:69:7d:ae:72:20:d6:82:
+ * 17:ab:ed:3f:b8:70:05:ec:8a:05:b9:b5:6b:bb:aa:
+ * 17:f4:60:90:9b:ae:cd:ad:72:26:c2:04:b6:12:b6:
+ * 62:ff:4f:cc:bd:1b:0c:90:84:10:90:d8:3a:59:cd:
+ * ad:6c:98:1d:4c
+ * ASN1 OID: prime256v1
+ */
+static void test_nordic_key(void)
+{
+ EccPoint pub_nat_key;
+ EccPoint pub_nat_key_tmp;
+ char *fname_priv = "nordic_test_key.pri";
+ char *fname_pub = "nordic_test_key.pub";
+ uint8_t tmp[NUM_ECC_BYTES];
+ uint32_t priv_nat_key[NUM_ECC_DIGITS];
+ uint32_t priv_nat_key_tmp[NUM_ECC_DIGITS];
+ uint32_t random_seed[NUM_ECC_DIGITS * 2];
+
+ /*
+ * This is the private and public part of a test key that comes from the
+ * Nordic SDK, pc-nrfutil/nordicsemi/dfu/tests/key.pem. That key is an
+ * uncompressed key based on the (insecure?) NIST-256P curve.
+ */
+ uint8_t priv_raw_key[] = {
+ 0x3d, 0x96, 0x50, 0x10, 0x9e, 0xff, 0x89, 0x0b,
+ 0x86, 0x5e, 0x5e, 0x90, 0x9f, 0x8e, 0xf0, 0xfb,
+ 0x69, 0xad, 0xc6, 0xa1, 0x50, 0xd1, 0x44, 0xdd,
+ 0x12, 0x26, 0xe6, 0x1b, 0x50, 0xcc, 0x37, 0x9d };
+
+ uint8_t pub_raw_key[] = {
+ 0x65, 0x8d, 0xa2, 0xed, 0xdb, 0x98, 0x1f, 0x69,
+ 0x7d, 0xae, 0x72, 0x20, 0xd6, 0x82, 0x17, 0xab,
+ 0xed, 0x3f, 0xb8, 0x70, 0x05, 0xec, 0x8a, 0x05,
+ 0xb9, 0xb5, 0x6b, 0xbb, 0xaa, 0x17, 0xf4, 0x60,
+
+ 0x90, 0x9b, 0xae, 0xcd, 0xad, 0x72, 0x26, 0xc2,
+ 0x04, 0xb6, 0x12, 0xb6, 0x62, 0xff, 0x4f, 0xcc,
+ 0xbd, 0x1b, 0x0c, 0x90, 0x84, 0x10, 0x90, 0xd8,
+ 0x3a, 0x59, 0xcd, 0xad, 0x6c, 0x98, 0x1d, 0x4c };
+
+ memset(random_seed, 0, sizeof(random_seed));
+ /*
+ * Convert from raw bytes to the little-endian words as decribed in:
+ * https://github.com/01org/tinycrypt/blob/master/documentation/tinycrypt.rst
+ */
+ ecc_bytes2native(random_seed, priv_raw_key);
+
+ if (ecc_make_key(&pub_nat_key, priv_nat_key, random_seed) != TC_SUCCESS) {
+ fprintf(stderr, "Failed generating key pair\n");
+ return;
+ }
+
+ /*
+ * Now we should have a key pair in native format, let's convert it back
+ * again and save it to disk (first the private key and then the public
+ * key).
+ */
+ if (fs_write_private_key(fname_priv, priv_nat_key, sizeof(priv_nat_key))
+ != TC_SUCCESS) {
+ fprintf(stderr, "%s : 0x04%d failed\n", __func__, __LINE__);
+ return;
+ }
+
+ if (fs_write_public_key(fname_pub, &pub_nat_key, sizeof(pub_nat_key))
+ != TC_SUCCESS) {
+ fprintf(stderr, "%s : 0x04%d failed\n", __func__, __LINE__);
+ return;
+ }
+
+ /*
+ * Both the private and the public key should have been saved
+ * successfully now, let's read them from disk again and compare that we
+ * get back the same as the inparameters.
+ */
+ if (fs_read_private_key(fname_priv, priv_nat_key_tmp, sizeof(priv_nat_key_tmp))
+ != TC_SUCCESS) {
+ fprintf(stderr, "%s : 0x04%d failed\n", __func__, __LINE__);
+ return;
+ }
+
+ if (fs_read_public_key(fname_pub, &pub_nat_key_tmp, sizeof(pub_nat_key_tmp))
+ != TC_SUCCESS) {
+ fprintf(stderr, "%s : 0x04%d failed\n", __func__, __LINE__);
+ return;
+ }
+
+ if (memcmp(priv_nat_key, priv_nat_key_tmp, NUM_ECC_BYTES) != 0 ||
+ memcmp(&pub_nat_key, &pub_nat_key_tmp, sizeof(EccPoint) != 0))
+ fprintf(stderr, "Nordic key test failed\n");
+ else
+ printf("Nordic key test passed\n");
+ return;
+}
+
+
+static void print_usage(char *program)
+{
+ printf("Usage: %s [OPTIONS]\n", program);
+ printf(" -c creates pub/priv key pair\n");
+ printf(" -i infile indata\n");
+ printf(" -k keyfile file containing the private key\n");
+ printf(" -o outfile file to be created\n");
+ printf(" -s signing enabled\n");
+ printf(" -t run tests\n");
+}
+
+int main(int argc, char *argv[])
+{
+ char keyname[MAX_KEYNAME_LEN];
+ int opt;
+ FILE *fd_in = NULL;
+ FILE *fd_key = NULL;
+
+ while ((opt = getopt (argc, argv, "ci:hk:o:st")) != -1)
+ {
+ switch (opt)
+ {
+ case 'c':
+ printf("Creating priv/pub keypair\n");
+ param[CREATE_KEY_PAIR] = true;
+ break;
+
+ case 'i':
+ printf("in file: \"%s\"\n", optarg);
+ fd_in = fopen(optarg, "r");
+ if (!fd_in)
+ errx(1, "Cannot open: %s", optarg);
+ break;
+
+ case 'k':
+ printf ("key file: \"%s\"\n", optarg);
+ fd_key = fopen(optarg, "r");
+ if (!fd_key)
+ errx(1, "Cannot open: %s", optarg);
+ break;
+
+ case 'o':
+ printf("out file: \"%s\"\n", optarg);
+ memset(&keyname, 0, sizeof(keyname));
+ snprintf(keyname, MAX_KEYNAME_LEN, "%s", optarg);
+ break;
+
+ case 's':
+ printf("Signing enabled\n");
+ break;
+
+ case 't':
+ printf("Running tests\n");
+ test_nordic_key();
+ break;
+
+ case 'h':
+ default:
+ print_usage(argv[0]);
+ }
+ }
+err:
+ if (fd_in)
+ fclose(fd_in);
+ if (fd_key)
+ fclose(fd_key);
+
return 0;
}
diff --git a/source/signtest.c b/source/signtest.c
new file mode 100644
index 0000000..366e6c5
--- /dev/null
+++ b/source/signtest.c
@@ -0,0 +1,78 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <ecc.h>
+#include <ecc_dsa.h>
+#include <ecc_dh.h>
+#include <sha256.h>
+#include <utils.h>
+
+static const char *str = "abc";
+
+void hash_str(const uint8_t *str, uint8_t *digest, uint32_t size)
+{
+ struct tc_sha256_state_struct s;
+
+ memset(&s, 0, sizeof(struct tc_sha256_state_struct));
+
+ printf("Running ecc_test using Tinycrypt\n");
+ if (tc_sha256_init(&s) != TC_SUCCESS)
+ perror("SHA256 init failed\n");
+
+ if (tc_sha256_update(&s, "abc", 3) != TC_SUCCESS)
+ perror("SHA256 update failed\n");
+
+ if (tc_sha256_final(digest, &s) != TC_SUCCESS)
+ perror("SHA256 final failed\n");
+}
+
+void hex_print(const char *str, uint8_t *d, uint32_t size)
+{
+ int i;
+ printf("String \"%s\" : ", str);
+ for (i = 0; i < size; i++)
+ printf("%02x", d[i]);
+ printf("\n");
+}
+
+int main(int argc, char argv[])
+{
+ uint8_t d[TC_SHA256_DIGEST_SIZE] = { 0 };
+ uint32_t r[NUM_ECC_DIGITS];
+ uint32_t s[NUM_ECC_DIGITS];
+ uint8_t key[NUM_ECC_BYTES] = {
+ 0x16, 0x26, 0x07, 0x83, 0xe4, 0x0b, 0x16, 0x73,
+ 0x16, 0x73, 0x62, 0x2a, 0xc8, 0xa5, 0xb0, 0x45,
+ 0xfc, 0x3e, 0xa4, 0xaf, 0x70, 0xf7, 0x27, 0xf3,
+ 0xf9, 0xe9, 0x2b, 0xdd, 0x3a, 0x1d, 0xdc, 0x42 };
+ uint32_t privkey[NUM_ECC_DIGITS];
+ uint32_t randnr[NUM_ECC_DIGITS * 2];
+ EccPoint pubkey;
+
+ hash_str(str, d, sizeof(d));
+ hex_print(str, d, sizeof(d));
+
+
+ memset(r, 0, sizeof(r));
+ memset(s, 0, sizeof(s));
+ memset(randnr, 0, sizeof(randnr));
+ randnr[0] = 2; /* Just to make it happy with no zeroes */
+
+ if (ecc_make_key(&pubkey,
+ privkey,
+ (uint32_t *)key) != TC_SUCCESS)
+ perror("Failed generating key pair\n");
+
+ if (ecdsa_sign(r, s, (uint32_t *)key, randnr, (uint32_t *)d) != TC_SUCCESS)
+ perror("Failed to create a EC-DSA signature\n");
+
+ hex_print("r", (uint8_t *)r, sizeof(r));
+ hex_print("s", (uint8_t *)s, sizeof(s));
+
+ if (ecdsa_verify(&pubkey, (uint32_t *)d, r, s) != TC_SUCCESS)
+ perror("Verification failed\n");
+ else
+ printf("Successfully verified the signature\n");
+
+ return 0;
+}