pike.git
/
src
/
post_modules
/
Nettle
/
hogweed.cmod
version
»
Context lines:
10
20
40
80
file
none
3
pike.git/src/post_modules/Nettle/hogweed.cmod:1:
+
/* -*- 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"
+
#include "operators.h"
+
#include "interpret.h"
+
#include "module.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_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
+
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;
+
+
DECLARE_STORAGE;
+
+
/*! @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
+
{
+
if (THIS->curve) {
+
Pike_error("The curve has already been initialized!\n");
+
}
+
+
switch(curve) {
+
case SECP192R1: THIS->curve = &nettle_secp_192r1; break;
+
case SECP224R1: THIS->curve = &nettle_secp_224r1; break;
+
case SECP256R1: THIS->curve = &nettle_secp_256r1; break;
+
case SECP384R1: THIS->curve = &nettle_secp_384r1; break;
+
case SECP521R1: THIS->curve = &nettle_secp_521r1; break;
+
default:
+
Pike_error("Invalid curve\n");
+
break;
+
}
+
}
+
+
/*! @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.
+
*/
+
PIKEFUN string(7bit) name()
+
{
+
if (THIS->curve == &nettle_secp_192r1) {
+
ref_push_string(MK_STRING("SECP_192R1"));
+
} else if (THIS->curve == &nettle_secp_224r1) {
+
ref_push_string(MK_STRING("SECP_224R1"));
+
} else if (THIS->curve == &nettle_secp_256r1) {
+
ref_push_string(MK_STRING("SECP_256R1"));
+
} else if (THIS->curve == &nettle_secp_384r1) {
+
ref_push_string(MK_STRING("SECP_384R1"));
+
} else if (THIS->curve == &nettle_secp_521r1) {
+
ref_push_string(MK_STRING("SECP_521R1"));
+
} else {
+
ref_push_string(MK_STRING("UNKNOWN"));
+
}
+
}
+
+
/*! @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 exponent.
+
*/
+
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 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_point_init(&THIS->point, curve);
+
}
+
+
EXIT
+
{
+
const struct ecc_curve *curve =
+
(((const struct Nettle_ECC_Curve_struct *)parent_storage(1, Nettle_ECC_Curve_program))->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)
+
{
+
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);
+
push_constant_text("Crypto.Random.random_string");
+
APPLY_MASTER("resolv",1);
+
assign_svalue(&THIS->random, Pike_sp-1);
+
pop_stack();
+
}
+
+
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 */
+
+
/*! @endmodule Nettle
+
*/
+
+
void
+
hogweed_init(void)
+
{
+
INIT;
+
+
#ifdef HAVE_NETTLE_ECDSA_H
+
ADD_INT_CONSTANT("SECP192R1", SECP192R1, 0);
+
ADD_INT_CONSTANT("SECP224R1", SECP224R1, 0);
+
ADD_INT_CONSTANT("SECP256R1", SECP256R1, 0);
+
ADD_INT_CONSTANT("SECP384R1", SECP384R1, 0);
+
ADD_INT_CONSTANT("SECP521R1", SECP521R1, 0);
+
#endif /* HAVE_NETTLE_ECDSA_H */
+
}
+
+
void
+
hogweed_exit(void)
+
{
+
EXIT;
+
}
+
+
#endif
Newline at end of file added.