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.
 
 
 
 
 

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