/* Helper to scan a hex string. */ static gcry_mpi_t scanval (const char *string) { gpg_err_code_t rc; gcry_mpi_t val; rc = _gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL); if (rc) log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (rc)); return val; }
gcry_mpi_t _gcry_ecc_ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p) { gpg_err_code_t rc; int pbytes = (mpi_get_nbits (p)+7)/8; size_t n; unsigned char *buf, *ptr; gcry_mpi_t result; buf = xmalloc ( 1 + 2*pbytes ); *buf = 04; /* Uncompressed point. */ ptr = buf+1; rc = _gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, x); if (rc) log_fatal ("mpi_print failed: %s\n", gpg_strerror (rc)); if (n < pbytes) { memmove (ptr+(pbytes-n), ptr, n); memset (ptr, 0, (pbytes-n)); } ptr += pbytes; rc = _gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, y); if (rc) log_fatal ("mpi_print failed: %s\n", gpg_strerror (rc)); if (n < pbytes) { memmove (ptr+(pbytes-n), ptr, n); memset (ptr, 0, (pbytes-n)); } rc = _gcry_mpi_scan (&result, GCRYMPI_FMT_USG, buf, 1+2*pbytes, NULL); if (rc) log_fatal ("mpi_scan failed: %s\n", gpg_strerror (rc)); xfree (buf); return result; }
/* * Generate a deterministic secret exponent K less than DSA_Q. H1 is * the to be signed digest with a length of HLEN bytes. HALGO is the * algorithm used to create the hash. On success the value for K is * stored at R_K. */ gpg_err_code_t _gcry_dsa_gen_rfc6979_k (gcry_mpi_t *r_k, gcry_mpi_t dsa_q, gcry_mpi_t dsa_x, const unsigned char *h1, unsigned int hlen, int halgo, unsigned int extraloops) { gpg_err_code_t rc; unsigned char *V = NULL; unsigned char *K = NULL; unsigned char *x_buf = NULL; unsigned char *h1_buf = NULL; gcry_md_hd_t hd = NULL; unsigned char *t = NULL; gcry_mpi_t k = NULL; unsigned int tbits, qbits; int i; qbits = mpi_get_nbits (dsa_q); if (!qbits || !h1 || !hlen) return GPG_ERR_EINVAL; if (_gcry_md_get_algo_dlen (halgo) != hlen) return GPG_ERR_DIGEST_ALGO; /* Step b: V = 0x01 0x01 0x01 ... 0x01 */ V = xtrymalloc (hlen); if (!V) { rc = gpg_err_code_from_syserror (); goto leave; } for (i=0; i < hlen; i++) V[i] = 1; /* Step c: K = 0x00 0x00 0x00 ... 0x00 */ K = xtrycalloc (1, hlen); if (!K) { rc = gpg_err_code_from_syserror (); goto leave; } rc = int2octets (&x_buf, dsa_x, (qbits+7)/8); if (rc) goto leave; rc = bits2octets (&h1_buf, h1, hlen*8, dsa_q, qbits); if (rc) goto leave; /* Create a handle to compute the HMACs. */ rc = _gcry_md_open (&hd, halgo, (GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC)); if (rc) goto leave; /* Step d: K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); _gcry_md_write (hd, "", 1); _gcry_md_write (hd, x_buf, (qbits+7)/8); _gcry_md_write (hd, h1_buf, (qbits+7)/8); memcpy (K, _gcry_md_read (hd, 0), hlen); /* Step e: V = HMAC_K(V) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); memcpy (V, _gcry_md_read (hd, 0), hlen); /* Step f: K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); _gcry_md_write (hd, "\x01", 1); _gcry_md_write (hd, x_buf, (qbits+7)/8); _gcry_md_write (hd, h1_buf, (qbits+7)/8); memcpy (K, _gcry_md_read (hd, 0), hlen); /* Step g: V = HMAC_K(V) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); memcpy (V, _gcry_md_read (hd, 0), hlen); /* Step h. */ t = xtrymalloc ((qbits+7)/8+hlen); if (!t) { rc = gpg_err_code_from_syserror (); goto leave; } again: for (tbits = 0; tbits < qbits;) { /* V = HMAC_K(V) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); memcpy (V, _gcry_md_read (hd, 0), hlen); /* T = T || V */ memcpy (t+(tbits+7)/8, V, hlen); tbits += 8*hlen; } /* k = bits2int (T) */ mpi_free (k); k = NULL; rc = _gcry_mpi_scan (&k, GCRYMPI_FMT_USG, t, (tbits+7)/8, NULL); if (rc) goto leave; if (tbits > qbits) mpi_rshift (k, k, tbits - qbits); /* Check: k < q and k > 1 */ if (!(mpi_cmp (k, dsa_q) < 0 && mpi_cmp_ui (k, 0) > 0)) { /* K = HMAC_K(V || 0x00) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); _gcry_md_write (hd, "", 1); memcpy (K, _gcry_md_read (hd, 0), hlen); /* V = HMAC_K(V) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); memcpy (V, _gcry_md_read (hd, 0), hlen); goto again; } /* The caller may have requested that we introduce some extra loops. This is for example useful if the caller wants another value for K because the last returned one yielded an R of 0. Because this is very unlikely we implement it in a straightforward way. */ if (extraloops) { extraloops--; /* K = HMAC_K(V || 0x00) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); _gcry_md_write (hd, "", 1); memcpy (K, _gcry_md_read (hd, 0), hlen); /* V = HMAC_K(V) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); memcpy (V, _gcry_md_read (hd, 0), hlen); goto again; } /* log_mpidump (" k", k); */ leave: xfree (t); _gcry_md_close (hd); xfree (h1_buf); xfree (x_buf); xfree (K); xfree (V); if (rc) mpi_free (k); else *r_k = k; return rc; }
/* Decode the EdDSA style encoded PK and set it into RESULT. CTX is the usual curve context. If R_ENCPK is not NULL, the encoded PK is stored at that address; this is a new copy to be released by the caller. In contrast to the supplied PK, this is not an MPI and thus guaranteed to be properly padded. R_ENCPKLEN receives the length of that encoded key. */ gpg_err_code_t _gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx, mpi_point_t result, unsigned char **r_encpk, unsigned int *r_encpklen) { gpg_err_code_t rc; unsigned char *rawmpi; unsigned int rawmpilen; int sign; if (mpi_is_opaque (pk)) { const unsigned char *buf; buf = mpi_get_opaque (pk, &rawmpilen); if (!buf) return GPG_ERR_INV_OBJ; rawmpilen = (rawmpilen + 7)/8; /* Handle compression prefixes. The size of the buffer will be odd in this case. */ if (rawmpilen > 1 && (rawmpilen%2)) { /* First check whether the public key has been given in standard uncompressed format (SEC1). No need to recover x in this case. */ if (buf[0] == 0x04) { gcry_mpi_t x, y; rc = _gcry_mpi_scan (&x, GCRYMPI_FMT_STD, buf+1, (rawmpilen-1)/2, NULL); if (rc) return rc; rc = _gcry_mpi_scan (&y, GCRYMPI_FMT_STD, buf+1+(rawmpilen-1)/2, (rawmpilen-1)/2,NULL); if (rc) { mpi_free (x); return rc; } if (r_encpk) { rc = eddsa_encode_x_y (x, y, ctx->nbits/8, 0, r_encpk, r_encpklen); if (rc) { mpi_free (x); mpi_free (y); return rc; } } mpi_snatch (result->x, x); mpi_snatch (result->y, y); mpi_set_ui (result->z, 1); return 0; } /* Check whether the public key has been prefixed with a 0x40 byte to explicitly indicate compressed format using a SEC1 alike prefix byte. This is a Libgcrypt extension. */ if (buf[0] == 0x40) { rawmpilen--; buf++; } } /* EdDSA compressed point. */ rawmpi = xtrymalloc (rawmpilen? rawmpilen:1); if (!rawmpi) return gpg_err_code_from_syserror (); memcpy (rawmpi, buf, rawmpilen); reverse_buffer (rawmpi, rawmpilen); } else { /* Note: Without using an opaque MPI it is not reliable possible to find out whether the public key has been given in uncompressed format. Thus we expect native EdDSA format. */ rawmpi = _gcry_mpi_get_buffer (pk, ctx->nbits/8, &rawmpilen, NULL); if (!rawmpi) return gpg_err_code_from_syserror (); } if (rawmpilen) { sign = !!(rawmpi[0] & 0x80); rawmpi[0] &= 0x7f; } else sign = 0; _gcry_mpi_set_buffer (result->y, rawmpi, rawmpilen, 0); if (r_encpk) { /* Revert to little endian. */ if (sign && rawmpilen) rawmpi[0] |= 0x80; reverse_buffer (rawmpi, rawmpilen); *r_encpk = rawmpi; if (r_encpklen) *r_encpklen = rawmpilen; } else xfree (rawmpi); rc = _gcry_ecc_eddsa_recover_x (result->x, result->y, sign, ctx); mpi_set_ui (result->z, 1); return rc; }
/* RESULT must have been initialized and is set on success to the point given by VALUE. */ gcry_err_code_t _gcry_ecc_os2ec (mpi_point_t result, gcry_mpi_t value) { gcry_err_code_t rc; size_t n; const unsigned char *buf; unsigned char *buf_memory; gcry_mpi_t x, y; if (mpi_is_opaque (value)) { unsigned int nbits; buf = mpi_get_opaque (value, &nbits); if (!buf) return GPG_ERR_INV_OBJ; n = (nbits + 7)/8; buf_memory = NULL; } else { n = (mpi_get_nbits (value)+7)/8; buf_memory = xmalloc (n); rc = _gcry_mpi_print (GCRYMPI_FMT_USG, buf_memory, n, &n, value); if (rc) { xfree (buf_memory); return rc; } buf = buf_memory; } if (n < 1) { xfree (buf_memory); return GPG_ERR_INV_OBJ; } if (*buf != 4) { xfree (buf_memory); return GPG_ERR_NOT_IMPLEMENTED; /* No support for point compression. */ } if ( ((n-1)%2) ) { xfree (buf_memory); return GPG_ERR_INV_OBJ; } n = (n-1)/2; rc = _gcry_mpi_scan (&x, GCRYMPI_FMT_USG, buf+1, n, NULL); if (rc) { xfree (buf_memory); return rc; } rc = _gcry_mpi_scan (&y, GCRYMPI_FMT_USG, buf+1+n, n, NULL); xfree (buf_memory); if (rc) { mpi_free (x); return rc; } mpi_set (result->x, x); mpi_set (result->y, y); mpi_set_ui (result->z, 1); mpi_free (x); mpi_free (y); return 0; }