util_security.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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) : result_(other.result_), len_(other.len_)
  84. {
  85. }
  86. HMACResult& operator=(const HMACResult& other)
  87. {
  88. result_ = other.result_;
  89. len_ = other.len_;
  90. return *this;
  91. }
  92. bool operator==(const HMACResult& other) const
  93. {
  94. if (len_ != other.len_) {
  95. throw std::domain_error("comparing different hmac is undefined");
  96. }
  97. return compare(result_.data(), other.result_.data(), len_);
  98. }
  99. bool operator!=(const HMACResult& other) const { return !(*this == other); }
  100. size_t length() const { return len_; }
  101. const std::string& getBytes() const { return result_; }
  102. private:
  103. std::string result_;
  104. size_t len_;
  105. };
  106. /**
  107. * Implements HMAC-SHA* per RFC 6234. It supports the same cryptographic hash
  108. * algorithms that MessageDigest supports, but at most the SHA-1, SHA-2
  109. * algorithms as specified in the RFC.
  110. */
  111. class HMAC {
  112. public:
  113. /**
  114. * Constructs a new HMAC. It is recommended to use the |create| or
  115. * |createRandom| factory methods instead.
  116. *
  117. * @see create
  118. * @see createRandom
  119. */
  120. HMAC(const std::string& algorithm, const char* secret, size_t length);
  121. /**
  122. * Creates a new instance using the specified algorithm and secret.
  123. */
  124. static std::unique_ptr<HMAC> create(const std::string& algorithm,
  125. const std::string& secret)
  126. {
  127. return create(algorithm, secret.data(), secret.length());
  128. }
  129. /**
  130. * Creates a new instance using the specified algorithm and secret.
  131. */
  132. static std::unique_ptr<HMAC> create(const std::string& algorithm,
  133. const char* secret, size_t length)
  134. {
  135. if (!supports(algorithm)) {
  136. return nullptr;
  137. }
  138. return make_unique<HMAC>(algorithm, 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 std::string& secret)
  144. {
  145. return create("sha-1", secret.data(), secret.length());
  146. }
  147. /**
  148. * Creates a new instance using sha-1 and the specified secret.
  149. */
  150. static std::unique_ptr<HMAC> create(const char* secret, size_t length)
  151. {
  152. return create("sha-1", secret, length);
  153. }
  154. /**
  155. * Creates a new instance using the specified algorithm and a random secret.
  156. */
  157. static std::unique_ptr<HMAC> createRandom(const std::string& algorithm);
  158. /**
  159. * Creates a new instance using sha-1 and a random secret.
  160. */
  161. static std::unique_ptr<HMAC> createRandom() { return createRandom("sha-1"); }
  162. /**
  163. * Tells if this implementation supports a specific hash algorithm.
  164. */
  165. static bool supports(const std::string& algorithm);
  166. /**
  167. * Tells the length in bytes of the resulting HMAC.
  168. */
  169. size_t length() const { return md_->getDigestLength(); }
  170. /**
  171. * Resets the instance, clearing the internal state. The instance can be
  172. * re-used afterwards.
  173. */
  174. void reset()
  175. {
  176. if (clean_) {
  177. return;
  178. }
  179. md_->reset();
  180. md_->update(ipad_.data(), ipad_.length());
  181. clean_ = true;
  182. }
  183. /**
  184. * Updates the HMAC with new message data.
  185. */
  186. void update(const std::string& data)
  187. {
  188. md_->update(data.data(), data.length());
  189. clean_ = false;
  190. }
  191. /**
  192. * Updates the HMAC with new message data.
  193. */
  194. void update(const char* data, size_t length)
  195. {
  196. md_->update(data, length);
  197. clean_ = false;
  198. }
  199. /**
  200. * Returns the result. This can only be called once. After the call the
  201. * internal state is reset and new HMACs can be computed with the same
  202. * instance.
  203. */
  204. HMACResult getResult()
  205. {
  206. auto rv = md_->digest();
  207. md_->reset();
  208. md_->update(opad_.data(), opad_.length());
  209. md_->update(rv.data(), rv.length());
  210. rv = md_->digest();
  211. clean_ = false;
  212. reset();
  213. return HMACResult(rv);
  214. }
  215. /**
  216. * Returns the resulting HMAC of string in one go. You cannot mix call to this
  217. * method with calls to update.
  218. */
  219. HMACResult getResult(const std::string& str)
  220. {
  221. reset();
  222. update(str);
  223. return getResult();
  224. }
  225. /**
  226. * Returns the resulting HMAC of string in one go. You cannot mix call to this
  227. * method with calls to update.
  228. */
  229. HMACResult getResult(const char* data, size_t len)
  230. {
  231. reset();
  232. update(data, len);
  233. return getResult();
  234. }
  235. private:
  236. const size_t blockSize_;
  237. std::unique_ptr<MessageDigest> md_;
  238. std::string ipad_, opad_;
  239. bool clean_;
  240. };
  241. /**
  242. * Create A PKBDF2-HMAC. See RFC 2898.
  243. *
  244. * Example:
  245. * result = PBKDF2(HMAC::create("password"), random_salt, salt_len, 1000);
  246. */
  247. HMACResult PBKDF2(HMAC* hmac, const char* salt, size_t salt_length,
  248. size_t iterations, size_t key_length = 0);
  249. /**
  250. * Create A PKBDF2-HMAC. See RFC 2898.
  251. *
  252. * Example:
  253. * result = PBKDF2(HMAC::create("password"), random_salt, 1000);
  254. */
  255. inline HMACResult PBKDF2(HMAC* hmac, const std::string& salt, size_t iterations,
  256. size_t key_length = 0)
  257. {
  258. return PBKDF2(hmac, salt.data(), salt.length(), iterations, key_length);
  259. }
  260. } // namespace security
  261. } // namespace util
  262. } // namespace aria2
  263. #endif // D_UTIL_SECURITY_H