d5f6892013-11-24Martin Nilsson /* -*- c -*- || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */ #include "global.h" #include "builtin_functions.h"
e604c62014-01-04Henrik Grubbström (Grubba) #include "operators.h"
d5f6892013-11-24Martin Nilsson #include "interpret.h" #include "module.h"
6dc29f2016-03-14Martin Nilsson #include "mapping.h"
f05d052016-10-08Henrik Grubbström (Grubba) #include "stralloc.h"
6dc29f2016-03-14Martin Nilsson #include "constants.h"
d5f6892013-11-24Martin Nilsson  #include "nettle_config.h" #ifdef HAVE_LIBHOGWEED DECLARATIONS #include "nettle.h" #include <nettle/dsa.h> #include <nettle/rsa.h>
9071e02014-10-30Martin Nilsson /* Includes <gmp.h> */
2b1c922013-12-24Henrik Grubbström (Grubba) #include "bignum.h"
877f412014-01-04Henrik Grubbström (Grubba) /*! @module Nettle */
86e2562014-10-24Arne Goedeke static void random_func_wrapper(void *f, pike_nettle_size_t num, uint8_t *out)
d5f6892013-11-24Martin Nilsson { push_int(num); apply_svalue((struct svalue *)f, 1); if(TYPEOF(Pike_sp[-1])!=T_STRING) Pike_error("Random function did not return string value.\n");
4ae9502016-03-19Martin Nilsson  if((unsigned)Pike_sp[-1].u.string->len != (unsigned)num || Pike_sp[-1].u.string->size_shift != 0)
d5f6892013-11-24Martin Nilsson  Pike_error("Random function did not return correct number of bytes.\n"); memcpy(out, Pike_sp[-1].u.string->str, num); pop_stack(); }
f6a6ad2013-12-08Henrik Grubbström (Grubba) /*! @decl array(object(Gmp.mpz)) @ *! dsa_generate_keypair(int p_bits, int q_bits, @
b432312014-04-06Martin Nilsson  *! function(int(0..):string(0..255)) rnd)
6668dd2013-12-06Henrik Grubbström (Grubba)  *! *! Generates a DSA key pair with @[p_bits] number of bits (sometimes
d5f6892013-11-24Martin Nilsson  *! referred to as L) for p, and @[q_bits] number of bits (sometimes *! referred to as N) for q, using the random function @[rnd]. *! *! Valid combinations as per FIPS 186-3 are *! @pre{ *! p_bits q_bits *! 1024 160
230ae02013-11-25Martin Nilsson  *! 2048 224 (rejected by some versions of Hogweed)
d5f6892013-11-24Martin Nilsson  *! 2048 256 *! 3072 256 *! @} *! *! @returns *! @array
6668dd2013-12-06Henrik Grubbström (Grubba)  *! @elem Gmp.mpz 0
d5f6892013-11-24Martin Nilsson  *! The value p, the modulo.
6668dd2013-12-06Henrik Grubbström (Grubba)  *! @elem Gmp.mpz 1
d5f6892013-11-24Martin Nilsson  *! The value q, the group order.
6668dd2013-12-06Henrik Grubbström (Grubba)  *! @elem Gmp.mpz 2
d5f6892013-11-24Martin Nilsson  *! The value g, the generator.
6668dd2013-12-06Henrik Grubbström (Grubba)  *! @elem Gmp.mpz 3
d5f6892013-11-24Martin Nilsson  *! The value y, the public value.
6668dd2013-12-06Henrik Grubbström (Grubba)  *! @elem Gmp.mpz 4
d5f6892013-11-24Martin Nilsson  *! The value x, the private value. *! @endarray */
f6a6ad2013-12-08Henrik Grubbström (Grubba) PIKEFUN array(object(Gmp.mpz))
b432312014-04-06Martin Nilsson  dsa_generate_keypair(int p_bits, int q_bits, function(int(0..):string(0..255)) rnd)
d5f6892013-11-24Martin Nilsson {
c17a992014-04-24Henrik Grubbström (Grubba) #ifdef dsa_params_init
1cfe7f2014-04-17Henrik Grubbström (Grubba)  /* Nettle 3.0 or later. */ struct dsa_params params; mpz_t pub; mpz_t key; dsa_params_init(&params); if (!dsa_generate_params(&params, rnd, random_func_wrapper, NULL, NULL, p_bits, q_bits)) {
ce83e52015-05-08Martin Nilsson  dsa_params_clear(&params);
1cfe7f2014-04-17Henrik Grubbström (Grubba)  Pike_error("Illegal parameter value.\n"); } mpz_init(pub); mpz_init(key); dsa_generate_keypair(&params, pub, key, rnd, random_func_wrapper); push_bignum((MP_INT *)&params.p); push_bignum((MP_INT *)&params.q); push_bignum((MP_INT *)&params.g); dsa_params_clear(&params); push_bignum((MP_INT *)pub); push_bignum((MP_INT *)key); mpz_clear(key); mpz_clear(pub); #else
d5f6892013-11-24Martin Nilsson  struct dsa_public_key pub; struct dsa_private_key key;
b6a4092013-12-25Henrik Grubbström (Grubba)  dsa_public_key_init(&pub); dsa_private_key_init(&key);
d5f6892013-11-24Martin Nilsson  if( !nettle_dsa_generate_keypair(&pub, &key, rnd, random_func_wrapper,
14150e2014-01-13Per Hedbor  NULL, NULL, p_bits #ifdef HAVE_DSA_QBITS_KEYPAIR_ARG , q_bits #endif ) )
d5f6892013-11-24Martin Nilsson  {
b6a4092013-12-25Henrik Grubbström (Grubba)  dsa_private_key_clear(&key); dsa_public_key_clear(&pub);
28aa062013-12-02Martin Nilsson  Pike_error("Illegal parameter value.\n");
d5f6892013-11-24Martin Nilsson  }
b6a4092013-12-25Henrik Grubbström (Grubba)  push_bignum((MP_INT *)&pub.p); push_bignum((MP_INT *)&pub.q); push_bignum((MP_INT *)&pub.g); push_bignum((MP_INT *)&pub.y); push_bignum((MP_INT *)&key.x); dsa_private_key_clear(&key); dsa_public_key_clear(&pub);
c17a992014-04-24Henrik Grubbström (Grubba) #endif /* dsa_params_init */
d5f6892013-11-24Martin Nilsson  f_aggregate(5);
b6a4092013-12-25Henrik Grubbström (Grubba)  stack_pop_n_elems_keep_top(args); /* Remove p_bits, q_bits and rnd. */
d5f6892013-11-24Martin Nilsson }
6668dd2013-12-06Henrik Grubbström (Grubba) /*! @decl array(object(Gmp.mpz)) @
4624362014-01-30Henrik Grubbström (Grubba)  *! rsa_generate_keypair(int bits, int e, @
b432312014-04-06Martin Nilsson  *! function(int(0..):string(0..255)) rnd)
6668dd2013-12-06Henrik Grubbström (Grubba)  *! *! Generates an RSA key pair with a @[bits] sized modulus (n), using
d5f6892013-11-24Martin Nilsson  *! the provided value for @[e] and random function @[rnd]. *! *! @returns *! @array
6668dd2013-12-06Henrik Grubbström (Grubba)  *! @elem Gmp.mpz 0
d5f6892013-11-24Martin Nilsson  *! The value n, the modulo.
6668dd2013-12-06Henrik Grubbström (Grubba)  *! @elem Gmp.mpz 1
d5f6892013-11-24Martin Nilsson  *! The value d, the private exponent.
6668dd2013-12-06Henrik Grubbström (Grubba)  *! @elem Gmp.mpz 2
d5f6892013-11-24Martin Nilsson  *! The value p, a prime.
6668dd2013-12-06Henrik Grubbström (Grubba)  *! @elem Gmp.mpz 3
d5f6892013-11-24Martin Nilsson  *! The value q, a prime. *! @endarray */ PIKEFUN array(object(Gmp.mpz))
b432312014-04-06Martin Nilsson  rsa_generate_keypair(int bits, int e, function(int(0..):string(0..255)) rnd)
d5f6892013-11-24Martin Nilsson { struct rsa_public_key pub; struct rsa_private_key key;
b6a4092013-12-25Henrik Grubbström (Grubba)  rsa_public_key_init(&pub); rsa_private_key_init(&key);
4bf09f2013-12-27Henrik Grubbström (Grubba)  mpz_set_ui((MP_INT *)&pub.e, e);
d5f6892013-11-24Martin Nilsson  if( !nettle_rsa_generate_keypair(&pub, &key, rnd, random_func_wrapper, NULL, NULL, bits, 0) ) {
b6a4092013-12-25Henrik Grubbström (Grubba)  rsa_private_key_clear(&key); rsa_public_key_clear(&pub);
28aa062013-12-02Martin Nilsson  Pike_error("Illegal parameter value.\n");
d5f6892013-11-24Martin Nilsson  }
b6a4092013-12-25Henrik Grubbström (Grubba)  push_bignum((MP_INT *)&pub.n); push_bignum((MP_INT *)&key.d); push_bignum((MP_INT *)&key.p); push_bignum((MP_INT *)&key.q); rsa_private_key_clear(&key); rsa_public_key_clear(&pub);
d5f6892013-11-24Martin Nilsson  f_aggregate(4);
b6a4092013-12-25Henrik Grubbström (Grubba)  stack_pop_n_elems_keep_top(args); /* Remove bits, e and rnd. */
d5f6892013-11-24Martin Nilsson }
c17a992014-04-24Henrik Grubbström (Grubba) #ifdef dsa_params_init
29b7002014-04-21Henrik Grubbström (Grubba)  /*! @class DH_Params *! *! Diffie-Hellman Parameters. */ PIKECLASS DH_Params
9e336b2014-06-19Henrik Grubbström (Grubba) program_flags PROGRAM_CLEAR_STORAGE;
29b7002014-04-21Henrik Grubbström (Grubba) { CVAR struct dsa_params params; INIT { dsa_params_init(&THIS->params); } EXIT { dsa_params_clear(&THIS->params); } /*! @decl Gmp.mpz p *! *! Prime. */ /*! @decl Gmp.mpz g *! *! Generator. */ /*! @decl Gmp.mpz q *! *! Order. */ PIKEFUN Gmp_mpz `p() { push_bignum(THIS->params.p); } PIKEFUN void `p=(Gmp_mpz|int p) { convert_svalue_to_bignum(p); mpz_from_svalue(THIS->params.p, p); } PIKEFUN Gmp_mpz `g() { push_bignum(THIS->params.g); } PIKEFUN void `g=(Gmp_mpz|int g) { convert_svalue_to_bignum(g); mpz_from_svalue(THIS->params.g, g); } PIKEFUN Gmp_mpz `q() { push_bignum(THIS->params.q); } PIKEFUN void `q=(Gmp_mpz|int q) { convert_svalue_to_bignum(q); mpz_from_svalue(THIS->params.q, q); } /*! @decl void generate(int p_bits, int q_bits, @ *! function(int(0..):string(8bit)) rnd) *! *! Generate a new set of Diffie-Hellman parameters. *! *! @note *! Throws errors for unsupported parameters. *! *! @note *! This function is not available in all installations of Pike. */ PIKEFUN void generate(int p_bits, int q_bits, function(int(0..):string(8bit)) rnd) { if (!dsa_generate_params(&THIS->params, rnd, random_func_wrapper, NULL, NULL, p_bits, q_bits)) { Pike_error("Illegal parameter value.\n"); } } /*! @decl array(Gmp.mpz) generate_keypair(function(int(0..):string(8bit)) rnd) *! *! Generate a Diffie-Hellman key pair. *! *! @returns *! Returns the following array: *! @array *! @elem Gmp.mpz 0 *! The generated public key.
a797162014-04-30Henrik Grubbström (Grubba)  *! @elem Gmp.mpz 1
29b7002014-04-21Henrik Grubbström (Grubba)  *! The corresponding private key. *! @endarray */ PIKEFUN array(Gmp_mpz) generate_keypair(function(int(0..):string(8bit)) rnd) { int psgn = mpz_sgn(THIS->params.p); mpz_t pub; mpz_t key; if (!psgn) { SIMPLE_DIVISION_BY_ZERO_ERROR("generate_keypair"); } if (psgn < 0) { Pike_error("The prime must be positive.\n"); } mpz_init(pub); mpz_init(key); dsa_generate_keypair(&THIS->params, pub, key, rnd, random_func_wrapper); push_bignum((MP_INT *)pub); push_bignum((MP_INT *)key); mpz_clear(key); mpz_clear(pub); f_aggregate(2); } } /*! @endclass */
c17a992014-04-24Henrik Grubbström (Grubba) #endif /* dsa_params_init */
29b7002014-04-21Henrik Grubbström (Grubba) 
4bf09f2013-12-27Henrik Grubbström (Grubba) #ifdef HAVE_NETTLE_ECDSA_H #include <nettle/ecc-curve.h> #include <nettle/ecc.h>
e604c62014-01-04Henrik Grubbström (Grubba) #include <nettle/ecdsa.h>
a8acae2015-01-27Martin Nilsson #define SECP192R1 0 #define SECP224R1 1 #define SECP256R1 2 #define SECP384R1 3 #define SECP521R1 4
95186a2015-02-14Henrik Grubbström (Grubba) #ifndef ecc_point_equal_p
2bc49a2016-02-02Martin Nilsson static int ecc_point_equal_p(const struct ecc_point *a, const struct ecc_point *b)
95186a2015-02-14Henrik Grubbström (Grubba) { return (a->ecc == b->ecc) && !mpn_cmp(a->p, b->p, ecc_size_a(a->ecc)); } #endif
4bf09f2013-12-27Henrik Grubbström (Grubba) /*! @class ECC_Curve *! *! Elliptic Curve Definition */ PIKECLASS ECC_Curve {
e56f692015-01-21Henrik Grubbström (Grubba)  /*! @decl inherit __builtin.Nettle.ECC_Curve */ INHERIT "__builtin.Nettle.ECC_Curve";
4bf09f2013-12-27Henrik Grubbström (Grubba)  CVAR const struct ecc_curve *curve;
4885c52013-12-30Henrik Grubbström (Grubba) 
1ee3c82016-12-25Henrik Grubbström (Grubba)  /* Initialized to the scalar constant 1. */ CVAR struct ecc_scalar scalar_one;
29b7002014-04-21Henrik Grubbström (Grubba)  DECLARE_STORAGE;
1ee3c82016-12-25Henrik Grubbström (Grubba)  EXIT {
199b882016-12-26Henrik Grubbström (Grubba)  if (THIS->curve) { ecc_scalar_clear(&THIS->scalar_one); }
1ee3c82016-12-25Henrik Grubbström (Grubba)  }
a8acae2015-01-27Martin Nilsson  /*! @decl void create(int(0..) curve)
3852ef2014-01-04Henrik Grubbström (Grubba)  *! *! Initialize the curve.
a8acae2015-01-27Martin Nilsson  *! *! @param curve *! The curve type the object should be initialized as. *! @int *! @value Nettle.SECP192R1 *! @value Nettle.SECP224R1 *! @value Nettle.SECP256R1 *! @value Nettle.SECP384R1 *! @value Nettle.SECP521R1 *! @endint
3852ef2014-01-04Henrik Grubbström (Grubba)  */
a8acae2015-01-27Martin Nilsson  PIKEFUN void create(int(0..) curve)
3852ef2014-01-04Henrik Grubbström (Grubba)  flags ID_STATIC {
1ee3c82016-12-25Henrik Grubbström (Grubba)  mpz_t mpz_one;
3852ef2014-01-04Henrik Grubbström (Grubba)  if (THIS->curve) { Pike_error("The curve has already been initialized!\n"); }
a8acae2015-01-27Martin Nilsson  switch(curve) {
21071f2016-09-23Henrik Grubbström (Grubba) #ifdef HAVE_CURVE_NETTLE_SECP_192R1
a8acae2015-01-27Martin Nilsson  case SECP192R1: THIS->curve = &nettle_secp_192r1; break;
21071f2016-09-23Henrik Grubbström (Grubba) #endif /* HAVE_CURVE_NETTLE_SECP_192R1 */ #ifdef HAVE_CURVE_NETTLE_SECP_224R1
a8acae2015-01-27Martin Nilsson  case SECP224R1: THIS->curve = &nettle_secp_224r1; break;
21071f2016-09-23Henrik Grubbström (Grubba) #endif /* HAVE_CURVE_NETTLE_SECP_224R1 */ #ifdef HAVE_CURVE_NETTLE_SECP_256R1
a8acae2015-01-27Martin Nilsson  case SECP256R1: THIS->curve = &nettle_secp_256r1; break;
21071f2016-09-23Henrik Grubbström (Grubba) #endif /* HAVE_CURVE_NETTLE_SECP_256R1 */ #ifdef HAVE_CURVE_NETTLE_SECP_384R1
a8acae2015-01-27Martin Nilsson  case SECP384R1: THIS->curve = &nettle_secp_384r1; break;
21071f2016-09-23Henrik Grubbström (Grubba) #endif /* HAVE_CURVE_NETTLE_SECP_384R1 */ #ifdef HAVE_CURVE_NETTLE_SECP_521R1
a8acae2015-01-27Martin Nilsson  case SECP521R1: THIS->curve = &nettle_secp_521r1; break;
21071f2016-09-23Henrik Grubbström (Grubba) #endif /* HAVE_CURVE_NETTLE_SECP_521R1 */
3852ef2014-01-04Henrik Grubbström (Grubba)  default:
a8acae2015-01-27Martin Nilsson  Pike_error("Invalid curve\n");
3852ef2014-01-04Henrik Grubbström (Grubba)  break; }
1ee3c82016-12-25Henrik Grubbström (Grubba)  ecc_scalar_init(&THIS->scalar_one, THIS->curve); mpz_init_set_si(mpz_one, 1); ecc_scalar_set(&THIS->scalar_one, mpz_one); mpz_clear(mpz_one);
3852ef2014-01-04Henrik Grubbström (Grubba)  }
95186a2015-02-14Henrik Grubbström (Grubba)  /*! @decl protected local int(0..1) `==(mixed x) *! *! @returns *! Returns @expr{1@} if @[x] is the same @[Curve], *! and @expr{0@} (zero) otherwise. */
5b9d5c2015-01-27Henrik Grubbström (Grubba)  PIKEFUN int(0..1) `==(mixed x) flags ID_PROTECTED|ID_LOCAL; { struct Nettle_ECC_Curve_struct *c; struct inherit *inh; struct program *p; if (!x || (TYPEOF(*x) != PIKE_T_OBJECT) || !x->u.object || !x->u.object->prog) RETURN 0; p = x->u.object->prog; inh = p->inherits + SUBTYPEOF(*x); p = inh->prog; if (p != Nettle_ECC_Curve_program) { int lfun_eq; if ((low_get_storage(p, Nettle_ECC_Curve_program) == -1) || ((lfun_eq = FIND_LFUN(p, LFUN_EQ)) == -1)) { /* p does not inherit ECC.Curve, or has made `==() private. */ RETURN 0; } /* Let's see if LFUN::`==() in x traverses down to ECC.Curve. */ /* FIXME: We're recursing via potentially broken code, * so we probably ought to use CYCLIC here. */ lfun_eq += inh->identifier_level; ref_push_object_inherit(Pike_fp->current_object, Pike_fp->context - Pike_fp->current_object->prog->inherits); apply_low(x->u.object, lfun_eq, 1); stack_pop_n_elems_keep_top(args); return; } c = (struct Nettle_ECC_Curve_struct *) (PIKE_OBJ_STORAGE(x->u.object) + INHERIT_FROM_INT(x->u.object->prog, SUBTYPEOF(*x))->storage_offset + Nettle_ECC_Curve_storage_offset); RETURN c->curve == THIS->curve; }
4885c52013-12-30Henrik Grubbström (Grubba)  /*! @decl string(7bit) name() *! *! Returns the name of the curve.
f3df592016-12-23Henrik Grubbström (Grubba)  *! *! @seealso *! @[jose_name()]
4885c52013-12-30Henrik Grubbström (Grubba)  */ PIKEFUN string(7bit) name() {
adefa42016-09-24Martin Nilsson #ifdef HAVE_CURVE_NETTLE_SECP_192R1
4885c52013-12-30Henrik Grubbström (Grubba)  if (THIS->curve == &nettle_secp_192r1) { ref_push_string(MK_STRING("SECP_192R1"));
adefa42016-09-24Martin Nilsson  return; } #endif /* HAVE_CURVE_NETTLE_SECP_192R1 */ #ifdef HAVE_CURVE_NETTLE_SECP_224R1 if (THIS->curve == &nettle_secp_224r1) {
4885c52013-12-30Henrik Grubbström (Grubba)  ref_push_string(MK_STRING("SECP_224R1"));
adefa42016-09-24Martin Nilsson  return; } #endif /* HAVE_CURVE_NETTLE_SECP_224R1 */ #ifdef HAVE_CURVE_NETTLE_SECP_256R1 if (THIS->curve == &nettle_secp_256r1) {
4885c52013-12-30Henrik Grubbström (Grubba)  ref_push_string(MK_STRING("SECP_256R1"));
adefa42016-09-24Martin Nilsson  return; } #endif /* HAVE_CURVE_NETTLE_SECP_256R1 */ #ifdef HAVE_CURVE_NETTLE_SECP_384R1 if (THIS->curve == &nettle_secp_384r1) {
4885c52013-12-30Henrik Grubbström (Grubba)  ref_push_string(MK_STRING("SECP_384R1"));
adefa42016-09-24Martin Nilsson  return; } #endif /* HAVE_CURVE_NETTLE_SECP_384R1 */ #ifdef HAVE_CURVE_NETTLE_SECP_521R1 if (THIS->curve == &nettle_secp_521r1) {
4885c52013-12-30Henrik Grubbström (Grubba)  ref_push_string(MK_STRING("SECP_521R1"));
adefa42016-09-24Martin Nilsson  return;
4885c52013-12-30Henrik Grubbström (Grubba)  }
adefa42016-09-24Martin Nilsson #endif /* HAVE_CURVE_NETTLE_SECP_521R1 */ ref_push_string(MK_STRING("UNKNOWN"));
4885c52013-12-30Henrik Grubbström (Grubba)  }
4bf09f2013-12-27Henrik Grubbström (Grubba) 
f3df592016-12-23Henrik Grubbström (Grubba)  /*! @decl string(7bit) jose_name() *! *! Returns the name of the curve according to JOSE *! (@rfc{7518:6.2.1.1@}). *! *! @returns *! Returns the JOSE name for supported curves, *! and @[UNDEFINED] otherwise. *! *! @seealso *! @[name()] */ PIKEFUN string(7bit) jose_name() { #ifdef HAVE_CURVE_NETTLE_SECP_256R1 if (THIS->curve == &nettle_secp_256r1) { ref_push_string(MK_STRING("P-256R")); return; } #endif /* HAVE_CURVE_NETTLE_SECP_256R1 */ #ifdef HAVE_CURVE_NETTLE_SECP_384R1 if (THIS->curve == &nettle_secp_384r1) { ref_push_string(MK_STRING("P-384")); return; } #endif /* HAVE_CURVE_NETTLE_SECP_384R1 */ #ifdef HAVE_CURVE_NETTLE_SECP_521R1 if (THIS->curve == &nettle_secp_521r1) { ref_push_string(MK_STRING("P-521")); return; } #endif /* HAVE_CURVE_NETTLE_SECP_521R1 */ push_undefined(); }
4bf09f2013-12-27Henrik Grubbström (Grubba)  /*! @decl int size() *! *! @returns *! Returns the size in bits for a single coordinate on the curve. */ PIKEFUN int size() {
4107672015-01-28Henrik Grubbström (Grubba) #ifdef HAVE_NETTLE_ECC_BIT_SIZE
a8acae2015-01-27Martin Nilsson  push_int(ecc_bit_size(THIS->curve));
4107672015-01-28Henrik Grubbström (Grubba) #else if (THIS->curve == &nettle_secp_192r1) { push_int(192); } else if (THIS->curve == &nettle_secp_224r1) { push_int(224); } else if (THIS->curve == &nettle_secp_256r1) { push_int(256); } else if (THIS->curve == &nettle_secp_384r1) { push_int(384); } else if (THIS->curve == &nettle_secp_521r1) { push_int(521); } else { push_int(0); } #endif
4bf09f2013-12-27Henrik Grubbström (Grubba)  }
b432312014-04-06Martin Nilsson  /*! @decl Gmp.mpz new_scalar(function(int(0..):string(8bit)) rnd)
4bf09f2013-12-27Henrik Grubbström (Grubba)  *! *! @param rnd *! Randomness function to use as source. *! *! @returns *! Returns a random scalar suitable to use as an @[ECDSA] private key *! or as an ECDH exponent. */
b432312014-04-06Martin Nilsson  PIKEFUN object(Gmp.mpz) new_scalar(function(int(0..):string(8bit)) rnd)
4bf09f2013-12-27Henrik Grubbström (Grubba)  { struct ecc_scalar s; struct object *ret;
0ba9722013-12-28Henrik Grubbström (Grubba)  if (!THIS->curve) Pike_error("No curve defined.\n");
4bf09f2013-12-27Henrik Grubbström (Grubba)  ecc_scalar_init(&s, THIS->curve); ecc_scalar_random(&s, rnd, random_func_wrapper);
c3982f2014-10-29Martin Nilsson  push_object(ret = fast_clone_object(bignum_program));
4bf09f2013-12-27Henrik Grubbström (Grubba)  ecc_scalar_get(&s, (mpz_ptr)ret->storage); ecc_scalar_clear(&s); }
4b485c2015-01-23Henrik Grubbström (Grubba)  static int Nettle_ECC_Curve_Point_program_fun_num; /*! @decl Point `*(Gmp.mpz|int scalar)
4bf09f2013-12-27Henrik Grubbström (Grubba)  *! *! Multiply the curve by a scalar. *!
0ba9722013-12-28Henrik Grubbström (Grubba)  *! This can be used to get the public key from a private key. *!
4bf09f2013-12-27Henrik Grubbström (Grubba)  *! @returns
4b485c2015-01-23Henrik Grubbström (Grubba)  *! Returns a new @[Point] on the curve.
4bf09f2013-12-27Henrik Grubbström (Grubba)  */
4b485c2015-01-23Henrik Grubbström (Grubba)  PIKEFUN Nettle_ECC_Curve_Point `*(object(Gmp.mpz)|int scalar)
4bf09f2013-12-27Henrik Grubbström (Grubba)  { struct ecc_scalar s; struct ecc_point r; struct object *x; struct object *y;
0ba9722013-12-28Henrik Grubbström (Grubba)  if (!THIS->curve) Pike_error("No curve defined.\n");
4bf09f2013-12-27Henrik Grubbström (Grubba)  convert_svalue_to_bignum(scalar); ecc_scalar_init(&s, THIS->curve); ecc_point_init(&r, THIS->curve); if (!ecc_scalar_set(&s, (mpz_srcptr)scalar->u.object->storage)) { ecc_scalar_clear(&s); ecc_point_clear(&r); SIMPLE_ARG_ERROR("`*", 1, "Invalid scalar for curve."); } ecc_point_mul_g(&r, &s);
c3982f2014-10-29Martin Nilsson  push_object(x = fast_clone_object(bignum_program)); push_object(y = fast_clone_object(bignum_program));
4bf09f2013-12-27Henrik Grubbström (Grubba)  ecc_point_get(&r, (mpz_ptr)x->storage, (mpz_ptr)y->storage); ecc_scalar_clear(&s); ecc_point_clear(&r);
4b485c2015-01-23Henrik Grubbström (Grubba)  apply_current(Nettle_ECC_Curve_Point_program_fun_num, 2);
4bf09f2013-12-27Henrik Grubbström (Grubba)  }
0ba9722013-12-28Henrik Grubbström (Grubba) 
4b485c2015-01-23Henrik Grubbström (Grubba)  /*! @decl Point point_mul(Gmp.mpz|int x, Gmp.mpz|int y, @ *! Gmp.mpz|int scalar)
0ba9722013-12-28Henrik Grubbström (Grubba)  *! *! Multiply a point on the curve by a scalar. *! *! A typical use is for Elliptic Curve Diffie Hellman (ECDH) key exchange. *!
7ac1572015-03-06Martin Nilsson  *! This is equivalent to @expr{(Point(x, y) * scalar)@}.
4b485c2015-01-23Henrik Grubbström (Grubba)  *!
0ba9722013-12-28Henrik Grubbström (Grubba)  *! @returns
4b485c2015-01-23Henrik Grubbström (Grubba)  *! Returns the new @[Point] on the curve.
cafd1a2014-11-15Henrik Grubbström (Grubba)  *! *! @throws *! Throws an error if the point (@[x], @[y]) isn't on the curve.
0ba9722013-12-28Henrik Grubbström (Grubba)  */
4b485c2015-01-23Henrik Grubbström (Grubba)  PIKEFUN Nettle_ECC_Curve_Point point_mul(object(Gmp.mpz)|int x,
0ba9722013-12-28Henrik Grubbström (Grubba)  object(Gmp.mpz)|int y, object(Gmp.mpz)|int scalar) { struct ecc_point p; struct ecc_scalar s; struct ecc_point r; struct object *rx; struct object *ry; if (!THIS->curve) Pike_error("No curve defined.\n"); convert_svalue_to_bignum(x); convert_svalue_to_bignum(y); convert_svalue_to_bignum(scalar); ecc_point_init(&p, THIS->curve); ecc_scalar_init(&s, THIS->curve); if (!ecc_point_set(&p, (mpz_srcptr)x->u.object->storage, (mpz_srcptr)y->u.object->storage)) { ecc_scalar_clear(&s); ecc_point_clear(&p); SIMPLE_ARG_ERROR("point_mul", 1, "Invalid point on curve."); } if (!ecc_scalar_set(&s, (mpz_srcptr)scalar->u.object->storage)) { ecc_scalar_clear(&s); ecc_point_clear(&p); SIMPLE_ARG_ERROR("point_mul", 3, "Invalid scalar for curve."); } ecc_point_init(&r, THIS->curve); ecc_point_mul(&r, &s, &p);
c3982f2014-10-29Martin Nilsson  push_object(rx = fast_clone_object(bignum_program)); push_object(ry = fast_clone_object(bignum_program));
0ba9722013-12-28Henrik Grubbström (Grubba)  ecc_point_get(&r, (mpz_ptr)rx->storage, (mpz_ptr)ry->storage); ecc_point_clear(&r); ecc_scalar_clear(&s); ecc_point_clear(&p);
4b485c2015-01-23Henrik Grubbström (Grubba)  apply_current(Nettle_ECC_Curve_Point_program_fun_num, 2);
0ba9722013-12-28Henrik Grubbström (Grubba)  stack_pop_n_elems_keep_top(args); }
e604c62014-01-04Henrik Grubbström (Grubba) 
9231902014-12-11Henrik Grubbström (Grubba)  /*! @class Point *! *! A point on an elliptic curve. */ PIKECLASS Point program_flags PROGRAM_USES_PARENT|PROGRAM_NEEDS_PARENT|PROGRAM_CLEAR_STORAGE; { CVAR struct ecc_point point;
e56f692015-01-21Henrik Grubbström (Grubba)  /*! @decl inherit ECC_Curve::Point */ EXTRA { /* Perform an inherit of the Point class that our parent * contains via its inherit of __builtin.Nettle.ECC_Curve. */ struct program *parent_prog = Pike_compiler->previous->new_program; struct object *parent_obj = Pike_compiler->previous->fake_object; int parent_Point_fun_num = really_low_find_shared_string_identifier(MK_STRING("Point"), parent_prog, SEE_PROTECTED|SEE_PRIVATE); if (parent_Point_fun_num >= 0) { struct program *parent_Point_prog = low_program_from_function(parent_obj, parent_Point_fun_num); if (parent_Point_prog) { parent_Point_fun_num = really_low_reference_inherited_identifier(Pike_compiler->previous, 0, parent_Point_fun_num); low_inherit(parent_Point_prog, 0, parent_Point_fun_num, 1 + 42, 0, NULL); } } }
1818b42015-01-20Martin Nilsson 
9231902014-12-11Henrik Grubbström (Grubba)  INIT {
1ee3c82016-12-25Henrik Grubbström (Grubba)  const struct Nettle_ECC_Curve_struct *parent = parent_storage(1, Nettle_ECC_Curve_program); const struct ecc_curve *curve = parent->curve;
9231902014-12-11Henrik Grubbström (Grubba)  if (!curve) Pike_error("No curve selected.\n"); ecc_point_init(&THIS->point, curve);
1ee3c82016-12-25Henrik Grubbström (Grubba)  /* Make sure that the point is on the curve by initializing it to 'g'. */ ecc_point_mul_g(&THIS->point, &parent->scalar_one);
9231902014-12-11Henrik Grubbström (Grubba)  } EXIT {
1ee3c82016-12-25Henrik Grubbström (Grubba)  const struct Nettle_ECC_Curve_struct *parent = parent_storage(1, Nettle_ECC_Curve_program); const struct ecc_curve *curve = parent->curve;
9231902014-12-11Henrik Grubbström (Grubba)  if (!curve) return; ecc_point_clear(&THIS->point); }
95186a2015-02-14Henrik Grubbström (Grubba)  /*! @decl protected local int(0..1) _equal(mixed x) *! *! @returns *! Returns @expr{1@} if @[x] is a @[Point] on the same *! @[Curve] and has the same coordinates, and otherwise
7ac1572015-03-06Martin Nilsson  *! returns @expr{0@} (zero).
95186a2015-02-14Henrik Grubbström (Grubba)  */ PIKEFUN int(0..1) _equal(mixed x) flags ID_PROTECTED|ID_LOCAL; { struct inherit *inh; struct program *p; const struct ecc_point *xp; if (!x || (TYPEOF(*x) != PIKE_T_OBJECT) || !x->u.object || !x->u.object->prog) RETURN 0; p = x->u.object->prog; inh = p->inherits + SUBTYPEOF(*x); p = inh->prog; if (p != Nettle_ECC_Curve_Point_program) { int lfun__equal; if ((low_get_storage(p, Nettle_ECC_Curve_Point_program) == -1) || ((lfun__equal = FIND_LFUN(p, LFUN__EQUAL)) == -1)) { /* p does not inherit ECC.Curve, or has made _equal() private. */ RETURN 0; } /* Let's see if LFUN::_equal() in x traverses down to ECC.Curve. */ /* FIXME: We're recursing via potentially broken code, * so we probably ought to use CYCLIC here. */ lfun__equal += inh->identifier_level; ref_push_object_inherit(Pike_fp->current_object, Pike_fp->context - Pike_fp->current_object->prog->inherits); apply_low(x->u.object, lfun__equal, 1); stack_pop_n_elems_keep_top(args); return; } /* Find the other point. */ xp = &((struct Nettle_ECC_Curve_Point_struct *) (PIKE_OBJ_STORAGE(x->u.object) + inh->storage_offset + Nettle_ECC_Curve_Point_storage_offset))->point; /* Compare and return. */ RETURN ecc_point_equal_p(&(THIS->point), xp); }
9231902014-12-11Henrik Grubbström (Grubba)  /*! @decl string(7bit) name() *! *! Returns the string @expr{"Point"@} followed by *! the parenthesized name of the curve. */ PIKEFUN string(7bit) name() { ref_push_string(MK_STRING("Point(")); apply_external(1, f_Nettle_ECC_Curve_name_fun_num, 0); ref_push_string(MK_STRING(")")); f_add(3); } /*! @decl ECC_Curve get_curve() *! *! Get the elliptic curve that is in use. */ PIKEFUN object(Nettle_ECC_Curve) get_curve() { struct external_variable_context loc; loc.o = Pike_fp->current_object; loc.inherit = Pike_fp->context; find_external_context(&loc, 1); ref_push_object_inherit(loc.o, loc.inherit - loc.o->prog->inherits); } /*! @decl object(Gmp.mpz) get_x() *! *! Get the x coordinate of the point. *! *! @seealso *! @[get_y()] */ PIKEFUN object(Gmp.mpz) get_x() { struct object *ret; push_object(ret = fast_clone_object(bignum_program)); ecc_point_get(&THIS->point, (mpz_ptr)ret->storage, NULL); } /*! @decl object(Gmp.mpz) get_y() *! *! Get the y coordinate of the point. *! *! @seealso *! @[get_x()] */ PIKEFUN object(Gmp.mpz) get_y() { struct object *ret; push_object(ret = fast_clone_object(bignum_program)); ecc_point_get(&THIS->point, NULL, (mpz_ptr)ret->storage); } /*! @decl void set(object(Gmp.mpz)|int x, object(Gmp.mpz)|int y) *! *! Change to the selected point on the curve. *! *! @note *! Throws errors if the point isn't on the curve. */ PIKEFUN void set(object(Gmp.mpz)|int x, object(Gmp.mpz)|int y) { convert_svalue_to_bignum(x); convert_svalue_to_bignum(y); if (!ecc_point_set(&THIS->point, (mpz_srcptr)x->u.object->storage, (mpz_srcptr)y->u.object->storage)) { SIMPLE_ARG_ERROR("set", 1, "Invalid point on curve."); } } /*! @decl Point `*(Gmp.mpz|int scalar) *! *! Multiply the point on the curve by a scalar. *! *! A typical use is for Elliptic Curve Diffie Hellman (ECDH) key exchange. *! *! @returns *! Returns the new point on the curve. */ PIKEFUN Nettle_ECC_Curve_Point `*(object(Gmp.mpz)|int scalar) flags ID_PROTECTED; { struct ecc_scalar s; struct ecc_point r; struct object *rx; struct object *ry; const struct ecc_curve *curve = (((const struct Nettle_ECC_Curve_struct *)parent_storage(1, Nettle_ECC_Curve_program))->curve); if (!curve) Pike_error("No curve defined.\n"); convert_svalue_to_bignum(scalar); ecc_scalar_init(&s, curve); if (!ecc_scalar_set(&s, (mpz_srcptr)scalar->u.object->storage)) { ecc_scalar_clear(&s); SIMPLE_ARG_ERROR("`*", 1, "Invalid scalar for curve."); } ecc_point_init(&r, curve); ecc_point_mul(&r, &s, &THIS->point); push_object(rx = fast_clone_object(bignum_program)); push_object(ry = fast_clone_object(bignum_program)); ecc_point_get(&r, (mpz_ptr)rx->storage, (mpz_ptr)ry->storage); ecc_point_clear(&r); ecc_scalar_clear(&s); apply_external(1, Nettle_ECC_Curve_Point_program_fun_num, 2); } } /*! @endclass Point */
e604c62014-01-04Henrik Grubbström (Grubba)  /*! @class ECDSA *! *! Elliptic Curve Digital Signing Algorithm */ PIKECLASS ECDSA
9e336b2014-06-19Henrik Grubbström (Grubba)  program_flags PROGRAM_USES_PARENT|PROGRAM_NEEDS_PARENT|PROGRAM_CLEAR_STORAGE;
e604c62014-01-04Henrik Grubbström (Grubba)  {
c88bb12015-05-27Henrik Grubbström (Grubba)  /*! @decl inherit Point
65394a2015-05-27Henrik Grubbström (Grubba)  *! *! This point represents the public key.
c88bb12015-05-27Henrik Grubbström (Grubba)  */
65394a2015-05-27Henrik Grubbström (Grubba)  EXTRA { /* Perform an inherit of the Point class that our parent contains. */ struct program *parent_prog = Pike_compiler->previous->new_program; struct object *parent_obj = Pike_compiler->previous->fake_object; int parent_Point_fun_num = really_low_find_shared_string_identifier(MK_STRING("Point"), parent_prog, SEE_PROTECTED|SEE_PRIVATE); if (parent_Point_fun_num >= 0) { struct program *parent_Point_prog = low_program_from_function(parent_obj, parent_Point_fun_num); #ifdef PIKE_DEBUG if (parent_Point_prog != Nettle_ECC_Curve_Point_program) { Pike_fatal("Unexpected Point program.\n"); } #endif if (parent_Point_prog) { parent_Point_fun_num = really_low_reference_inherited_identifier(Pike_compiler->previous, 0, parent_Point_fun_num); low_inherit(parent_Point_prog, 0, parent_Point_fun_num, 1 + 42, 0, NULL); } } }
c88bb12015-05-27Henrik Grubbström (Grubba) 
9104d02014-01-13Henrik Grubbström (Grubba)  /*! @decl inherit __builtin.Nettle.Sign */ INHERIT "__builtin.Nettle.Sign";
e604c62014-01-04Henrik Grubbström (Grubba)  CVAR struct ecc_scalar key;
b432312014-04-06Martin Nilsson  PIKEVAR function(int(0..):string(0..255)) random
e604c62014-01-04Henrik Grubbström (Grubba)  flags ID_PROTECTED; INIT { const struct ecc_curve *curve =
13e2ba2014-04-26Henrik Grubbström (Grubba)  (((const struct Nettle_ECC_Curve_struct *)parent_storage(1, Nettle_ECC_Curve_program))->curve);
e604c62014-01-04Henrik Grubbström (Grubba)  if (!curve) Pike_error("No curve selected.\n"); ecc_scalar_init(&THIS->key, curve);
6dc29f2016-03-14Martin Nilsson  struct svalue *random = simple_mapping_string_lookup(get_builtin_constants(), "random_string"); if(!random || (TYPEOF(*random) != T_FUNCTION)) Pike_error("Unable to resolve random function.\n"); assign_svalue(&THIS->random, random);
e604c62014-01-04Henrik Grubbström (Grubba)  } EXIT { const struct ecc_curve *curve =
13e2ba2014-04-26Henrik Grubbström (Grubba)  (((const struct Nettle_ECC_Curve_struct *)parent_storage(1, Nettle_ECC_Curve_program))->curve);
e604c62014-01-04Henrik Grubbström (Grubba)  if (!curve) return; ecc_scalar_clear(&THIS->key); }
c88bb12015-05-27Henrik Grubbström (Grubba)  static int f_Nettle_ECC_Curve_ECDSA_inherited_Point_set_fun_num = -1; EXTRA { f_Nettle_ECC_Curve_ECDSA_inherited_Point_set_fun_num = really_low_reference_inherited_identifier(NULL, 1, f_Nettle_ECC_Curve_Point_set_fun_num); }
e604c62014-01-04Henrik Grubbström (Grubba)  /*! @decl string(7bit) name() *! *! Returns the string @expr{"ECDSA"@} followed by *! the parenthesized name of the curve. */ PIKEFUN string(7bit) name() { ref_push_string(MK_STRING("ECDSA("));
895c722014-03-29Henrik Grubbström (Grubba)  apply_external(1, f_Nettle_ECC_Curve_name_fun_num, 0);
e604c62014-01-04Henrik Grubbström (Grubba)  ref_push_string(MK_STRING(")")); f_add(3); } /*! @decl ECC_Curve get_curve() *! *! Get the elliptic curve that is in use. */
895c722014-03-29Henrik Grubbström (Grubba)  PIKEFUN object(Nettle_ECC_Curve) get_curve()
e604c62014-01-04Henrik Grubbström (Grubba)  { struct external_variable_context loc; loc.o = Pike_fp->current_object; loc.inherit = Pike_fp->context; find_external_context(&loc, 1); ref_push_object_inherit(loc.o, loc.inherit - loc.o->prog->inherits); } /*! @decl Gmp.mpz get_private_key() *! *! Get the private key. */ PIKEFUN object(Gmp.mpz) get_private_key() { struct object *ret;
c3982f2014-10-29Martin Nilsson  push_object(ret = fast_clone_object(bignum_program));
e604c62014-01-04Henrik Grubbström (Grubba)  ecc_scalar_get(&THIS->key, (mpz_ptr)ret->storage); } /*! @decl void set_private_key(object(Gmp.mpz)|int k) *!
4624362014-01-30Henrik Grubbström (Grubba)  *! Set the private key (and corresponding private key).
e604c62014-01-04Henrik Grubbström (Grubba)  *! *! @note *! Throws errors if the key isn't valid for the curve. */ PIKEFUN void set_private_key(object(Gmp.mpz)|int k) {
c88bb12015-05-27Henrik Grubbström (Grubba)  struct ecc_point *pub;
e604c62014-01-04Henrik Grubbström (Grubba)  convert_svalue_to_bignum(k); if (!ecc_scalar_set(&THIS->key, (mpz_srcptr)k->u.object->storage)) { SIMPLE_ARG_ERROR("set_private_key", 1, "Invalid key for curve."); }
4624362014-01-30Henrik Grubbström (Grubba)  /* Set the corresponding public key, */
c88bb12015-05-27Henrik Grubbström (Grubba)  pub = &((struct Nettle_ECC_Curve_Point_struct *) get_inherited_storage(1, Nettle_ECC_Curve_Point_program))-> point; ecc_point_mul_g(pub, &THIS->key);
e604c62014-01-04Henrik Grubbström (Grubba)  } /*! @decl object(Gmp.mpz) get_x() *! *! Get the x coordinate of the public key. *! *! @seealso *! @[get_y()] */ PIKEFUN object(Gmp.mpz) get_x() {
c88bb12015-05-27Henrik Grubbström (Grubba)  struct ecc_point *pub;
e604c62014-01-04Henrik Grubbström (Grubba)  struct object *ret;
c3982f2014-10-29Martin Nilsson  push_object(ret = fast_clone_object(bignum_program));
c88bb12015-05-27Henrik Grubbström (Grubba)  pub = &((struct Nettle_ECC_Curve_Point_struct *) get_inherited_storage(1, Nettle_ECC_Curve_Point_program))-> point; ecc_point_get(pub, (mpz_ptr)ret->storage, NULL);
e604c62014-01-04Henrik Grubbström (Grubba)  } /*! @decl object(Gmp.mpz) get_y() *! *! Get the y coordinate of the public key. *! *! @seealso *! @[get_x()] */ PIKEFUN object(Gmp.mpz) get_y() {
c88bb12015-05-27Henrik Grubbström (Grubba)  struct ecc_point *pub;
e604c62014-01-04Henrik Grubbström (Grubba)  struct object *ret;
c3982f2014-10-29Martin Nilsson  push_object(ret = fast_clone_object(bignum_program));
c88bb12015-05-27Henrik Grubbström (Grubba)  pub = &((struct Nettle_ECC_Curve_Point_struct *) get_inherited_storage(1, Nettle_ECC_Curve_Point_program))-> point; ecc_point_get(pub, NULL, (mpz_ptr)ret->storage);
e604c62014-01-04Henrik Grubbström (Grubba)  } /*! @decl void set_public_key(object(Gmp.mpz)|int x, object(Gmp.mpz)|int y) *! *! Change to the selected point on the curve as public key. *! *! @note *! Throws errors if the point isn't on the curve. */ PIKEFUN void set_public_key(object(Gmp.mpz)|int x, object(Gmp.mpz)|int y) {
c88bb12015-05-27Henrik Grubbström (Grubba)  apply_current(f_Nettle_ECC_Curve_ECDSA_inherited_Point_set_fun_num, args);
e604c62014-01-04Henrik Grubbström (Grubba)  }
b432312014-04-06Martin Nilsson  /*! @decl void set_random(function(int(0..):string(8bit)) r)
e604c62014-01-04Henrik Grubbström (Grubba)  *! *! Set the random function, used to generate keys and parameters, *! to the function @[r]. */
b432312014-04-06Martin Nilsson  PIKEFUN void set_random(function(int(0..):string(8bit)) r)
e604c62014-01-04Henrik Grubbström (Grubba)  { assign_svalue(&THIS->random, r); } /*! @decl int(0..1) raw_verify(string(8bit) digest, @ *! object(Gmp.mpz) r, @ *! object(Gmp.mpz) s) *! *! Verify the signature @[r], @[s] against the message digest @[digest]. */ PIKEFUN int(0..1) raw_verify(string(0..255) digest, object(Gmp.mpz)|int r, object(Gmp.mpz)|int s) {
c88bb12015-05-27Henrik Grubbström (Grubba)  struct ecc_point *pub;
e604c62014-01-04Henrik Grubbström (Grubba)  struct dsa_signature sig; int ret; NO_WIDE_STRING(digest); dsa_signature_init(&sig); if (!mpz_from_svalue((MP_INT *)&sig.r, r)) { dsa_signature_clear(&sig); SIMPLE_ARG_TYPE_ERROR("raw_verify", 1, "Gmp.mpz|int"); } if (!mpz_from_svalue((MP_INT *)&sig.s, s)) { dsa_signature_clear(&sig); SIMPLE_ARG_TYPE_ERROR("raw_verify", 2, "Gmp.mpz|int"); }
c88bb12015-05-27Henrik Grubbström (Grubba)  pub = &((struct Nettle_ECC_Curve_Point_struct *) get_inherited_storage(1, Nettle_ECC_Curve_Point_program))-> point; ret = ecdsa_verify(pub, digest->len, STR0(digest), &sig);
e604c62014-01-04Henrik Grubbström (Grubba)  dsa_signature_clear(&sig); RETURN ret; } /*! @decl array(Gmp.mpz) raw_sign(string(8bit) digest) *! *! Sign the message digest @[digest]. Returns the signature *! as two @[Gmp.mpz] objects. */ PIKEFUN array(object(Gmp.mpz)) raw_sign(string(8bit) digest) { struct dsa_signature sig; struct object *r, *s; NO_WIDE_STRING(digest); dsa_signature_init(&sig); ecdsa_sign(&THIS->key, &THIS->random, random_func_wrapper, digest->len, STR0(digest), &sig); push_bignum((MP_INT *)&sig.r); push_bignum((MP_INT *)&sig.s); dsa_signature_clear(&sig); f_aggregate(2); stack_pop_n_elems_keep_top(args); } /*! @decl void generate_key() *! *! Generate a new set of private and public keys on the current curve. */ PIKEFUN void generate_key() {
c88bb12015-05-27Henrik Grubbström (Grubba)  struct ecc_point *pub; pub = &((struct Nettle_ECC_Curve_Point_struct *) get_inherited_storage(1, Nettle_ECC_Curve_Point_program))-> point; ecdsa_generate_keypair(pub, &THIS->key,
e604c62014-01-04Henrik Grubbström (Grubba)  &THIS->random, random_func_wrapper); } } /*! @endclass ECDSA */
4bf09f2013-12-27Henrik Grubbström (Grubba) } /*! @endclass ECC_Curve */ #endif /* HAVE_NETTLE_ECDSA_H */
f05d052016-10-08Henrik Grubbström (Grubba) #if defined(HAVE_NETTLE_EDDSA_H) && defined(HAVE_NETTLE_CURVE25519_H) #include <nettle/curve25519.h> #include <nettle/eddsa.h> /*! @class Curve25519 *!
c7b3012016-10-09Henrik Grubbström (Grubba)  *! Elliptic Curve Definition for the curve *! @expr{y^2 = x^2 + 486662 x^2 + x (mod 2^255 - 19)@}. *! *! This curve is standardized in @rfc{7748@}. *! *! @note *! The API for this curve differs somewhat from the API *! used by the other @[Curve]s. *! *! @seealso *! @[Curve], @rfc{7748@}
f05d052016-10-08Henrik Grubbström (Grubba)  */ PIKECLASS Curve25519 { DECLARE_STORAGE; /*! @decl string(7bit) name() *! *! Returns the name of the curve. */ PIKEFUN string(7bit) name() { ref_push_string(MK_STRING("Curve25519")); } /*! @decl int size() *! *! @returns *! Returns the size in bits for a single coordinate on the curve. */ PIKEFUN int size() { push_int(255); } /*! @decl Gmp.mpz new_scalar(function(int(0..):string(8bit)) rnd) *! *! @param rnd *! Randomness function to use as source. *! *! @returns *! Returns a random scalar suitable to use as an @[ECDSA] private key *! or as an ECDH exponent. */ PIKEFUN string(8bit) new_scalar(function(int(0..):string(8bit)) rnd) { push_int(CURVE25519_SIZE); apply_svalue(rnd, 1); } /*! @decl string(8bit) `*(string(8bit) scalar) *! *! Multiply the curve by a scalar. *! *! This can be used to get the public key from a private key. *! *! @returns *! Returns a new point on the curve. */ PIKEFUN string(8bit) `*(string(8bit) scalar) { struct pike_string *res; if (scalar->len != CURVE25519_SIZE) Pike_error("Invalid scalar.\n"); res = begin_shared_string(CURVE25519_SIZE); curve25519_mul_g(STR0(res), STR0(scalar)); push_string(end_shared_string(res)); } /*! @decl string(8bit) point_mul(string(8bit) x, string(8bit) scalar) *! *! Multiply a point on the curve by a scalar. *! *! A typical use is for Elliptic Curve Diffie Hellman (ECDH) key exchange. *! *! @returns *! Returns the new point on the curve. */ PIKEFUN string(8bit) point_mul(string(8bit) x, string(8bit) scalar) { struct pike_string *res; if (x->len != CURVE25519_SIZE) Pike_error("Invalid x.\n"); if (scalar->len != CURVE25519_SIZE) Pike_error("Invalid scalar.\n"); res = begin_shared_string(CURVE25519_SIZE); curve25519_mul(STR0(res), STR0(scalar), STR0(x)); push_string(end_shared_string(res)); } /*! @class EdDSA *! *! Edwards Curve Digital Signing Algorithm */ PIKECLASS EdDSA program_flags PROGRAM_USES_PARENT|PROGRAM_NEEDS_PARENT|PROGRAM_CLEAR_STORAGE; { /*! @decl inherit __builtin.Nettle.Sign */ INHERIT "__builtin.Nettle.Sign"; PIKEVAR string(8bit) private_key flags ID_PRIVATE|ID_HIDDEN; PIKEVAR string(8bit) public_key flags ID_PRIVATE|ID_HIDDEN; PIKEVAR function(int(0..):string(0..255)) random flags ID_PROTECTED; INIT { struct svalue *random = simple_mapping_string_lookup(get_builtin_constants(), "random_string"); if(!random || (TYPEOF(*random) != T_FUNCTION)) Pike_error("Unable to resolve random function.\n"); assign_svalue(&THIS->random, random); } /*! @decl string(7bit) name() *! *! Returns the string @expr{"EdDSA"@}. */ PIKEFUN string(7bit) name() { ref_push_string(MK_STRING("EdDSA")); } /*! @decl Curve25519 get_curve() *! *! Get the elliptic curve that is in use. */ PIKEFUN object(Nettle_Curve25519) get_curve() { struct external_variable_context loc; loc.o = Pike_fp->current_object; loc.inherit = Pike_fp->context; find_external_context(&loc, 1); ref_push_object_inherit(loc.o, loc.inherit - loc.o->prog->inherits); } /*! @decl string(8bit) get_private_key() *! *! Get the private key. */ PIKEFUN string(8bit) get_private_key() { if (THIS->private_key) { ref_push_string(THIS->private_key); } else { push_undefined(); } } /*! @decl void set_private_key(string(8bit) k) *! *! Set the private key (and corresponding public key). *! *! @note *! Throws errors if the key isn't valid for the curve. */ PIKEFUN void set_private_key(string(8bit) k) { struct pike_string *pub; if (k->len != ED25519_KEY_SIZE) Pike_error("Invalid private key.\n"); if (THIS->private_key) { free_string(THIS->private_key); } copy_shared_string(THIS->private_key, k); /* Set the corresponding public key, */ pub = begin_shared_string(ED25519_KEY_SIZE); ed25519_sha512_public_key(STR0(pub), STR0(k)); if (THIS->public_key) { free_string(THIS->public_key); } THIS->public_key = end_shared_string(pub); } /*! @decl string(8bit) get_x() *! *! Get the x coordinate of the public key. */ PIKEFUN string(8bit) get_x() { if (THIS->public_key) { ref_push_string(THIS->public_key); } else { push_undefined(); } } /*! @decl void set_public_key(string(8bit) x) *! *! Change to the selected point on the curve as public key. *! *! @note *! Throws errors if the point isn't on the curve. */ PIKEFUN void set_public_key(string(8bit) x) { if (THIS->public_key == x) return; if (x->len != ED25519_KEY_SIZE) Pike_error("Invalid key.\n"); if (THIS->public_key) { free_string(THIS->public_key); } if (THIS->private_key) { free_string(THIS->private_key); THIS->private_key = NULL; } copy_shared_string(THIS->public_key, x); } /*! @decl void set_random(function(int(0..):string(8bit)) r) *! *! Set the random function, used to generate keys and parameters, *! to the function @[r]. */ PIKEFUN void set_random(function(int(0..):string(8bit)) r) { assign_svalue(&THIS->random, r); } /*! @decl int(0..1) raw_verify(string(8bit) message, string(8bit) signature) *! *! Verify the @[signature] against the @[message]. */ PIKEFUN int(0..1) raw_verify(string(8bit) message, string(8bit) signature) { if (!THIS->public_key) Pike_error("No public key.\n"); if (signature->len != ED25519_SIGNATURE_SIZE) { push_int(0); return; } push_int(ed25519_sha512_verify(STR0(THIS->public_key), message->len, STR0(message), STR0(signature))); } /*! @decl string(8bit) raw_sign(string(8bit) message) *! *! Sign the @[message]. */ PIKEFUN string(8bit) raw_sign(string(8bit) message) { struct pike_string *res; if (!THIS->private_key) Pike_error("No private key.\n"); if (!THIS->public_key) Pike_error("No public key.\n"); res = begin_shared_string(ED25519_SIGNATURE_SIZE); ed25519_sha512_sign(STR0(THIS->public_key), STR0(THIS->private_key), message->len, STR0(message), STR0(res)); push_string(end_shared_string(res)); } /*! @decl void generate_key() *! *! Generate a new set of private and public keys on the current curve. */ PIKEFUN void generate_key() { push_int(ED25519_KEY_SIZE); apply_svalue(&THIS->random, 1); apply_current(f_Nettle_Curve25519_EdDSA_set_private_key_fun_num, 1); } } /*! @endclass EdDSA */ } /*! @endclass Curve25519 */ #endif /* HAVE_NETTLE_EDDSA_H && HAVE_NETTLE_CURVE25519_H */
877f412014-01-04Henrik Grubbström (Grubba) /*! @endmodule Nettle */
d5f6892013-11-24Martin Nilsson void hogweed_init(void) { INIT;
a8acae2015-01-27Martin Nilsson 
68ab9a2015-02-07Henrik Grubbström (Grubba) #ifdef HAVE_NETTLE_ECDSA_H
21071f2016-09-23Henrik Grubbström (Grubba) #ifdef HAVE_CURVE_NETTLE_SECP_192R1
a8acae2015-01-27Martin Nilsson  ADD_INT_CONSTANT("SECP192R1", SECP192R1, 0);
21071f2016-09-23Henrik Grubbström (Grubba) #endif /* HAVE_CURVE_NETTLE_SECP_192R1 */ #ifdef HAVE_CURVE_NETTLE_SECP_224R1
a8acae2015-01-27Martin Nilsson  ADD_INT_CONSTANT("SECP224R1", SECP224R1, 0);
21071f2016-09-23Henrik Grubbström (Grubba) #endif /* HAVE_CURVE_NETTLE_SECP_224R1 */ #ifdef HAVE_CURVE_NETTLE_SECP_256R1
a8acae2015-01-27Martin Nilsson  ADD_INT_CONSTANT("SECP256R1", SECP256R1, 0);
21071f2016-09-23Henrik Grubbström (Grubba) #endif /* HAVE_CURVE_NETTLE_SECP_256R1 */ #ifdef HAVE_CURVE_NETTLE_SECP_384R1
a8acae2015-01-27Martin Nilsson  ADD_INT_CONSTANT("SECP384R1", SECP384R1, 0);
21071f2016-09-23Henrik Grubbström (Grubba) #endif /* HAVE_CURVE_NETTLE_SECP_384R1 */ #ifdef HAVE_CURVE_NETTLE_SECP_521R1
a8acae2015-01-27Martin Nilsson  ADD_INT_CONSTANT("SECP521R1", SECP521R1, 0);
21071f2016-09-23Henrik Grubbström (Grubba) #endif /* HAVE_CURVE_NETTLE_SECP_521R1 */
68ab9a2015-02-07Henrik Grubbström (Grubba) #endif /* HAVE_NETTLE_ECDSA_H */
f05d052016-10-08Henrik Grubbström (Grubba)  #ifdef NETTLE_CURVE25519_RFC7748 ADD_INT_CONSTANT("CURVE25519_RFC7748", 1, 0); #endif
d5f6892013-11-24Martin Nilsson } void hogweed_exit(void) { EXIT; } #endif