/* -*- 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 "pike_compiler.h" |
#include "builtin_functions.h" |
#include "operators.h" |
#include "interpret.h" |
#include "module.h" |
#include "mapping.h" |
#include "stralloc.h" |
#include "constants.h" |
|
#include "nettle_config.h" |
|
#ifdef HAVE_LIBHOGWEED |
|
DECLARATIONS |
|
#include "nettle.h" |
#include <nettle/dsa.h> |
#include <nettle/rsa.h> |
|
/* Includes <gmp.h> */ |
#include "bignum.h" |
|
/*! @module Nettle |
*/ |
|
static void random_func_wrapper(void *f, pike_nettle_size_t num, uint8_t *out) |
{ |
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"); |
if((unsigned)Pike_sp[-1].u.string->len != (unsigned)num || |
Pike_sp[-1].u.string->size_shift != 0) |
Pike_error("Random function did not return correct number of bytes.\n"); |
memcpy(out, Pike_sp[-1].u.string->str, num); |
pop_stack(); |
} |
|
/*! @decl array(object(Gmp.mpz)) @ |
*! dsa_generate_keypair(int p_bits, int q_bits, @ |
*! function(int(0..):string(0..255)) rnd) |
*! |
*! Generates a DSA key pair with @[p_bits] number of bits (sometimes |
*! 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 |
*! 2048 224 (rejected by some versions of Hogweed) |
*! 2048 256 |
*! 3072 256 |
*! @} |
*! |
*! @returns |
*! @array |
*! @elem Gmp.mpz 0 |
*! The value p, the modulo. |
*! @elem Gmp.mpz 1 |
*! The value q, the group order. |
*! @elem Gmp.mpz 2 |
*! The value g, the generator. |
*! @elem Gmp.mpz 3 |
*! The value y, the public value. |
*! @elem Gmp.mpz 4 |
*! The value x, the private value. |
*! @endarray |
*/ |
PIKEFUN array(object(Gmp.mpz)) |
dsa_generate_keypair(int p_bits, int q_bits, function(int(0..):string(0..255)) rnd) |
{ |
#ifdef dsa_params_init |
/* Nettle 3.0 or later. */ |
struct dsa_params params; |
mpz_t pub; |
mpz_t key; |
|
dsa_params_init(¶ms); |
|
if (!dsa_generate_params(¶ms, rnd, random_func_wrapper, |
NULL, NULL, p_bits, q_bits)) { |
dsa_params_clear(¶ms); |
Pike_error("Illegal parameter value.\n"); |
} |
|
mpz_init(pub); |
mpz_init(key); |
|
dsa_generate_keypair(¶ms, pub, key, rnd, random_func_wrapper); |
|
push_bignum((MP_INT *)¶ms.p); |
push_bignum((MP_INT *)¶ms.q); |
push_bignum((MP_INT *)¶ms.g); |
|
dsa_params_clear(¶ms); |
|
push_bignum((MP_INT *)pub); |
push_bignum((MP_INT *)key); |
|
mpz_clear(key); |
mpz_clear(pub); |
|
#else |
struct dsa_public_key pub; |
struct dsa_private_key key; |
|
dsa_public_key_init(&pub); |
dsa_private_key_init(&key); |
|
if( !nettle_dsa_generate_keypair(&pub, &key, rnd, random_func_wrapper, |
NULL, NULL, p_bits |
#ifdef HAVE_DSA_QBITS_KEYPAIR_ARG |
, q_bits |
#endif |
) ) |
{ |
dsa_private_key_clear(&key); |
dsa_public_key_clear(&pub); |
|
Pike_error("Illegal parameter value.\n"); |
} |
|
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); |
#endif /* dsa_params_init */ |
|
f_aggregate(5); |
stack_pop_n_elems_keep_top(args); /* Remove p_bits, q_bits and rnd. */ |
} |
|
/*! @decl array(object(Gmp.mpz)) @ |
*! rsa_generate_keypair(int bits, int e, @ |
*! function(int(0..):string(0..255)) rnd) |
*! |
*! Generates an RSA key pair with a @[bits] sized modulus (n), using |
*! the provided value for @[e] and random function @[rnd]. |
*! |
*! @returns |
*! @array |
*! @elem Gmp.mpz 0 |
*! The value n, the modulo. |
*! @elem Gmp.mpz 1 |
*! The value d, the private exponent. |
*! @elem Gmp.mpz 2 |
*! The value p, a prime. |
*! @elem Gmp.mpz 3 |
*! The value q, a prime. |
*! @endarray |
*/ |
PIKEFUN array(object(Gmp.mpz)) |
rsa_generate_keypair(int bits, int e, function(int(0..):string(0..255)) rnd) |
{ |
struct rsa_public_key pub; |
struct rsa_private_key key; |
|
rsa_public_key_init(&pub); |
rsa_private_key_init(&key); |
|
mpz_set_ui((MP_INT *)&pub.e, e); |
|
if( !nettle_rsa_generate_keypair(&pub, &key, rnd, random_func_wrapper, |
NULL, NULL, bits, 0) ) |
{ |
rsa_private_key_clear(&key); |
rsa_public_key_clear(&pub); |
|
Pike_error("Illegal parameter value.\n"); |
} |
|
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); |
|
f_aggregate(4); |
stack_pop_n_elems_keep_top(args); /* Remove bits, e and rnd. */ |
} |
|
#ifdef dsa_params_init |
|
/*! @class DH_Params |
*! |
*! Diffie-Hellman Parameters. |
*/ |
PIKECLASS DH_Params |
program_flags PROGRAM_CLEAR_STORAGE; |
{ |
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. |
*! @elem Gmp.mpz 1 |
*! 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 |
*/ |
|
#endif /* dsa_params_init */ |
|
#ifdef HAVE_NETTLE_ECDSA_H |
#include <nettle/ecc-curve.h> |
|
#include <nettle/ecc.h> |
|
#include <nettle/ecdsa.h> |
|
#define SECP192R1 0 |
#define SECP224R1 1 |
#define SECP256R1 2 |
#define SECP384R1 3 |
#define SECP521R1 4 |
|
#ifndef ecc_point_equal_p |
static int ecc_point_equal_p(const struct ecc_point *a, const struct ecc_point *b) |
{ |
return (a->ecc == b->ecc) && !mpn_cmp(a->p, b->p, ecc_size_a(a->ecc)); |
} |
#endif |
|
/*! @class ECC_Curve |
*! |
*! Elliptic Curve Definition |
*/ |
PIKECLASS ECC_Curve |
{ |
/*! @decl inherit __builtin.Nettle.ECC_Curve |
*/ |
INHERIT "__builtin.Nettle.ECC_Curve"; |
|
CVAR const struct ecc_curve *curve; |
|
/* Initialized to the scalar constant 1. */ |
CVAR struct ecc_scalar scalar_one; |
|
DECLARE_STORAGE; |
|
EXIT |
{ |
if (THIS->curve) { |
ecc_scalar_clear(&THIS->scalar_one); |
} |
} |
|
/*! @decl void create(int(0..) curve) |
*! |
*! Initialize the curve. |
*! |
*! @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 |
*/ |
PIKEFUN void create(int(0..) curve) |
flags ID_STATIC |
{ |
mpz_t mpz_one; |
|
if (THIS->curve) { |
Pike_error("The curve has already been initialized!\n"); |
} |
|
switch(curve) { |
#ifdef HAVE_CURVE_NETTLE_SECP_192R1 |
case SECP192R1: THIS->curve = &nettle_secp_192r1; break; |
#endif /* HAVE_CURVE_NETTLE_SECP_192R1 */ |
#ifdef HAVE_CURVE_NETTLE_SECP_224R1 |
case SECP224R1: THIS->curve = &nettle_secp_224r1; break; |
#endif /* HAVE_CURVE_NETTLE_SECP_224R1 */ |
#ifdef HAVE_CURVE_NETTLE_SECP_256R1 |
case SECP256R1: THIS->curve = &nettle_secp_256r1; break; |
#endif /* HAVE_CURVE_NETTLE_SECP_256R1 */ |
#ifdef HAVE_CURVE_NETTLE_SECP_384R1 |
case SECP384R1: THIS->curve = &nettle_secp_384r1; break; |
#endif /* HAVE_CURVE_NETTLE_SECP_384R1 */ |
#ifdef HAVE_CURVE_NETTLE_SECP_521R1 |
case SECP521R1: THIS->curve = &nettle_secp_521r1; break; |
#endif /* HAVE_CURVE_NETTLE_SECP_521R1 */ |
default: |
Pike_error("Invalid curve\n"); |
break; |
} |
|
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); |
} |
|
/*! @decl protected local int(0..1) `==(mixed x) |
*! |
*! @returns |
*! Returns @expr{1@} if @[x] is the same @[Curve], |
*! and @expr{0@} (zero) otherwise. |
*/ |
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; |
} |
|
/*! @decl string(7bit) name() |
*! |
*! Returns the name of the curve. |
*! |
*! @seealso |
*! @[jose_name()] |
*/ |
PIKEFUN string(7bit) name() |
{ |
#ifdef HAVE_CURVE_NETTLE_SECP_192R1 |
if (THIS->curve == &nettle_secp_192r1) { |
ref_push_string(MK_STRING("SECP_192R1")); |
return; |
} |
#endif /* HAVE_CURVE_NETTLE_SECP_192R1 */ |
#ifdef HAVE_CURVE_NETTLE_SECP_224R1 |
if (THIS->curve == &nettle_secp_224r1) { |
ref_push_string(MK_STRING("SECP_224R1")); |
return; |
} |
#endif /* HAVE_CURVE_NETTLE_SECP_224R1 */ |
#ifdef HAVE_CURVE_NETTLE_SECP_256R1 |
if (THIS->curve == &nettle_secp_256r1) { |
ref_push_string(MK_STRING("SECP_256R1")); |
return; |
} |
#endif /* HAVE_CURVE_NETTLE_SECP_256R1 */ |
#ifdef HAVE_CURVE_NETTLE_SECP_384R1 |
if (THIS->curve == &nettle_secp_384r1) { |
ref_push_string(MK_STRING("SECP_384R1")); |
return; |
} |
#endif /* HAVE_CURVE_NETTLE_SECP_384R1 */ |
#ifdef HAVE_CURVE_NETTLE_SECP_521R1 |
if (THIS->curve == &nettle_secp_521r1) { |
ref_push_string(MK_STRING("SECP_521R1")); |
return; |
} |
#endif /* HAVE_CURVE_NETTLE_SECP_521R1 */ |
ref_push_string(MK_STRING("UNKNOWN")); |
} |
|
/*! @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-256")); |
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(); |
} |
|
/*! @decl int size() |
*! |
*! @returns |
*! Returns the size in bits for a single coordinate on the curve. |
*/ |
PIKEFUN int size() |
{ |
#ifdef HAVE_NETTLE_ECC_BIT_SIZE |
push_int(ecc_bit_size(THIS->curve)); |
#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 |
} |
|
/*! @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 secret factor. |
*/ |
PIKEFUN object(Gmp.mpz) new_scalar(function(int(0..):string(8bit)) rnd) |
{ |
struct ecc_scalar s; |
struct object *ret; |
|
if (!THIS->curve) Pike_error("No curve defined.\n"); |
|
ecc_scalar_init(&s, THIS->curve); |
|
ecc_scalar_random(&s, rnd, random_func_wrapper); |
|
push_object(ret = fast_clone_object(bignum_program)); |
ecc_scalar_get(&s, (mpz_ptr)ret->storage); |
|
ecc_scalar_clear(&s); |
} |
|
static int Nettle_ECC_Curve_Point_program_fun_num; |
|
/*! @decl Point `*(Gmp.mpz|int 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 Nettle_ECC_Curve_Point `*(object(Gmp.mpz)|int scalar) |
{ |
struct ecc_scalar s; |
struct ecc_point r; |
struct object *x; |
struct object *y; |
|
if (!THIS->curve) Pike_error("No curve defined.\n"); |
|
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); |
push_object(x = fast_clone_object(bignum_program)); |
push_object(y = fast_clone_object(bignum_program)); |
ecc_point_get(&r, (mpz_ptr)x->storage, (mpz_ptr)y->storage); |
|
ecc_scalar_clear(&s); |
ecc_point_clear(&r); |
|
apply_current(Nettle_ECC_Curve_Point_program_fun_num, 2); |
} |
|
/*! @decl Point point_mul(Gmp.mpz|int x, Gmp.mpz|int y, @ |
*! Gmp.mpz|int scalar) |
*! |
*! Multiply a point on the curve by a scalar. |
*! |
*! A typical use is for Elliptic Curve Diffie Hellman (ECDH) key exchange. |
*! |
*! This is equivalent to @expr{(Point(x, y) * scalar)@}. |
*! |
*! @returns |
*! Returns the new @[Point] on the curve. |
*! |
*! @throws |
*! Throws an error if the point (@[x], @[y]) isn't on the curve. |
*/ |
PIKEFUN Nettle_ECC_Curve_Point point_mul(object(Gmp.mpz)|int x, |
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); |
|
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); |
ecc_point_clear(&p); |
|
apply_current(Nettle_ECC_Curve_Point_program_fun_num, 2); |
stack_pop_n_elems_keep_top(args); |
} |
|
/*! @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; |
|
/*! @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); |
} |
} |
} |
|
INIT |
{ |
const struct Nettle_ECC_Curve_struct *parent = |
parent_storage(1, Nettle_ECC_Curve_program); |
const struct ecc_curve *curve = parent->curve; |
|
if (!curve) Pike_error("No curve selected.\n"); |
ecc_point_init(&THIS->point, curve); |
|
/* Make sure that the point is on the curve by initializing it to 'g'. */ |
ecc_point_mul_g(&THIS->point, &parent->scalar_one); |
} |
|
EXIT |
{ |
const struct Nettle_ECC_Curve_struct *parent = |
parent_storage(1, Nettle_ECC_Curve_program); |
const struct ecc_curve *curve = parent->curve; |
|
if (!curve) return; |
ecc_point_clear(&THIS->point); |
} |
|
/*! @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 |
*! returns @expr{0@} (zero). |
*/ |
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); |
} |
|
/*! @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) |
flags ID_VARIANT; |
{ |
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 |
*/ |
|
/*! @class ECDSA |
*! |
*! Elliptic Curve Digital Signing Algorithm |
*/ |
PIKECLASS ECDSA |
program_flags PROGRAM_USES_PARENT|PROGRAM_NEEDS_PARENT|PROGRAM_CLEAR_STORAGE; |
{ |
/*! @decl inherit Point |
*! |
*! This point represents the public key. |
*/ |
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); |
} |
} |
} |
|
/*! @decl inherit __builtin.Nettle.Sign |
*/ |
INHERIT "__builtin.Nettle.Sign"; |
|
CVAR struct ecc_scalar key; |
|
PIKEVAR function(int(0..):string(0..255)) random |
flags ID_PROTECTED; |
|
INIT |
{ |
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 selected.\n"); |
ecc_scalar_init(&THIS->key, curve); |
|
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); |
} |
|
EXIT |
{ |
const struct ecc_curve *curve = |
(((const struct Nettle_ECC_Curve_struct *)parent_storage(1, Nettle_ECC_Curve_program))->curve); |
if (!curve) return; |
ecc_scalar_clear(&THIS->key); |
} |
|
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); |
} |
|
/*! @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(")); |
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 Gmp.mpz get_private_key() |
*! |
*! Get the private key. |
*/ |
PIKEFUN object(Gmp.mpz) get_private_key() |
{ |
struct object *ret; |
push_object(ret = fast_clone_object(bignum_program)); |
ecc_scalar_get(&THIS->key, (mpz_ptr)ret->storage); |
} |
|
/*! @decl void set_private_key(object(Gmp.mpz)|int k) |
*! |
*! Set the private key (and corresponding private key). |
*! |
*! @note |
*! Throws errors if the key isn't valid for the curve. |
*/ |
PIKEFUN void set_private_key(object(Gmp.mpz)|int k) |
{ |
struct ecc_point *pub; |
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."); |
} |
/* Set the corresponding public key, */ |
pub = &((struct Nettle_ECC_Curve_Point_struct *) |
get_inherited_storage(1, Nettle_ECC_Curve_Point_program))-> |
point; |
ecc_point_mul_g(pub, &THIS->key); |
} |
|
/*! @decl object(Gmp.mpz) get_x() |
*! |
*! Get the x coordinate of the public key. |
*! |
*! @seealso |
*! @[get_y()] |
*/ |
PIKEFUN object(Gmp.mpz) get_x() |
{ |
struct ecc_point *pub; |
struct object *ret; |
push_object(ret = fast_clone_object(bignum_program)); |
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); |
} |
|
/*! @decl object(Gmp.mpz) get_y() |
*! |
*! Get the y coordinate of the public key. |
*! |
*! @seealso |
*! @[get_x()] |
*/ |
PIKEFUN object(Gmp.mpz) get_y() |
{ |
struct ecc_point *pub; |
struct object *ret; |
push_object(ret = fast_clone_object(bignum_program)); |
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); |
} |
|
/*! @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) |
{ |
apply_current(f_Nettle_ECC_Curve_ECDSA_inherited_Point_set_fun_num, args); |
} |
|
/*! @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) 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) |
{ |
struct ecc_point *pub; |
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"); |
} |
|
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); |
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() |
{ |
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, |
&THIS->random, random_func_wrapper); |
} |
} |
/*! @endclass ECDSA |
*/ |
} |
|
/*! @endclass ECC_Curve |
*/ |
|
#endif /* HAVE_NETTLE_ECDSA_H */ |
|
#if defined(HAVE_NETTLE_EDDSA_H) && defined(HAVE_NETTLE_CURVE25519_H) |
#include <nettle/curve25519.h> |
|
#include <nettle/eddsa.h> |
|
/*! @class Curve25519 |
*! |
*! 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@} |
*/ |
PIKECLASS Curve25519 |
{ |
/*! @decl inherit __builtin.Nettle.ECC_Curve |
*/ |
INHERIT "__builtin.Nettle.ECC_Curve"; |
|
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 Point `*(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)); |
|
apply_current(Nettle_Curve25519_Point_program_fun_num, 1); |
} |
|
/*! @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 Point |
*! |
*! A point on an elliptic curve. |
*/ |
PIKECLASS Point |
program_flags PROGRAM_USES_PARENT|PROGRAM_NEEDS_PARENT|PROGRAM_CLEAR_STORAGE; |
{ |
PIKEVAR string(8bit) point flags ID_PRIVATE|ID_PROTECTED|ID_HIDDEN; |
|
/*! @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); |
} |
} |
} |
|
PIKEFUN void set(string(8bit) x, string(8bit)|void y) |
flags ID_VARIANT; |
{ |
if (x->len != CURVE25519_SIZE) { |
Pike_error("Invalid x.\n"); |
} |
if (y && y->len) { |
Pike_error("Invalid y.\n"); |
} |
if (THIS->point) { |
free_string(THIS->point); |
} |
add_ref(THIS->point = x); |
} |
|
/* NB: Little-endian byte-order! */ |
const p_wchar0 curve25519_scalar_one[CURVE25519_SIZE] = { |
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
}; |
|
PIKEFUN string(8bit) get_x() |
{ |
if (!THIS->point) { |
/* Default to 'g'. */ |
struct pike_string *res; |
res = begin_shared_string(CURVE25519_SIZE); |
curve25519_mul_g(STR0(res), curve25519_scalar_one); |
THIS->point = end_shared_string(res); |
} |
ref_push_string(THIS->point); |
} |
|
PIKEFUN string(8bit) get_y() |
{ |
push_text(""); |
} |
|
PIKEFUN void create(string(8bit)|Stdio_Buffer data) |
flags ID_PROTECTED|ID_VARIANT; |
{ |
if (TYPEOF(*data) == PIKE_T_OBJECT) { |
push_int(CURVE25519_SIZE); |
apply(data->u.object, "read", 1); |
} |
apply_current(f_Nettle_Curve25519_Point_set_fun_num, 1); |
} |
|
PIKEFUN Nettle_Curve25519_Point `*(string(8bit) scalar) |
flags ID_PROTECTED; |
{ |
struct pike_string *res; |
if (scalar->len != CURVE25519_SIZE) Pike_error("Invalid scalar.\n"); |
res = begin_shared_string(CURVE25519_SIZE); |
if (THIS->point) { |
curve25519_mul(STR0(res), STR0(scalar), STR0(THIS->point)); |
} else { |
curve25519_mul_g(STR0(res), STR0(scalar)); |
} |
push_string(end_shared_string(res)); |
|
apply_external(1, Nettle_Curve25519_Point_program_fun_num, 1); |
} |
} |
/*! @endclass Point |
*/ |
|
/*! @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 */ |
|
/*! @endmodule Nettle |
*/ |
|
void |
hogweed_init(void) |
{ |
INIT; |
|
#ifdef HAVE_NETTLE_ECDSA_H |
#ifdef HAVE_CURVE_NETTLE_SECP_192R1 |
ADD_INT_CONSTANT("SECP192R1", SECP192R1, 0); |
#endif /* HAVE_CURVE_NETTLE_SECP_192R1 */ |
#ifdef HAVE_CURVE_NETTLE_SECP_224R1 |
ADD_INT_CONSTANT("SECP224R1", SECP224R1, 0); |
#endif /* HAVE_CURVE_NETTLE_SECP_224R1 */ |
#ifdef HAVE_CURVE_NETTLE_SECP_256R1 |
ADD_INT_CONSTANT("SECP256R1", SECP256R1, 0); |
#endif /* HAVE_CURVE_NETTLE_SECP_256R1 */ |
#ifdef HAVE_CURVE_NETTLE_SECP_384R1 |
ADD_INT_CONSTANT("SECP384R1", SECP384R1, 0); |
#endif /* HAVE_CURVE_NETTLE_SECP_384R1 */ |
#ifdef HAVE_CURVE_NETTLE_SECP_521R1 |
ADD_INT_CONSTANT("SECP521R1", SECP521R1, 0); |
#endif /* HAVE_CURVE_NETTLE_SECP_521R1 */ |
#endif /* HAVE_NETTLE_ECDSA_H */ |
|
#ifdef NETTLE_CURVE25519_RFC7748 |
ADD_INT_CONSTANT("CURVE25519_RFC7748", 1, 0); |
#endif |
} |
|
void |
hogweed_exit(void) |
{ |
EXIT; |
} |
|
#endif |
|