totp.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. #include "totp.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <stdint.h>
  5. #include <string.h>
  6. #include <math.h>
  7. #include "../hmac/hmac_sha1.h"
  8. #include "../hmac/hmac_sha256.h"
  9. #include "../hmac/hmac_sha512.h"
  10. #include "../hmac/byteswap.h"
  11. #include "../timezone_utils/timezone_utils.h"
  12. /*
  13. Generates the timeblock for a time in seconds.
  14. Timeblocks are the amount of intervals in a given time. For example,
  15. if 1,000,000 seconds has passed for 30 second intervals, you would get
  16. 33,333 timeblocks (intervals), where timeblock++ is effectively +30 seconds.
  17. for_time is a time in seconds to get the current timeblocks
  18. Returns
  19. timeblock given for_time, using data->interval
  20. error, 0
  21. */
  22. uint64_t totp_timecode(uint8_t interval, uint64_t for_time) {
  23. return for_time / interval;
  24. }
  25. /*
  26. Generates an OTP (One Time Password).
  27. input is a number used to generate the OTP
  28. out_str is the null-terminated output string already allocated
  29. Returns
  30. OTP code if otp code was successfully generated
  31. 0 otherwise
  32. */
  33. uint32_t otp_generate(
  34. TOTP_ALGO algo,
  35. uint8_t digits,
  36. const uint8_t* plain_secret,
  37. size_t plain_secret_length,
  38. uint64_t input) {
  39. uint8_t* hmac = malloc(64);
  40. if(hmac == NULL) return OTP_ERROR;
  41. memset(hmac, 0, 64);
  42. uint64_t input_swapped = swap_uint64(input);
  43. int hmac_len = (*algo)(plain_secret, plain_secret_length, (uint8_t*)&input_swapped, 8, hmac);
  44. if(hmac_len == 0) {
  45. free(hmac);
  46. return OTP_ERROR;
  47. }
  48. uint64_t offset = (hmac[hmac_len - 1] & 0xF);
  49. uint64_t i_code =
  50. ((hmac[offset] & 0x7F) << 24 | (hmac[offset + 1] & 0xFF) << 16 |
  51. (hmac[offset + 2] & 0xFF) << 8 | (hmac[offset + 3] & 0xFF));
  52. i_code %= (uint64_t)pow(10, digits);
  53. free(hmac);
  54. return i_code;
  55. }
  56. /*
  57. Generates a OTP key using the totp algorithm.
  58. for_time is the time the generated key will be created for
  59. offset is a timeblock adjustment for the generated key
  60. out_str is the null-terminated output string already allocated
  61. Returns
  62. TOTP code if otp code was successfully generated
  63. 0 otherwise
  64. */
  65. uint32_t totp_at(
  66. TOTP_ALGO algo,
  67. uint8_t digits,
  68. const uint8_t* plain_secret,
  69. size_t plain_secret_length,
  70. uint64_t for_time,
  71. float timezone,
  72. uint8_t interval) {
  73. uint64_t for_time_adjusted =
  74. timezone_offset_apply(for_time, timezone_offset_from_hours(timezone));
  75. return otp_generate(
  76. algo,
  77. digits,
  78. plain_secret,
  79. plain_secret_length,
  80. totp_timecode(interval, for_time_adjusted));
  81. }
  82. static int totp_algo_sha1(
  83. const uint8_t* key,
  84. size_t key_length,
  85. const uint8_t* input,
  86. size_t input_length,
  87. uint8_t* output) {
  88. hmac_sha1(key, key_length, input, input_length, output);
  89. return HMAC_SHA1_RESULT_SIZE;
  90. }
  91. static int totp_algo_sha256(
  92. const uint8_t* key,
  93. size_t key_length,
  94. const uint8_t* input,
  95. size_t input_length,
  96. uint8_t* output) {
  97. hmac_sha256(key, key_length, input, input_length, output);
  98. return HMAC_SHA256_RESULT_SIZE;
  99. }
  100. static int totp_algo_sha512(
  101. const uint8_t* key,
  102. size_t key_length,
  103. const uint8_t* input,
  104. size_t input_length,
  105. uint8_t* output) {
  106. hmac_sha512(key, key_length, input, input_length, output);
  107. return HMAC_SHA512_RESULT_SIZE;
  108. }
  109. const TOTP_ALGO TOTP_ALGO_SHA1 = (TOTP_ALGO)(&totp_algo_sha1);
  110. const TOTP_ALGO TOTP_ALGO_SHA256 = (TOTP_ALGO)(&totp_algo_sha256);
  111. const TOTP_ALGO TOTP_ALGO_SHA512 = (TOTP_ALGO)(&totp_algo_sha512);