util_security.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2014 Nils Maier
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * In addition, as a special exception, the copyright holders give
  22. * permission to link the code of portions of this program with the
  23. * OpenSSL library under certain conditions as described in each
  24. * individual source file, and distribute linked combinations
  25. * including the two.
  26. * You must obey the GNU General Public License in all respects
  27. * for all of the code used other than OpenSSL. If you modify
  28. * file(s) with this exception, you may extend this exception to your
  29. * version of the file(s), but you are not obligated to do so. If you
  30. * do not wish to do so, delete this exception statement from your
  31. * version. If you delete this exception statement from all source
  32. * files in the program, then also delete it here.
  33. */
  34. /* copyright --> */
  35. #ifndef D_UTIL_SECURITY_H
  36. #define D_UTIL_SECURITY_H
  37. #include "common.h"
  38. #include <string>
  39. #include <stdexcept>
  40. #include "a2functional.h"
  41. #include "MessageDigest.h"
  42. namespace aria2 {
  43. namespace util {
  44. namespace security {
  45. /**
  46. * Compare to bytes in constant time.
  47. *
  48. * @param a First byte.
  49. * @param b Second byte.
  50. * @return True, if both match, false otherwise.
  51. */
  52. bool compare(const uint8_t a, const uint8_t b);
  53. /**
  54. * Compare two byte arrays in constant time. The arrays must have the same
  55. * length!
  56. *
  57. * @param a First byte array.
  58. * @param b Second byte array.
  59. * @return True, if both match, false otherwise.
  60. */
  61. bool compare(const uint8_t* a, const uint8_t* b, size_t length);
  62. inline bool compare(const char* a, const char* b, size_t length)
  63. {
  64. return compare(reinterpret_cast<const uint8_t*>(a),
  65. reinterpret_cast<const uint8_t*>(b), length * sizeof(char));
  66. }
  67. /**
  68. * HMAC Result wrapper. While it is still possible to get the raw result bytes,
  69. * when using this wrapper it is ensured that constant-time comparison is used.
  70. * Also, this wrapper makes it an error to compare results of a different
  71. * length, helping to prevent logic errors either during development, or
  72. * triggering in the wild. Therefore |.getBytes()| use should be avoided.
  73. */
  74. class HMACResult {
  75. public:
  76. HMACResult(const std::string& result) : result_(result), len_(result.length())
  77. {
  78. }
  79. HMACResult(const char* result, size_t length)
  80. : result_(result, length), len_(length)
  81. {
  82. }
  83. HMACResult(const HMACResult& other) = default;
  84. HMACResult& operator=(const HMACResult& other) = default;
  85. bool operator==(const HMACResult& other) const
  86. {
  87. if (len_ != other.len_) {
  88. throw std::domain_error("comparing different hmac is undefined");
  89. }
  90. return compare(result_.data(), other.result_.data(), len_);
  91. }
  92. bool operator!=(const HMACResult& other) const { return !(*this == other); }
  93. size_t length() const { return len_; }
  94. const std::string& getBytes() const { return result_; }
  95. private:
  96. std::string result_;
  97. size_t len_;
  98. };
  99. /**
  100. * Implements HMAC-SHA* per RFC 6234. It supports the same cryptographic hash
  101. * algorithms that MessageDigest supports, but at most the SHA-1, SHA-2
  102. * algorithms as specified in the RFC.
  103. */
  104. class HMAC {
  105. public:
  106. /**
  107. * Constructs a new HMAC. It is recommended to use the |create| or
  108. * |createRandom| factory methods instead.
  109. *
  110. * @see create
  111. * @see createRandom
  112. */
  113. HMAC(const std::string& algorithm, const char* secret, size_t length);
  114. /**
  115. * Creates a new instance using the specified algorithm and secret.
  116. */
  117. static std::unique_ptr<HMAC> create(const std::string& algorithm,
  118. const std::string& secret)
  119. {
  120. return create(algorithm, secret.data(), secret.length());
  121. }
  122. /**
  123. * Creates a new instance using the specified algorithm and secret.
  124. */
  125. static std::unique_ptr<HMAC> create(const std::string& algorithm,
  126. const char* secret, size_t length)
  127. {
  128. if (!supports(algorithm)) {
  129. return nullptr;
  130. }
  131. return make_unique<HMAC>(algorithm, secret, length);
  132. }
  133. /**
  134. * Creates a new instance using sha-1 and the specified secret.
  135. */
  136. static std::unique_ptr<HMAC> create(const std::string& secret)
  137. {
  138. return create("sha-1", secret.data(), secret.length());
  139. }
  140. /**
  141. * Creates a new instance using sha-1 and the specified secret.
  142. */
  143. static std::unique_ptr<HMAC> create(const char* secret, size_t length)
  144. {
  145. return create("sha-1", secret, length);
  146. }
  147. /**
  148. * Creates a new instance using the specified algorithm and a random secret.
  149. */
  150. static std::unique_ptr<HMAC> createRandom(const std::string& algorithm);
  151. /**
  152. * Creates a new instance using sha-1 and a random secret.
  153. */
  154. static std::unique_ptr<HMAC> createRandom() { return createRandom("sha-1"); }
  155. /**
  156. * Tells if this implementation supports a specific hash algorithm.
  157. */
  158. static bool supports(const std::string& algorithm);
  159. /**
  160. * Tells the length in bytes of the resulting HMAC.
  161. */
  162. size_t length() const { return md_->getDigestLength(); }
  163. /**
  164. * Resets the instance, clearing the internal state. The instance can be
  165. * re-used afterwards.
  166. */
  167. void reset()
  168. {
  169. if (clean_) {
  170. return;
  171. }
  172. md_->reset();
  173. md_->update(ipad_.data(), ipad_.length());
  174. clean_ = true;
  175. }
  176. /**
  177. * Updates the HMAC with new message data.
  178. */
  179. void update(const std::string& data)
  180. {
  181. md_->update(data.data(), data.length());
  182. clean_ = false;
  183. }
  184. /**
  185. * Updates the HMAC with new message data.
  186. */
  187. void update(const char* data, size_t length)
  188. {
  189. md_->update(data, length);
  190. clean_ = false;
  191. }
  192. /**
  193. * Returns the result. This can only be called once. After the call the
  194. * internal state is reset and new HMACs can be computed with the same
  195. * instance.
  196. */
  197. HMACResult getResult()
  198. {
  199. auto rv = md_->digest();
  200. md_->reset();
  201. md_->update(opad_.data(), opad_.length());
  202. md_->update(rv.data(), rv.length());
  203. rv = md_->digest();
  204. clean_ = false;
  205. reset();
  206. return HMACResult(rv);
  207. }
  208. /**
  209. * Returns the resulting HMAC of string in one go. You cannot mix call to this
  210. * method with calls to update.
  211. */
  212. HMACResult getResult(const std::string& str)
  213. {
  214. reset();
  215. update(str);
  216. return getResult();
  217. }
  218. /**
  219. * Returns the resulting HMAC of string in one go. You cannot mix call to this
  220. * method with calls to update.
  221. */
  222. HMACResult getResult(const char* data, size_t len)
  223. {
  224. reset();
  225. update(data, len);
  226. return getResult();
  227. }
  228. private:
  229. const size_t blockSize_;
  230. std::unique_ptr<MessageDigest> md_;
  231. std::string ipad_, opad_;
  232. bool clean_;
  233. };
  234. /**
  235. * Create A PKBDF2-HMAC. See RFC 2898.
  236. *
  237. * Example:
  238. * result = PBKDF2(HMAC::create("password"), random_salt, salt_len, 1000);
  239. */
  240. HMACResult PBKDF2(HMAC* hmac, const char* salt, size_t salt_length,
  241. size_t iterations, size_t key_length = 0);
  242. /**
  243. * Create A PKBDF2-HMAC. See RFC 2898.
  244. *
  245. * Example:
  246. * result = PBKDF2(HMAC::create("password"), random_salt, 1000);
  247. */
  248. inline HMACResult PBKDF2(HMAC* hmac, const std::string& salt, size_t iterations,
  249. size_t key_length = 0)
  250. {
  251. return PBKDF2(hmac, salt.data(), salt.length(), iterations, key_length);
  252. }
  253. } // namespace security
  254. } // namespace util
  255. } // namespace aria2
  256. #endif // D_UTIL_SECURITY_H