totp.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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. {
  24. return for_time/interval;
  25. }
  26. /*
  27. Converts an integer into an 8 byte array.
  28. out_bytes is the null-terminated output string already allocated
  29. */
  30. void otp_num_to_bytes(uint64_t integer, uint8_t* out_bytes)
  31. {
  32. out_bytes[7] = UINT64_GET_BYTE(integer, 0);
  33. out_bytes[6] = UINT64_GET_BYTE(integer, 1);
  34. out_bytes[5] = UINT64_GET_BYTE(integer, 2);
  35. out_bytes[4] = UINT64_GET_BYTE(integer, 3);
  36. out_bytes[3] = UINT64_GET_BYTE(integer, 4);
  37. out_bytes[2] = UINT64_GET_BYTE(integer, 5);
  38. out_bytes[1] = UINT64_GET_BYTE(integer, 6);
  39. out_bytes[0] = UINT64_GET_BYTE(integer, 7);
  40. }
  41. /*
  42. Generates an OTP (One Time Password).
  43. input is a number used to generate the OTP
  44. out_str is the null-terminated output string already allocated
  45. Returns
  46. OTP code if otp code was successfully generated
  47. 0 otherwise
  48. */
  49. uint32_t otp_generate(TOTP_ALGO algo, uint8_t digits, const uint8_t* plain_secret, uint8_t plain_secret_length, uint64_t input)
  50. {
  51. uint8_t* bytes = malloc(8);
  52. memset(bytes, 0, 8);
  53. uint8_t* hmac = malloc(64);
  54. memset(hmac, 0, 64);
  55. otp_num_to_bytes(input, bytes);
  56. int hmac_len = (*(algo))(plain_secret, plain_secret_length, bytes, 8, hmac);
  57. if (hmac_len == 0) {
  58. free(hmac);
  59. free(bytes);
  60. return OTP_ERROR;
  61. }
  62. uint64_t offset = (hmac[hmac_len-1] & 0xF);
  63. uint64_t i_code =
  64. ((hmac[offset] & 0x7F) << 24 |
  65. (hmac[offset + 1] & 0xFF) << 16 |
  66. (hmac[offset + 2] & 0xFF) << 8 |
  67. (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(TOTP_ALGO algo, uint8_t digits, const uint8_t* plain_secret, uint8_t plain_secret_length, uint64_t for_time, float timezone, uint8_t interval)
  83. {
  84. uint64_t for_time_adjusted = timezone_offset_apply(for_time, timezone_offset_from_hours(timezone));
  85. return otp_generate(algo, digits, plain_secret, plain_secret_length, totp_timecode(interval, for_time_adjusted));
  86. }
  87. static int totp_algo_sha1(const uint8_t* key, uint8_t key_length, const uint8_t* input, uint8_t input_length, 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(const uint8_t* key, uint8_t key_length, const uint8_t* input, uint8_t input_length, uint8_t* output) {
  92. hmac_sha256(key, key_length, input, input_length, output);
  93. return HMAC_SHA256_RESULT_SIZE;
  94. }
  95. static int totp_algo_sha512(const uint8_t* key, uint8_t key_length, const uint8_t* input, uint8_t input_length, uint8_t* output) {
  96. hmac_sha512(key, key_length, input, input_length, output);
  97. return HMAC_SHA512_RESULT_SIZE;
  98. }
  99. const TOTP_ALGO TOTP_ALGO_SHA1 = (TOTP_ALGO)(&totp_algo_sha1);
  100. const TOTP_ALGO TOTP_ALGO_SHA256 = (TOTP_ALGO)(&totp_algo_sha256);
  101. const TOTP_ALGO TOTP_ALGO_SHA512 = (TOTP_ALGO)(&totp_algo_sha512);