You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

217 lines
7.3 KiB

  1. /**
  2. * @file decaf/crypto.hxx
  3. * @author Mike Hamburg
  4. *
  5. * @copyright
  6. * Copyright (c) 2015 Cryptography Research, Inc. \n
  7. * Released under the MIT License. See LICENSE.txt for license information.
  8. *
  9. * @brief Example cryptography using Decaf.
  10. * @warning FIXME: this is out of sync with crypto_*.h
  11. */
  12. #ifndef __DECAF_CRYPTO_HXX__
  13. #define __DECAF_CRYPTO_HXX__ 1
  14. #include <decaf.hxx>
  15. #include <decaf/shake.hxx>
  16. /** @cond internal */
  17. #if __cplusplus >= 201103L
  18. #define NOEXCEPT noexcept
  19. #else
  20. #define NOEXCEPT throw()
  21. #endif
  22. /** @endcond */
  23. /* TODO: decide on copy vs reference */
  24. namespace decaf {
  25. template <typename Group> class PrivateKey;
  26. /** @brief A public key using a particular EC group */
  27. template <typename Group> class PublicKey : public Serializable<PublicKey<Group> > {
  28. private:
  29. /** @cond internal */
  30. friend class PrivateKey<Group>;
  31. static const size_t CHALLENGE_BYTES = Group::Scalar::SER_BYTES;
  32. //const typename Group::Point p;
  33. FixedArrayBuffer<Group::Point::SER_BYTES> ser;
  34. /** @endcond */
  35. public:
  36. /** Create without init */
  37. PublicKey(NOINIT) : ser(NOINIT()) {}
  38. /** SHAKE instance size for sigs etc */
  39. static const size_t SHAKE_BITS = 256;
  40. /** Size of a signature */
  41. static const size_t SIG_BYTES = Group::Point::SER_BYTES + Group::Scalar::SER_BYTES;
  42. /** @brief Set the public key to a point */
  43. inline explicit PublicKey(const typename Group::Point &p) NOEXCEPT : ser(p.serialize()) {}
  44. /** @brief Get the private key for a given public key */
  45. inline explicit PublicKey(const PrivateKey<Group> &priv) NOEXCEPT;
  46. /** @brief Read a private key from a string*/
  47. inline explicit PublicKey(const FixedBlock<Group::Point::SER_BYTES> &b) NOEXCEPT : ser(b) {}
  48. /** @brief Return the corresponding EC point */
  49. inline typename Group::Point point() const throw(CryptoException) {
  50. return typename Group::Point(ser);
  51. }
  52. /** @brief Verify a sig. TODO: nothrow version? */
  53. inline void verify_shake(const SHAKE<SHAKE_BITS> &ctx_, const FixedBlock<SIG_BYTES> &sig) throw(CryptoException) {
  54. SHAKE<SHAKE_BITS> ctx(ctx_);
  55. ctx << ser << sig.slice(0,Group::Point::SER_BYTES);
  56. FixedArrayBuffer<CHALLENGE_BYTES> challenge;
  57. ctx.output(challenge);
  58. typename Group::Scalar response;
  59. decaf_error_t scalar_OK = Group::Scalar::decode(
  60. response,
  61. sig.slice(Group::Point::SER_BYTES, Group::Scalar::SER_BYTES)
  62. );
  63. const typename Group::Point combo = point().non_secret_combo_with_base(
  64. typename Group::Scalar(challenge), response
  65. );
  66. if (!decaf_successful(scalar_OK)
  67. || combo != typename Group::Point(sig.slice(0,Group::Point::SER_BYTES)))
  68. throw CryptoException();
  69. //return scalar_OK & (combo == typename Group::Point(sig.slice(0,Group::Point::SER_BYTES)));
  70. }
  71. /** @brief Sign from a message. */
  72. inline void verify(const Block &message, const FixedBlock<SIG_BYTES> &sig) throw(CryptoException) {
  73. SHAKE<SHAKE_BITS> ctx;
  74. ctx << message;
  75. verify_shake(ctx,sig);
  76. }
  77. /** @brief Serialize into a buffer. */
  78. inline void serializeInto(unsigned char *x) const NOEXCEPT {
  79. memcpy(x,ser.data(),Group::Point::SER_BYTES);
  80. }
  81. /** @brief Serialize into a buffer. */
  82. inline size_t serSize() const NOEXCEPT {
  83. return Group::Point::SER_BYTES;
  84. }
  85. /** @brief Copy operator */
  86. inline PublicKey &operator=(const PublicKey &x) NOEXCEPT { ser = x.ser; return *this; }
  87. };
  88. /** @brief A private key using a particular EC group */
  89. template <typename Group> class PrivateKey : public Serializable<PrivateKey<Group> > {
  90. public:
  91. /** Size of associated symmetric key */
  92. static const size_t SYM_BYTES = 32;
  93. /** SHAKE instance size for sigs etc */
  94. static const size_t SHAKE_BITS = PublicKey<Group>::SHAKE_BITS;
  95. private:
  96. /** @cond internal */
  97. static const size_t SCALAR_HASH_BYTES = Group::Scalar::SER_BYTES + 8;
  98. friend class PublicKey<Group>;
  99. FixedArrayBuffer<SYM_BYTES> sym;
  100. typename Group::Scalar scalar;
  101. PublicKey<Group> pub_;
  102. /** @endcond */
  103. public:
  104. /** @brief Don't initialize */
  105. inline PrivateKey(const NOINIT &ni) NOEXCEPT : sym(ni), scalar(ni), pub_(ni) {}
  106. /** @brief Construct at random */
  107. inline PrivateKey(Rng &r) :
  108. sym(r),
  109. scalar(SHAKE<SHAKE_BITS>::hash(sym, SCALAR_HASH_BYTES)),
  110. pub_((Group::Precomputed::base() * scalar).serialize()) {}
  111. /** @brief Construct from buffer */
  112. inline PrivateKey(const FixedBlock<SYM_BYTES> &sym_) :
  113. sym(sym_),
  114. scalar(SHAKE<SHAKE_BITS>::hash(sym, SCALAR_HASH_BYTES)),
  115. pub_(SecureBuffer(Group::Precomputed::Base * scalar)) {}
  116. /** @brief Compressed representation */
  117. inline const FixedBlock<SYM_BYTES> &ser_compressed() const NOEXCEPT {
  118. return sym;
  119. }
  120. /** @brief Serialize */
  121. inline size_t serSize() const NOEXCEPT {
  122. return SYM_BYTES;
  123. }
  124. /** @brief Serialize */
  125. inline void serializeInto(unsigned char *target) const NOEXCEPT {
  126. memcpy(target,sym.data(),serSize());
  127. }
  128. /** @brief Uncompressed representation */
  129. inline SecureBuffer ser_uncompressed() const throw(std::bad_alloc) {
  130. SecureBuffer b(SYM_BYTES + Group::Scalar::SER_BYTES + Group::Point::SER_BYTES);
  131. Buffer(b).slice(0,SYM_BYTES).assign(sym);
  132. Buffer(b).slice(SYM_BYTES,Group::Scalar::SER_BYTES).assign(scalar);
  133. Buffer(b).slice(SYM_BYTES+Group::Scalar::SER_BYTES,Group::Point::SER_BYTES).assign(pub_.ser);
  134. return b;
  135. }
  136. /** @brief Sign from a SHAKE context. TODO: double check random oracle eval of this; destructive version? */
  137. inline SecureBuffer sign_shake(const SHAKE<SHAKE_BITS> &ctx_) throw(std::bad_alloc) {
  138. SHAKE<SHAKE_BITS> ctx(ctx_);
  139. ctx << sym << "decaf_255_sign_shake";
  140. typename Group::Scalar nonce(ctx.output(SCALAR_HASH_BYTES));
  141. SecureBuffer g_nonce = (Group::Precomputed::base() * nonce).serialize();
  142. ctx = ctx_;
  143. ctx << pub_.ser << g_nonce;
  144. SecureBuffer challenge(ctx.output(PublicKey<Group>::CHALLENGE_BYTES));
  145. SecureBuffer response((nonce - scalar * typename Group::Scalar(challenge)).serialize());
  146. SecureBuffer ret(PublicKey<Group>::SIG_BYTES);
  147. Buffer(ret).slice(0,Group::Point::SER_BYTES).assign(g_nonce);
  148. Buffer(ret).slice(Group::Point::SER_BYTES, Group::Scalar::SER_BYTES).assign(response);
  149. return ret;
  150. }
  151. /** @brief Sign from a message. */
  152. inline SecureBuffer sign(const Block &message) {
  153. SHAKE<SHAKE_BITS> ctx;
  154. ctx << message;
  155. return sign_shake(ctx);
  156. }
  157. /** @brief Get the corresponding public key */
  158. inline const PublicKey<Group> &pub() const { return pub_; }
  159. /** @brief Copy operator */
  160. inline PrivateKey &operator=(const PrivateKey &x) NOEXCEPT {
  161. sym = x.sym;
  162. scalar = x.scalar;
  163. pub_ = x.pub_;
  164. return *this;
  165. }
  166. };
  167. /** @cond internal */
  168. template <typename Group>
  169. inline PublicKey<Group>::PublicKey(
  170. const PrivateKey<Group> &priv
  171. ) NOEXCEPT : ser(priv.pub_.ser){}
  172. /** @endcond */
  173. #undef NOEXCEPT
  174. } /* namespace decaf */
  175. #endif /* __DECAF_CRYPTO_HXX__ */