/* $OpenBSD: math_group.c,v 1.18 2003/06/03 14:28:16 ho Exp $ */ /* $EOM: math_group.c,v 1.25 2000/04/07 19:53:26 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. All rights reserved. * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include "sysdep.h" #include "gmp_util.h" #include "log.h" #include "math_2n.h" #include "math_ec2n.h" #include "math_group.h" #include "math_mp.h" /* We do not want to export these definitions. */ int modp_getlen (struct group *); void modp_getraw (struct group *, math_mp_t, u_int8_t *); int modp_setraw (struct group *, math_mp_t, u_int8_t *, int); int modp_setrandom (struct group *, math_mp_t); int modp_operation (struct group *, math_mp_t, math_mp_t, math_mp_t); int ec2n_getlen (struct group *); void ec2n_getraw (struct group *, ec2np_ptr, u_int8_t *); int ec2n_setraw (struct group *, ec2np_ptr, u_int8_t *, int); int ec2n_setrandom (struct group *, ec2np_ptr); int ec2n_operation (struct group *, ec2np_ptr, ec2np_ptr, ec2np_ptr); struct ec2n_group { ec2np_t gen; /* Generator */ ec2ng_t grp; ec2np_t a, b, c, d; }; struct modp_group { math_mp_t gen; /* Generator */ math_mp_t p; /* Prime */ math_mp_t a, b, c, d; }; /* * This module provides access to the operations on the specified group * and is absolutly free of any cryptographic devices. This is math :-). */ #define OAKLEY_GRP_1 1 #define OAKLEY_GRP_2 2 #define OAKLEY_GRP_3 3 #define OAKLEY_GRP_4 4 #define OAKLEY_GRP_5 5 #ifdef not_until_IANA_assigns_the_groups #define OAKLEY_GRP_6 6 #define OAKLEY_GRP_7 7 #define OAKLEY_GRP_8 8 #define OAKLEY_GRP_9 9 #define OAKLEY_GRP_10 10 #define OAKLEY_GRP_11 11 #define OAKLEY_GRP_12 12 #define OAKLEY_GRP_13 13 #define OAKLEY_GRP_14 14 #define OAKLEY_GRP_15 15 #define OAKLEY_GRP_16 16 #define OAKLEY_GRP_17 17 #define OAKLEY_GRP_18 18 #endif /* IANA */ /* Describe preconfigured MODP groups */ /* * The Generalized Number Field Sieve has an asymptotic running time * of: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3))), where q is the * group order, e.g. q = 2**768. */ struct modp_dscr oakley_modp[] = { { OAKLEY_GRP_1, 72, /* This group is insecure, only sufficient for DES */ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", "0x02" }, { OAKLEY_GRP_2, 82, /* This group is a bit better */ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" "FFFFFFFFFFFFFFFF", "0x02" }, { OAKLEY_GRP_5, 102, /* This group is yet a bit better, but non-standard */ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" "83655D23DCA3AD961C62F356208552BB9ED529077096966D" "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", "0x02" }, #ifdef not_until_IANA_assigns_the_groups { OAKLEY_GRP_14, 135, /* 2048 bit, non-standard */ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" "83655D23DCA3AD961C62F356208552BB9ED529077096966D" "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" "15728E5A8AACAA68FFFFFFFFFFFFFFFF", "0x02" }, { OAKLEY_GRP_15, 170, /* 3072 bit, non-standard */ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" "83655D23DCA3AD961C62F356208552BB9ED529077096966D" "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", "0x02" }, { OAKLEY_GRP_16, 195, /* 4096 bit, non-standard */ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" "83655D23DCA3AD961C62F356208552BB9ED529077096966D" "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" "FFFFFFFFFFFFFFFF", "0x02" }, { OAKLEY_GRP_17, 220, /* 6144 bit, non-standard */ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" "83655D23DCA3AD961C62F356208552BB9ED529077096966D" "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF", "0x02" }, { OAKLEY_GRP_18, 250, /* 8192 bit, non-standard */ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" "83655D23DCA3AD961C62F356208552BB9ED529077096966D" "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", "0x02" }, #endif /* IANA */ }; #ifdef USE_EC /* Describe preconfigured EC2N groups */ /* * Related collision-search methods can compute discrete logarithmns * in O(sqrt(r)), r being the subgroup order. */ struct ec2n_dscr oakley_ec2n[] = { { OAKLEY_GRP_3, 76, /* This group is also considered insecure (P1363) */ "0x0800000000000000000000004000000000000001", "0x7b", "0x00", "0x7338f" }, { OAKLEY_GRP_4, 91, "0x020000000000000000000000000000200000000000000001", "0x18", "0x00", "0x1ee9" }, }; #endif /* USE_EC */ /* XXX I want to get rid of the casting here. */ struct group groups[] = { { MODP, OAKLEY_GRP_1, 0, &oakley_modp[0], 0, 0, 0, 0, 0, (int (*) (struct group *))modp_getlen, (void (*) (struct group *, void *, u_int8_t *))modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int))modp_setraw, (int (*) (struct group *, void *))modp_setrandom, (int (*) (struct group *, void *, void *, void *))modp_operation }, { MODP, OAKLEY_GRP_2, 0, &oakley_modp[1], 0, 0, 0, 0, 0, (int (*) (struct group *))modp_getlen, (void (*) (struct group *, void *, u_int8_t *))modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int))modp_setraw, (int (*) (struct group *, void *))modp_setrandom, (int (*) (struct group *, void *, void *, void *))modp_operation }, #ifdef USE_EC { EC2N, OAKLEY_GRP_3, 0, &oakley_ec2n[0], 0, 0, 0, 0, 0, (int (*) (struct group *))ec2n_getlen, (void (*) (struct group *, void *, u_int8_t *))ec2n_getraw, (int (*) (struct group *, void *, u_int8_t *, int))ec2n_setraw, (int (*) (struct group *, void *))ec2n_setrandom, (int (*) (struct group *, void *, void *, void *))ec2n_operation }, { EC2N, OAKLEY_GRP_4, 0, &oakley_ec2n[1], 0, 0, 0, 0, 0, (int (*) (struct group *))ec2n_getlen, (void (*) (struct group *, void *, u_int8_t *))ec2n_getraw, (int (*) (struct group *, void *, u_int8_t *, int))ec2n_setraw, (int (*) (struct group *, void *))ec2n_setrandom, (int (*) (struct group *, void *, void *, void *))ec2n_operation }, #endif /* USE_EC */ { MODP, OAKLEY_GRP_5, 0, &oakley_modp[2], 0, 0, 0, 0, 0, (int (*) (struct group *))modp_getlen, (void (*) (struct group *, void *, u_int8_t *))modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int))modp_setraw, (int (*) (struct group *, void *))modp_setrandom, (int (*) (struct group *, void *, void *, void *))modp_operation }, #ifdef USE_EC /* XXX Higher EC2N group go here... */ #endif /* USE_EC */ #ifdef not_until_IANA_assigns_the_groups { MODP, OAKLEY_GRP_14, 0, &oakley_modp[3], 0, 0, 0, 0, 0, (int (*) (struct group *))modp_getlen, (void (*) (struct group *, void *, u_int8_t *))modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int))modp_setraw, (int (*) (struct group *, void *))modp_setrandom, (int (*) (struct group *, void *, void *, void *))modp_operation }, { MODP, OAKLEY_GRP_15, 0, &oakley_modp[4], 0, 0, 0, 0, 0, (int (*) (struct group *))modp_getlen, (void (*) (struct group *, void *, u_int8_t *))modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int))modp_setraw, (int (*) (struct group *, void *))modp_setrandom, (int (*) (struct group *, void *, void *, void *))modp_operation }, { MODP, OAKLEY_GRP_16, 0, &oakley_modp[5], 0, 0, 0, 0, 0, (int (*) (struct group *))modp_getlen, (void (*) (struct group *, void *, u_int8_t *))modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int))modp_setraw, (int (*) (struct group *, void *))modp_setrandom, (int (*) (struct group *, void *, void *, void *))modp_operation }, { MODP, OAKLEY_GRP_17, 0, &oakley_modp[6], 0, 0, 0, 0, 0, (int (*) (struct group *))modp_getlen, (void (*) (struct group *, void *, u_int8_t *))modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int))modp_setraw, (int (*) (struct group *, void *))modp_setrandom, (int (*) (struct group *, void *, void *, void *))modp_operation }, { MODP, OAKLEY_GRP_18, 0, &oakley_modp[7], 0, 0, 0, 0, 0, (int (*) (struct group *))modp_getlen, (void (*) (struct group *, void *, u_int8_t *))modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int))modp_setraw, (int (*) (struct group *, void *))modp_setrandom, (int (*) (struct group *, void *, void *, void *))modp_operation }, #endif /* IANA */ }; /* * Initialize the group structure for later use, * this is done by converting the values given in the describtion * and converting them to their native representation. */ void group_init (void) { int i; for (i = sizeof (groups) / sizeof (groups[0]) - 1; i >= 0; i--) switch (groups[i].type) { #ifdef USE_EC case EC2N: /* Initialize an Elliptic Curve over GF(2**n) */ ec2n_init (&groups[i]); break; #endif case MODP: /* Initialize an over GF(p) */ modp_init (&groups[i]); break; default: log_print ("Unknown group type %d at index %d in group_init().", groups[i].type, i); break; } } struct group * group_get (int id) { struct group *new, *clone; if (id < 1 || id > (sizeof (groups) / sizeof (groups[0]))) { log_print ("group_get: group ID (%d) out of range", id); return 0; } clone = &groups[id - 1]; new = malloc (sizeof *new); if (!new) { log_error ("group_get: malloc (%lu) failed", (unsigned long)sizeof *new); return 0; } switch (clone->type) { #ifdef USE_EC case EC2N: new = ec2n_clone (new, clone); break; #endif case MODP: new = modp_clone (new, clone); break; default: log_print ("group_get: unknown group type %d", clone->type); free (new); return 0; } LOG_DBG ((LOG_MISC, 70, "group_get: returning %p of group %d", new, new->id)); return new; } void group_free (struct group *grp) { switch (grp->type) { #ifdef USE_EC case EC2N: ec2n_free (grp); break; #endif case MODP: modp_free (grp); break; default: log_print ("group_free: unknown group type %d", grp->type); break; } free (grp); } struct group * modp_clone (struct group *new, struct group *clone) { struct modp_group *new_grp, *clone_grp = clone->group; new_grp = malloc (sizeof *new_grp); if (!new_grp) { log_print ("modp_clone: malloc (%lu) failed", (unsigned long)sizeof *new_grp); free (new); return 0; } memcpy (new, clone, sizeof (struct group)); new->group = new_grp; #if MP_FLAVOUR == MP_FLAVOUR_GMP mpz_init_set (new_grp->p, clone_grp->p); mpz_init_set (new_grp->gen, clone_grp->gen); mpz_init (new_grp->a); mpz_init (new_grp->b); mpz_init (new_grp->c); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL new_grp->p = BN_dup (clone_grp->p); new_grp->gen = BN_dup (clone_grp->gen); new_grp->a = BN_new (); new_grp->b = BN_new (); new_grp->c = BN_new (); #endif new->gen = new_grp->gen; new->a = new_grp->a; new->b = new_grp->b; new->c = new_grp->c; return new; } void modp_free (struct group *old) { struct modp_group *grp = old->group; #if MP_FLAVOUR == MP_FLAVOUR_GMP mpz_clear (grp->p); mpz_clear (grp->gen); mpz_clear (grp->a); mpz_clear (grp->b); mpz_clear (grp->c); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL BN_clear_free (grp->p); BN_clear_free (grp->gen); BN_clear_free (grp->a); BN_clear_free (grp->b); BN_clear_free (grp->c); #endif free (grp); } void modp_init (struct group *group) { struct modp_dscr *dscr = (struct modp_dscr *)group->group; struct modp_group *grp; grp = malloc (sizeof *grp); if (!grp) log_fatal ("modp_init: malloc (%lu) failed", (unsigned long)sizeof *grp); group->bits = dscr->bits; #if MP_FLAVOUR == MP_FLAVOUR_GMP mpz_init_set_str (grp->p, dscr->prime, 0); mpz_init_set_str (grp->gen, dscr->gen, 0); mpz_init (grp->a); mpz_init (grp->b); mpz_init (grp->c); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL grp->p = BN_new (); BN_hex2bn (&grp->p, dscr->prime + 2); grp->gen = BN_new (); BN_hex2bn (&grp->gen, dscr->gen + 2); grp->a = BN_new (); grp->b = BN_new (); grp->c = BN_new (); #endif group->gen = grp->gen; group->a = grp->a; group->b = grp->b; group->c = grp->c; group->group = grp; } #ifdef USE_EC struct group * ec2n_clone (struct group *new, struct group *clone) { struct ec2n_group *new_grp, *clone_grp = clone->group; new_grp = malloc (sizeof *new_grp); if (!new_grp) { log_error ("ec2n_clone: malloc (%lu) failed", (unsigned long)sizeof *new_grp); free (new); return 0; } memcpy (new, clone, sizeof (struct group)); new->group = new_grp; ec2ng_init (new_grp->grp); ec2np_init (new_grp->gen); ec2np_init (new_grp->a); ec2np_init (new_grp->b); ec2np_init (new_grp->c); if (ec2ng_set (new_grp->grp, clone_grp->grp)) goto fail; if (ec2np_set (new_grp->gen, clone_grp->gen)) goto fail; new->gen = new_grp->gen; new->a = new_grp->a; new->b = new_grp->b; new->c = new_grp->c; new->d = ((ec2np_ptr)new->a)->x; return new; fail: ec2ng_clear (new_grp->grp); ec2np_clear (new_grp->gen); ec2np_clear (new_grp->a); ec2np_clear (new_grp->b); ec2np_clear (new_grp->c); free (new_grp); free (new); return 0; } void ec2n_free (struct group *old) { struct ec2n_group *grp = old->group; ec2ng_clear (grp->grp); ec2np_clear (grp->gen); ec2np_clear (grp->a); ec2np_clear (grp->b); ec2np_clear (grp->c); free (grp); } void ec2n_init (struct group *group) { struct ec2n_dscr *dscr = (struct ec2n_dscr *)group->group; struct ec2n_group *grp; grp = malloc (sizeof *grp); if (!grp) log_fatal ("ec2n_init: malloc (%lu) failed", (unsigned long)sizeof *grp); group->bits = dscr->bits; ec2ng_init (grp->grp); ec2np_init (grp->gen); ec2np_init (grp->a); ec2np_init (grp->b); ec2np_init (grp->c); if (ec2ng_set_p_str (grp->grp, dscr->polynomial)) goto fail; grp->grp->p->bits = b2n_sigbit (grp->grp->p); if (ec2ng_set_a_str (grp->grp, dscr->a)) goto fail; if (ec2ng_set_b_str (grp->grp, dscr->b)) goto fail; if (ec2np_set_x_str (grp->gen, dscr->gen_x)) goto fail; if (ec2np_find_y (grp->gen, grp->grp)) goto fail; /* Sanity check */ if (!ec2np_ison (grp->gen, grp->grp)) log_fatal ("ec2n_init: generator is not on curve"); group->gen = grp->gen; group->a = grp->a; group->b = grp->b; group->c = grp->c; group->d = ((ec2np_ptr)group->a)->x; group->group = grp; return; fail: log_fatal ("ec2n_init: general failure"); } #endif /* USE_EC */ int modp_getlen (struct group *group) { struct modp_group *grp = (struct modp_group *)group->group; return mpz_sizeinoctets (grp->p); } void modp_getraw (struct group *grp, math_mp_t v, u_int8_t *d) { mpz_getraw (d, v, grp->getlen (grp)); } int modp_setraw (struct group *grp, math_mp_t d, u_int8_t *s, int l) { mpz_setraw (d, s, l); return 0; } int modp_setrandom (struct group *grp, math_mp_t d) { int i, l = grp->getlen (grp); u_int32_t tmp = 0; #if MP_FLAVOUR == MP_FLAVOUR_GMP mpz_set_ui (d, 0); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL BN_set_word (d, 0); #endif for (i = 0; i < l; i++) { if (i % 4) tmp = sysdep_random (); #if MP_FLAVOUR == MP_FLAVOUR_GMP mpz_mul_2exp (d, d, 8); mpz_add_ui (d, d, tmp & 0xFF); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL BN_lshift (d, d, 8); BN_add_word (d, tmp & 0xFF); #endif tmp >>= 8; } return 0; } int modp_operation (struct group *group, math_mp_t d, math_mp_t a, math_mp_t e) { struct modp_group *grp = (struct modp_group *)group->group; #if MP_FLAVOUR == MP_FLAVOUR_GMP mpz_powm (d, a, e, grp->p); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL BN_CTX *ctx = BN_CTX_new (); BN_mod_exp (d, a, e, grp->p, ctx); BN_CTX_free (ctx); #endif return 0; } #ifdef USE_EC int ec2n_getlen (struct group *group) { struct ec2n_group *grp = (struct ec2n_group *)group->group; int bits = b2n_sigbit (grp->grp->p) - 1; return (7 + bits) >> 3; } void ec2n_getraw (struct group *group, ec2np_ptr xo, u_int8_t *e) { struct ec2n_group *grp = (struct ec2n_group *)group->group; int chunks, bytes, i, j; b2n_ptr x = xo->x; CHUNK_TYPE tmp; bytes = b2n_sigbit (grp->grp->p) - 1; chunks = (CHUNK_MASK + bytes) >> CHUNK_SHIFTS; bytes = ((7 + (bytes & CHUNK_MASK)) >> 3); for (i = chunks - 1; i >= 0; i--) { tmp = (i >= x->chunks ? 0 : x->limp[i]); for (j = (i == chunks - 1 ? bytes : CHUNK_BYTES) - 1; j >= 0; j--) { e[j] = tmp & 0xff; tmp >>= 8; } e += (i == chunks - 1 ? bytes : CHUNK_BYTES); } } int ec2n_setraw (struct group *grp, ec2np_ptr out, u_int8_t *s, int l) { int len, bytes, i, j; b2n_ptr outx = out->x; CHUNK_TYPE tmp; len = (CHUNK_BYTES - 1 + l) / CHUNK_BYTES; if (b2n_resize (outx, len)) return -1; bytes = ((l - 1) % CHUNK_BYTES) + 1; for (i = len - 1; i >= 0; i--) { tmp = 0; for (j = (i == len - 1 ? bytes : CHUNK_BYTES); j > 0; j--) { tmp <<= 8; tmp |= *s++; } outx->limp[i] = tmp; } return 0; } int ec2n_setrandom (struct group *group, ec2np_ptr x) { b2n_ptr d = x->x; struct ec2n_group *grp = (struct ec2n_group *)group->group; return b2n_random (d, b2n_sigbit (grp->grp->p) - 1); } /* * This is an attempt at operation abstraction. It can happen * that we need to initialize the y variable for the operation * to proceed correctly. When this is the case operation has * to supply the variable 'a' with the chunks of the Y cooridnate * set to zero. */ int ec2n_operation (struct group *grp, ec2np_ptr d, ec2np_ptr a, ec2np_ptr e) { b2n_ptr ex = e->x; struct ec2n_group *group = (struct ec2n_group *)grp->group; if (a->y->chunks == 0) if (ec2np_find_y (a, group->grp)) return -1; return ec2np_mul (d, a, ex, group->grp); } #endif /* USE_EC */