totp.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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 "../timezone_utils/timezone_utils.h"
  11. #define UINT64_GET_BYTE(integer, index) ((integer >> (8 * index)) & 0xFF)
  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. Converts an integer into an 8 byte array.
  27. out_bytes is the null-terminated output string already allocated
  28. */
  29. void otp_num_to_bytes(uint64_t integer, uint8_t* out_bytes) {
  30. out_bytes[7] = UINT64_GET_BYTE(integer, 0);
  31. out_bytes[6] = UINT64_GET_BYTE(integer, 1);
  32. out_bytes[5] = UINT64_GET_BYTE(integer, 2);
  33. out_bytes[4] = UINT64_GET_BYTE(integer, 3);
  34. out_bytes[3] = UINT64_GET_BYTE(integer, 4);
  35. out_bytes[2] = UINT64_GET_BYTE(integer, 5);
  36. out_bytes[1] = UINT64_GET_BYTE(integer, 6);
  37. out_bytes[0] = UINT64_GET_BYTE(integer, 7);
  38. }
  39. /*
  40. Generates an OTP (One Time Password).
  41. input is a number used to generate the OTP
  42. out_str is the null-terminated output string already allocated
  43. Returns
  44. OTP code if otp code was successfully generated
  45. 0 otherwise
  46. */
  47. uint32_t otp_generate(
  48. TOTP_ALGO algo,
  49. uint8_t digits,
  50. const uint8_t* plain_secret,
  51. uint8_t plain_secret_length,
  52. uint64_t input) {
  53. uint8_t* bytes = malloc(8);
  54. memset(bytes, 0, 8);
  55. uint8_t* hmac = malloc(64);
  56. memset(hmac, 0, 64);
  57. otp_num_to_bytes(input, bytes);
  58. int hmac_len = (*(algo))(plain_secret, plain_secret_length, bytes, 8, hmac);
  59. if(hmac_len == 0) {
  60. free(hmac);
  61. free(bytes);
  62. return OTP_ERROR;
  63. }
  64. uint64_t offset = (hmac[hmac_len - 1] & 0xF);
  65. uint64_t i_code =
  66. ((hmac[offset] & 0x7F) << 24 | (hmac[offset + 1] & 0xFF) << 16 |
  67. (hmac[offset + 2] & 0xFF) << 8 | (hmac[offset + 3] & 0xFF));
  68. i_code %= (uint64_t)pow(10, digits);
  69. free(hmac);
  70. free(bytes);
  71. return i_code;
  72. }
  73. /*
  74. Generates a OTP key using the totp algorithm.
  75. for_time is the time the generated key will be created for
  76. offset is a timeblock adjustment for the generated key
  77. out_str is the null-terminated output string already allocated
  78. Returns
  79. TOTP code if otp code was successfully generated
  80. 0 otherwise
  81. */
  82. uint32_t totp_at(
  83. TOTP_ALGO algo,
  84. uint8_t digits,
  85. const uint8_t* plain_secret,
  86. uint8_t plain_secret_length,
  87. uint64_t for_time,
  88. float timezone,
  89. uint8_t interval) {
  90. uint64_t for_time_adjusted =
  91. timezone_offset_apply(for_time, timezone_offset_from_hours(timezone));
  92. return otp_generate(
  93. algo,
  94. digits,
  95. plain_secret,
  96. plain_secret_length,
  97. totp_timecode(interval, for_time_adjusted));
  98. }
  99. static int totp_algo_sha1(
  100. const uint8_t* key,
  101. uint8_t key_length,
  102. const uint8_t* input,
  103. uint8_t input_length,
  104. uint8_t* output) {
  105. hmac_sha1(key, key_length, input, input_length, output);
  106. return HMAC_SHA1_RESULT_SIZE;
  107. }
  108. static int totp_algo_sha256(
  109. const uint8_t* key,
  110. uint8_t key_length,
  111. const uint8_t* input,
  112. uint8_t input_length,
  113. uint8_t* output) {
  114. hmac_sha256(key, key_length, input, input_length, output);
  115. return HMAC_SHA256_RESULT_SIZE;
  116. }
  117. static int totp_algo_sha512(
  118. const uint8_t* key,
  119. uint8_t key_length,
  120. const uint8_t* input,
  121. uint8_t input_length,
  122. uint8_t* output) {
  123. hmac_sha512(key, key_length, input, input_length, output);
  124. return HMAC_SHA512_RESULT_SIZE;
  125. }
  126. const TOTP_ALGO TOTP_ALGO_SHA1 = (TOTP_ALGO)(&totp_algo_sha1);
  127. const TOTP_ALGO TOTP_ALGO_SHA256 = (TOTP_ALGO)(&totp_algo_sha256);
  128. const TOTP_ALGO TOTP_ALGO_SHA512 = (TOTP_ALGO)(&totp_algo_sha512);