aboutsummaryrefslogtreecommitdiff
path: root/src/util/crypto_ecc.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-05-15 13:45:53 +0000
committerChristian Grothoff <christian@grothoff.org>2015-05-15 13:45:53 +0000
commit1fa44a546134cd03a827387b664a2bbee1a209f8 (patch)
treed65c7ce10c2b30fbdc498030fc240d95c1011eb6 /src/util/crypto_ecc.c
parentc0e6f18c0ebe60bff0437740d64a7de43b9304ca (diff)
downloadgnunet-1fa44a546134cd03a827387b664a2bbee1a209f8.tar.gz
gnunet-1fa44a546134cd03a827387b664a2bbee1a209f8.zip
ecdh-eddsa implementation now works
Diffstat (limited to 'src/util/crypto_ecc.c')
-rw-r--r--src/util/crypto_ecc.c193
1 files changed, 189 insertions, 4 deletions
diff --git a/src/util/crypto_ecc.c b/src/util/crypto_ecc.c
index c3a60e841..a29e27a44 100644
--- a/src/util/crypto_ecc.c
+++ b/src/util/crypto_ecc.c
@@ -1430,7 +1430,9 @@ derive_h (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1430 label, strlen (label), 1430 label, strlen (label),
1431 context, strlen (context), 1431 context, strlen (context),
1432 NULL, 0); 1432 NULL, 0);
1433 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof (hc)); 1433 GNUNET_CRYPTO_mpi_scan_unsigned (&h,
1434 (unsigned char *) &hc,
1435 sizeof (hc));
1434 return h; 1436 return h;
1435} 1437}
1436 1438
@@ -1466,7 +1468,9 @@ GNUNET_CRYPTO_ecdsa_private_key_derive (const struct GNUNET_CRYPTO_EcdsaPrivateK
1466 GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub); 1468 GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
1467 1469
1468 h = derive_h (&pub, label, context); 1470 h = derive_h (&pub, label, context);
1469 GNUNET_CRYPTO_mpi_scan_unsigned (&x, priv->d, sizeof (priv->d)); 1471 GNUNET_CRYPTO_mpi_scan_unsigned (&x,
1472 priv->d,
1473 sizeof (priv->d));
1470 d = gcry_mpi_new (256); 1474 d = gcry_mpi_new (256);
1471 gcry_mpi_mulm (d, h, x, n); 1475 gcry_mpi_mulm (d, h, x, n);
1472 gcry_mpi_release (h); 1476 gcry_mpi_release (h);
@@ -1543,6 +1547,78 @@ GNUNET_CRYPTO_ecdsa_public_key_derive (const struct GNUNET_CRYPTO_EcdsaPublicKey
1543 1547
1544 1548
1545/** 1549/**
1550 * Reverse the sequence of the bytes in @a buffer
1551 *
1552 * @param[in|out] buffer buffer to invert
1553 * @param length number of bytes in @a buffer
1554 */
1555static void
1556reverse_buffer (unsigned char *buffer,
1557 size_t length)
1558{
1559 unsigned char tmp;
1560 size_t i;
1561
1562 for (i=0; i < length/2; i++)
1563 {
1564 tmp = buffer[i];
1565 buffer[i] = buffer[length-1-i];
1566 buffer[length-1-i] = tmp;
1567 }
1568}
1569
1570
1571/**
1572 * Convert the secret @a d of an EdDSA key to the
1573 * value that is actually used in the EdDSA computation.
1574 *
1575 * @param d secret input
1576 * @return value used for the calculation in EdDSA
1577 */
1578static gcry_mpi_t
1579eddsa_d_to_a (gcry_mpi_t d)
1580{
1581 unsigned char rawmpi[32]; /* 256-bit value */
1582 size_t rawmpilen;
1583 unsigned char digest[64]; /* 512-bit hash value */
1584 gcry_buffer_t hvec[2];
1585 int b;
1586 gcry_mpi_t a;
1587
1588 b = 256 / 8; /* number of bytes in `d` */
1589
1590 /* Note that we clear DIGEST so we can use it as input to left pad
1591 the key with zeroes for hashing. */
1592 memset (hvec, 0, sizeof hvec);
1593 rawmpilen = sizeof (rawmpi);
1594 GNUNET_assert (0 ==
1595 gcry_mpi_print (GCRYMPI_FMT_USG,
1596 rawmpi, rawmpilen, &rawmpilen,
1597 d));
1598 hvec[0].data = digest;
1599 hvec[0].off = 0;
1600 hvec[0].len = b > rawmpilen? b - rawmpilen : 0;
1601 hvec[1].data = rawmpi;
1602 hvec[1].off = 0;
1603 hvec[1].len = rawmpilen;
1604 GNUNET_assert (0 ==
1605 gcry_md_hash_buffers (GCRY_MD_SHA512,
1606 0 /* flags */,
1607 digest,
1608 hvec, 2));
1609 /* Compute the A value. */
1610 reverse_buffer (digest, 32); /* Only the first half of the hash. */
1611 digest[0] = (digest[0] & 0x7f) | 0x40;
1612 digest[31] &= 0xf8;
1613
1614 GNUNET_CRYPTO_mpi_scan_unsigned (&a,
1615 digest,
1616 32);
1617 return a;
1618}
1619
1620
1621/**
1546 * @ingroup crypto 1622 * @ingroup crypto
1547 * Derive key material from a ECDH public key and a private EdDSA key. 1623 * Derive key material from a ECDH public key and a private EdDSA key.
1548 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa. 1624 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
@@ -1557,7 +1633,64 @@ GNUNET_CRYPTO_eddsa_ecdh (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
1557 const struct GNUNET_CRYPTO_EcdhePublicKey *pub, 1633 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1558 struct GNUNET_HashCode *key_material) 1634 struct GNUNET_HashCode *key_material)
1559{ 1635{
1560 return GNUNET_SYSERR; 1636 gcry_mpi_point_t result;
1637 gcry_mpi_point_t q;
1638 gcry_mpi_t d;
1639 gcry_mpi_t a;
1640 gcry_ctx_t ctx;
1641 gcry_sexp_t pub_sexpr;
1642 gcry_mpi_t result_x;
1643 unsigned char xbuf[256 / 8];
1644 size_t rsize;
1645
1646 /* first, extract the q = dP value from the public key */
1647 if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1648 "(public-key(ecc(curve " CURVE ")(q %b)))",
1649 (int)sizeof (pub->q_y), pub->q_y))
1650 return GNUNET_SYSERR;
1651 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1652 gcry_sexp_release (pub_sexpr);
1653 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1654
1655 /* second, extract the d value from our private key */
1656 GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1657
1658 /* NOW, because this is EdDSA, HASH 'd' first! */
1659 a = eddsa_d_to_a (d);
1660 gcry_mpi_release (d);
1661
1662 /* then call the 'multiply' function, to compute the product */
1663 result = gcry_mpi_point_new (0);
1664 gcry_mpi_ec_mul (result, a, q, ctx);
1665 gcry_mpi_point_release (q);
1666 gcry_mpi_release (a);
1667
1668 /* finally, convert point to string for hashing */
1669 result_x = gcry_mpi_new (256);
1670 if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
1671 {
1672 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
1673 gcry_mpi_point_release (result);
1674 gcry_ctx_release (ctx);
1675 return GNUNET_SYSERR;
1676 }
1677 gcry_mpi_point_release (result);
1678 gcry_ctx_release (ctx);
1679
1680 rsize = sizeof (xbuf);
1681 GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
1682 /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
1683 as that does not include the sign bit; x should be a 255-bit
1684 value, so with the sign it should fit snugly into the 256-bit
1685 xbuf */
1686 GNUNET_assert (0 ==
1687 gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
1688 result_x));
1689 GNUNET_CRYPTO_hash (xbuf,
1690 rsize,
1691 key_material);
1692 gcry_mpi_release (result_x);
1693 return GNUNET_OK;
1561} 1694}
1562 1695
1563 1696
@@ -1576,7 +1709,59 @@ GNUNET_CRYPTO_ecdh_eddsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1576 const struct GNUNET_CRYPTO_EddsaPublicKey *pub, 1709 const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
1577 struct GNUNET_HashCode *key_material) 1710 struct GNUNET_HashCode *key_material)
1578{ 1711{
1579 return GNUNET_SYSERR; 1712 gcry_mpi_point_t result;
1713 gcry_mpi_point_t q;
1714 gcry_mpi_t d;
1715 gcry_ctx_t ctx;
1716 gcry_sexp_t pub_sexpr;
1717 gcry_mpi_t result_x;
1718 unsigned char xbuf[256 / 8];
1719 size_t rsize;
1720
1721 /* first, extract the q = dP value from the public key */
1722 if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1723 "(public-key(ecc(curve " CURVE ")(q %b)))",
1724 (int)sizeof (pub->q_y), pub->q_y))
1725 return GNUNET_SYSERR;
1726 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1727 gcry_sexp_release (pub_sexpr);
1728 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1729
1730 /* second, extract the d value from our private key */
1731 GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1732
1733 /* then call the 'multiply' function, to compute the product */
1734 result = gcry_mpi_point_new (0);
1735 gcry_mpi_ec_mul (result, d, q, ctx);
1736 gcry_mpi_point_release (q);
1737 gcry_mpi_release (d);
1738
1739 /* finally, convert point to string for hashing */
1740 result_x = gcry_mpi_new (256);
1741 if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
1742 {
1743 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
1744 gcry_mpi_point_release (result);
1745 gcry_ctx_release (ctx);
1746 return GNUNET_SYSERR;
1747 }
1748 gcry_mpi_point_release (result);
1749 gcry_ctx_release (ctx);
1750
1751 rsize = sizeof (xbuf);
1752 GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
1753 /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
1754 as that does not include the sign bit; x should be a 255-bit
1755 value, so with the sign it should fit snugly into the 256-bit
1756 xbuf */
1757 GNUNET_assert (0 ==
1758 gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
1759 result_x));
1760 GNUNET_CRYPTO_hash (xbuf,
1761 rsize,
1762 key_material);
1763 gcry_mpi_release (result_x);
1764 return GNUNET_OK;
1580} 1765}
1581 1766
1582 1767