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.
 
 
 
 
 

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