Commit f7e6d08d authored by Jan Včelák's avatar Jan Včelák 🚀
Browse files

Full Domain Hash signing: OpenSSL, Nettle/GnuTLS

parents
#include "gnutls_fdh.h"
#include "gnutls_mgf.h"
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <nettle/bignum.h>
#include <stdbool.h>
#include <stdio.h>
#include <gnutls/abstract.h>
static void cleanup_datum(gnutls_datum_t *datum)
{
gnutls_free(datum->data);
}
#define auto_gnutls_datum_t gnutls_datum_t __attribute__((cleanup(cleanup_datum)))
/*!
* Convert GnuTLS RSA private key into Nettle RSA key.
*/
static bool key_g2n(const gnutls_x509_privkey_t key,
struct rsa_public_key *public_key,
struct rsa_private_key *private_key)
{
// export RSA parameters
auto_gnutls_datum_t m = { 0 };
auto_gnutls_datum_t e = { 0 };
auto_gnutls_datum_t d = { 0 };
auto_gnutls_datum_t p = { 0 };
auto_gnutls_datum_t q = { 0 };
int r = gnutls_x509_privkey_export_rsa_raw(key, &m, &e, &d, &p, &q, NULL);
if (r != GNUTLS_E_SUCCESS) {
return false;
}
// import into Nettle structs
struct rsa_public_key pub = { 0 };
struct rsa_private_key priv = { 0 };
nettle_mpz_init_set_str_256_u(pub.n, m.size, m.data);
nettle_mpz_init_set_str_256_u(pub.e, e.size, e.data);
if (nettle_rsa_public_key_prepare(&pub) != 1) {
nettle_rsa_public_key_clear(&pub);
return false;
}
nettle_mpz_init_set_str_256_u(priv.d, d.size, d.data);
nettle_mpz_init_set_str_256_u(priv.p, p.size, p.data);
nettle_mpz_init_set_str_256_u(priv.q, q.size, q.data);
if (nettle_rsa_private_key_prepare(&priv) != 1) {
nettle_rsa_public_key_clear(&pub);
nettle_rsa_private_key_clear(&priv);
return false;
}
// assign the result
*public_key = pub;
*private_key = priv;
return true;
}
/*!
* Convert GnuTLS digest algorithm to Nettle hash abstraction.
*/
static const struct nettle_hash *hash_g2n(gnutls_digest_algorithm_t digest)
{
switch (digest) {
case GNUTLS_DIG_MD2: return &nettle_md2;
case GNUTLS_DIG_MD5: return &nettle_md5;
case GNUTLS_DIG_RMD160: return &nettle_ripemd160;
case GNUTLS_DIG_SHA1: return &nettle_sha1;
case GNUTLS_DIG_SHA224: return &nettle_sha224;
case GNUTLS_DIG_SHA256: return &nettle_sha256;
case GNUTLS_DIG_SHA384: return &nettle_sha384;
case GNUTLS_DIG_SHA512: return &nettle_sha512;
default:
return 0;
};
}
/*!
* Get size of Full Domain Hash result.
*/
size_t nettle_fdh_len(const struct rsa_public_key *key)
{
return key ? key->size : 0;
}
size_t nettle_fdh_sign(const uint8_t *data, size_t data_len,
uint8_t *sign, size_t sign_len,
const struct rsa_public_key *pubkey,
const struct rsa_private_key *privkey,
const struct nettle_hash *hash)
{
if (!data || !pubkey || !privkey || !sign || !hash || sign_len < pubkey->size) {
return 0;
}
size_t out_len = pubkey->size;
// compute MGF1 mask, use the same size as RSA modulo
uint8_t mask[out_len];
mgf_nettle(mask, out_len, data, data_len, &nettle_sha256);
// clear the highest bit of the mask
mask[0] &= 0x7f;
// preform raw RSA signature
mpz_t sign_mpz;
nettle_mpz_init_set_str_256_u(sign_mpz, out_len, mask);
mpz_powm(sign_mpz, sign_mpz, privkey->d, pubkey->n);
nettle_mpz_get_str_256(out_len, sign, sign_mpz);
mpz_clear(sign_mpz);
return out_len;
}
size_t gnutls_fdh_len(gnutls_x509_privkey_t key)
{
if (!key) {
return 0;
}
unsigned int bits = 0;
gnutls_x509_privkey_get_pk_algorithm2(key, &bits);
assert(bits % 8 == 0);
return bits / 8;
}
size_t gnutls_fdh_sign(const uint8_t *data, size_t data_len,
uint8_t *sign, size_t sign_len,
gnutls_x509_privkey_t key,
gnutls_digest_algorithm_t digest)
{
struct rsa_public_key pubkey = { 0 };
struct rsa_private_key privkey = { 0 };
const struct nettle_hash *hash = hash_g2n(digest);
if (!hash) {
return 0;
}
if (!key_g2n(key, &pubkey, &privkey)) {
return 0;
}
int r = nettle_fdh_sign(data, data_len, sign, sign_len, &pubkey, &privkey, hash);
rsa_public_key_clear(&pubkey);
rsa_private_key_clear(&privkey);
return r;
}
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <gnutls/x509.h>
#include <nettle/nettle-meta.h>
#include <nettle/rsa.h>
/*!
* Get size of Full Domain Hash result.
*/
size_t nettle_fdh_len(const struct rsa_public_key *key);
/*!
* Compute Full Domain Hash.
*
* \param[in] data Input data.
* \param[in] data_len Length of the input data.
* \param[out] sign Output buffer.
* \param[in] sign_len Capacity of the output buffer.
* \param[in] pubkey RSA public key.
* \param[in] privkey RSA private key.
* \param[in] hash Hash function.
*
* \return Size of the Full Domain Hash, zero on error.
*/
size_t nettle_fdh_sign(const uint8_t *data, size_t data_len,
uint8_t *sign, size_t sign_len,
const struct rsa_public_key *pubkey,
const struct rsa_private_key *privkey,
const struct nettle_hash *hash);
size_t gnutls_fdh_len(gnutls_x509_privkey_t key);
size_t gnutls_fdh_sign(const uint8_t *data, size_t data_len,
uint8_t *sign, size_t sign_len,
gnutls_x509_privkey_t key,
gnutls_digest_algorithm_t hash);
#include <assert.h>
#include <nettle/nettle-meta.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define MIN(a,b) \
({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; })
/*!
* MGF1, Mask Generation Function based on a hash function.
*/
void mgf_nettle(uint8_t *mask, size_t mask_len,
const uint8_t *seed, size_t seed_len,
const struct nettle_hash *hash)
{
if (!mask || !seed || !hash) {
return;
}
uint8_t context[hash->context_size];
uint8_t digest[hash->digest_size];
for (size_t c = 0; mask_len > 0; c += 1) {
uint8_t counter[4] = {
(c >> 24) & 0xFF,
(c >> 16) & 0xFF,
(c >> 8) & 0xFF,
(c >> 0) & 0xFF,
};
assert(c >> 32 == 0);
hash->init(context);
hash->update(context, seed_len, seed);
hash->update(context, sizeof(counter), counter);
hash->digest(context, sizeof(digest), digest);
size_t copy = MIN(mask_len, sizeof(digest));
memcpy(mask, digest, copy);
mask += copy;
mask_len -= copy;
}
}
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <nettle/nettle-meta.h>
/*!
* MGF1, Mask Generation Function based on a hash function.
*
* \see RFC 2437, section 10.2.1
*
* \param[out] mask Resulting mask.
* \param[in] mask_len Requested length of the mask.
* \param[in] seed Seed.
* \param[in] seed_len Length of the seed.
* \param[in] hash Hash function.
*/
void mgf_nettle(uint8_t *mask, size_t mask_len,
const uint8_t *seed, size_t seed_len,
const struct nettle_hash *hash);
#include "openssl_fdh.h"
#include <stdbool.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
/*!
* Get size of Full Domain Hash result.
*/
size_t openssl_fdh_len(RSA *key)
{
if (!key) {
return 0;
}
return RSA_size(key);
}
/*!
* Compute Full Domain Hash.
*/
size_t openssl_fdh_sign(const uint8_t *data, size_t data_len,
uint8_t *sign, size_t sign_len,
RSA *key, const EVP_MD *hash)
{
if (!data || !key || !sign || !hash || sign_len < RSA_size(key)) {
return 0;
}
size_t out_len = BN_num_bytes(key->n);
// compute MGF1 mask, use the same size as RSA modulo
uint8_t mask[out_len];
if (PKCS1_MGF1(mask, out_len, data, data_len, hash) != 0) {
return 0;
}
// clear the highest bit of the mask
mask[0] &= 0x7f;
// preform raw RSA signature
int r = RSA_private_encrypt(out_len, mask, sign, key, RSA_NO_PADDING);
if (r < 0) {
return 0;
}
return r;
}
/*!
* Compute Full Domain Hash.
*/
bool openssl_fdh_verify(const uint8_t *data, size_t data_len,
uint8_t *sign, size_t sign_len,
RSA *key, const EVP_MD *hash)
{
if (!data || !key || !sign || !hash || sign_len < RSA_size(key)) {
return 0;
}
// compute MGF1 mask, use the same size as RSA modulo
size_t mask_len = BN_num_bytes(key->n);
uint8_t mask[mask_len];
if (PKCS1_MGF1(mask, mask_len, data, data_len, hash) != 0) {
return 0;
}
// clear the highest bit of the mask
mask[0] &= 0x7f;
// preform raw RSA signature
int r = -10;
// int r = RSA_private_decrypt();
// int r = RSA_private_encrypt(mask_len, mask, sign, key, RSA_NO_PADDING);
if (r < 0) {
return 0;
}
return r;
}
#pragma once
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <stdint.h>
#include <stdlib.h>
/*!
* Get size of Full Domain Hash result.
*/
size_t openssl_fdh_len(RSA *key);
/*!
* Compute Full Domain Hash.
*
* \param[in] data Input data.
* \param[in] data_len Length of the input data.
* \param[out] sign Output buffer.
* \param[in] sign_len Capacity of the output buffer.
* \param[in] key RSA key.
* \param[in] hash Hash function.
*
* \return Size of the Full Domain Hash, zero on error.
*/
size_t openssl_fdh_sign(const uint8_t *seed, size_t seed_len,
uint8_t *sign, size_t sign_len,
RSA *key, const EVP_MD *hash);
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment