1 /*
2 Copyright (C) 2011-2014 Yubico AB. All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are
6 met:
7
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10
11 2. Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "yubikeyutil.h"
30 #include <yubikey.h>
31 #include <QDebug>
32 #include <QRegExp>
33 #ifdef Q_OS_WIN
34 #include "crandom.h"
35 #endif
36
~YubiKeyUtil()37 YubiKeyUtil::~YubiKeyUtil() {
38 }
39
hexModhexDecode(unsigned char * result,size_t * resultLen,const char * str,size_t strLen,size_t minSize,size_t maxSize,bool modhex)40 int YubiKeyUtil::hexModhexDecode(unsigned char *result, size_t *resultLen,
41 const char *str, size_t strLen,
42 size_t minSize, size_t maxSize,
43 bool modhex)
44 {
45 if ((strLen % 2 != 0) || (strLen < minSize) || (strLen > maxSize)) {
46 *resultLen = 0;
47 return -1;
48 }
49
50 *resultLen = strLen / 2;
51 if (modhex) {
52 if (yubikey_modhex_p(str)) {
53 yubikey_modhex_decode((char *)result, str, *resultLen);
54 return 1;
55 }
56 } else {
57 if (yubikey_hex_p(str)) {
58 yubikey_hex_decode((char *)result, str, *resultLen);
59 return 1;
60 }
61 }
62
63 return 0;
64 }
65
hexModhexEncode(char * result,size_t * resultLen,const unsigned char * str,size_t strLen,bool modhex)66 int YubiKeyUtil::hexModhexEncode(char *result, size_t *resultLen,
67 const unsigned char *str, size_t strLen,
68 bool modhex)
69 {
70 *resultLen = strLen * 2;
71 if (modhex) {
72 yubikey_modhex_encode((char *)result, (char *)str, strLen);
73 return 1;
74 } else {
75 yubikey_hex_encode((char *)result, (char *)str, strLen);
76 return 1;
77 }
78
79 return 0;
80 }
81
qstrHexEncode(const unsigned char * str,size_t strLen)82 QString YubiKeyUtil::qstrHexEncode(const unsigned char *str, size_t strLen) {
83 char result[strLen * 2 + 1];
84 size_t resultLen;
85 memset(&result, 0, sizeof(result));
86
87 int rc = hexModhexEncode(result, &resultLen, str, strLen, false);
88
89 if(rc > 0) {
90 qDebug() << "hex encoded string: " << QString(result) << sizeof(result);
91 return QString::fromLocal8Bit(result);
92 }
93
94 return QString("");
95 }
96
qstrHexDecode(unsigned char * result,size_t * resultLen,const QString & str)97 void YubiKeyUtil::qstrHexDecode(unsigned char *result, size_t *resultLen,
98 const QString &str) {
99
100 if(str.size() % 2 != 0) {
101 return;
102 }
103
104 char hex[MAX_SIZE];
105 YubiKeyUtil::qstrToRaw(hex, sizeof(hex), str);
106 size_t hexLen = strlen(hex);
107
108 //Hex decode
109 hexModhexDecode(result, resultLen,
110 hex, hexLen,
111 0, MAX_SIZE,
112 false);
113 }
114
qstrModhexEncode(const unsigned char * str,size_t strLen)115 QString YubiKeyUtil::qstrModhexEncode(const unsigned char *str, size_t strLen) {
116 char result[strLen * 2 + 1];
117 size_t resultLen;
118 memset(&result, 0, sizeof(result));
119
120 int rc = hexModhexEncode(result, &resultLen, str, strLen, true);
121
122 if(rc > 0) {
123 qDebug() << "modhex encoded string: " << QString(result) << sizeof(result);
124 return QString::fromLocal8Bit(result);
125 }
126
127 return QString("");
128 }
129
qstrModhexDecode(unsigned char * result,size_t * resultLen,const QString & str)130 void YubiKeyUtil::qstrModhexDecode(unsigned char *result, size_t *resultLen,
131 const QString &str) {
132
133 if(str.size() % 2 != 0) {
134 *resultLen = 0;
135 return;
136 }
137
138 char modhex[MAX_SIZE];
139 YubiKeyUtil::qstrToRaw(modhex, sizeof(modhex), str);
140 size_t modhexLen = strlen(modhex);
141
142 //Hex decode
143 hexModhexDecode(result, resultLen,
144 modhex, modhexLen,
145 0, MAX_SIZE,
146 true);
147 }
148
qstrDecDecode(unsigned char * result,size_t * resultLen,const QString & str)149 void YubiKeyUtil::qstrDecDecode(unsigned char *result, size_t *resultLen,
150 const QString &str) {
151 if(str.size() % 2 != 0) {
152 *resultLen = 0;
153 return;
154 }
155
156 *resultLen = str.size() / 2;
157
158 for(size_t i = 0; i < *resultLen; i++) {
159 unsigned char val = str.mid(i * 2, 2).toInt();
160 result[i] = ((val / 10) << 4) | (val % 10);
161 }
162 }
163
qstrToRaw(char * result,size_t resultLen,const QString & str)164 void YubiKeyUtil::qstrToRaw(char *result, size_t resultLen,
165 const QString &str) {
166 QByteArray strByteArr = str.toLocal8Bit();
167
168 size_t strLen = strByteArr.size() + 1;
169 strLen = (resultLen < strLen)? resultLen : strLen;
170
171 memset(result, 0, strLen);
172 strncpy(result, (char *) strByteArr.data(), strLen);
173 }
174
qstrClean(QString * str,size_t maxSize,bool reverse)175 void YubiKeyUtil::qstrClean(QString *str, size_t maxSize, bool reverse) {
176 *str = str->toLower();
177
178 QRegExp rx("[^0-9a-f]");
179 *str = str->replace(rx, QString(""));
180
181 if(maxSize > 0) {
182 if(reverse) {
183 *str = str->rightJustified(maxSize, '0', true);
184 } else {
185 *str = str->leftJustified(maxSize, '0', true);
186 }
187 }
188 }
189
qstrModhexClean(QString * str,size_t maxSize,bool reverse)190 void YubiKeyUtil::qstrModhexClean(QString *str, size_t maxSize, bool reverse) {
191 *str = str->toLower();
192
193 QRegExp rx("[^b-lnrt-v]");
194 *str = str->replace(rx, QString(""));
195
196 if(maxSize > 0) {
197 if(reverse) {
198 *str = str->rightJustified(maxSize, 'c', true);
199 } else {
200 *str = str->leftJustified(maxSize, 'c', true);
201 }
202 }
203 }
204
generateRandom(unsigned char * result,size_t resultLen)205 int YubiKeyUtil::generateRandom(unsigned char *result, size_t resultLen) {
206 size_t bufSize = resultLen;
207
208 unsigned char buf[bufSize];
209 memset(&buf, 0, sizeof(buf));
210
211 size_t bufLen = 0;
212
213 #ifdef Q_OS_WIN
214 CRandom random;
215 random.getRand(buf, bufSize);
216
217 bufLen = sizeof(buf);
218 #else
219 const char *random_places[] = {
220 "/dev/srandom",
221 "/dev/urandom",
222 "/dev/random",
223 0
224 };
225
226 const char **random_place;
227
228 for (random_place = random_places; *random_place; random_place++) {
229 FILE *random_file = fopen(*random_place, "r");
230 if (random_file) {
231 size_t read_bytes = 0;
232
233 while (read_bytes < bufSize) {
234 size_t n = fread(&buf[read_bytes],
235 1, bufSize - read_bytes,
236 random_file);
237 read_bytes += n;
238 }
239
240 fclose(random_file);
241
242 bufLen = sizeof(buf);
243
244 break; /* from for loop */
245 }
246 }
247 #endif
248
249 if(bufLen > 0) {
250 memcpy(result, buf, bufLen);
251 return 1;
252 }
253
254 return 0;
255 }
256
generateRandomHex(size_t resultLen)257 QString YubiKeyUtil::generateRandomHex(size_t resultLen) {
258 QString result("");
259
260 if (resultLen % 2 != 0) {
261 return result;
262 }
263
264 size_t bufSize = resultLen / 2;
265 unsigned char buf[bufSize];
266 memset(&buf, 0, sizeof(buf));
267
268 if(generateRandom(buf, bufSize) > 0) {
269 result = qstrHexEncode(buf, bufSize);
270 }
271
272 return result;
273 }
274
generateRandomModhex(size_t resultLen)275 QString YubiKeyUtil::generateRandomModhex(size_t resultLen) {
276 QString result("");
277
278 if (resultLen % 2 != 0) {
279 return result;
280 }
281
282 size_t bufSize = resultLen / 2;
283 unsigned char buf[bufSize];
284 memset(&buf, 0, sizeof(buf));
285
286 if(generateRandom(buf, bufSize) > 0) {
287 result = qstrModhexEncode(buf, bufSize);
288 }
289
290 return result;
291 }
292
getNextHex(size_t resultLen,const QString & str,int scheme)293 QString YubiKeyUtil::getNextHex(size_t resultLen,
294 const QString &str, int scheme) {
295 QString result("");
296
297 qDebug() << "str = " << str
298 << " len = " << str.length();
299
300 switch(scheme) {
301 case GEN_SCHEME_FIXED:
302 result = str;
303 break;
304
305 case GEN_SCHEME_INCR:
306 {
307 //Hex clean
308 QString hexStr(str);
309 qstrClean(&hexStr, resultLen);
310
311 //Hex decode
312 unsigned char hexDecoded[MAX_SIZE];
313 size_t hexDecodedLen = 0;
314 memset(&hexDecoded, 0, sizeof(hexDecoded));
315
316 qstrHexDecode(hexDecoded, &hexDecodedLen, hexStr);
317 if(hexDecodedLen <= 0) {
318 break;
319 }
320
321 qDebug() << "hexDecoded = " << QString((char*)hexDecoded)
322 << " len = " << hexDecodedLen;
323
324 //Increment
325 for (int i = hexDecodedLen; i--; ) {
326 if (++hexDecoded[i]) {
327 break;
328 }
329 }
330
331 //Hex encode
332 result = qstrHexEncode(hexDecoded, hexDecodedLen);
333
334 qDebug() << "hexEncoded = " << result
335 << " len = " << result.size();
336 }
337 break;
338
339 case GEN_SCHEME_RAND:
340 result = generateRandomHex(resultLen);
341 break;
342 }
343
344 return result;
345 }
346
getNextModhex(size_t resultLen,const QString & str,int scheme)347 QString YubiKeyUtil::getNextModhex(size_t resultLen,
348 const QString &str, int scheme) {
349 QString tmpStr(str);
350 qstrModhexClean(&tmpStr, resultLen);
351 unsigned char result[resultLen];
352 size_t len;
353 QString hex;
354 qstrModhexDecode(result, &len, tmpStr);
355 if(len == 0) {
356 return "";
357 }
358 hex = qstrHexEncode(result, len);
359 hex = getNextHex(resultLen, hex, scheme);
360 qstrHexDecode(result, &len, hex);
361 return qstrModhexEncode(result, len);
362 }
363