openssl_help.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #pragma once
  8. #include "base/bytes.h"
  9. #include "base/algorithm.h"
  10. #include "base/assertion.h"
  11. #include "base/basic_types.h"
  12. extern "C" {
  13. #include <openssl/bn.h>
  14. #include <openssl/sha.h>
  15. #include <openssl/aes.h>
  16. #include <openssl/modes.h>
  17. #include <openssl/crypto.h>
  18. #include <openssl/evp.h>
  19. #include <openssl/hmac.h>
  20. #include <openssl/rsa.h>
  21. #include <openssl/pem.h>
  22. #include <openssl/err.h>
  23. } // extern "C"
  24. #ifdef small
  25. #undef small
  26. #endif // small
  27. namespace openssl {
  28. class Context {
  29. public:
  30. Context() : _data(BN_CTX_new()) {
  31. }
  32. Context(const Context &other) = delete;
  33. Context(Context &&other) : _data(base::take(other._data)) {
  34. }
  35. Context &operator=(const Context &other) = delete;
  36. Context &operator=(Context &&other) {
  37. _data = base::take(other._data);
  38. return *this;
  39. }
  40. ~Context() {
  41. if (_data) {
  42. BN_CTX_free(_data);
  43. }
  44. }
  45. BN_CTX *raw() const {
  46. return _data;
  47. }
  48. private:
  49. BN_CTX *_data = nullptr;
  50. };
  51. class BigNum {
  52. public:
  53. BigNum() = default;
  54. BigNum(const BigNum &other)
  55. : _data((other.failed() || other.isZero())
  56. ? nullptr
  57. : BN_dup(other.raw()))
  58. , _failed(other._failed) {
  59. }
  60. BigNum(BigNum &&other)
  61. : _data(std::exchange(other._data, nullptr))
  62. , _failed(std::exchange(other._failed, false)) {
  63. }
  64. BigNum &operator=(const BigNum &other) {
  65. if (other.failed()) {
  66. _failed = true;
  67. } else if (other.isZero()) {
  68. clear();
  69. _failed = false;
  70. } else if (!_data) {
  71. _data = BN_dup(other.raw());
  72. _failed = false;
  73. } else {
  74. _failed = !BN_copy(raw(), other.raw());
  75. }
  76. return *this;
  77. }
  78. BigNum &operator=(BigNum &&other) {
  79. std::swap(_data, other._data);
  80. std::swap(_failed, other._failed);
  81. return *this;
  82. }
  83. ~BigNum() {
  84. clear();
  85. }
  86. explicit BigNum(unsigned int word) : BigNum() {
  87. setWord(word);
  88. }
  89. explicit BigNum(bytes::const_span bytes) : BigNum() {
  90. setBytes(bytes);
  91. }
  92. BigNum &setWord(unsigned int word) {
  93. if (!word) {
  94. clear();
  95. _failed = false;
  96. } else {
  97. _failed = !BN_set_word(raw(), word);
  98. }
  99. return *this;
  100. }
  101. BigNum &setBytes(bytes::const_span bytes) {
  102. if (bytes.empty()) {
  103. clear();
  104. _failed = false;
  105. } else {
  106. _failed = !BN_bin2bn(
  107. reinterpret_cast<const unsigned char*>(bytes.data()),
  108. bytes.size(),
  109. raw());
  110. }
  111. return *this;
  112. }
  113. BigNum &setAdd(const BigNum &a, const BigNum &b) {
  114. if (a.failed() || b.failed()) {
  115. _failed = true;
  116. } else {
  117. _failed = !BN_add(raw(), a.raw(), b.raw());
  118. }
  119. return *this;
  120. }
  121. BigNum &setSub(const BigNum &a, const BigNum &b) {
  122. if (a.failed() || b.failed()) {
  123. _failed = true;
  124. } else {
  125. _failed = !BN_sub(raw(), a.raw(), b.raw());
  126. }
  127. return *this;
  128. }
  129. BigNum &setMul(
  130. const BigNum &a,
  131. const BigNum &b,
  132. const Context &context = Context()) {
  133. if (a.failed() || b.failed()) {
  134. _failed = true;
  135. } else {
  136. _failed = !BN_mul(raw(), a.raw(), b.raw(), context.raw());
  137. }
  138. return *this;
  139. }
  140. BigNum &setModAdd(
  141. const BigNum &a,
  142. const BigNum &b,
  143. const BigNum &m,
  144. const Context &context = Context()) {
  145. if (a.failed() || b.failed() || m.failed()) {
  146. _failed = true;
  147. } else if (a.isNegative() || b.isNegative() || m.isNegative()) {
  148. _failed = true;
  149. } else if (!BN_mod_add(raw(), a.raw(), b.raw(), m.raw(), context.raw())) {
  150. _failed = true;
  151. } else if (isNegative()) {
  152. _failed = true;
  153. } else {
  154. _failed = false;
  155. }
  156. return *this;
  157. }
  158. BigNum &setModSub(
  159. const BigNum &a,
  160. const BigNum &b,
  161. const BigNum &m,
  162. const Context &context = Context()) {
  163. if (a.failed() || b.failed() || m.failed()) {
  164. _failed = true;
  165. } else if (a.isNegative() || b.isNegative() || m.isNegative()) {
  166. _failed = true;
  167. } else if (!BN_mod_sub(raw(), a.raw(), b.raw(), m.raw(), context.raw())) {
  168. _failed = true;
  169. } else if (isNegative()) {
  170. _failed = true;
  171. } else {
  172. _failed = false;
  173. }
  174. return *this;
  175. }
  176. BigNum &setModMul(
  177. const BigNum &a,
  178. const BigNum &b,
  179. const BigNum &m,
  180. const Context &context = Context()) {
  181. if (a.failed() || b.failed() || m.failed()) {
  182. _failed = true;
  183. } else if (a.isNegative() || b.isNegative() || m.isNegative()) {
  184. _failed = true;
  185. } else if (!BN_mod_mul(raw(), a.raw(), b.raw(), m.raw(), context.raw())) {
  186. _failed = true;
  187. } else if (isNegative()) {
  188. _failed = true;
  189. } else {
  190. _failed = false;
  191. }
  192. return *this;
  193. }
  194. BigNum &setModInverse(
  195. const BigNum &a,
  196. const BigNum &m,
  197. const Context &context = Context()) {
  198. if (a.failed() || m.failed()) {
  199. _failed = true;
  200. } else if (a.isNegative() || m.isNegative()) {
  201. _failed = true;
  202. } else if (!BN_mod_inverse(raw(), a.raw(), m.raw(), context.raw())) {
  203. _failed = true;
  204. } else if (isNegative()) {
  205. _failed = true;
  206. } else {
  207. _failed = false;
  208. }
  209. return *this;
  210. }
  211. BigNum &setModExp(
  212. const BigNum &base,
  213. const BigNum &power,
  214. const BigNum &m,
  215. const Context &context = Context()) {
  216. if (base.failed() || power.failed() || m.failed()) {
  217. _failed = true;
  218. } else if (base.isNegative() || power.isNegative() || m.isNegative()) {
  219. _failed = true;
  220. } else if (!BN_mod_exp(raw(), base.raw(), power.raw(), m.raw(), context.raw())) {
  221. _failed = true;
  222. } else if (isNegative()) {
  223. _failed = true;
  224. } else {
  225. _failed = false;
  226. }
  227. return *this;
  228. }
  229. BigNum &setGcd(
  230. const BigNum &a,
  231. const BigNum &b,
  232. const Context &context = Context()) {
  233. if (a.failed() || b.failed()) {
  234. _failed = true;
  235. } else if (a.isNegative() || b.isNegative()) {
  236. _failed = true;
  237. } else if (!BN_gcd(raw(), a.raw(), b.raw(), context.raw())) {
  238. _failed = true;
  239. } else if (isNegative()) {
  240. _failed = true;
  241. } else {
  242. _failed = false;
  243. }
  244. return *this;
  245. }
  246. [[nodiscard]] bool isZero() const {
  247. return !failed() && (!_data || BN_is_zero(raw()));
  248. }
  249. [[nodiscard]] bool isOne() const {
  250. return !failed() && _data && BN_is_one(raw());
  251. }
  252. [[nodiscard]] bool isNegative() const {
  253. return !failed() && _data && BN_is_negative(raw());
  254. }
  255. [[nodiscard]] bool isPrime(const Context &context = Context()) const {
  256. if (failed() || !_data) {
  257. return false;
  258. }
  259. constexpr auto kMillerRabinIterationCount = 64;
  260. const auto result = BN_is_prime_ex(
  261. raw(),
  262. kMillerRabinIterationCount,
  263. context.raw(),
  264. nullptr);
  265. if (result == 1) {
  266. return true;
  267. } else if (result != 0) {
  268. _failed = true;
  269. }
  270. return false;
  271. }
  272. BigNum &subWord(unsigned int word) {
  273. if (failed()) {
  274. return *this;
  275. } else if (!BN_sub_word(raw(), word)) {
  276. _failed = true;
  277. }
  278. return *this;
  279. }
  280. BigNum &divWord(BN_ULONG word, BN_ULONG *mod = nullptr) {
  281. Expects(word != 0);
  282. const auto result = failed()
  283. ? (BN_ULONG)-1
  284. : BN_div_word(raw(), word);
  285. if (result == (BN_ULONG)-1) {
  286. _failed = true;
  287. }
  288. if (mod) {
  289. *mod = result;
  290. }
  291. return *this;
  292. }
  293. [[nodiscard]] BN_ULONG countModWord(BN_ULONG word) const {
  294. Expects(word != 0);
  295. return failed() ? (BN_ULONG)-1 : BN_mod_word(raw(), word);
  296. }
  297. [[nodiscard]] int bitsSize() const {
  298. return failed() ? 0 : BN_num_bits(raw());
  299. }
  300. [[nodiscard]] int bytesSize() const {
  301. return failed() ? 0 : BN_num_bytes(raw());
  302. }
  303. [[nodiscard]] bytes::vector getBytes() const {
  304. if (failed()) {
  305. return {};
  306. }
  307. auto length = BN_num_bytes(raw());
  308. auto result = bytes::vector(length);
  309. auto resultSize = BN_bn2bin(
  310. raw(),
  311. reinterpret_cast<unsigned char*>(result.data()));
  312. Assert(resultSize == length);
  313. return result;
  314. }
  315. [[nodiscard]] BIGNUM *raw() {
  316. if (!_data) _data = BN_new();
  317. return _data;
  318. }
  319. [[nodiscard]] const BIGNUM *raw() const {
  320. if (!_data) _data = BN_new();
  321. return _data;
  322. }
  323. [[nodiscard]] BIGNUM *takeRaw() {
  324. return _failed
  325. ? nullptr
  326. : _data
  327. ? std::exchange(_data, nullptr)
  328. : BN_new();
  329. }
  330. [[nodiscard]] bool failed() const {
  331. return _failed;
  332. }
  333. [[nodiscard]] static BigNum Add(const BigNum &a, const BigNum &b) {
  334. return BigNum().setAdd(a, b);
  335. }
  336. [[nodiscard]] static BigNum Sub(const BigNum &a, const BigNum &b) {
  337. return BigNum().setSub(a, b);
  338. }
  339. [[nodiscard]] static BigNum Mul(
  340. const BigNum &a,
  341. const BigNum &b,
  342. const Context &context = Context()) {
  343. return BigNum().setMul(a, b, context);
  344. }
  345. [[nodiscard]] static BigNum ModAdd(
  346. const BigNum &a,
  347. const BigNum &b,
  348. const BigNum &mod,
  349. const Context &context = Context()) {
  350. return BigNum().setModAdd(a, b, mod, context);
  351. }
  352. [[nodiscard]] static BigNum ModSub(
  353. const BigNum &a,
  354. const BigNum &b,
  355. const BigNum &mod,
  356. const Context &context = Context()) {
  357. return BigNum().setModSub(a, b, mod, context);
  358. }
  359. [[nodiscard]] static BigNum ModMul(
  360. const BigNum &a,
  361. const BigNum &b,
  362. const BigNum &mod,
  363. const Context &context = Context()) {
  364. return BigNum().setModMul(a, b, mod, context);
  365. }
  366. [[nodiscard]] static BigNum ModInverse(
  367. const BigNum &a,
  368. const BigNum &mod,
  369. const Context &context = Context()) {
  370. return BigNum().setModInverse(a, mod, context);
  371. }
  372. [[nodiscard]] static BigNum ModExp(
  373. const BigNum &base,
  374. const BigNum &power,
  375. const BigNum &mod,
  376. const Context &context = Context()) {
  377. return BigNum().setModExp(base, power, mod, context);
  378. }
  379. [[nodiscard]] static int Compare(const BigNum &a, const BigNum &b) {
  380. return a.failed() ? -1 : b.failed() ? 1 : BN_cmp(a.raw(), b.raw());
  381. }
  382. static void Div(
  383. BigNum *dv,
  384. BigNum *rem,
  385. const BigNum &a,
  386. const BigNum &b,
  387. const Context &context = Context()) {
  388. if (!dv && !rem) {
  389. return;
  390. } else if (a.failed()
  391. || b.failed()
  392. || !BN_div(
  393. dv ? dv->raw() : nullptr,
  394. rem ? rem->raw() : nullptr,
  395. a.raw(),
  396. b.raw(),
  397. context.raw())) {
  398. if (dv) {
  399. dv->_failed = true;
  400. }
  401. if (rem) {
  402. rem->_failed = true;
  403. }
  404. } else {
  405. if (dv) {
  406. dv->_failed = false;
  407. }
  408. if (rem) {
  409. rem->_failed = false;
  410. }
  411. }
  412. }
  413. [[nodiscard]] static BigNum Failed() {
  414. auto result = BigNum();
  415. result._failed = true;
  416. return result;
  417. }
  418. private:
  419. void clear() {
  420. BN_clear_free(std::exchange(_data, nullptr));
  421. }
  422. mutable BIGNUM *_data = nullptr;
  423. mutable bool _failed = false;
  424. };
  425. namespace details {
  426. template <typename Context, typename Method, typename Arg>
  427. inline void ShaUpdate(Context context, Method method, Arg &&arg) {
  428. const auto span = bytes::make_span(arg);
  429. method(context, span.data(), span.size());
  430. }
  431. template <typename Context, typename Method, typename Arg, typename ...Args>
  432. inline void ShaUpdate(Context context, Method method, Arg &&arg, Args &&...args) {
  433. const auto span = bytes::make_span(arg);
  434. method(context, span.data(), span.size());
  435. ShaUpdate(context, method, args...);
  436. }
  437. template <size_type Size, typename Method>
  438. inline void Sha(
  439. bytes::span dst,
  440. Method method,
  441. bytes::const_span data) {
  442. Expects(dst.size() >= Size);
  443. method(
  444. reinterpret_cast<const unsigned char*>(data.data()),
  445. data.size(),
  446. reinterpret_cast<unsigned char*>(dst.data()));
  447. }
  448. template <size_type Size, typename Method>
  449. [[nodiscard]] inline bytes::vector Sha(
  450. Method method,
  451. bytes::const_span data) {
  452. auto bytes = bytes::vector(Size);
  453. Sha<Size>(bytes, method, data);
  454. return bytes;
  455. }
  456. template <
  457. size_type Size,
  458. typename Context,
  459. typename Init,
  460. typename Update,
  461. typename Finalize,
  462. typename ...Args,
  463. typename = std::enable_if_t<(sizeof...(Args) > 1)>>
  464. [[nodiscard]] bytes::vector Sha(
  465. Context context,
  466. Init init,
  467. Update update,
  468. Finalize finalize,
  469. Args &&...args) {
  470. auto bytes = bytes::vector(Size);
  471. init(&context);
  472. ShaUpdate(&context, update, args...);
  473. finalize(reinterpret_cast<unsigned char*>(bytes.data()), &context);
  474. return bytes;
  475. }
  476. template <
  477. size_type Size,
  478. typename Evp>
  479. [[nodiscard]] bytes::vector Pbkdf2(
  480. bytes::const_span password,
  481. bytes::const_span salt,
  482. int iterations,
  483. Evp evp) {
  484. auto result = bytes::vector(Size);
  485. PKCS5_PBKDF2_HMAC(
  486. reinterpret_cast<const char*>(password.data()),
  487. password.size(),
  488. reinterpret_cast<const unsigned char*>(salt.data()),
  489. salt.size(),
  490. iterations,
  491. evp,
  492. result.size(),
  493. reinterpret_cast<unsigned char*>(result.data()));
  494. return result;
  495. }
  496. } // namespace details
  497. constexpr auto kSha1Size = size_type(SHA_DIGEST_LENGTH);
  498. constexpr auto kSha256Size = size_type(SHA256_DIGEST_LENGTH);
  499. constexpr auto kSha512Size = size_type(SHA512_DIGEST_LENGTH);
  500. [[nodiscard]] inline bytes::vector Sha1(bytes::const_span data) {
  501. return details::Sha<kSha1Size>(SHA1, data);
  502. }
  503. inline void Sha1To(bytes::span dst, bytes::const_span data) {
  504. details::Sha<kSha1Size>(dst, SHA1, data);
  505. }
  506. template <
  507. typename ...Args,
  508. typename = std::enable_if_t<(sizeof...(Args) > 1)>>
  509. [[nodiscard]] inline bytes::vector Sha1(Args &&...args) {
  510. return details::Sha<kSha1Size>(
  511. SHA_CTX(),
  512. SHA1_Init,
  513. SHA1_Update,
  514. SHA1_Final,
  515. args...);
  516. }
  517. [[nodiscard]] inline bytes::vector Sha256(bytes::const_span data) {
  518. return details::Sha<kSha256Size>(SHA256, data);
  519. }
  520. inline void Sha256To(bytes::span dst, bytes::const_span data) {
  521. details::Sha<kSha256Size>(dst, SHA256, data);
  522. }
  523. template <
  524. typename ...Args,
  525. typename = std::enable_if_t<(sizeof...(Args) > 1)>>
  526. [[nodiscard]] inline bytes::vector Sha256(Args &&...args) {
  527. return details::Sha<kSha256Size>(
  528. SHA256_CTX(),
  529. SHA256_Init,
  530. SHA256_Update,
  531. SHA256_Final,
  532. args...);
  533. }
  534. [[nodiscard]] inline bytes::vector Sha512(bytes::const_span data) {
  535. return details::Sha<kSha512Size>(SHA512, data);
  536. }
  537. inline void Sha512To(bytes::span dst, bytes::const_span data) {
  538. details::Sha<kSha512Size>(dst, SHA512, data);
  539. }
  540. template <
  541. typename ...Args,
  542. typename = std::enable_if_t<(sizeof...(Args) > 1)>>
  543. [[nodiscard]] inline bytes::vector Sha512(Args &&...args) {
  544. return details::Sha<kSha512Size>(
  545. SHA512_CTX(),
  546. SHA512_Init,
  547. SHA512_Update,
  548. SHA512_Final,
  549. args...);
  550. }
  551. inline bytes::vector Pbkdf2Sha512(
  552. bytes::const_span password,
  553. bytes::const_span salt,
  554. int iterations) {
  555. return details::Pbkdf2<kSha512Size>(
  556. password,
  557. salt,
  558. iterations,
  559. EVP_sha512());
  560. }
  561. inline bytes::vector HmacSha256(
  562. bytes::const_span key,
  563. bytes::const_span data) {
  564. auto result = bytes::vector(kSha256Size);
  565. auto length = (unsigned int)kSha256Size;
  566. HMAC(
  567. EVP_sha256(),
  568. key.data(),
  569. key.size(),
  570. reinterpret_cast<const unsigned char*>(data.data()),
  571. data.size(),
  572. reinterpret_cast<unsigned char*>(result.data()),
  573. &length);
  574. return result;
  575. }
  576. } // namespace openssl