totp.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #include "totp.h"
  2. #include <stdlib.h>
  3. #include <stdint.h>
  4. #include <math.h>
  5. #include <timezone_utils.h>
  6. #include "../hmac/hmac_sha1.h"
  7. #include "../hmac/hmac_sha256.h"
  8. #include "../hmac/hmac_sha512.h"
  9. #include "../hmac/byteswap.h"
  10. #define HMAC_MAX_RESULT_SIZE HMAC_SHA512_RESULT_SIZE
  11. /**
  12. * @brief Generates the timeblock for a time in seconds.
  13. * Timeblocks are the amount of intervals in a given time. For example,
  14. * if 1,000,000 seconds has passed for 30 second intervals, you would get
  15. * 33,333 timeblocks (intervals), where timeblock++ is effectively +30 seconds.
  16. * @param interval in seconds
  17. * @param for_time a time in seconds to get the current timeblocks
  18. * @return Timeblock given \p for_time using \p interval
  19. */
  20. uint64_t totp_timecode(uint8_t interval, uint64_t for_time) {
  21. return for_time / interval;
  22. }
  23. /**
  24. * @brief Generates an OTP (One Time Password)
  25. * @param algo hashing algorithm to be used
  26. * @param plain_secret plain token secret
  27. * @param plain_secret_length plain token secret length
  28. * @param input input data for OTP code generation
  29. * @return OTP code if code was successfully generated; 0 otherwise
  30. */
  31. uint64_t otp_generate(
  32. TOTP_ALGO algo,
  33. const uint8_t* plain_secret,
  34. size_t plain_secret_length,
  35. uint64_t input) {
  36. uint8_t hmac[HMAC_MAX_RESULT_SIZE] = {0};
  37. uint64_t input_swapped = swap_uint64(input);
  38. int hmac_len =
  39. (*algo)(plain_secret, plain_secret_length, (uint8_t*)&input_swapped, 8, &hmac[0]);
  40. if(hmac_len == 0) {
  41. return OTP_ERROR;
  42. }
  43. uint64_t offset = (hmac[hmac_len - 1] & 0xF);
  44. uint64_t i_code =
  45. ((hmac[offset] & 0x7F) << 24 | (hmac[offset + 1] & 0xFF) << 16 |
  46. (hmac[offset + 2] & 0xFF) << 8 | (hmac[offset + 3] & 0xFF));
  47. return i_code;
  48. }
  49. uint64_t totp_at(
  50. TOTP_ALGO algo,
  51. const uint8_t* plain_secret,
  52. size_t plain_secret_length,
  53. uint64_t for_time,
  54. float timezone,
  55. uint8_t interval) {
  56. uint64_t for_time_adjusted =
  57. timezone_offset_apply(for_time, timezone_offset_from_hours(timezone));
  58. return otp_generate(
  59. algo, plain_secret, plain_secret_length, totp_timecode(interval, for_time_adjusted));
  60. }
  61. static int totp_algo_sha1(
  62. const uint8_t* key,
  63. size_t key_length,
  64. const uint8_t* input,
  65. size_t input_length,
  66. uint8_t* output) {
  67. hmac_sha1(key, key_length, input, input_length, output);
  68. return HMAC_SHA1_RESULT_SIZE;
  69. }
  70. static int totp_algo_sha256(
  71. const uint8_t* key,
  72. size_t key_length,
  73. const uint8_t* input,
  74. size_t input_length,
  75. uint8_t* output) {
  76. hmac_sha256(key, key_length, input, input_length, output);
  77. return HMAC_SHA256_RESULT_SIZE;
  78. }
  79. static int totp_algo_sha512(
  80. const uint8_t* key,
  81. size_t key_length,
  82. const uint8_t* input,
  83. size_t input_length,
  84. uint8_t* output) {
  85. hmac_sha512(key, key_length, input, input_length, output);
  86. return HMAC_SHA512_RESULT_SIZE;
  87. }
  88. const TOTP_ALGO TOTP_ALGO_SHA1 = (TOTP_ALGO)(&totp_algo_sha1);
  89. const TOTP_ALGO TOTP_ALGO_SHA256 = (TOTP_ALGO)(&totp_algo_sha256);
  90. const TOTP_ALGO TOTP_ALGO_SHA512 = (TOTP_ALGO)(&totp_algo_sha512);