/* returns zero on success. Fails if the number is zero. */ int _gnutls_mpi_scan_nz (bigint_t * ret_mpi, const void *buffer, size_t nbytes) { int ret; ret = _gnutls_mpi_scan (ret_mpi, buffer, nbytes); if (ret < 0) return ret; /* MPIs with 0 bits are illegal */ if (_gnutls_mpi_cmp_ui (*ret_mpi, 0) == 0) { _gnutls_mpi_release (ret_mpi); return GNUTLS_E_MPI_SCAN_FAILED; } return 0; }
/* this function reads an integer * from asn1 structs. Combines the read and mpi_scan * steps. */ int _gnutls_x509_read_int (ASN1_TYPE node, const char *value, bigint_t * ret_mpi) { int result; opaque *tmpstr = NULL; int tmpstr_size; tmpstr_size = 0; result = asn1_read_value (node, value, NULL, &tmpstr_size); if (result != ASN1_MEM_ERROR) { gnutls_assert (); return _gnutls_asn2err (result); } tmpstr = gnutls_malloc (tmpstr_size); if (tmpstr == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } result = asn1_read_value (node, value, tmpstr, &tmpstr_size); if (result != ASN1_SUCCESS) { gnutls_assert (); gnutls_free (tmpstr); return _gnutls_asn2err (result); } result = _gnutls_mpi_scan (ret_mpi, tmpstr, tmpstr_size); gnutls_free (tmpstr); if (result < 0) { gnutls_assert (); return result; } return 0; }
/* ID should be: * 3 for MAC * 2 for IV * 1 for encryption key */ int _gnutls_pkcs12_string_to_key (unsigned int id, const opaque * salt, unsigned int salt_size, unsigned int iter, const char *pw, unsigned int req_keylen, opaque * keybuf) { int rc; unsigned int i, j; digest_hd_st md; bigint_t num_b1 = NULL, num_ij = NULL; bigint_t mpi512 = NULL; unsigned int pwlen; opaque hash[20], buf_b[64], buf_i[128], *p; size_t cur_keylen; size_t n; const opaque buf_512[] = /* 2^64 */ { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; cur_keylen = 0; if (pw == NULL) pwlen = 0; else pwlen = strlen (pw); if (pwlen > 63 / 2) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if ((rc = _pkcs12_check_pass (pw, pwlen)) < 0) { gnutls_assert (); return rc; } rc = _gnutls_mpi_scan (&mpi512, buf_512, sizeof (buf_512)); if (rc < 0) { gnutls_assert (); return rc; } /* Store salt and password in BUF_I */ p = buf_i; for (i = 0; i < 64; i++) *p++ = salt[i % salt_size]; if (pw) { for (i = j = 0; i < 64; i += 2) { *p++ = 0; *p++ = pw[j]; if (++j > pwlen) /* Note, that we include the trailing zero */ j = 0; } } else memset (p, 0, 64); for (;;) { rc = _gnutls_hash_init (&md, GNUTLS_MAC_SHA1); if (rc < 0) { gnutls_assert (); goto cleanup; } for (i = 0; i < 64; i++) { unsigned char lid = id & 0xFF; _gnutls_hash (&md, &lid, 1); } _gnutls_hash (&md, buf_i, pw ? 128 : 64); _gnutls_hash_deinit (&md, hash); for (i = 1; i < iter; i++) { rc = _gnutls_hash_init (&md, GNUTLS_MAC_SHA1); if (rc < 0) { gnutls_assert (); goto cleanup; } _gnutls_hash (&md, hash, 20); _gnutls_hash_deinit (&md, hash); } for (i = 0; i < 20 && cur_keylen < req_keylen; i++) keybuf[cur_keylen++] = hash[i]; if (cur_keylen == req_keylen) { rc = 0; /* ready */ goto cleanup; } /* need more bytes. */ for (i = 0; i < 64; i++) buf_b[i] = hash[i % 20]; n = 64; rc = _gnutls_mpi_scan (&num_b1, buf_b, n); if (rc < 0) { gnutls_assert (); goto cleanup; } _gnutls_mpi_add_ui (num_b1, num_b1, 1); for (i = 0; i < 128; i += 64) { n = 64; rc = _gnutls_mpi_scan (&num_ij, buf_i + i, n); if (rc < 0) { gnutls_assert (); goto cleanup; } _gnutls_mpi_addm (num_ij, num_ij, num_b1, mpi512); n = 64; rc = _gnutls_mpi_print (num_ij, buf_i + i, &n); if (rc < 0) { gnutls_assert (); goto cleanup; } _gnutls_mpi_release (&num_ij); } } cleanup: _gnutls_mpi_release (&num_ij); _gnutls_mpi_release (&num_b1); _gnutls_mpi_release (&mpi512); return rc; }
/* ID should be: * 3 for MAC * 2 for IV * 1 for encryption key * * Note that this function produces different key for the * NULL password, and for the password with zero length. */ int _gnutls_pkcs12_string_to_key (unsigned int id, const uint8_t * salt, unsigned int salt_size, unsigned int iter, const char *pw, unsigned int req_keylen, uint8_t * keybuf) { int rc; unsigned int i, j; digest_hd_st md; bigint_t num_b1 = NULL, num_ij = NULL; bigint_t mpi512 = NULL; unsigned int pwlen; uint8_t hash[20], buf_b[64], buf_i[MAX_PASS_LEN*2+64], *p; uint8_t d[64]; size_t cur_keylen; size_t n, m, p_size, i_size; const uint8_t buf_512[] = /* 2^64 */ { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; cur_keylen = 0; if (pw == NULL) pwlen = 0; else pwlen = strlen (pw); if (pwlen > MAX_PASS_LEN) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if ((rc = _pkcs12_check_pass (pw, pwlen)) < 0) { gnutls_assert (); return rc; } rc = _gnutls_mpi_scan (&mpi512, buf_512, sizeof (buf_512)); if (rc < 0) { gnutls_assert (); return rc; } /* Store salt and password in BUF_I */ p_size = ((pwlen/64)*64) + 64; if (p_size > sizeof(buf_i)-64) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); p = buf_i; for (i = 0; i < 64; i++) *p++ = salt[i % salt_size]; if (pw) { for (i = j = 0; i < p_size; i += 2) { *p++ = 0; *p++ = pw[j]; if (++j > pwlen) /* Note, that we include the trailing (0) */ j = 0; } } else memset (p, 0, p_size); i_size = 64+p_size; for (;;) { rc = _gnutls_hash_init (&md, GNUTLS_MAC_SHA1); if (rc < 0) { gnutls_assert (); goto cleanup; } memset(d, id & 0xff, 64); _gnutls_hash (&md, d, 64); _gnutls_hash (&md, buf_i, pw ? i_size : 64); _gnutls_hash_deinit (&md, hash); for (i = 1; i < iter; i++) { rc = _gnutls_hash_fast (GNUTLS_MAC_SHA1, hash, 20, hash); if (rc < 0) { gnutls_assert (); goto cleanup; } } for (i = 0; i < 20 && cur_keylen < req_keylen; i++) keybuf[cur_keylen++] = hash[i]; if (cur_keylen == req_keylen) { rc = 0; /* ready */ goto cleanup; } /* need more bytes. */ for (i = 0; i < 64; i++) buf_b[i] = hash[i % 20]; n = 64; rc = _gnutls_mpi_scan (&num_b1, buf_b, n); if (rc < 0) { gnutls_assert (); goto cleanup; } _gnutls_mpi_add_ui (num_b1, num_b1, 1); for (i = 0; i < 128; i += 64) { n = 64; rc = _gnutls_mpi_scan (&num_ij, buf_i + i, n); if (rc < 0) { gnutls_assert (); goto cleanup; } _gnutls_mpi_addm (num_ij, num_ij, num_b1, mpi512); n = 64; #ifndef PKCS12_BROKEN_KEYGEN m = (_gnutls_mpi_get_nbits (num_ij) + 7) / 8; #else m = n; #endif memset (buf_i + i, 0, n - m); rc = _gnutls_mpi_print (num_ij, buf_i + i + n - m, &n); if (rc < 0) { gnutls_assert (); goto cleanup; } _gnutls_mpi_release (&num_ij); } } cleanup: _gnutls_mpi_release (&num_ij); _gnutls_mpi_release (&num_b1); _gnutls_mpi_release (&mpi512); return rc; }
bigint_t _gnutls_mpi_randomize (bigint_t r, unsigned int bits, gnutls_rnd_level_t level) { size_t size = 1 + (bits / 8); int ret; int rem, i; bigint_t tmp; char tmpbuf[512]; opaque *buf; int buf_release = 0; if (size < sizeof (tmpbuf)) { buf = tmpbuf; } else { buf = gnutls_malloc (size); if (buf == NULL) { gnutls_assert (); goto cleanup; } buf_release = 1; } ret = _gnutls_rnd (level, buf, size); if (ret < 0) { gnutls_assert (); goto cleanup; } /* mask the bits that weren't requested */ rem = bits % 8; if (rem == 0) { buf[0] = 0; } else { for (i = 8; i >= rem; i--) buf[0] = clearbit (buf[0], i); } ret = _gnutls_mpi_scan (&tmp, buf, size); if (ret < 0) { gnutls_assert (); goto cleanup; } if (buf_release != 0) { gnutls_free (buf); buf = NULL; } if (r != NULL) { _gnutls_mpi_set (r, tmp); _gnutls_mpi_release (&tmp); return r; } return tmp; cleanup: if (buf_release != 0) gnutls_free (buf); return NULL; }