/*
This file is part of GNUnet.
Copyright (C) 2020 GNUnet e.V.
GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
GNUnet is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
SPDX-License-Identifier: AGPL3.0-or-later
*/
/**
* @file util/gnunet-crypto-tgv.c
* @brief Generate test vectors for cryptographic operations.
* @author Florian Dold
*
* Test vectors have the following format (TypeScript pseudo code):
*
* interface TestVectorFile {
* encoding: "base32crockford";
* producer?: string;
* vectors: TestVector[];
* }
*
* enum Operation {
* Hash("hash"),
* ...
* }
*
* interface TestVector {
* operation: Operation;
* // Inputs for the operation
* [ k: string]: string | number;
* };
*
*
*/
#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_signatures.h"
#include "gnunet_testing_lib.h"
#include
#include
GNUNET_NETWORK_STRUCT_BEGIN
/**
* Sample signature struct.
*
* Purpose is #GNUNET_SIGNATURE_PURPOSE_TEST
*/
struct TestSignatureDataPS
{
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
uint32_t testval;
};
GNUNET_NETWORK_STRUCT_END
/**
* Create a fresh test vector for a given operation label.
*
* @param vecs array of vectors to append the new vector to
* @param vecname label for the operation of the vector
* @returns the fresh test vector
*/
static json_t *
vec_for (json_t *vecs, const char *vecname)
{
json_t *t = json_object ();
json_object_set_new (t,
"operation",
json_string (vecname));
json_array_append_new (vecs, t);
return t;
}
/**
* Add a base32crockford encoded value
* to a test vector.
*
* @param vec test vector to add to
* @param label label for the value
* @param data data to add
* @param size size of data
*/
static void
d2j (json_t *vec,
const char *label,
const void *data,
size_t size)
{
char *buf;
json_t *json;
buf = GNUNET_STRINGS_data_to_string_alloc (data, size);
json = json_string (buf);
GNUNET_free (buf);
GNUNET_break (NULL != json);
json_object_set_new (vec, label, json);
}
/**
* Add a number to a test vector.
*
* @param vec test vector to add to
* @param label label for the value
* @param data data to add
* @param size size of data
*/
static void
uint2j (json_t *vec,
const char *label,
unsigned int num)
{
json_t *json = json_integer (num);
json_object_set_new (vec, label, json);
}
/**
* Main function that will be run.
*
* @param cls closure
* @param args remaining command-line arguments
* @param cfgfile name of the configuration file used (for saving, can be NULL!)
* @param cfg configuration
*/
static void
run (void *cls,
char *const *args,
const char *cfgfile,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
json_t *vecfile = json_object ();
json_t *vecs = json_array ();
json_object_set_new (vecfile,
"encoding",
json_string ("base32crockford"));
json_object_set_new (vecfile,
"producer",
json_string ("GNUnet " PACKAGE_VERSION " " VCS_VERSION));
json_object_set_new (vecfile,
"vectors",
vecs);
{
json_t *vec = vec_for (vecs, "hash");
struct GNUNET_HashCode hc;
char *str = "Hello, GNUnet";
GNUNET_CRYPTO_hash (str, strlen (str), &hc);
d2j (vec, "input", str, strlen (str));
d2j (vec, "output", &hc, sizeof (struct GNUNET_HashCode));
}
{
json_t *vec = vec_for (vecs, "ecdhe_key_derivation");
struct GNUNET_CRYPTO_EcdhePrivateKey priv1;
struct GNUNET_CRYPTO_EcdhePublicKey pub1;
struct GNUNET_CRYPTO_EcdhePrivateKey priv2;
struct GNUNET_HashCode skm;
GNUNET_CRYPTO_ecdhe_key_create (&priv1);
GNUNET_CRYPTO_ecdhe_key_create (&priv2);
GNUNET_CRYPTO_ecdhe_key_get_public (&priv1,
&pub1);
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_ecc_ecdh (&priv2,
&pub1,
&skm));
d2j (vec,
"priv1",
&priv1,
sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
d2j (vec,
"pub1",
&pub1,
sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
d2j (vec,
"priv2",
&priv2,
sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
d2j (vec,
"skm",
&skm,
sizeof (struct GNUNET_HashCode));
}
{
json_t *vec = vec_for (vecs, "eddsa_key_derivation");
struct GNUNET_CRYPTO_EddsaPrivateKey priv;
struct GNUNET_CRYPTO_EddsaPublicKey pub;
GNUNET_CRYPTO_eddsa_key_create (&priv);
GNUNET_CRYPTO_eddsa_key_get_public (&priv,
&pub);
d2j (vec,
"priv",
&priv,
sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
d2j (vec,
"pub",
&pub,
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
}
{
json_t *vec = vec_for (vecs, "eddsa_signing");
struct GNUNET_CRYPTO_EddsaPrivateKey priv;
struct GNUNET_CRYPTO_EddsaPublicKey pub;
struct GNUNET_CRYPTO_EddsaSignature sig;
struct TestSignatureDataPS data = { 0 };
GNUNET_CRYPTO_eddsa_key_create (&priv);
GNUNET_CRYPTO_eddsa_key_get_public (&priv,
&pub);
data.purpose.size = htonl (sizeof (data));
data.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
GNUNET_CRYPTO_eddsa_sign (&priv,
&data,
&sig);
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TEST,
&data,
&sig,
&pub));
d2j (vec,
"priv",
&priv,
sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
d2j (vec,
"pub",
&pub,
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
d2j (vec,
"data",
&data,
sizeof (struct TestSignatureDataPS));
d2j (vec,
"sig",
&sig,
sizeof (struct GNUNET_CRYPTO_EddsaSignature));
}
{
json_t *vec = vec_for (vecs, "kdf");
size_t out_len = 64;
char out[out_len];
char *ikm = "I'm the secret input key material";
char *salt = "I'm very salty";
char *ctx = "I'm a context chunk, also known as 'info' in the RFC";
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_kdf (&out,
out_len,
salt,
strlen (salt),
ikm,
strlen (ikm),
ctx,
strlen (ctx),
NULL));
d2j (vec,
"salt",
salt,
strlen (salt));
d2j (vec,
"ikm",
ikm,
strlen (ikm));
d2j (vec,
"ctx",
ctx,
strlen (ctx));
uint2j (vec,
"out_len %u\n",
(unsigned int) out_len);
d2j (vec,
"out",
out,
out_len);
}
{
json_t *vec = vec_for (vecs, "eddsa_ecdh");
struct GNUNET_CRYPTO_EcdhePrivateKey priv_ecdhe;
struct GNUNET_CRYPTO_EcdhePublicKey pub_ecdhe;
struct GNUNET_CRYPTO_EddsaPrivateKey priv_eddsa;
struct GNUNET_CRYPTO_EddsaPublicKey pub_eddsa;
struct GNUNET_HashCode key_material;
GNUNET_CRYPTO_ecdhe_key_create (&priv_ecdhe);
GNUNET_CRYPTO_ecdhe_key_get_public (&priv_ecdhe, &pub_ecdhe);
GNUNET_CRYPTO_eddsa_key_create (&priv_eddsa);
GNUNET_CRYPTO_eddsa_key_get_public (&priv_eddsa, &pub_eddsa);
GNUNET_CRYPTO_ecdh_eddsa (&priv_ecdhe, &pub_eddsa, &key_material);
d2j (vec, "priv_ecdhe",
&priv_ecdhe,
sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
d2j (vec, "pub_ecdhe",
&pub_ecdhe,
sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
d2j (vec, "priv_eddsa",
&priv_eddsa,
sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
d2j (vec, "pub_eddsa",
&pub_eddsa,
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
d2j (vec, "key_material",
&key_material,
sizeof (struct GNUNET_HashCode));
}
{
json_t *vec = vec_for (vecs, "rsa_blind_signing");
struct GNUNET_CRYPTO_RsaPrivateKey *skey;
struct GNUNET_CRYPTO_RsaPublicKey *pkey;
struct GNUNET_HashCode message_hash;
struct GNUNET_CRYPTO_RsaBlindingKeySecret bks;
struct GNUNET_CRYPTO_RsaSignature *blinded_sig;
struct GNUNET_CRYPTO_RsaSignature *sig;
void *blinded_data;
size_t blinded_len;
void *public_enc_data;
size_t public_enc_len;
void *blinded_sig_enc_data;
size_t blinded_sig_enc_length;
void *sig_enc_data;
size_t sig_enc_length;
skey = GNUNET_CRYPTO_rsa_private_key_create (2048);
pkey = GNUNET_CRYPTO_rsa_private_key_get_public (skey);
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&message_hash,
sizeof (struct GNUNET_HashCode));
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&bks,
sizeof (struct
GNUNET_CRYPTO_RsaBlindingKeySecret));
GNUNET_assert (GNUNET_YES ==
GNUNET_CRYPTO_rsa_blind (&message_hash,
&bks,
pkey,
&blinded_data,
&blinded_len));
blinded_sig = GNUNET_CRYPTO_rsa_sign_blinded (skey, blinded_data,
blinded_len);
sig = GNUNET_CRYPTO_rsa_unblind (blinded_sig, &bks, pkey);
GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_rsa_verify (&message_hash, sig,
pkey));
public_enc_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey,
&public_enc_data);
blinded_sig_enc_length = GNUNET_CRYPTO_rsa_signature_encode (blinded_sig,
&
blinded_sig_enc_data);
sig_enc_length = GNUNET_CRYPTO_rsa_signature_encode (sig, &sig_enc_data);
d2j (vec,
"message_hash",
&message_hash,
sizeof (struct GNUNET_HashCode));
d2j (vec,
"rsa_public_key",
public_enc_data,
public_enc_len);
d2j (vec,
"blinding_key_secret",
&bks,
sizeof (struct GNUNET_CRYPTO_RsaBlindingKeySecret));
d2j (vec,
"blinded_message",
blinded_data,
blinded_len);
d2j (vec,
"blinded_sig",
blinded_sig_enc_data,
blinded_sig_enc_length);
d2j (vec,
"sig",
sig_enc_data,
sig_enc_length);
GNUNET_CRYPTO_rsa_private_key_free (skey);
GNUNET_CRYPTO_rsa_public_key_free (pkey);
GNUNET_CRYPTO_rsa_signature_free (sig);
GNUNET_CRYPTO_rsa_signature_free (blinded_sig);
GNUNET_free (public_enc_data);
GNUNET_free (blinded_data);
GNUNET_free (sig_enc_data);
GNUNET_free (blinded_sig_enc_data);
}
json_dumpf (vecfile, stdout, JSON_INDENT (2));
json_decref (vecfile);
printf ("\n");
}
/**
* The main function of the test vector generation tool.
*
* @param argc number of arguments from the command line
* @param argv command line arguments
* @return 0 ok, 1 on error
*/
int
main (int argc,
char *const *argv)
{
const struct GNUNET_GETOPT_CommandLineOption options[] = {
GNUNET_GETOPT_OPTION_END
};
GNUNET_assert (GNUNET_OK ==
GNUNET_log_setup ("gnunet-crypto-tvg",
"INFO",
NULL));
if (GNUNET_OK !=
GNUNET_PROGRAM_run (argc, argv,
"gnunet-crypto-tvg",
"Generate test vectors for cryptographic operations",
options,
&run, NULL))
return 1;
return 0;
}
/* end of gnunet-crypto-tvg.c */