aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--lib/libotputil/lhotp.c237
-rw-r--r--lib/libotputil/lhotp.h62
-rw-r--r--lib/libotputil/libotputil.c188
4 files changed, 302 insertions, 187 deletions
diff --git a/Makefile.am b/Makefile.am
index 1d1cea8..0311d85 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -174,6 +174,8 @@ lib_libotputil_a_SOURCES = $(noinst_HEADERS) \
174 lib/libotputil/libotputil.c \ 174 lib/libotputil/libotputil.c \
175 lib/libotputil/lbv.c \ 175 lib/libotputil/lbv.c \
176 lib/libotputil/lbv.h \ 176 lib/libotputil/lbv.h \
177 lib/libotputil/lhotp.c \
178 lib/libotputil/lhotp.h \
177 lib/libotputil/lmisc.c \ 179 lib/libotputil/lmisc.c \
178 lib/libotputil/lmisc.h \ 180 lib/libotputil/lmisc.h \
179 lib/libotputil/lotp.c \ 181 lib/libotputil/lotp.c \
diff --git a/lib/libotputil/lhotp.c b/lib/libotputil/lhotp.c
new file mode 100644
index 0000000..979cf4b
--- /dev/null
+++ b/lib/libotputil/lhotp.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/lhotp.c
32 */
33#define _LIB_LIBOTPUTIL_LHOTP_C 1
34#include "lhotp.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 */
diff --git a/lib/libotputil/lhotp.h b/lib/libotputil/lhotp.h
new file mode 100644
index 0000000..dfff5c4
--- /dev/null
+++ b/lib/libotputil/lhotp.h
@@ -0,0 +1,62 @@
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/lhotp.h
32 */
33#ifndef _LIB_LIBOTPUTIL_LHOTP_H
34#define _LIB_LIBOTPUTIL_LHOTP_H 1
35
36
37///////////////
38// //
39// Headers //
40// //
41///////////////
42#pragma mark - Headers
43
44#include "libotputil.h"
45
46
47//////////////////
48// //
49// Prototypes //
50// //
51//////////////////
52#pragma mark - Prototypes
53
54extern char *
55otputil_code2str(
56 int code,
57 int code_digits,
58 char * dst,
59 size_t dstlen );
60
61
62#endif /* end of header file */
diff --git a/lib/libotputil/libotputil.c b/lib/libotputil/libotputil.c
index a12f899..5a90066 100644
--- a/lib/libotputil/libotputil.c
+++ b/lib/libotputil/libotputil.c
@@ -51,6 +51,7 @@
51 51
52#include "ldict-rfc1760.h" 52#include "ldict-rfc1760.h"
53#include "lmisc.h" 53#include "lmisc.h"
54#include "lhotp.h"
54 55
55 56
56////////////////// 57//////////////////
@@ -60,18 +61,6 @@
60////////////////// 61//////////////////
61#pragma mark - Prototypes 62#pragma mark - Prototypes
62 63
63//-----------------//
64// misc prototypes //
65//-----------------//
66#pragma mark misc prototypes
67
68static char *
69otputil_code2str(
70 int code,
71 int code_digits,
72 char * dst,
73 size_t dstlen );
74
75 64
76///////////////// 65/////////////////
77// // 66// //
@@ -519,34 +508,6 @@ otputil_set_param(
519#undef _SET_INPUT_NUM 508#undef _SET_INPUT_NUM
520 509
521 510
522//----------------//
523// misc functions //
524//----------------//
525#pragma mark misc functions
526
527char *
528otputil_code2str(
529 int code,
530 int code_digits,
531 char * dst,
532 size_t dstlen )
533{
534 static char buff[OTPUTIL_MAX_CODE_SIZE];
535
536 if (!(dst))
537 {
538 dst = buff;
539 dstlen = sizeof(buff);
540 };
541 if (dstlen < (size_t)(otputil_defaults.hotp_digits+1))
542 return(NULL);
543
544 snprintf(dst, dstlen, "%0*i", code_digits, code);
545
546 return(dst);
547}
548
549
550//---------------------// 511//---------------------//
551// Front-end functions // 512// Front-end functions //
552//---------------------// 513//---------------------//
@@ -620,151 +581,4 @@ otputil_timer(
620} 581}
621 582
622 583
623//---------------//
624// HOTP functions //
625//---------------//
626#pragma mark HOTP functions (RFC 4226)
627
628int
629otputil_hotp_code(
630 const otputil_bv_t * hotp_k,
631 uint64_t hotp_c,
632 int hotp_hmac,
633 int hotp_digits )
634{
635 const EVP_MD * evp_md;
636 uint32_t endianness;
637 uint64_t offset;
638 uint8_t * hmac_result;
639 uint32_t bin_code;
640 unsigned char md[EVP_MAX_MD_SIZE];
641 unsigned md_len;
642 int hotp_code;
643
644 if ( (!(hotp_k)) || (!(hotp_k->bv_val)) || (!(hotp_k->bv_len)) )
645 return(-1);
646
647 md_len = EVP_MAX_MD_SIZE;
648 hotp_digits = ((hotp_digits)) ? hotp_digits : (int)otputil_defaults.hotp_digits;
649
650 switch(hotp_hmac)
651 {
652 case OTPUTIL_MD_SHA1: evp_md = EVP_sha1(); break;
653 case OTPUTIL_MD_SHA256: evp_md = EVP_sha256(); break;
654 case OTPUTIL_MD_SHA512: evp_md = EVP_sha512(); break;
655 default: return(-1);
656 };
657
658 // converts T to big endian if system is little endian
659 endianness = 0xdeadbeef;
660 if ((*(const uint8_t *)&endianness) == 0xef)
661 {
662 hotp_c = ((hotp_c & 0x00000000ffffffff) << 32) | ((hotp_c & 0xffffffff00000000) >> 32);
663 hotp_c = ((hotp_c & 0x0000ffff0000ffff) << 16) | ((hotp_c & 0xffff0000ffff0000) >> 16);
664 hotp_c = ((hotp_c & 0x00ff00ff00ff00ff) << 8) | ((hotp_c & 0xff00ff00ff00ff00) >> 8);
665 };
666
667 // determines hash
668 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);
669
670 // dynamically truncates hash
671 offset = hmac_result[md_len-1] & 0x0f;
672 bin_code = (hmac_result[offset+0] & 0x7f) << 24
673 | (hmac_result[offset+1] & 0xff) << 16
674 | (hmac_result[offset+2] & 0xff) << 8
675 | (hmac_result[offset+3] & 0xff);
676
677 // truncates code to 6 digits
678 hotp_code = (int)(bin_code % otputil_upow(10, (uintmax_t)hotp_digits));
679
680 return(hotp_code);
681}
682
683
684char *
685otputil_hotp_str(
686 const otputil_bv_t * hotp_k,
687 uint64_t hotp_c,
688 int hotp_hmac,
689 int hotp_digits,
690 char * dst,
691 size_t dstlen )
692{
693 int otp_code;
694 static char buff[OTPUTIL_MAX_CODE_SIZE];
695
696 hotp_k = ((hotp_k)) ? hotp_k : &otputil_const_defaults_k;
697 hotp_digits = ((hotp_digits)) ? hotp_digits : (int)otputil_defaults.hotp_digits;
698 dstlen = ((dst)) ? dstlen : sizeof(buff);
699 dst = ((dst)) ? dst : buff;
700
701 if ((otp_code = otputil_hotp_code(hotp_k, hotp_c, hotp_hmac, hotp_digits)) == -1)
702 return(NULL);
703
704 return(otputil_code2str(otp_code, hotp_digits, dst, dstlen));
705}
706
707
708//---------------//
709// TOTP functions //
710//---------------//
711#pragma mark TOTP functions (RFC 6238)
712
713int
714otputil_totp_code(
715 const otputil_bv_t * totp_k,
716 uint64_t totp_t0,
717 uint64_t totp_tx,
718 uint64_t totp_time,
719 int totp_hmac,
720 int totp_digits )
721{
722 uint64_t hotp_c;
723
724 if (!(totp_tx))
725 return(-1);
726
727 totp_k = ((totp_k)) ? totp_k : &otputil_const_defaults_k;
728 totp_time = ((totp_time)) ? totp_time : ((uint64_t)time(NULL));
729 hotp_c = (totp_time - totp_t0) / totp_tx;
730
731 return(otputil_hotp_code(totp_k, hotp_c, totp_hmac, totp_digits));
732}
733
734
735char *
736otputil_totp_str(
737 const otputil_bv_t * totp_k,
738 uint64_t totp_t0,
739 uint64_t totp_tx,
740 uint64_t totp_time,
741 int totp_hmac,
742 int totp_digits,
743 char * dst,
744 size_t dstlen )
745{
746 int otp_code;
747 static char buff[OTPUTIL_MAX_CODE_SIZE];
748
749 dstlen = ((dst)) ? dstlen : sizeof(buff);
750 dst = ((dst)) ? dst : buff;
751
752 if ((otp_code = otputil_totp_code(totp_k, totp_t0, totp_tx, totp_time, totp_hmac, totp_digits)) == -1)
753 return(NULL);
754
755 return(otputil_code2str(otp_code, totp_digits, dst, dstlen));
756}
757
758
759uint64_t
760otputil_totp_timer(
761 uint64_t totp_t0,
762 uint64_t totp_tx,
763 uint64_t totp_time )
764{
765 assert(totp_tx != 0);
766 totp_time = ((totp_time)) ? totp_time : (uint64_t)time(NULL);
767 return(totp_tx - ((totp_time - totp_t0) % totp_tx));
768}
769
770/* end of source file */ 584/* end of source file */