| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public |  | 
| 2  * License, v. 2.0. If a copy of the MPL was not distributed with this |  | 
| 3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |  | 
| 4 |  | 
| 5 /* |  | 
| 6  * Diffie-Hellman parameter generation, key generation, and secret derivation. |  | 
| 7  * KEA secret generation and verification. |  | 
| 8  * |  | 
| 9  * $Id: dh.c,v 1.12 2012/06/14 18:55:10 wtc%google.com Exp $ |  | 
| 10  */ |  | 
| 11 #ifdef FREEBL_NO_DEPEND |  | 
| 12 #include "stubs.h" |  | 
| 13 #endif |  | 
| 14 |  | 
| 15 #include "prerr.h" |  | 
| 16 #include "secerr.h" |  | 
| 17 |  | 
| 18 #include "blapi.h" |  | 
| 19 #include "secitem.h" |  | 
| 20 #include "mpi.h" |  | 
| 21 #include "mpprime.h" |  | 
| 22 #include "secmpi.h" |  | 
| 23 |  | 
| 24 #define KEA_DERIVED_SECRET_LEN 128 |  | 
| 25 |  | 
| 26 /* Lengths are in bytes. */ |  | 
| 27 static unsigned int |  | 
| 28 dh_GetSecretKeyLen(unsigned int primeLen) |  | 
| 29 { |  | 
| 30     /* Based on Table 2 in NIST SP 800-57. */ |  | 
| 31     if (primeLen >= 1920) { /* 15360 bits */ |  | 
| 32         return 64;  /* 512 bits */ |  | 
| 33     } |  | 
| 34     if (primeLen >= 960) { /* 7680 bits */ |  | 
| 35         return 48;  /* 384 bits */ |  | 
| 36     } |  | 
| 37     if (primeLen >= 384) { /* 3072 bits */ |  | 
| 38         return 32;  /* 256 bits */ |  | 
| 39     } |  | 
| 40     if (primeLen >= 256) { /* 2048 bits */ |  | 
| 41         return 28;  /* 224 bits */ |  | 
| 42     } |  | 
| 43     return 20;  /* 160 bits */ |  | 
| 44 } |  | 
| 45 |  | 
| 46 SECStatus |  | 
| 47 DH_GenParam(int primeLen, DHParams **params) |  | 
| 48 { |  | 
| 49     PRArenaPool *arena; |  | 
| 50     DHParams *dhparams; |  | 
| 51     unsigned char *pb = NULL; |  | 
| 52     unsigned char *ab = NULL; |  | 
| 53     unsigned long counter = 0; |  | 
| 54     mp_int p, q, a, h, psub1, test; |  | 
| 55     mp_err err = MP_OKAY; |  | 
| 56     SECStatus rv = SECSuccess; |  | 
| 57     if (!params || primeLen < 0) { |  | 
| 58         PORT_SetError(SEC_ERROR_INVALID_ARGS); |  | 
| 59         return SECFailure; |  | 
| 60     } |  | 
| 61     arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE); |  | 
| 62     if (!arena) { |  | 
| 63         PORT_SetError(SEC_ERROR_NO_MEMORY); |  | 
| 64         return SECFailure; |  | 
| 65     } |  | 
| 66     dhparams = (DHParams *)PORT_ArenaZAlloc(arena, sizeof(DHParams)); |  | 
| 67     if (!dhparams) { |  | 
| 68         PORT_SetError(SEC_ERROR_NO_MEMORY); |  | 
| 69         PORT_FreeArena(arena, PR_TRUE); |  | 
| 70         return SECFailure; |  | 
| 71     } |  | 
| 72     dhparams->arena = arena; |  | 
| 73     MP_DIGITS(&p) = 0; |  | 
| 74     MP_DIGITS(&q) = 0; |  | 
| 75     MP_DIGITS(&a) = 0; |  | 
| 76     MP_DIGITS(&h) = 0; |  | 
| 77     MP_DIGITS(&psub1) = 0; |  | 
| 78     MP_DIGITS(&test) = 0; |  | 
| 79     CHECK_MPI_OK( mp_init(&p) ); |  | 
| 80     CHECK_MPI_OK( mp_init(&q) ); |  | 
| 81     CHECK_MPI_OK( mp_init(&a) ); |  | 
| 82     CHECK_MPI_OK( mp_init(&h) ); |  | 
| 83     CHECK_MPI_OK( mp_init(&psub1) ); |  | 
| 84     CHECK_MPI_OK( mp_init(&test) ); |  | 
| 85     /* generate prime with MPI, uses Miller-Rabin to generate strong prime. */ |  | 
| 86     pb = PORT_Alloc(primeLen); |  | 
| 87     CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(pb, primeLen) ); |  | 
| 88     pb[0]          |= 0x80; /* set high-order bit */ |  | 
| 89     pb[primeLen-1] |= 0x01; /* set low-order bit  */ |  | 
| 90     CHECK_MPI_OK( mp_read_unsigned_octets(&p, pb, primeLen) ); |  | 
| 91     CHECK_MPI_OK( mpp_make_prime(&p, primeLen * 8, PR_TRUE, &counter) ); |  | 
| 92     /* construct Sophie-Germain prime q = (p-1)/2. */ |  | 
| 93     CHECK_MPI_OK( mp_sub_d(&p, 1, &psub1) ); |  | 
| 94     CHECK_MPI_OK( mp_div_2(&psub1, &q)    ); |  | 
| 95     /* construct a generator from the prime. */ |  | 
| 96     ab = PORT_Alloc(primeLen); |  | 
| 97     /* generate a candidate number a in p's field */ |  | 
| 98     CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(ab, primeLen) ); |  | 
| 99     CHECK_MPI_OK( mp_read_unsigned_octets(&a, ab, primeLen) ); |  | 
| 100     /* force a < p (note that quot(a/p) <= 1) */ |  | 
| 101     if ( mp_cmp(&a, &p) > 0 ) |  | 
| 102         CHECK_MPI_OK( mp_sub(&a, &p, &a) ); |  | 
| 103     do { |  | 
| 104         /* check that a is in the range [2..p-1] */ |  | 
| 105         if ( mp_cmp_d(&a, 2) < 0 || mp_cmp(&a, &psub1) >= 0) { |  | 
| 106             /* a is outside of the allowed range.  Set a=3 and keep going. */ |  | 
| 107             mp_set(&a, 3); |  | 
| 108         } |  | 
| 109         /* if a**q mod p != 1 then a is a generator */ |  | 
| 110         CHECK_MPI_OK( mp_exptmod(&a, &q, &p, &test) ); |  | 
| 111         if ( mp_cmp_d(&test, 1) != 0 ) |  | 
| 112             break; |  | 
| 113         /* increment the candidate and try again. */ |  | 
| 114         CHECK_MPI_OK( mp_add_d(&a, 1, &a) ); |  | 
| 115     } while (PR_TRUE); |  | 
| 116     MPINT_TO_SECITEM(&p, &dhparams->prime, arena); |  | 
| 117     MPINT_TO_SECITEM(&a, &dhparams->base, arena); |  | 
| 118     *params = dhparams; |  | 
| 119 cleanup: |  | 
| 120     mp_clear(&p); |  | 
| 121     mp_clear(&q); |  | 
| 122     mp_clear(&a); |  | 
| 123     mp_clear(&h); |  | 
| 124     mp_clear(&psub1); |  | 
| 125     mp_clear(&test); |  | 
| 126     if (pb) PORT_ZFree(pb, primeLen); |  | 
| 127     if (ab) PORT_ZFree(ab, primeLen); |  | 
| 128     if (err) { |  | 
| 129         MP_TO_SEC_ERROR(err); |  | 
| 130         rv = SECFailure; |  | 
| 131     } |  | 
| 132     if (rv) |  | 
| 133         PORT_FreeArena(arena, PR_TRUE); |  | 
| 134     return rv; |  | 
| 135 } |  | 
| 136 |  | 
| 137 SECStatus |  | 
| 138 DH_NewKey(DHParams *params, DHPrivateKey **privKey) |  | 
| 139 { |  | 
| 140     PRArenaPool *arena; |  | 
| 141     DHPrivateKey *key; |  | 
| 142     mp_int g, xa, p, Ya; |  | 
| 143     mp_err   err = MP_OKAY; |  | 
| 144     SECStatus rv = SECSuccess; |  | 
| 145     if (!params || !privKey) { |  | 
| 146         PORT_SetError(SEC_ERROR_INVALID_ARGS); |  | 
| 147         return SECFailure; |  | 
| 148     } |  | 
| 149     arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE); |  | 
| 150     if (!arena) { |  | 
| 151         PORT_SetError(SEC_ERROR_NO_MEMORY); |  | 
| 152         return SECFailure; |  | 
| 153     } |  | 
| 154     key = (DHPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DHPrivateKey)); |  | 
| 155     if (!key) { |  | 
| 156         PORT_SetError(SEC_ERROR_NO_MEMORY); |  | 
| 157         PORT_FreeArena(arena, PR_TRUE); |  | 
| 158         return SECFailure; |  | 
| 159     } |  | 
| 160     key->arena = arena; |  | 
| 161     MP_DIGITS(&g)  = 0; |  | 
| 162     MP_DIGITS(&xa) = 0; |  | 
| 163     MP_DIGITS(&p)  = 0; |  | 
| 164     MP_DIGITS(&Ya) = 0; |  | 
| 165     CHECK_MPI_OK( mp_init(&g)  ); |  | 
| 166     CHECK_MPI_OK( mp_init(&xa) ); |  | 
| 167     CHECK_MPI_OK( mp_init(&p)  ); |  | 
| 168     CHECK_MPI_OK( mp_init(&Ya) ); |  | 
| 169     /* Set private key's p */ |  | 
| 170     CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->prime, ¶ms->prime) ); |  | 
| 171     SECITEM_TO_MPINT(key->prime, &p); |  | 
| 172     /* Set private key's g */ |  | 
| 173     CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->base, ¶ms->base) ); |  | 
| 174     SECITEM_TO_MPINT(key->base, &g); |  | 
| 175     /* Generate private key xa */ |  | 
| 176     SECITEM_AllocItem(arena, &key->privateValue, |  | 
| 177                       dh_GetSecretKeyLen(params->prime.len)); |  | 
| 178     RNG_GenerateGlobalRandomBytes(key->privateValue.data, |  | 
| 179                                   key->privateValue.len); |  | 
| 180     SECITEM_TO_MPINT( key->privateValue, &xa ); |  | 
| 181     /* xa < p */ |  | 
| 182     CHECK_MPI_OK( mp_mod(&xa, &p, &xa) ); |  | 
| 183     /* Compute public key Ya = g ** xa mod p */ |  | 
| 184     CHECK_MPI_OK( mp_exptmod(&g, &xa, &p, &Ya) ); |  | 
| 185     MPINT_TO_SECITEM(&Ya, &key->publicValue, key->arena); |  | 
| 186     *privKey = key; |  | 
| 187 cleanup: |  | 
| 188     mp_clear(&g); |  | 
| 189     mp_clear(&xa); |  | 
| 190     mp_clear(&p); |  | 
| 191     mp_clear(&Ya); |  | 
| 192     if (err) { |  | 
| 193         MP_TO_SEC_ERROR(err); |  | 
| 194         rv = SECFailure; |  | 
| 195     } |  | 
| 196     if (rv) |  | 
| 197         PORT_FreeArena(arena, PR_TRUE); |  | 
| 198     return rv; |  | 
| 199 } |  | 
| 200 |  | 
| 201 SECStatus |  | 
| 202 DH_Derive(SECItem *publicValue, |  | 
| 203           SECItem *prime, |  | 
| 204           SECItem *privateValue, |  | 
| 205           SECItem *derivedSecret, |  | 
| 206           unsigned int outBytes) |  | 
| 207 { |  | 
| 208     mp_int p, Xa, Yb, ZZ; |  | 
| 209     mp_err err = MP_OKAY; |  | 
| 210     int len = 0; |  | 
| 211     unsigned int nb; |  | 
| 212     unsigned char *secret = NULL; |  | 
| 213     if (!publicValue || !prime || !privateValue || !derivedSecret) { |  | 
| 214         PORT_SetError(SEC_ERROR_INVALID_ARGS); |  | 
| 215         return SECFailure; |  | 
| 216     } |  | 
| 217     memset(derivedSecret, 0, sizeof *derivedSecret); |  | 
| 218     MP_DIGITS(&p)  = 0; |  | 
| 219     MP_DIGITS(&Xa) = 0; |  | 
| 220     MP_DIGITS(&Yb) = 0; |  | 
| 221     MP_DIGITS(&ZZ) = 0; |  | 
| 222     CHECK_MPI_OK( mp_init(&p)  ); |  | 
| 223     CHECK_MPI_OK( mp_init(&Xa) ); |  | 
| 224     CHECK_MPI_OK( mp_init(&Yb) ); |  | 
| 225     CHECK_MPI_OK( mp_init(&ZZ) ); |  | 
| 226     SECITEM_TO_MPINT(*publicValue,  &Yb); |  | 
| 227     SECITEM_TO_MPINT(*privateValue, &Xa); |  | 
| 228     SECITEM_TO_MPINT(*prime,        &p); |  | 
| 229     /* ZZ = (Yb)**Xa mod p */ |  | 
| 230     CHECK_MPI_OK( mp_exptmod(&Yb, &Xa, &p, &ZZ) ); |  | 
| 231     /* number of bytes in the derived secret */ |  | 
| 232     len = mp_unsigned_octet_size(&ZZ); |  | 
| 233     if (len <= 0) { |  | 
| 234         err = MP_BADARG; |  | 
| 235         goto cleanup; |  | 
| 236     } |  | 
| 237     /* allocate a buffer which can hold the entire derived secret. */ |  | 
| 238     secret = PORT_Alloc(len); |  | 
| 239     /* grab the derived secret */ |  | 
| 240     err = mp_to_unsigned_octets(&ZZ, secret, len); |  | 
| 241     if (err >= 0) err = MP_OKAY; |  | 
| 242     /* |  | 
| 243     ** if outBytes is 0 take all of the bytes from the derived secret. |  | 
| 244     ** if outBytes is not 0 take exactly outBytes from the derived secret, zero |  | 
| 245     ** pad at the beginning if necessary, and truncate beginning bytes |  | 
| 246     ** if necessary. |  | 
| 247     */ |  | 
| 248     if (outBytes > 0) |  | 
| 249         nb = outBytes; |  | 
| 250     else |  | 
| 251         nb = len; |  | 
| 252     SECITEM_AllocItem(NULL, derivedSecret, nb); |  | 
| 253     if (len < nb) { |  | 
| 254         unsigned int offset = nb - len; |  | 
| 255         memset(derivedSecret->data, 0, offset); |  | 
| 256         memcpy(derivedSecret->data + offset, secret, len); |  | 
| 257     } else { |  | 
| 258         memcpy(derivedSecret->data, secret + len - nb, nb); |  | 
| 259     } |  | 
| 260 cleanup: |  | 
| 261     mp_clear(&p); |  | 
| 262     mp_clear(&Xa); |  | 
| 263     mp_clear(&Yb); |  | 
| 264     mp_clear(&ZZ); |  | 
| 265     if (secret) { |  | 
| 266         /* free the buffer allocated for the full secret. */ |  | 
| 267         PORT_ZFree(secret, len); |  | 
| 268     } |  | 
| 269     if (err) { |  | 
| 270         MP_TO_SEC_ERROR(err); |  | 
| 271         if (derivedSecret->data) |  | 
| 272             PORT_ZFree(derivedSecret->data, derivedSecret->len); |  | 
| 273         return SECFailure; |  | 
| 274     } |  | 
| 275     return SECSuccess; |  | 
| 276 } |  | 
| 277 |  | 
| 278 SECStatus |  | 
| 279 KEA_Derive(SECItem *prime, |  | 
| 280            SECItem *public1, |  | 
| 281            SECItem *public2, |  | 
| 282            SECItem *private1, |  | 
| 283            SECItem *private2, |  | 
| 284            SECItem *derivedSecret) |  | 
| 285 { |  | 
| 286     mp_int p, Y, R, r, x, t, u, w; |  | 
| 287     mp_err err; |  | 
| 288     unsigned char *secret = NULL; |  | 
| 289     unsigned int len = 0, offset; |  | 
| 290     if (!prime || !public1 || !public2 || !private1 || !private2 || |  | 
| 291         !derivedSecret) { |  | 
| 292         PORT_SetError(SEC_ERROR_INVALID_ARGS); |  | 
| 293         return SECFailure; |  | 
| 294     } |  | 
| 295     memset(derivedSecret, 0, sizeof *derivedSecret); |  | 
| 296     MP_DIGITS(&p) = 0; |  | 
| 297     MP_DIGITS(&Y) = 0; |  | 
| 298     MP_DIGITS(&R) = 0; |  | 
| 299     MP_DIGITS(&r) = 0; |  | 
| 300     MP_DIGITS(&x) = 0; |  | 
| 301     MP_DIGITS(&t) = 0; |  | 
| 302     MP_DIGITS(&u) = 0; |  | 
| 303     MP_DIGITS(&w) = 0; |  | 
| 304     CHECK_MPI_OK( mp_init(&p) ); |  | 
| 305     CHECK_MPI_OK( mp_init(&Y) ); |  | 
| 306     CHECK_MPI_OK( mp_init(&R) ); |  | 
| 307     CHECK_MPI_OK( mp_init(&r) ); |  | 
| 308     CHECK_MPI_OK( mp_init(&x) ); |  | 
| 309     CHECK_MPI_OK( mp_init(&t) ); |  | 
| 310     CHECK_MPI_OK( mp_init(&u) ); |  | 
| 311     CHECK_MPI_OK( mp_init(&w) ); |  | 
| 312     SECITEM_TO_MPINT(*prime,    &p); |  | 
| 313     SECITEM_TO_MPINT(*public1,  &Y); |  | 
| 314     SECITEM_TO_MPINT(*public2,  &R); |  | 
| 315     SECITEM_TO_MPINT(*private1, &r); |  | 
| 316     SECITEM_TO_MPINT(*private2, &x); |  | 
| 317     /* t = DH(Y, r, p) = Y ** r mod p */ |  | 
| 318     CHECK_MPI_OK( mp_exptmod(&Y, &r, &p, &t) ); |  | 
| 319     /* u = DH(R, x, p) = R ** x mod p */ |  | 
| 320     CHECK_MPI_OK( mp_exptmod(&R, &x, &p, &u) ); |  | 
| 321     /* w = (t + u) mod p */ |  | 
| 322     CHECK_MPI_OK( mp_addmod(&t, &u, &p, &w) ); |  | 
| 323     /* allocate a buffer for the full derived secret */ |  | 
| 324     len = mp_unsigned_octet_size(&w); |  | 
| 325     secret = PORT_Alloc(len); |  | 
| 326     /* grab the secret */ |  | 
| 327     err = mp_to_unsigned_octets(&w, secret, len); |  | 
| 328     if (err > 0) err = MP_OKAY; |  | 
| 329     /* allocate output buffer */ |  | 
| 330     SECITEM_AllocItem(NULL, derivedSecret, KEA_DERIVED_SECRET_LEN); |  | 
| 331     memset(derivedSecret->data, 0, derivedSecret->len); |  | 
| 332     /* copy in the 128 lsb of the secret */ |  | 
| 333     if (len >= KEA_DERIVED_SECRET_LEN) { |  | 
| 334         memcpy(derivedSecret->data, secret + (len - KEA_DERIVED_SECRET_LEN), |  | 
| 335                KEA_DERIVED_SECRET_LEN); |  | 
| 336     } else { |  | 
| 337         offset = KEA_DERIVED_SECRET_LEN - len; |  | 
| 338         memcpy(derivedSecret->data + offset, secret, len); |  | 
| 339     } |  | 
| 340 cleanup: |  | 
| 341     mp_clear(&p); |  | 
| 342     mp_clear(&Y); |  | 
| 343     mp_clear(&R); |  | 
| 344     mp_clear(&r); |  | 
| 345     mp_clear(&x); |  | 
| 346     mp_clear(&t); |  | 
| 347     mp_clear(&u); |  | 
| 348     mp_clear(&w); |  | 
| 349     if (secret) |  | 
| 350         PORT_ZFree(secret, len); |  | 
| 351     if (err) { |  | 
| 352         MP_TO_SEC_ERROR(err); |  | 
| 353         return SECFailure; |  | 
| 354     } |  | 
| 355     return SECSuccess; |  | 
| 356 } |  | 
| 357 |  | 
| 358 PRBool |  | 
| 359 KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime) |  | 
| 360 { |  | 
| 361     mp_int p, q, y, r; |  | 
| 362     mp_err err; |  | 
| 363     int cmp = 1;  /* default is false */ |  | 
| 364     if (!Y || !prime || !subPrime) { |  | 
| 365         PORT_SetError(SEC_ERROR_INVALID_ARGS); |  | 
| 366         return SECFailure; |  | 
| 367     } |  | 
| 368     MP_DIGITS(&p) = 0; |  | 
| 369     MP_DIGITS(&q) = 0; |  | 
| 370     MP_DIGITS(&y) = 0; |  | 
| 371     MP_DIGITS(&r) = 0; |  | 
| 372     CHECK_MPI_OK( mp_init(&p) ); |  | 
| 373     CHECK_MPI_OK( mp_init(&q) ); |  | 
| 374     CHECK_MPI_OK( mp_init(&y) ); |  | 
| 375     CHECK_MPI_OK( mp_init(&r) ); |  | 
| 376     SECITEM_TO_MPINT(*prime,    &p); |  | 
| 377     SECITEM_TO_MPINT(*subPrime, &q); |  | 
| 378     SECITEM_TO_MPINT(*Y,        &y); |  | 
| 379     /* compute r = y**q mod p */ |  | 
| 380     CHECK_MPI_OK( mp_exptmod(&y, &q, &p, &r) ); |  | 
| 381     /* compare to 1 */ |  | 
| 382     cmp = mp_cmp_d(&r, 1); |  | 
| 383 cleanup: |  | 
| 384     mp_clear(&p); |  | 
| 385     mp_clear(&q); |  | 
| 386     mp_clear(&y); |  | 
| 387     mp_clear(&r); |  | 
| 388     if (err) { |  | 
| 389         MP_TO_SEC_ERROR(err); |  | 
| 390         return PR_FALSE; |  | 
| 391     } |  | 
| 392     return (cmp == 0) ? PR_TRUE : PR_FALSE; |  | 
| 393 } |  | 
| OLD | NEW | 
|---|