blob: ee6f5ddd4dd3bcecdb90d9c14c8e36600793d833 [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001// Copyright (C) 2010 David Sugar, Tycho Softworks.
2//
3// This file is part of GNU uCommon C++.
4//
5// GNU uCommon C++ is free software: you can redistribute it and/or modify
6// it under the terms of the GNU Lesser General Public License as published
7// by the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// GNU uCommon C++ is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU Lesser General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public License
16// along with GNU uCommon C++. If not, see <http://www.gnu.org/licenses/>.
17
18#include "local.h"
19
20Digest::Digest()
21{
22 hashtype = NULL;
23 hashid = 0;
24 context = NULL;
25 bufsize = 0;
26 textbuf[0] = 0;
27}
28
29Digest::Digest(const char *type)
30{
31 hashtype = NULL;
32 hashid = 0;
33 context = NULL;
34 bufsize = 0;
35 textbuf[0] = 0;
36
37 set(type);
38}
39
40Digest::~Digest()
41{
42 release();
43}
44
45const char *Digest::c_str(void)
46{
47 if(!bufsize)
48 get();
49
50 return textbuf;
51}
52
53void Digest::uuid(char *str, const char *name, const unsigned char *ns)
54{
55 unsigned mask = 0x50;
56 const char *type = "sha1";
57 if(!has("sha1")) {
58 mask = 0x30;
59 type = "md5";
60 }
61
62 Digest md(type);
63 if(ns)
64 md.put(ns, 16);
65 md.puts(name);
66 unsigned char *buf = (unsigned char *)md.get();
67
68 buf[6] &= 0x0f;
69 buf[6] |= mask;
70 buf[8] &= 0x3f;
71 buf[8] |= 0x80;
72
73 String::hexdump(buf, str, "4-2-2-2-6");
74}
75
76String Digest::uuid(const char *name, const unsigned char *ns)
77{
78 char buf[38];
79 uuid(buf, name, ns);
80 return String(buf);
81}
82
83#if defined(_MSWINDOWS_)
84
85static void cexport(HCERTSTORE ca, FILE *fp)
86{
87 PCCERT_CONTEXT cert = NULL;
88 const uint8_t *cp;
89 char buf[80];
90
91 while ((cert = CertEnumCertificatesInStore(ca, cert)) != NULL) {
92 fprintf(fp, "-----BEGIN CERTIFICATE-----\n");
93 size_t total = cert->cbCertEncoded;
94 size_t count;
95 cp = (const uint8_t *)cert->pbCertEncoded;
96 while(total) {
97 count = String::b64encode(buf, cp, total, 64);
98 if(count)
99 fprintf(fp, "%s\n", buf);
100 total -= count;
101 cp += count;
102 }
103 fprintf(fp, "-----END CERTIFICATE-----\n");
104 }
105}
106
107const char *secure::oscerts(void)
108{
109 const char *path = "c:/temp/ca-bundle.crt";
110 if(!is_file(path)) {
111 if(oscerts(path))
112 return NULL;
113 }
114 return path;
115}
116
117int secure::oscerts(const char *pathname)
118{
119 bool caset;
120 string_t target;
121
122 if(pathname[1] == ':' || pathname[0] == '/' || pathname[0] == '\\')
123 target = pathname;
124 else
125 target = shell::path(shell::USER_CONFIG) + "/" + pathname;
126
127 FILE *fp = fopen(*target, "wt");
128
129 if(!fp)
130 return ENOSYS;
131
132 HCERTSTORE ca = CertOpenSystemStoreA((HCRYPTPROV)NULL, "ROOT");
133 if(ca) {
134 caset = true;
135 cexport(ca, fp);
136 CertCloseStore(ca, 0);
137 }
138
139 ca = CertOpenSystemStoreA((HCRYPTPROV)NULL, "CA");
140 if(ca) {
141 caset = true;
142 cexport(ca, fp);
143 CertCloseStore(ca, 0);
144 }
145
146 fclose(fp);
147
148 if(!caset) {
149 fsys::erase(*target);
150 return ENOSYS;
151 }
152 return 0;
153}
154
155#else
156const char *secure::oscerts(void)
157{
158 if(is_file("/etc/ssl/certs/ca-certificates.crt"))
159 return "/etc/ssl/certs/ca-certificates.crt";
160
161 if(is_file("/etc/pki/tls/ca-bundle.crt"))
162 return "/etc/pki/tls/ca-bundle.crt";
163
164 if(is_file("/etc/ssl/ca-bundle.pem"))
165 return "/etc/ssl/ca-bundle.pem";
166
167 return NULL;
168}
169
170int secure::oscerts(const char *pathname)
171{
172 string_t source = oscerts();
173 string_t target;
174
175 if(pathname[0] == '/')
176 target = pathname;
177 else
178 target = shell::path(shell::USER_CONFIG) + "/" + pathname;
179
180 if(!source)
181 return ENOSYS;
182
183 return fsys::copy(*source, *target);
184}
185#endif
186
187void secure::uuid(char *str)
188{
189 static unsigned char buf[16];
190 static Timer::tick_t prior = 0l;
191 static unsigned short seq;
192 Timer::tick_t current = Timer::ticks();
193
194 Mutex::protect(&buf);
195
196 // get our (random) node identifier...
197 if(!prior)
198 Random::fill(buf + 10, 6);
199
200 if(current == prior)
201 ++seq;
202 else
203 Random::fill((unsigned char *)&seq, sizeof(seq));
204
205 buf[8] = (unsigned char)((seq >> 8) & 0xff);
206 buf[9] = (unsigned char)(seq & 0xff);
207 buf[3] = (unsigned char)(current & 0xff);
208 buf[2] = (unsigned char)((current >> 8) & 0xff);
209 buf[1] = (unsigned char)((current >> 16) & 0xff);
210 buf[0] = (unsigned char)((current >> 24) & 0xff);
211 buf[5] = (unsigned char)((current >> 32) & 0xff);
212 buf[4] = (unsigned char)((current >> 40) & 0xff);
213 buf[7] = (unsigned char)((current >> 48) & 0xff);
214 buf[6] = (unsigned char)((current >> 56) & 0xff);
215
216 buf[6] &= 0x0f;
217 buf[6] |= 0x10;
218 buf[8] |= 0x80;
219 String::hexdump(buf, str, "4-2-2-2-6");
220 Mutex::release(&buf);
221}
222
223String secure::uuid(void)
224{
225 char buf[38];
226 uuid(buf);
227 return String(buf);
228}
229
230HMAC::HMAC()
231{
232 hmactype = NULL;
233 hmacid = 0;
234 context = NULL;
235 bufsize = 0;
236 textbuf[0] = 0;
237}
238
239HMAC::HMAC(const char *digest, const char *key, size_t len)
240{
241 context = NULL;
242 bufsize = 0;
243 hmactype = NULL;
244 hmacid = 0;
245 textbuf[0] = 0;
246
247 set(digest, key, len);
248}
249
250HMAC::~HMAC()
251{
252 release();
253}
254
255const char *HMAC::c_str(void)
256{
257 if(!bufsize)
258 get();
259
260 return textbuf;
261}
262
263Cipher::Key::Key(const char *cipher)
264{
265 hashtype = algotype = NULL;
266 hashid = algoid = 0;
267
268 secure::init();
269
270 set(cipher);
271}
272
273Cipher::Key::Key(const char *cipher, const char *digest)
274{
275 hashtype = algotype = NULL;
276 hashid = algoid = 0;
277
278 secure::init();
279 set(cipher, digest);
280}
281
282Cipher::Key::Key(const char *cipher, const char *digest, const char *text, size_t size, const unsigned char *salt, unsigned rounds)
283{
284 hashtype = algotype = NULL;
285 hashid = algoid = 0;
286
287 secure::init();
288
289 set(cipher, digest);
290 assign(text, size, salt, rounds);
291}
292
293Cipher::Key::Key()
294{
295 secure::init();
296 clear();
297}
298
299Cipher::Key::~Key()
300{
301 clear();
302}
303
304void Cipher::Key::clear(void)
305{
306 algotype = NULL;
307 hashtype = NULL;
308 algoid = hashid = 0;
309 keysize = blksize = 0;
310
311 zerofill(keybuf, sizeof(keybuf));
312 zerofill(ivbuf, sizeof(ivbuf));
313}
314
315Cipher::Cipher(key_t key, mode_t mode, unsigned char *address, size_t size)
316{
317 bufaddr = NULL;
318 bufsize = bufpos = 0;
319 context = NULL;
320 set(key, mode, address, size);
321}
322
323Cipher::Cipher()
324{
325 bufaddr = NULL;
326 bufsize = bufpos = 0;
327 context = NULL;
328}
329
330Cipher::~Cipher()
331{
332 flush();
333 release();
334}
335
336size_t Cipher::flush(void)
337{
338 size_t total = bufpos;
339
340 if(bufpos && bufsize) {
341 push(bufaddr, bufpos);
342 bufpos = 0;
343 }
344 bufaddr = NULL;
345 return total;
346}
347
348size_t Cipher::puts(const char *text)
349{
350 char padbuf[64];
351 if(!text || !bufaddr)
352 return 0;
353
354 size_t len = strlen(text) + 1;
355 unsigned pad = len % keys.iosize();
356
357 size_t count = put((const unsigned char *)text, len - pad);
358 if(pad) {
359 memcpy(padbuf, text + len - pad, pad);
360 memset(padbuf + pad, 0, keys.iosize() - pad);
361 count += put((const unsigned char *)padbuf, keys.iosize());
362 zerofill(padbuf, sizeof(padbuf));
363 }
364 return flush();
365}
366
367void Cipher::set(unsigned char *address, size_t size)
368{
369 flush();
370 bufsize = size;
371 bufaddr = address;
372 bufpos = 0;
373}
374
375size_t Cipher::process(unsigned char *buf, size_t len, bool flag)
376{
377 set(buf);
378 if(flag)
379 return pad(buf, len);
380 else
381 return put(buf, len);
382}
383
384int Random::get(void)
385{
386 uint16_t v;;
387 fill((unsigned char *)&v, sizeof(v));
388 v /= 2;
389 return (int)v;
390}
391
392int Random::get(int min, int max)
393{
394 unsigned rand;
395 int range = max - min + 1;
396 unsigned umax;
397
398 if(max < min)
399 return 0;
400
401 memset(&umax, 0xff, sizeof(umax));
402
403 do {
404 fill((unsigned char *)&rand, sizeof(rand));
405 } while(rand > umax - (umax % range));
406
407 return min + (rand % range);
408}
409
410double Random::real(void)
411{
412 unsigned umax;
413 unsigned rand;
414
415 memset(&umax, 0xff, sizeof(umax));
416 fill((unsigned char *)&rand, sizeof(rand));
417
418 return ((double)rand) / ((double)umax);
419}
420
421double Random::real(double min, double max)
422{
423 return real() * (max - min) + min;
424}
425
426void Random::uuid(char *str)
427{
428 unsigned char buf[16];
429
430 fill(buf, sizeof(buf));
431 buf[6] &= 0x0f;
432 buf[6] |= 0x40;
433 buf[8] &= 0x3f;
434 buf[8] |= 0x80;
435 String::hexdump(buf, str, "4-2-2-2-6");
436}
437
438String Random::uuid(void)
439{
440 char buf[38];
441 uuid(buf);
442 return String(buf);
443}
444