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.
 
 
 
 
 

382 lines
13 KiB

  1. /**
  2. * @file shake.hxx
  3. * @copyright
  4. * Based on CC0 code by David Leon Gil, 2015 \n
  5. * Copyright (c) 2015 Cryptography Research, Inc. \n
  6. * Released under the MIT License. See LICENSE.txt for license information.
  7. * @author Mike Hamburg
  8. * @brief SHA-3-n and SHAKE-n instances, C++ wrapper.
  9. * @warning EXPERIMENTAL! The names, parameter orders etc are likely to change.
  10. */
  11. #ifndef __SHAKE_HXX__
  12. #define __SHAKE_HXX__
  13. #include "shake.h"
  14. #include <string>
  15. #include <sys/types.h>
  16. /** @cond internal */
  17. #if __cplusplus >= 201103L
  18. #define DELETE = delete
  19. #define NOEXCEPT noexcept
  20. #define EXPLICIT_CON explicit
  21. #define GET_DATA(str) ((const unsigned char *)&(str)[0])
  22. #else
  23. #define DELETE
  24. #define NOEXCEPT throw()
  25. #define EXPLICIT_CON
  26. #define GET_DATA(str) ((const unsigned char *)((str).data()))
  27. #endif
  28. /** @endcond */
  29. namespace decaf {
  30. /** A Keccak sponge internal class */
  31. class KeccakSponge {
  32. protected:
  33. /** The C-wrapper sponge state */
  34. keccak_sponge_t sp;
  35. /** Initialize from parameters */
  36. inline KeccakSponge(const struct kparams_s *params) NOEXCEPT { sponge_init(sp, params); }
  37. /** No initialization */
  38. inline KeccakSponge(const NOINIT &) NOEXCEPT { }
  39. public:
  40. /** Destructor zeroizes state */
  41. inline ~KeccakSponge() NOEXCEPT { sponge_destroy(sp); }
  42. };
  43. /**
  44. * Hash function derived from Keccak
  45. * @todo throw exceptions when hash is misused.
  46. */
  47. class KeccakHash : public KeccakSponge {
  48. protected:
  49. /** Initialize from parameters */
  50. inline KeccakHash(const kparams_s *params) NOEXCEPT : KeccakSponge(params) {}
  51. public:
  52. /** Add more data to running hash */
  53. inline void update(const uint8_t *__restrict__ in, size_t len) { sha3_update(sp,in,len); }
  54. /** Add more data to running hash, C++ version. */
  55. inline void update(const Block &s) { sha3_update(sp,s.data(),s.size()); }
  56. /** Add more data, stream version. */
  57. inline KeccakHash &operator<<(const Block &s) { update(s); return *this; }
  58. /** Same as <<. */
  59. inline KeccakHash &operator+=(const Block &s) { return *this << s; }
  60. /**
  61. * @brief Output bytes from the sponge.
  62. * @todo make this throw exceptions.
  63. */
  64. inline void output(TmpBuffer b) { sha3_output(sp,b.data(),b.size()); }
  65. /**
  66. * @brief Output bytes from the sponge.
  67. * @todo make this throw exceptions.
  68. */
  69. inline void output(Buffer &b) { sha3_output(sp,b.data(),b.size()); }
  70. /** @brief Output bytes from the sponge. */
  71. inline SecureBuffer output(size_t len) {
  72. SecureBuffer buffer(len);
  73. sha3_output(sp,buffer,len);
  74. return buffer;
  75. }
  76. /** @brief Return the sponge's default output size. */
  77. inline size_t default_output_size() const NOEXCEPT {
  78. return sponge_default_output_bytes(sp);
  79. }
  80. /** Output the default number of bytes. */
  81. inline SecureBuffer output() {
  82. return output(default_output_size());
  83. }
  84. };
  85. /** Fixed-output-length SHA3 */
  86. template<int bits> class SHA3 : public KeccakHash {
  87. private:
  88. /** Get the parameter template block for this hash */
  89. static inline const struct kparams_s *get_params();
  90. public:
  91. /** Initializer */
  92. inline SHA3() NOEXCEPT : KeccakHash(get_params()) {}
  93. /** Reset the hash to the empty string */
  94. inline void reset() NOEXCEPT { sponge_init(sp, get_params()); }
  95. };
  96. /** Variable-output-length SHAKE */
  97. template<int bits>
  98. class SHAKE : public KeccakHash {
  99. private:
  100. /** Get the parameter template block for this hash */
  101. static inline const struct kparams_s *get_params();
  102. public:
  103. /** Initializer */
  104. inline SHAKE() NOEXCEPT : KeccakHash(get_params()) {}
  105. /** Reset the hash to the empty string */
  106. inline void reset() NOEXCEPT { sponge_init(sp, get_params()); }
  107. };
  108. /** @cond internal */
  109. template<> inline const struct kparams_s *SHAKE<128>::get_params() { return &SHAKE128_params_s; }
  110. template<> inline const struct kparams_s *SHAKE<256>::get_params() { return &SHAKE256_params_s; }
  111. template<> inline const struct kparams_s *SHA3<224>::get_params() { return &SHA3_224_params_s; }
  112. template<> inline const struct kparams_s *SHA3<256>::get_params() { return &SHA3_256_params_s; }
  113. template<> inline const struct kparams_s *SHA3<384>::get_params() { return &SHA3_384_params_s; }
  114. template<> inline const struct kparams_s *SHA3<512>::get_params() { return &SHA3_512_params_s; }
  115. /** @endcond */
  116. /** @brief An exception for misused protocol, eg encrypt with no key. */
  117. class ProtocolException : public std::exception {
  118. public:
  119. /** @return "ProtocolException" */
  120. virtual const char * what() const NOEXCEPT { return "ProtocolException"; }
  121. };
  122. /** Sponge-based random-number generator */
  123. class SpongeRng : private KeccakSponge {
  124. public:
  125. class RngException : public std::exception {
  126. private:
  127. const char *const what_;
  128. public:
  129. const int err_code;
  130. const char *what() const NOEXCEPT { return what_; }
  131. RngException(int err_code, const char *what_) NOEXCEPT : what_(what_), err_code(err_code) {}
  132. };
  133. /** Initialize, deterministically by default, from block */
  134. inline SpongeRng( const Block &in, bool deterministic = true )
  135. : KeccakSponge((NOINIT())) {
  136. spongerng_init_from_buffer(sp,in.data(),in.size(),deterministic);
  137. }
  138. /** Initialize, non-deterministically by default, from C/C++ filename */
  139. inline SpongeRng( const std::string &in = "/dev/urandom", size_t len = 32, bool deterministic = false )
  140. throw(RngException)
  141. : KeccakSponge((NOINIT())) {
  142. int ret = spongerng_init_from_file(sp,in.c_str(),len,deterministic);
  143. if (ret) {
  144. throw RngException(ret, "Couldn't load from file");
  145. }
  146. }
  147. /** Read data to a buffer. */
  148. inline void read(Buffer &buffer) NOEXCEPT { spongerng_next(sp,buffer.data(),buffer.size()); }
  149. /** Read data to a buffer. */
  150. inline void read(TmpBuffer buffer) NOEXCEPT { read((Buffer &)buffer); }
  151. /** Read data to a C++ string
  152. * @warning TODO Future versions of this function may throw RngException if a
  153. * nondeterministic RNG fails a reseed.
  154. */
  155. inline SecureBuffer read(size_t length) throw(std::bad_alloc) {
  156. SecureBuffer out(length); read(out); return out;
  157. }
  158. private:
  159. SpongeRng(const SpongeRng &) DELETE;
  160. SpongeRng &operator=(const SpongeRng &) DELETE;
  161. };
  162. /**@cond internal*/
  163. inline Ed255::Scalar::Scalar(SpongeRng &rng) NOEXCEPT {
  164. *this = rng.read(SER_BYTES);
  165. }
  166. inline Ed255::Point::Point(SpongeRng &rng, bool uniform) NOEXCEPT {
  167. SecureBuffer buffer((uniform ? 2 : 1) * HASH_BYTES);
  168. rng.read(buffer);
  169. set_to_hash(buffer);
  170. }
  171. inline SecureBuffer Ed255::Point::steg_encode(SpongeRng &rng) const NOEXCEPT {
  172. SecureBuffer out(STEG_BYTES);
  173. bool done;
  174. do {
  175. rng.read(out.slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1));
  176. done = invert_elligator(out, out[HASH_BYTES-1] & 7); /* 7 is kind of MAGIC */
  177. } while (!done);
  178. return out;
  179. }
  180. /**@endcond*/
  181. class Strobe : private KeccakSponge {
  182. public:
  183. /* TODO: pull out parameters */
  184. /** Am I a server or a client? */
  185. enum client_or_server { SERVER, CLIENT };
  186. inline Strobe (
  187. client_or_server whoami,
  188. const kparams_s &params = STROBE_256
  189. ) NOEXCEPT : KeccakSponge(NOINIT()) {
  190. strobe_init(sp, &params, whoami == CLIENT);
  191. }
  192. inline void key (
  193. const Block &data, bool more = false
  194. ) throw(ProtocolException) {
  195. if (!strobe_key(sp, data, data.size(), more)) throw ProtocolException();
  196. }
  197. inline void nonce(const Block &data, bool more = false
  198. ) throw(ProtocolException) {
  199. if (!strobe_nonce(sp, data, data.size(), more)) throw ProtocolException();
  200. }
  201. inline void send_plaintext(const Block &data, bool more = false
  202. ) throw(ProtocolException) {
  203. if (!strobe_plaintext(sp, data, data.size(), true, more))
  204. throw(ProtocolException());
  205. }
  206. inline void recv_plaintext(const Block &data, bool more = false
  207. ) throw(ProtocolException) {
  208. if (!strobe_plaintext(sp, data, data.size(), false, more))
  209. throw(ProtocolException());
  210. }
  211. inline void ad(const Block &data, bool more = false
  212. ) throw(ProtocolException) {
  213. if (!strobe_ad(sp, data, data.size(), more))
  214. throw(ProtocolException());
  215. }
  216. inline void encrypt_no_auth(
  217. Buffer &out, const Block &data, bool more = false
  218. ) throw(LengthException,ProtocolException) {
  219. if (out.size() != data.size()) throw LengthException();
  220. if (!strobe_encrypt(sp, out, data, data.size(), more)) throw(ProtocolException());
  221. }
  222. inline void encrypt_no_auth(
  223. TmpBuffer out, const Block &data, bool more = false
  224. ) throw(LengthException,ProtocolException) {
  225. encrypt_no_auth((Buffer &)out, data, more);
  226. }
  227. inline SecureBuffer encrypt_no_auth(const Block &data, bool more = false
  228. ) throw(ProtocolException) {
  229. SecureBuffer out(data.size()); encrypt_no_auth(out, data, more); return out;
  230. }
  231. inline void decrypt_no_auth(
  232. Buffer &out, const Block &data, bool more = false
  233. ) throw(LengthException,ProtocolException) {
  234. if (out.size() != data.size()) throw LengthException();
  235. if (!strobe_decrypt(sp, out, data, data.size(), more)) throw ProtocolException();
  236. }
  237. inline void decrypt_no_auth(
  238. TmpBuffer out, const Block &data, bool more = false
  239. ) throw(LengthException,ProtocolException) {
  240. decrypt_no_auth((Buffer &)out, data, more);
  241. }
  242. inline SecureBuffer decrypt_no_auth(const Block &data, bool more = false
  243. ) throw(ProtocolException) {
  244. SecureBuffer out(data.size()); decrypt_no_auth(out, data, more); return out;
  245. }
  246. inline void produce_auth(Buffer &out) throw(LengthException,ProtocolException) {
  247. if (out.size() > STROBE_MAX_AUTH_BYTES) throw LengthException();
  248. if (!strobe_produce_auth(sp, out, out.size())) throw ProtocolException();
  249. }
  250. inline void produce_auth(TmpBuffer out) throw(LengthException,ProtocolException) {
  251. produce_auth((Buffer &)out);
  252. }
  253. inline SecureBuffer produce_auth(
  254. uint8_t bytes = 8
  255. ) throw(ProtocolException) {
  256. SecureBuffer out(bytes); produce_auth(out); return out;
  257. }
  258. inline void encrypt(
  259. Buffer &out, const Block &data, uint8_t auth = 8
  260. ) throw(LengthException,ProtocolException) {
  261. if (out.size() < data.size() || out.size() != data.size() + auth) throw LengthException();
  262. encrypt_no_auth(out.slice(0,data.size()), data);
  263. produce_auth(out.slice(data.size(),auth));
  264. }
  265. inline void encrypt (
  266. TmpBuffer out, const Block &data, uint8_t auth = 8
  267. ) throw(LengthException,ProtocolException) {
  268. encrypt((Buffer &)out, data, auth);
  269. }
  270. inline SecureBuffer encrypt (
  271. const Block &data, uint8_t auth = 8
  272. ) throw(LengthException,ProtocolException,std::bad_alloc ){
  273. SecureBuffer out(data.size() + auth); encrypt(out, data, auth); return out;
  274. }
  275. inline void decrypt (
  276. Buffer &out, const Block &data, uint8_t bytes = 8
  277. ) throw(LengthException, CryptoException, ProtocolException) {
  278. if (out.size() > data.size() || out.size() != data.size() - bytes) throw LengthException();
  279. decrypt_no_auth(out, data.slice(0,out.size()));
  280. verify_auth(data.slice(out.size(),bytes));
  281. }
  282. inline void decrypt (
  283. TmpBuffer out, const Block &data, uint8_t bytes = 8
  284. ) throw(LengthException,CryptoException,ProtocolException) {
  285. decrypt((Buffer &)out, data, bytes);
  286. }
  287. inline SecureBuffer decrypt (
  288. const Block &data, uint8_t bytes = 8
  289. ) throw(LengthException,CryptoException,ProtocolException,std::bad_alloc) {
  290. if (data.size() < bytes) throw LengthException();
  291. SecureBuffer out(data.size() - bytes); decrypt(out, data, bytes); return out;
  292. }
  293. inline void verify_auth(const Block &auth) throw(LengthException,CryptoException) {
  294. if (auth.size() == 0 || auth.size() > STROBE_MAX_AUTH_BYTES) throw LengthException();
  295. if (!strobe_verify_auth(sp, auth, auth.size())) throw CryptoException();
  296. }
  297. inline void prng(Buffer &out, bool more = false) NOEXCEPT {
  298. (void)strobe_prng(sp, out, out.size(), more);
  299. }
  300. inline void prng(TmpBuffer out, bool more = false) NOEXCEPT {
  301. prng((Buffer &)out, more);
  302. }
  303. inline SecureBuffer prng(size_t bytes, bool more = false) {
  304. SecureBuffer out(bytes); prng(out, more); return out;
  305. }
  306. inline void respec(const kparams_s &params) throw(ProtocolException) {
  307. if (!strobe_respec(sp, &params)) throw(ProtocolException());
  308. }
  309. };
  310. } /* namespace decaf */
  311. #undef NOEXCEPT
  312. #undef EXPLICIT_CON
  313. #undef GET_DATA
  314. #undef DELETE
  315. #endif /* __SHAKE_HXX__ */