totp.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #include "totp.h"
  2. #include <stdlib.h>
  3. #include <stdint.h>
  4. #include <math.h>
  5. #include "../../config/wolfssl/config.h"
  6. #include <wolfssl/wolfcrypt/hmac.h>
  7. #ifdef NO_INLINE
  8. #include <wolfssl/wolfcrypt/misc.h>
  9. #else
  10. #define WOLFSSL_MISC_INCLUDED
  11. #include <wolfcrypt/src/misc.c>
  12. #endif
  13. #define HMAC_MAX_RESULT_SIZE WC_SHA512_DIGEST_SIZE
  14. static int32_t timezone_offset_from_hours(float hours) {
  15. return hours * 3600.0f;
  16. }
  17. static uint64_t timezone_offset_apply(uint64_t time, int32_t offset) {
  18. uint64_t for_time_adjusted;
  19. if(offset > 0) {
  20. for_time_adjusted = time - offset;
  21. } else {
  22. for_time_adjusted = time + (-offset);
  23. }
  24. return for_time_adjusted;
  25. }
  26. /**
  27. * @brief Generates the timeblock for a time in seconds.
  28. * Timeblocks are the amount of intervals in a given time. For example,
  29. * if 1,000,000 seconds has passed for 30 second intervals, you would get
  30. * 33,333 timeblocks (intervals), where timeblock++ is effectively +30 seconds.
  31. * @param interval in seconds
  32. * @param for_time a time in seconds to get the current timeblocks
  33. * @return Timeblock given \p for_time using \p interval
  34. */
  35. uint64_t totp_timecode(uint8_t interval, uint64_t for_time) {
  36. return for_time / interval;
  37. }
  38. /**
  39. * @brief Generates an OTP (One Time Password)
  40. * @param algo hashing algorithm to be used
  41. * @param plain_secret plain token secret
  42. * @param plain_secret_length plain token secret length
  43. * @param input input data for OTP code generation
  44. * @return OTP code if code was successfully generated; 0 otherwise
  45. */
  46. uint64_t otp_generate(
  47. TOTP_ALGO algo,
  48. const uint8_t* plain_secret,
  49. size_t plain_secret_length,
  50. uint64_t input) {
  51. uint8_t hmac[HMAC_MAX_RESULT_SIZE] = {0};
  52. uint64_t input_swapped = ByteReverseWord64(input);
  53. int hmac_len =
  54. (*algo)(plain_secret, plain_secret_length, (uint8_t*)&input_swapped, 8, &hmac[0]);
  55. if(hmac_len == 0) {
  56. return OTP_ERROR;
  57. }
  58. uint64_t offset = (hmac[hmac_len - 1] & 0xF);
  59. uint64_t i_code =
  60. ((hmac[offset] & 0x7F) << 24 | (hmac[offset + 1] & 0xFF) << 16 |
  61. (hmac[offset + 2] & 0xFF) << 8 | (hmac[offset + 3] & 0xFF));
  62. return i_code;
  63. }
  64. uint64_t totp_at(
  65. TOTP_ALGO algo,
  66. const uint8_t* plain_secret,
  67. size_t plain_secret_length,
  68. uint64_t for_time,
  69. float timezone,
  70. uint8_t interval) {
  71. uint64_t for_time_adjusted =
  72. timezone_offset_apply(for_time, timezone_offset_from_hours(timezone));
  73. return otp_generate(
  74. algo, plain_secret, plain_secret_length, totp_timecode(interval, for_time_adjusted));
  75. }
  76. uint64_t hotp_at(
  77. TOTP_ALGO algo,
  78. const uint8_t* plain_secret,
  79. size_t plain_secret_length,
  80. uint64_t counter) {
  81. return otp_generate(algo, plain_secret, plain_secret_length, counter);
  82. }
  83. static int totp_algo_common(
  84. int type,
  85. const uint8_t* key,
  86. size_t key_length,
  87. const uint8_t* input,
  88. size_t input_length,
  89. uint8_t* output) {
  90. Hmac hmac;
  91. int ret = wc_HmacSetKey(&hmac, type, key, key_length);
  92. if(ret == 0) {
  93. ret = wc_HmacUpdate(&hmac, input, input_length);
  94. }
  95. if(ret == 0) {
  96. ret = wc_HmacFinal(&hmac, output);
  97. }
  98. wc_HmacFree(&hmac);
  99. return ret == 0 ? wc_HmacSizeByType(type) : 0;
  100. }
  101. static int totp_algo_sha1(
  102. const uint8_t* key,
  103. size_t key_length,
  104. const uint8_t* input,
  105. size_t input_length,
  106. uint8_t* output) {
  107. return totp_algo_common(WC_SHA, key, key_length, input, input_length, output);
  108. }
  109. static int totp_algo_sha256(
  110. const uint8_t* key,
  111. size_t key_length,
  112. const uint8_t* input,
  113. size_t input_length,
  114. uint8_t* output) {
  115. return totp_algo_common(WC_SHA256, key, key_length, input, input_length, output);
  116. }
  117. static int totp_algo_sha512(
  118. const uint8_t* key,
  119. size_t key_length,
  120. const uint8_t* input,
  121. size_t input_length,
  122. uint8_t* output) {
  123. return totp_algo_common(WC_SHA512, key, key_length, input, input_length, output);
  124. }
  125. const TOTP_ALGO TOTP_ALGO_SHA1 = (TOTP_ALGO)(&totp_algo_sha1);
  126. const TOTP_ALGO TOTP_ALGO_SHA256 = (TOTP_ALGO)(&totp_algo_sha256);
  127. const TOTP_ALGO TOTP_ALGO_SHA512 = (TOTP_ALGO)(&totp_algo_sha512);