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.
 
 
 
 
 

345 lines
10 KiB

  1. /*
  2. * Example Decaf cyrpto routines, C++ wrapper.
  3. * @warning These are merely examples, though they ought to be secure. But real
  4. * protocols will decide differently on magic numbers, formats, which items to
  5. * hash, etc.
  6. * @warning Experimental! The names, parameter orders etc are likely to change.
  7. */
  8. #include <decaf/decaf_$(gf_bits).hxx>
  9. #include <decaf/eddsa_$(gf_bits).h>
  10. #include <decaf/shake.hxx>
  11. #include <decaf/sha512.hxx>
  12. /** @cond internal */
  13. #if __cplusplus >= 201103L
  14. #define NOEXCEPT noexcept
  15. #else
  16. #define NOEXCEPT throw()
  17. #endif
  18. /** @endcond */
  19. namespace decaf {
  20. /** A public key for crypto over some Group */
  21. template <typename Group> struct EdDSA;
  22. /** A public key for crypto over $(name) */
  23. template<> struct EdDSA<$(cxx_ns)> {
  24. /** @cond internal */
  25. class PrivateKey;
  26. class PublicKey;
  27. /** @endcond */
  28. /** Prehash context for EdDSA. TODO: test me! */
  29. class Prehash : public $(re.sub(r"SHAKE(\d+)",r"SHAKE<\1>", eddsa_hash.upper())) {
  30. public:
  31. /** Do we support contexts for signatures? If not, they must always be NULL */
  32. static const bool SUPPORTS_CONTEXTS = $(C_NS)_EDDSA_SUPPORTS_CONTEXTS;
  33. private:
  34. typedef $(re.sub(r"SHAKE(\d+)",r"SHAKE<\1>", eddsa_hash.upper())) Super;
  35. SecureBuffer context_;
  36. friend class PrivateKey;
  37. friend class PublicKey;
  38. void init() throw(LengthException) {
  39. Super::reset();
  40. if (context_.size() > 255
  41. || (context_.size() != 0 && !SUPPORTS_CONTEXTS)
  42. ) {
  43. throw LengthException();
  44. }
  45. if (SUPPORTS_CONTEXTS) {
  46. uint8_t dom[2] = {2, context_.size() };
  47. update(dom,2);
  48. update(context_);
  49. }
  50. }
  51. public:
  52. /** Number of output bytes in prehash */
  53. static const size_t OUTPUT_BYTES = Super::DEFAULT_OUTPUT_BYTES;
  54. /** Create the prehash */
  55. Prehash(Block context = Block(NULL,0)) throw(LengthException) {
  56. context_ = context;
  57. init();
  58. }
  59. /** Reset this hash */
  60. void reset() NOEXCEPT { init(); }
  61. /** Output from this hash */
  62. SecureBuffer final() throw(std::bad_alloc) {
  63. SecureBuffer ret = Super::final(OUTPUT_BYTES);
  64. reset();
  65. return ret;
  66. }
  67. /** Output from this hash */
  68. void final(Buffer &b) throw(LengthException) {
  69. if (b.size() != OUTPUT_BYTES) throw LengthException();
  70. Super::final(b);
  71. reset();
  72. }
  73. };
  74. class PrivateKey : public Serializable<PrivateKey> {
  75. private:
  76. /** @cond internal */
  77. friend class PublicKey;
  78. /** @endcond */
  79. /** The pre-expansion form of the signing key. */
  80. FixedArrayBuffer<$(C_NS)_EDDSA_PRIVATE_BYTES> priv_;
  81. /** The post-expansion public key. */
  82. FixedArrayBuffer<$(C_NS)_EDDSA_PUBLIC_BYTES> pub_;
  83. public:
  84. /** Underlying group */
  85. typedef $(cxx_ns) Group;
  86. /** Signature size. */
  87. static const size_t SIG_BYTES = $(C_NS)_EDDSA_SIGNATURE_BYTES;
  88. /** Serialization size. */
  89. static const size_t SER_BYTES = $(C_NS)_EDDSA_PRIVATE_BYTES;
  90. /** Do we support contexts for signatures? If not, they must always be NULL */
  91. static const bool SUPPORTS_CONTEXTS = $(C_NS)_EDDSA_SUPPORTS_CONTEXTS;
  92. /** Create but don't initialize */
  93. inline explicit PrivateKey(const NOINIT&) NOEXCEPT : priv_((NOINIT())), pub_((NOINIT())) { }
  94. /** Read a private key from a string */
  95. inline explicit PrivateKey(const FixedBlock<SER_BYTES> &b) NOEXCEPT { *this = b; }
  96. /** Copy constructor */
  97. inline PrivateKey(const PrivateKey &k) NOEXCEPT { *this = k; }
  98. /** Create at random */
  99. inline explicit PrivateKey(Rng &r) NOEXCEPT : priv_(r) {
  100. $(c_ns)_eddsa_derive_public_key(pub_.data(), priv_.data());
  101. }
  102. /** Assignment from string */
  103. inline PrivateKey &operator=(const FixedBlock<SER_BYTES> &b) NOEXCEPT {
  104. memcpy(priv_.data(),b.data(),b.size());
  105. $(c_ns)_eddsa_derive_public_key(pub_.data(), priv_.data());
  106. return *this;
  107. }
  108. /** Copy assignment */
  109. inline PrivateKey &operator=(const PrivateKey &k) NOEXCEPT {
  110. memcpy(priv_.data(),k.priv_.data(), priv_.size());
  111. memcpy(pub_.data(),k.pub_.data(), pub_.size());
  112. return *this;
  113. }
  114. /** Serialization size. */
  115. inline size_t ser_size() const NOEXCEPT { return SER_BYTES; }
  116. /** Serialize into a buffer. */
  117. inline void serialize_into(unsigned char *x) const NOEXCEPT {
  118. memcpy(x,priv_.data(), priv_.size());
  119. }
  120. /** Return the corresponding public key */
  121. inline PublicKey pub() const NOEXCEPT {
  122. PublicKey pub(*this);
  123. return pub;
  124. }
  125. /**
  126. * Sign a message.
  127. * @param [in] message The message to be signed.
  128. * @param [in] prehashed If true, the message to be signed is already hashed.
  129. * @param [in] context A context for the signature; must be at most 255 bytes;
  130. * must be absent if SUPPORTS_CONTEXTS == false.
  131. *
  132. * @warning It is generally unsafe to use Ed25519 with both prehashed and non-prehashed messages.
  133. */
  134. inline SecureBuffer sign (
  135. const Block &message,
  136. bool prehashed = false,
  137. const Block &context = Block(NULL,0)
  138. ) const throw(LengthException, std::bad_alloc) {
  139. if (context.size() > 255
  140. || (context.size() != 0 && !SUPPORTS_CONTEXTS)
  141. ) {
  142. throw LengthException();
  143. }
  144. SecureBuffer out(SIG_BYTES);
  145. $(c_ns)_eddsa_sign (
  146. out.data(),
  147. priv_.data(),
  148. pub_.data(),
  149. message.data(),
  150. message.size(),
  151. prehashed
  152. #if $(C_NS)_EDDSA_SUPPORTS_CONTEXTS
  153. , context.data(),
  154. context.size()
  155. #endif
  156. );
  157. return out;
  158. }
  159. /* Sign a prehash context, and reset the context */
  160. inline SecureBuffer sign ( Prehash &ph ) const throw(std::bad_alloc) {
  161. FixedArrayBuffer<Prehash::OUTPUT_BYTES> m;
  162. ph.final(m);
  163. return sign(m, true, ph.context_);
  164. }
  165. }; /* class PrivateKey */
  166. class PublicKey : public Serializable<PublicKey> {
  167. private:
  168. /** @cond internal */
  169. friend class PrivateKey;
  170. /** @endcond */
  171. public:
  172. /** The pre-expansion form of the signature */
  173. FixedArrayBuffer<$(C_NS)_EDDSA_PUBLIC_BYTES> pub_;
  174. /* PERF FUTURE: Pre-cached decoding? Precomputed table?? */
  175. public:
  176. /** Underlying group */
  177. typedef $(cxx_ns) Group;
  178. /** Signature size. */
  179. static const size_t SIG_BYTES = $(C_NS)_EDDSA_SIGNATURE_BYTES;
  180. /** Serialization size. */
  181. static const size_t SER_BYTES = $(C_NS)_EDDSA_PRIVATE_BYTES;
  182. /** Do we support contexts for signatures? If not, they must always be NULL */
  183. static const bool SUPPORTS_CONTEXTS = $(C_NS)_EDDSA_SUPPORTS_CONTEXTS;
  184. /** Create but don't initialize */
  185. inline explicit PublicKey(const NOINIT&) NOEXCEPT : pub_((NOINIT())) { }
  186. /** Read a private key from a string */
  187. inline explicit PublicKey(const FixedBlock<SER_BYTES> &b) NOEXCEPT { *this = b; }
  188. /** Copy constructor */
  189. inline PublicKey(const PublicKey &k) NOEXCEPT { *this = k; }
  190. /** Copy constructor */
  191. inline explicit PublicKey(const PrivateKey &k) NOEXCEPT { *this = k; }
  192. /** Assignment from string */
  193. inline PublicKey &operator=(const FixedBlock<SER_BYTES> &b) NOEXCEPT {
  194. memcpy(pub_.data(),b.data(),b.size());
  195. return *this;
  196. }
  197. /** Assignment from private key */
  198. inline PublicKey &operator=(const PublicKey &p) NOEXCEPT {
  199. return *this = p.pub_;
  200. }
  201. /** Assignment from private key */
  202. inline PublicKey &operator=(const PrivateKey &p) NOEXCEPT {
  203. return *this = p.pub_;
  204. }
  205. /** Serialization size. */
  206. inline size_t ser_size() const NOEXCEPT { return SER_BYTES; }
  207. /** Serialize into a buffer. */
  208. inline void serialize_into(unsigned char *x) const NOEXCEPT {
  209. memcpy(x,pub_.data(), pub_.size());
  210. }
  211. /** Verify a signature, returning DECAF_FAILURE if verification fails */
  212. inline decaf_error_t WARN_UNUSED verify_noexcept (
  213. const FixedBlock<SIG_BYTES> &sig,
  214. const Block &message,
  215. bool prehashed = false,
  216. const Block &context = Block(NULL,0)
  217. ) const NOEXCEPT {
  218. if (context.size() > 255
  219. || (context.size() != 0 && !SUPPORTS_CONTEXTS)
  220. ) {
  221. return DECAF_FAILURE;
  222. }
  223. return $(c_ns)_eddsa_verify (
  224. sig.data(),
  225. pub_.data(),
  226. message.data(),
  227. message.size(),
  228. prehashed
  229. #if $(C_NS)_EDDSA_SUPPORTS_CONTEXTS
  230. , context.data(),
  231. context.size()
  232. #endif
  233. );
  234. }
  235. /** Verify a signature, throwing an exception if verification fails
  236. * @param [in] sig The signature.
  237. * @param [in] message The signed message.
  238. * @param [in] prehashed If true, the message is already hashed.
  239. * @param [in] context A context for the signature; must be at most 255 bytes;
  240. * must be absent if SUPPORTS_CONTEXTS == false.
  241. *
  242. * @warning It is generally unsafe to use Ed25519 with both prehashed and non-prehashed messages.
  243. */
  244. inline void verify (
  245. const FixedBlock<SIG_BYTES> &sig,
  246. const Block &message,
  247. bool prehashed = false,
  248. const Block &context = Block(NULL,0)
  249. ) const throw(LengthException,CryptoException) {
  250. if (context.size() > 255
  251. || (context.size() != 0 && !SUPPORTS_CONTEXTS)
  252. ) {
  253. throw LengthException();
  254. }
  255. if (DECAF_SUCCESS != verify_noexcept( sig, message, prehashed, context )) {
  256. throw CryptoException();
  257. }
  258. }
  259. /* Verify a prehash context, and reset the context */
  260. inline decaf_error_t WARN_UNUSED verify_noexcept (
  261. const FixedBlock<SIG_BYTES> &sig,
  262. Prehash &ph
  263. ) const NOEXCEPT {
  264. FixedArrayBuffer<Prehash::OUTPUT_BYTES> m;
  265. ph.final(m);
  266. return verify_noexcept(sig, m, true, ph.context_);
  267. }
  268. /* Verify a prehash context, and reset the context */
  269. inline void verify (
  270. const FixedBlock<SIG_BYTES> &sig,
  271. Prehash &ph
  272. ) const throw(CryptoException) {
  273. FixedArrayBuffer<Prehash::OUTPUT_BYTES> m;
  274. ph.final(m);
  275. verify(sig, m, true, ph.context_);
  276. }
  277. }; /* class PublicKey */
  278. }; /* template<> struct EdDSA<$(cxx_ns)> */
  279. #undef NOEXCEPT
  280. } /* namespace decaf */