aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/lib/libotputil/lrfc4226-hotp.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libotputil/lrfc4226-hotp.c')
-rw-r--r--lib/libotputil/lrfc4226-hotp.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/lib/libotputil/lrfc4226-hotp.c b/lib/libotputil/lrfc4226-hotp.c
new file mode 100644
index 0000000..15ee45d
--- /dev/null
+++ b/lib/libotputil/lrfc4226-hotp.c
@@ -0,0 +1,237 @@
1/*
2 * OTP Utilities
3 * Copyright (C) 2022 David M. Syzdek <david@syzdek.net>.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * Neither the name of David M. Syzdek nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID M SYZDEK BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30/*
31 * @file lib/libotputil/lrfc4226-hotp.c
32 */
33#define _LIB_LIBOTPUTIL_LRFC4226_HOTP_C 1
34#include "lrfc4226-hotp.h"
35
36///////////////
37// //
38// Headers //
39// //
40///////////////
41#pragma mark - Headers
42
43#include <errno.h>
44#include <stdarg.h>
45#include <string.h>
46#include <strings.h>
47#include <stdlib.h>
48#include <ctype.h>
49#include <openssl/evp.h>
50#include <openssl/hmac.h>
51
52#include "lmisc.h"
53
54
55/////////////////
56// //
57// Functions //
58// //
59/////////////////
60#pragma mark - Functions
61
62//----------------//
63// misc functions //
64//----------------//
65#pragma mark misc functions
66
67char *
68otputil_code2str(
69 int code,
70 int code_digits,
71 char * dst,
72 size_t dstlen )
73{
74 static char buff[OTPUTIL_MAX_CODE_SIZE];
75
76 if (!(dst))
77 {
78 dst = buff;
79 dstlen = sizeof(buff);
80 };
81 if (dstlen < (size_t)(otputil_defaults.hotp_digits+1))
82 return(NULL);
83
84 snprintf(dst, dstlen, "%0*i", code_digits, code);
85
86 return(dst);
87}
88
89
90//---------------//
91// HOTP functions //
92//---------------//
93#pragma mark HOTP functions (RFC 4226)
94
95int
96otputil_hotp_code(
97 const otputil_bv_t * hotp_k,
98 uint64_t hotp_c,
99 int hotp_hmac,
100 int hotp_digits )
101{
102 const EVP_MD * evp_md;
103 uint32_t endianness;
104 uint64_t offset;
105 uint8_t * hmac_result;
106 uint32_t bin_code;
107 unsigned char md[EVP_MAX_MD_SIZE];
108 unsigned md_len;
109 int hotp_code;
110
111 if ( (!(hotp_k)) || (!(hotp_k->bv_val)) || (!(hotp_k->bv_len)) )
112 return(-1);
113
114 md_len = EVP_MAX_MD_SIZE;
115 hotp_digits = ((hotp_digits)) ? hotp_digits : (int)otputil_defaults.hotp_digits;
116
117 switch(hotp_hmac)
118 {
119 case OTPUTIL_MD_SHA1: evp_md = EVP_sha1(); break;
120 case OTPUTIL_MD_SHA256: evp_md = EVP_sha256(); break;
121 case OTPUTIL_MD_SHA512: evp_md = EVP_sha512(); break;
122 default: return(-1);
123 };
124
125 // converts T to big endian if system is little endian
126 endianness = 0xdeadbeef;
127 if ((*(const uint8_t *)&endianness) == 0xef)
128 {
129 hotp_c = ((hotp_c & 0x00000000ffffffff) << 32) | ((hotp_c & 0xffffffff00000000) >> 32);
130 hotp_c = ((hotp_c & 0x0000ffff0000ffff) << 16) | ((hotp_c & 0xffff0000ffff0000) >> 16);
131 hotp_c = ((hotp_c & 0x00ff00ff00ff00ff) << 8) | ((hotp_c & 0xff00ff00ff00ff00) >> 8);
132 };
133
134 // determines hash
135 hmac_result = (uint8_t *)HMAC(evp_md, hotp_k->bv_val, (int)hotp_k->bv_len, (unsigned char *)&hotp_c, sizeof(hotp_c), md, &md_len);
136
137 // dynamically truncates hash
138 offset = hmac_result[md_len-1] & 0x0f;
139 bin_code = (hmac_result[offset+0] & 0x7f) << 24
140 | (hmac_result[offset+1] & 0xff) << 16
141 | (hmac_result[offset+2] & 0xff) << 8
142 | (hmac_result[offset+3] & 0xff);
143
144 // truncates code to 6 digits
145 hotp_code = (int)(bin_code % otputil_upow(10, (uintmax_t)hotp_digits));
146
147 return(hotp_code);
148}
149
150
151char *
152otputil_hotp_str(
153 const otputil_bv_t * hotp_k,
154 uint64_t hotp_c,
155 int hotp_hmac,
156 int hotp_digits,
157 char * dst,
158 size_t dstlen )
159{
160 int otp_code;
161 static char buff[OTPUTIL_MAX_CODE_SIZE];
162
163 hotp_k = ((hotp_k)) ? hotp_k : &otputil_const_defaults_k;
164 hotp_digits = ((hotp_digits)) ? hotp_digits : (int)otputil_defaults.hotp_digits;
165 dstlen = ((dst)) ? dstlen : sizeof(buff);
166 dst = ((dst)) ? dst : buff;
167
168 if ((otp_code = otputil_hotp_code(hotp_k, hotp_c, hotp_hmac, hotp_digits)) == -1)
169 return(NULL);
170
171 return(otputil_code2str(otp_code, hotp_digits, dst, dstlen));
172}
173
174
175//---------------//
176// TOTP functions //
177//---------------//
178#pragma mark TOTP functions (RFC 6238)
179
180int
181otputil_totp_code(
182 const otputil_bv_t * totp_k,
183 uint64_t totp_t0,
184 uint64_t totp_tx,
185 uint64_t totp_time,
186 int totp_hmac,
187 int totp_digits )
188{
189 uint64_t hotp_c;
190
191 if (!(totp_tx))
192 return(-1);
193
194 totp_k = ((totp_k)) ? totp_k : &otputil_const_defaults_k;
195 totp_time = ((totp_time)) ? totp_time : ((uint64_t)time(NULL));
196 hotp_c = (totp_time - totp_t0) / totp_tx;
197
198 return(otputil_hotp_code(totp_k, hotp_c, totp_hmac, totp_digits));
199}
200
201
202char *
203otputil_totp_str(
204 const otputil_bv_t * totp_k,
205 uint64_t totp_t0,
206 uint64_t totp_tx,
207 uint64_t totp_time,
208 int totp_hmac,
209 int totp_digits,
210 char * dst,
211 size_t dstlen )
212{
213 int otp_code;
214 static char buff[OTPUTIL_MAX_CODE_SIZE];
215
216 dstlen = ((dst)) ? dstlen : sizeof(buff);
217 dst = ((dst)) ? dst : buff;
218
219 if ((otp_code = otputil_totp_code(totp_k, totp_t0, totp_tx, totp_time, totp_hmac, totp_digits)) == -1)
220 return(NULL);
221
222 return(otputil_code2str(otp_code, totp_digits, dst, dstlen));
223}
224
225
226uint64_t
227otputil_totp_timer(
228 uint64_t totp_t0,
229 uint64_t totp_tx,
230 uint64_t totp_time )
231{
232 assert(totp_tx != 0);
233 totp_time = ((totp_time)) ? totp_time : (uint64_t)time(NULL);
234 return(totp_tx - ((totp_time - totp_t0) % totp_tx));
235}
236
237/* end of source file */