aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/lib
diff options
context:
space:
mode:
authorDavid M. Syzdek <david@syzdek.net>2023-01-10 00:21:06 -0900
committerDavid M. Syzdek <david@syzdek.net>2023-01-10 00:21:06 -0900
commit758d769d5125c6a2776554faa40abc7c9c504a50 (patch)
tree705cbaffcacd2b512d4889b6c4a722f6fe830344 /lib
parentefe30fd93111ed7984b8a735f52376ff7bb5c0f9 (diff)
downloadotputils-758d769d5125c6a2776554faa40abc7c9c504a50.tar.gz
otputils-758d769d5125c6a2776554faa40abc7c9c504a50.tar.bz2
otputils-758d769d5125c6a2776554faa40abc7c9c504a50.tar.xz
otputils-758d769d5125c6a2776554faa40abc7c9c504a50.zip
libotputil: moving OTP (RFC 2289) functions
Diffstat (limited to 'lib')
-rw-r--r--lib/libotputil/libotputil.c361
-rw-r--r--lib/libotputil/lotp.c425
-rw-r--r--lib/libotputil/lotp.h47
3 files changed, 472 insertions, 361 deletions
diff --git a/lib/libotputil/libotputil.c b/lib/libotputil/libotputil.c
index 702a328..b471b27 100644
--- a/lib/libotputil/libotputil.c
+++ b/lib/libotputil/libotputil.c
@@ -78,19 +78,6 @@ otputil_upow(
78 uintmax_t exp ); 78 uintmax_t exp );
79 79
80 80
81//----------------//
82// OTP prototypes //
83//----------------//
84#pragma mark OTP prototypes (RFC 2289)
85
86static int
87otputil_otp_encode_word(
88 char * dst,
89 const char * src,
90 size_t dstsize,
91 const char * terminator);
92
93
94///////////////// 81/////////////////
95// // 82// //
96// Variables // 83// Variables //
@@ -823,354 +810,6 @@ otputil_hotp_str(
823 810
824 811
825//---------------// 812//---------------//
826// OTP functions //
827//---------------//
828#pragma mark OTP functions (RFC 2289)
829
830otputil_bv_t *
831otputil_otp_decode(
832 const char * src,
833 otputil_bv_t * dst )
834{
835 static otputil_bv_t bv;
836 static uint8_t buff[OTPUTIL_MAX_DECODE_SIZE];
837 uint8_t * bv_val;
838 int method;
839 int i;
840 size_t pos;
841 size_t off;
842 size_t len;
843 char word[OTPUTIL_MAX_WORD_SIZE];
844 char * endptr;
845
846 assert(src != NULL);
847
848 if (!(dst))
849 {
850 dst = &bv;
851 dst->bv_len = sizeof(buff);
852 dst->bv_val = buff;
853 };
854 bv_val = dst->bv_val;
855
856 // checks for hexadecimal notation
857 method = OTPUTIL_ENC_HEX;
858 word[1] = '\0';
859 for(pos = 0, off = 0; ( ((src[pos])) && (method == OTPUTIL_ENC_HEX) ); pos++)
860 {
861 if ((isspace(src[pos])))
862 continue;
863 if ((isxdigit(src[pos])))
864 {
865 off++;
866 continue;
867 };
868 method = 0;
869 };
870 if (method == OTPUTIL_ENC_HEX)
871 {
872 // generate length of binary output in bytes
873 len = (off/2) + (off%2);
874 if ( (len = (off/2) + (off%2)) > dst->bv_len )
875 return(NULL);
876 dst->bv_len = len;
877
878 // convert to binary output
879 for(pos = 0, off = 0; ((src[pos])); pos++)
880 {
881 word[0] = src[pos];
882 i = (int)strtol(word, &endptr, 16);
883 if (endptr == word)
884 continue;
885 if ((off & 0x01) == 0)
886 bv_val[off/2] = (i << 4) & 0xf0;
887 if ((off & 0x01) == 1)
888 bv_val[off/2] |= (i << 0) & 0x0f;
889 off++;
890 };
891
892 return(dst);
893 };
894
895 // checks for six-word format with S/KEY dictionary
896
897 return(NULL);
898}
899
900
901size_t
902otputil_otp_decode_len(
903 const char * str )
904{
905 size_t bytes;
906 size_t bits;
907
908 assert(str != NULL);
909
910 bits = (strlen(str) / 2) * 11;
911 bytes = (bits / 8);
912 bytes++;
913
914 return(bytes);
915}
916
917
918const char *
919otputil_otp_encode(
920 const otputil_bv_t * bv,
921 char * dst,
922 size_t dstlen,
923 int methd )
924{
925 const uint8_t * dat;
926 static char buff[OTPUTIL_MAX_ENCODE_SIZE];
927 size_t off;
928 size_t len;
929 size_t pos;
930 int val;
931 uint8_t * bv_val;
932 int checksum;
933
934 assert(bv != NULL);
935 assert(methd != 0);
936 assert( (dst != NULL) || (dstlen == 0) );
937 assert( (dst == NULL) || (dstlen != 0) );
938
939 dstlen = ((dst)) ? dstlen : sizeof(buff);
940 dst = ((dst)) ? dst : buff;
941 dst[0] = '\0';
942 off = 0;
943 dat = bv->bv_val;
944
945 // encode in HEX
946 if (methd == OTPUTIL_ENC_HEX)
947 {
948 len = (bv->bv_len * 2) + (bv->bv_len / 2) + (bv->bv_len % 2);
949 if (dstlen < len)
950 return(NULL);
951 for(pos = 0; (pos < bv->bv_len); pos++)
952 { if ( ((pos % 2) == 0) && (pos != 0) )
953 { snprintf(&dst[off], 4, " %02X", dat[pos]);
954 off += 3;
955 } else
956 { snprintf(&dst[off], 4, "%02X", dat[pos]);
957 off += 2;
958 };
959 };
960 dst[(pos*2)+off] = '\0';
961 return(dst);
962 };
963
964 // encode with S/KEY dictionary
965 if (methd != OTPUTIL_ENC_SIXWORD)
966 return(NULL);
967 val = 0;
968 bv_val = bv->bv_val;
969 checksum = 0;
970 for(pos = 0; (pos < bv->bv_len); pos++)
971 {
972 // calculate checksum
973 checksum += (bv_val[pos] >> 6) & 0x03;
974 checksum += (bv_val[pos] >> 4) & 0x03;
975 checksum += (bv_val[pos] >> 2) & 0x03;
976 checksum += (bv_val[pos] >> 0) & 0x03;
977 checksum &= 0x03;
978
979 // determine encoded word
980 switch((pos * 8) % 11)
981 {
982 // byte 0: ( 00000000--- ----------- )
983 case 0:
984 val = (bv_val[pos] << 3) & 0x07F8;
985 break;
986
987 // byte 1: ( 00000000111 11111------ )
988 case 8:
989 val |= (bv_val[pos] >> 5) & 0x0007;
990 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
991 return(NULL);
992 val = (bv_val[pos] << 6) & 0x7C0;
993 break;
994
995 // byte 2: ( 11111222222 22--------- )
996 case 5:
997 val |= (bv_val[pos] >> 2) & 0x003f;
998 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
999 return(NULL);
1000 val = (bv_val[pos] << 9) & 0x07C0;
1001 break;
1002
1003 // byte 3: ( 2233333333- ----------- )
1004 case 2:
1005 val |= (bv_val[pos] << 1) & 0x01FE;
1006 break;
1007
1008 // byte 4: ( 22333333334 4444444---- )
1009 case 10:
1010 val |= (bv_val[pos] >> 7) & 0x0001;
1011 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
1012 return(NULL);
1013 val = (bv_val[pos] << 4) & 0x07F0;
1014 break;
1015
1016 // byte 5: ( 44444445555 5555------- )
1017 case 7:
1018 val |= (bv_val[pos] >> 4) & 0x000f;
1019 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
1020 return(NULL);
1021 val = (bv_val[pos] << 7) & 0x0780;
1022 break;
1023
1024 // byte 6: ( 55556666666 6---------- )
1025 case 4:
1026 val |= (bv_val[pos] >> 1) & 0x007f;
1027 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
1028 return(NULL);
1029 val = (bv_val[pos] << 10) & 0x0400;
1030 break;
1031
1032 // byte 7: ( 677777777-- ----------- )
1033 case 1:
1034 val |= (bv_val[pos] << 2) & 0x03fc;
1035 break;
1036
1037 // byte 8: ( 67777777788 888888----- )
1038 case 9:
1039 val |= (bv_val[pos] >> 6) & 0x0003;
1040 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
1041 return(NULL);
1042 val = (bv_val[pos] << 5) & 0x07e0;
1043 break;
1044
1045 // byte 9: ( 88888899999 999-------- )
1046 case 6:
1047 val |= (bv_val[pos] >> 3) & 0x001f;
1048 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
1049 return(NULL);
1050 val = (bv_val[pos] << 8) & 0x0700;
1051 break;
1052
1053 // byte 10: ( 999aaaaaaaa ----------- )
1054 case 3:
1055 val |= bv_val[pos] & 0x00ff;
1056 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
1057 return(NULL);
1058 break;
1059
1060 default:
1061 break;
1062 };
1063 };
1064
1065 // encode checksum
1066 switch((pos * 8) % 11)
1067 {
1068 // byte 0: ( XX--------- ----------- )
1069 case 0:
1070 val = (checksum << 9) & 0x0600;
1071 break;
1072
1073 // byte 1: ( 00000000xx- ----------- )
1074 case 8:
1075 val |= (checksum << 1) & 0x0060;
1076 break;
1077
1078 // byte 2: ( 11111xx---- ----------- )
1079 case 5:
1080 val |= (checksum << 4) & 0x0030;
1081 break;
1082
1083 // byte 3: ( 22xx------- ----------- )
1084 case 2:
1085 val |= (checksum << 7) & 0x0180;
1086 break;
1087
1088 // byte 4: ( 2233333333x x---------- )
1089 case 10:
1090 val |= (checksum >> 1) & 0x0001;
1091 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
1092 return(NULL);
1093 val = (checksum << 10) & 0x0400;
1094 break;
1095
1096 // byte 5: ( 4444444xx-- ----------- )
1097 case 7:
1098 val |= (checksum << 2) & 0x000c;
1099 break;
1100
1101 // byte 6: ( 5555xx----- ----------- )
1102 case 4:
1103 val |= (checksum << 5) & 0x0060;
1104 break;
1105
1106 // byte 7: ( 6xx-------- ----------- )
1107 case 1:
1108 val |= (checksum << 8) & 0x0300;
1109 break;
1110
1111 // byte 8: ( 677777777xx ----------- )
1112 case 9:
1113 val |= (checksum << 0) & 0x0003;
1114 break;
1115
1116 // byte 9: ( 888888xx--- ----------- )
1117 case 6:
1118 val |= (checksum << 3) & 0x0018;
1119 break;
1120
1121 // byte 10: ( 999xx------ ----------- )
1122 case 3:
1123 val |= (checksum << 6) & 0x00C0;
1124 break;
1125
1126 default:
1127 break;
1128 };
1129 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, NULL) == -1)
1130 return(NULL);
1131
1132 return(dst);
1133}
1134
1135
1136int
1137otputil_otp_encode_word(
1138 char * dst,
1139 const char * src,
1140 size_t dstsize,
1141 const char * terminator)
1142{
1143 if (bindle_strlcat(dst, src, dstsize) >= (dstsize-1))
1144 return(-1);
1145 if ((terminator))
1146 if (bindle_strlcat(dst, terminator, dstsize) >= (dstsize-1))
1147 return(-1);
1148 return(0);
1149}
1150
1151
1152size_t
1153otputil_otp_encode_len(
1154 const otputil_bv_t * bv )
1155{
1156 size_t len;
1157 size_t words;
1158 size_t bits;
1159
1160 assert(bv != NULL);
1161
1162 bits = (bv->bv_len * 8) + 2;
1163 words = (bits / 11);
1164 if ((words % 11) != 0)
1165 words++;
1166 if ((len = ((ssize_t)words) * 5) == 0)
1167 len = 1;
1168
1169 return(len);
1170}
1171
1172
1173//---------------//
1174// TOTP functions // 813// TOTP functions //
1175//---------------// 814//---------------//
1176#pragma mark TOTP functions (RFC 6238) 815#pragma mark TOTP functions (RFC 6238)
diff --git a/lib/libotputil/lotp.c b/lib/libotputil/lotp.c
new file mode 100644
index 0000000..252c12b
--- /dev/null
+++ b/lib/libotputil/lotp.c
@@ -0,0 +1,425 @@
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/libotputil.c
32 */
33#define _LIB_LIBOTPUTIL_LOTP_C 1
34#include "lotp.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 "ldict-rfc1760.h"
53
54
55//////////////////
56// //
57// Prototypes //
58// //
59//////////////////
60#pragma mark - Prototypes
61
62static int
63otputil_otp_encode_word(
64 char * dst,
65 const char * src,
66 size_t dstsize,
67 const char * terminator);
68
69
70/////////////////
71// //
72// Functions //
73// //
74/////////////////
75#pragma mark - Functions
76
77//---------------//
78// OTP functions //
79//---------------//
80#pragma mark OTP functions (RFC 2289)
81
82otputil_bv_t *
83otputil_otp_decode(
84 const char * src,
85 otputil_bv_t * dst )
86{
87 static otputil_bv_t bv;
88 static uint8_t buff[OTPUTIL_MAX_DECODE_SIZE];
89 uint8_t * bv_val;
90 int method;
91 int i;
92 size_t pos;
93 size_t off;
94 size_t len;
95 char word[OTPUTIL_MAX_WORD_SIZE];
96 char * endptr;
97
98 assert(src != NULL);
99
100 if (!(dst))
101 {
102 dst = &bv;
103 dst->bv_len = sizeof(buff);
104 dst->bv_val = buff;
105 };
106 bv_val = dst->bv_val;
107
108 // checks for hexadecimal notation
109 method = OTPUTIL_ENC_HEX;
110 word[1] = '\0';
111 for(pos = 0, off = 0; ( ((src[pos])) && (method == OTPUTIL_ENC_HEX) ); pos++)
112 {
113 if ((isspace(src[pos])))
114 continue;
115 if ((isxdigit(src[pos])))
116 {
117 off++;
118 continue;
119 };
120 method = 0;
121 };
122 if (method == OTPUTIL_ENC_HEX)
123 {
124 // generate length of binary output in bytes
125 len = (off/2) + (off%2);
126 if ( (len = (off/2) + (off%2)) > dst->bv_len )
127 return(NULL);
128 dst->bv_len = len;
129
130 // convert to binary output
131 for(pos = 0, off = 0; ((src[pos])); pos++)
132 {
133 word[0] = src[pos];
134 i = (int)strtol(word, &endptr, 16);
135 if (endptr == word)
136 continue;
137 if ((off & 0x01) == 0)
138 bv_val[off/2] = (i << 4) & 0xf0;
139 if ((off & 0x01) == 1)
140 bv_val[off/2] |= (i << 0) & 0x0f;
141 off++;
142 };
143
144 return(dst);
145 };
146
147 // checks for six-word format with S/KEY dictionary
148
149 return(NULL);
150}
151
152
153size_t
154otputil_otp_decode_len(
155 const char * str )
156{
157 size_t bytes;
158 size_t bits;
159
160 assert(str != NULL);
161
162 bits = (strlen(str) / 2) * 11;
163 bytes = (bits / 8);
164 bytes++;
165
166 return(bytes);
167}
168
169
170const char *
171otputil_otp_encode(
172 const otputil_bv_t * bv,
173 char * dst,
174 size_t dstlen,
175 int methd )
176{
177 const uint8_t * dat;
178 static char buff[OTPUTIL_MAX_ENCODE_SIZE];
179 size_t off;
180 size_t len;
181 size_t pos;
182 int val;
183 uint8_t * bv_val;
184 int checksum;
185
186 assert(bv != NULL);
187 assert(methd != 0);
188 assert( (dst != NULL) || (dstlen == 0) );
189 assert( (dst == NULL) || (dstlen != 0) );
190
191 dstlen = ((dst)) ? dstlen : sizeof(buff);
192 dst = ((dst)) ? dst : buff;
193 dst[0] = '\0';
194 off = 0;
195 dat = bv->bv_val;
196
197 // encode in HEX
198 if (methd == OTPUTIL_ENC_HEX)
199 {
200 len = (bv->bv_len * 2) + (bv->bv_len / 2) + (bv->bv_len % 2);
201 if (dstlen < len)
202 return(NULL);
203 for(pos = 0; (pos < bv->bv_len); pos++)
204 { if ( ((pos % 2) == 0) && (pos != 0) )
205 { snprintf(&dst[off], 4, " %02X", dat[pos]);
206 off += 3;
207 } else
208 { snprintf(&dst[off], 4, "%02X", dat[pos]);
209 off += 2;
210 };
211 };
212 dst[(pos*2)+off] = '\0';
213 return(dst);
214 };
215
216 // encode with S/KEY dictionary
217 if (methd != OTPUTIL_ENC_SIXWORD)
218 return(NULL);
219 val = 0;
220 bv_val = bv->bv_val;
221 checksum = 0;
222 for(pos = 0; (pos < bv->bv_len); pos++)
223 {
224 // calculate checksum
225 checksum += (bv_val[pos] >> 6) & 0x03;
226 checksum += (bv_val[pos] >> 4) & 0x03;
227 checksum += (bv_val[pos] >> 2) & 0x03;
228 checksum += (bv_val[pos] >> 0) & 0x03;
229 checksum &= 0x03;
230
231 // determine encoded word
232 switch((pos * 8) % 11)
233 {
234 // byte 0: ( 00000000--- ----------- )
235 case 0:
236 val = (bv_val[pos] << 3) & 0x07F8;
237 break;
238
239 // byte 1: ( 00000000111 11111------ )
240 case 8:
241 val |= (bv_val[pos] >> 5) & 0x0007;
242 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
243 return(NULL);
244 val = (bv_val[pos] << 6) & 0x7C0;
245 break;
246
247 // byte 2: ( 11111222222 22--------- )
248 case 5:
249 val |= (bv_val[pos] >> 2) & 0x003f;
250 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
251 return(NULL);
252 val = (bv_val[pos] << 9) & 0x07C0;
253 break;
254
255 // byte 3: ( 2233333333- ----------- )
256 case 2:
257 val |= (bv_val[pos] << 1) & 0x01FE;
258 break;
259
260 // byte 4: ( 22333333334 4444444---- )
261 case 10:
262 val |= (bv_val[pos] >> 7) & 0x0001;
263 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
264 return(NULL);
265 val = (bv_val[pos] << 4) & 0x07F0;
266 break;
267
268 // byte 5: ( 44444445555 5555------- )
269 case 7:
270 val |= (bv_val[pos] >> 4) & 0x000f;
271 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
272 return(NULL);
273 val = (bv_val[pos] << 7) & 0x0780;
274 break;
275
276 // byte 6: ( 55556666666 6---------- )
277 case 4:
278 val |= (bv_val[pos] >> 1) & 0x007f;
279 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
280 return(NULL);
281 val = (bv_val[pos] << 10) & 0x0400;
282 break;
283
284 // byte 7: ( 677777777-- ----------- )
285 case 1:
286 val |= (bv_val[pos] << 2) & 0x03fc;
287 break;
288
289 // byte 8: ( 67777777788 888888----- )
290 case 9:
291 val |= (bv_val[pos] >> 6) & 0x0003;
292 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
293 return(NULL);
294 val = (bv_val[pos] << 5) & 0x07e0;
295 break;
296
297 // byte 9: ( 88888899999 999-------- )
298 case 6:
299 val |= (bv_val[pos] >> 3) & 0x001f;
300 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
301 return(NULL);
302 val = (bv_val[pos] << 8) & 0x0700;
303 break;
304
305 // byte 10: ( 999aaaaaaaa ----------- )
306 case 3:
307 val |= bv_val[pos] & 0x00ff;
308 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
309 return(NULL);
310 break;
311
312 default:
313 break;
314 };
315 };
316
317 // encode checksum
318 switch((pos * 8) % 11)
319 {
320 // byte 0: ( XX--------- ----------- )
321 case 0:
322 val = (checksum << 9) & 0x0600;
323 break;
324
325 // byte 1: ( 00000000xx- ----------- )
326 case 8:
327 val |= (checksum << 1) & 0x0060;
328 break;
329
330 // byte 2: ( 11111xx---- ----------- )
331 case 5:
332 val |= (checksum << 4) & 0x0030;
333 break;
334
335 // byte 3: ( 22xx------- ----------- )
336 case 2:
337 val |= (checksum << 7) & 0x0180;
338 break;
339
340 // byte 4: ( 2233333333x x---------- )
341 case 10:
342 val |= (checksum >> 1) & 0x0001;
343 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, " ") == -1)
344 return(NULL);
345 val = (checksum << 10) & 0x0400;
346 break;
347
348 // byte 5: ( 4444444xx-- ----------- )
349 case 7:
350 val |= (checksum << 2) & 0x000c;
351 break;
352
353 // byte 6: ( 5555xx----- ----------- )
354 case 4:
355 val |= (checksum << 5) & 0x0060;
356 break;
357
358 // byte 7: ( 6xx-------- ----------- )
359 case 1:
360 val |= (checksum << 8) & 0x0300;
361 break;
362
363 // byte 8: ( 677777777xx ----------- )
364 case 9:
365 val |= (checksum << 0) & 0x0003;
366 break;
367
368 // byte 9: ( 888888xx--- ----------- )
369 case 6:
370 val |= (checksum << 3) & 0x0018;
371 break;
372
373 // byte 10: ( 999xx------ ----------- )
374 case 3:
375 val |= (checksum << 6) & 0x00C0;
376 break;
377
378 default:
379 break;
380 };
381 if (otputil_otp_encode_word(dst, otputil_dict_rfc1760[val], dstlen, NULL) == -1)
382 return(NULL);
383
384 return(dst);
385}
386
387
388int
389otputil_otp_encode_word(
390 char * dst,
391 const char * src,
392 size_t dstsize,
393 const char * terminator)
394{
395 if (bindle_strlcat(dst, src, dstsize) >= (dstsize-1))
396 return(-1);
397 if ((terminator))
398 if (bindle_strlcat(dst, terminator, dstsize) >= (dstsize-1))
399 return(-1);
400 return(0);
401}
402
403
404size_t
405otputil_otp_encode_len(
406 const otputil_bv_t * bv )
407{
408 size_t len;
409 size_t words;
410 size_t bits;
411
412 assert(bv != NULL);
413
414 bits = (bv->bv_len * 8) + 2;
415 words = (bits / 11);
416 if ((words % 11) != 0)
417 words++;
418 if ((len = ((ssize_t)words) * 5) == 0)
419 len = 1;
420
421 return(len);
422}
423
424
425/* end of source file */
diff --git a/lib/libotputil/lotp.h b/lib/libotputil/lotp.h
new file mode 100644
index 0000000..a1ef103
--- /dev/null
+++ b/lib/libotputil/lotp.h
@@ -0,0 +1,47 @@
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_LOTP_H
34#define _LIB_LIBOTPUTIL_LOTP_H 1
35
36
37///////////////
38// //
39// Headers //
40// //
41///////////////
42#pragma mark - Headers
43
44#include "libotputil.h"
45
46
47#endif /* end of header file */