blob: ee6f5ddd4dd3bcecdb90d9c14c8e36600793d833 [file] [log] [blame]
// Copyright (C) 2010 David Sugar, Tycho Softworks.
//
// This file is part of GNU uCommon C++.
//
// GNU uCommon C++ is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU uCommon C++ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with GNU uCommon C++. If not, see <http://www.gnu.org/licenses/>.
#include "local.h"
Digest::Digest()
{
hashtype = NULL;
hashid = 0;
context = NULL;
bufsize = 0;
textbuf[0] = 0;
}
Digest::Digest(const char *type)
{
hashtype = NULL;
hashid = 0;
context = NULL;
bufsize = 0;
textbuf[0] = 0;
set(type);
}
Digest::~Digest()
{
release();
}
const char *Digest::c_str(void)
{
if(!bufsize)
get();
return textbuf;
}
void Digest::uuid(char *str, const char *name, const unsigned char *ns)
{
unsigned mask = 0x50;
const char *type = "sha1";
if(!has("sha1")) {
mask = 0x30;
type = "md5";
}
Digest md(type);
if(ns)
md.put(ns, 16);
md.puts(name);
unsigned char *buf = (unsigned char *)md.get();
buf[6] &= 0x0f;
buf[6] |= mask;
buf[8] &= 0x3f;
buf[8] |= 0x80;
String::hexdump(buf, str, "4-2-2-2-6");
}
String Digest::uuid(const char *name, const unsigned char *ns)
{
char buf[38];
uuid(buf, name, ns);
return String(buf);
}
#if defined(_MSWINDOWS_)
static void cexport(HCERTSTORE ca, FILE *fp)
{
PCCERT_CONTEXT cert = NULL;
const uint8_t *cp;
char buf[80];
while ((cert = CertEnumCertificatesInStore(ca, cert)) != NULL) {
fprintf(fp, "-----BEGIN CERTIFICATE-----\n");
size_t total = cert->cbCertEncoded;
size_t count;
cp = (const uint8_t *)cert->pbCertEncoded;
while(total) {
count = String::b64encode(buf, cp, total, 64);
if(count)
fprintf(fp, "%s\n", buf);
total -= count;
cp += count;
}
fprintf(fp, "-----END CERTIFICATE-----\n");
}
}
const char *secure::oscerts(void)
{
const char *path = "c:/temp/ca-bundle.crt";
if(!is_file(path)) {
if(oscerts(path))
return NULL;
}
return path;
}
int secure::oscerts(const char *pathname)
{
bool caset;
string_t target;
if(pathname[1] == ':' || pathname[0] == '/' || pathname[0] == '\\')
target = pathname;
else
target = shell::path(shell::USER_CONFIG) + "/" + pathname;
FILE *fp = fopen(*target, "wt");
if(!fp)
return ENOSYS;
HCERTSTORE ca = CertOpenSystemStoreA((HCRYPTPROV)NULL, "ROOT");
if(ca) {
caset = true;
cexport(ca, fp);
CertCloseStore(ca, 0);
}
ca = CertOpenSystemStoreA((HCRYPTPROV)NULL, "CA");
if(ca) {
caset = true;
cexport(ca, fp);
CertCloseStore(ca, 0);
}
fclose(fp);
if(!caset) {
fsys::erase(*target);
return ENOSYS;
}
return 0;
}
#else
const char *secure::oscerts(void)
{
if(is_file("/etc/ssl/certs/ca-certificates.crt"))
return "/etc/ssl/certs/ca-certificates.crt";
if(is_file("/etc/pki/tls/ca-bundle.crt"))
return "/etc/pki/tls/ca-bundle.crt";
if(is_file("/etc/ssl/ca-bundle.pem"))
return "/etc/ssl/ca-bundle.pem";
return NULL;
}
int secure::oscerts(const char *pathname)
{
string_t source = oscerts();
string_t target;
if(pathname[0] == '/')
target = pathname;
else
target = shell::path(shell::USER_CONFIG) + "/" + pathname;
if(!source)
return ENOSYS;
return fsys::copy(*source, *target);
}
#endif
void secure::uuid(char *str)
{
static unsigned char buf[16];
static Timer::tick_t prior = 0l;
static unsigned short seq;
Timer::tick_t current = Timer::ticks();
Mutex::protect(&buf);
// get our (random) node identifier...
if(!prior)
Random::fill(buf + 10, 6);
if(current == prior)
++seq;
else
Random::fill((unsigned char *)&seq, sizeof(seq));
buf[8] = (unsigned char)((seq >> 8) & 0xff);
buf[9] = (unsigned char)(seq & 0xff);
buf[3] = (unsigned char)(current & 0xff);
buf[2] = (unsigned char)((current >> 8) & 0xff);
buf[1] = (unsigned char)((current >> 16) & 0xff);
buf[0] = (unsigned char)((current >> 24) & 0xff);
buf[5] = (unsigned char)((current >> 32) & 0xff);
buf[4] = (unsigned char)((current >> 40) & 0xff);
buf[7] = (unsigned char)((current >> 48) & 0xff);
buf[6] = (unsigned char)((current >> 56) & 0xff);
buf[6] &= 0x0f;
buf[6] |= 0x10;
buf[8] |= 0x80;
String::hexdump(buf, str, "4-2-2-2-6");
Mutex::release(&buf);
}
String secure::uuid(void)
{
char buf[38];
uuid(buf);
return String(buf);
}
HMAC::HMAC()
{
hmactype = NULL;
hmacid = 0;
context = NULL;
bufsize = 0;
textbuf[0] = 0;
}
HMAC::HMAC(const char *digest, const char *key, size_t len)
{
context = NULL;
bufsize = 0;
hmactype = NULL;
hmacid = 0;
textbuf[0] = 0;
set(digest, key, len);
}
HMAC::~HMAC()
{
release();
}
const char *HMAC::c_str(void)
{
if(!bufsize)
get();
return textbuf;
}
Cipher::Key::Key(const char *cipher)
{
hashtype = algotype = NULL;
hashid = algoid = 0;
secure::init();
set(cipher);
}
Cipher::Key::Key(const char *cipher, const char *digest)
{
hashtype = algotype = NULL;
hashid = algoid = 0;
secure::init();
set(cipher, digest);
}
Cipher::Key::Key(const char *cipher, const char *digest, const char *text, size_t size, const unsigned char *salt, unsigned rounds)
{
hashtype = algotype = NULL;
hashid = algoid = 0;
secure::init();
set(cipher, digest);
assign(text, size, salt, rounds);
}
Cipher::Key::Key()
{
secure::init();
clear();
}
Cipher::Key::~Key()
{
clear();
}
void Cipher::Key::clear(void)
{
algotype = NULL;
hashtype = NULL;
algoid = hashid = 0;
keysize = blksize = 0;
zerofill(keybuf, sizeof(keybuf));
zerofill(ivbuf, sizeof(ivbuf));
}
Cipher::Cipher(key_t key, mode_t mode, unsigned char *address, size_t size)
{
bufaddr = NULL;
bufsize = bufpos = 0;
context = NULL;
set(key, mode, address, size);
}
Cipher::Cipher()
{
bufaddr = NULL;
bufsize = bufpos = 0;
context = NULL;
}
Cipher::~Cipher()
{
flush();
release();
}
size_t Cipher::flush(void)
{
size_t total = bufpos;
if(bufpos && bufsize) {
push(bufaddr, bufpos);
bufpos = 0;
}
bufaddr = NULL;
return total;
}
size_t Cipher::puts(const char *text)
{
char padbuf[64];
if(!text || !bufaddr)
return 0;
size_t len = strlen(text) + 1;
unsigned pad = len % keys.iosize();
size_t count = put((const unsigned char *)text, len - pad);
if(pad) {
memcpy(padbuf, text + len - pad, pad);
memset(padbuf + pad, 0, keys.iosize() - pad);
count += put((const unsigned char *)padbuf, keys.iosize());
zerofill(padbuf, sizeof(padbuf));
}
return flush();
}
void Cipher::set(unsigned char *address, size_t size)
{
flush();
bufsize = size;
bufaddr = address;
bufpos = 0;
}
size_t Cipher::process(unsigned char *buf, size_t len, bool flag)
{
set(buf);
if(flag)
return pad(buf, len);
else
return put(buf, len);
}
int Random::get(void)
{
uint16_t v;;
fill((unsigned char *)&v, sizeof(v));
v /= 2;
return (int)v;
}
int Random::get(int min, int max)
{
unsigned rand;
int range = max - min + 1;
unsigned umax;
if(max < min)
return 0;
memset(&umax, 0xff, sizeof(umax));
do {
fill((unsigned char *)&rand, sizeof(rand));
} while(rand > umax - (umax % range));
return min + (rand % range);
}
double Random::real(void)
{
unsigned umax;
unsigned rand;
memset(&umax, 0xff, sizeof(umax));
fill((unsigned char *)&rand, sizeof(rand));
return ((double)rand) / ((double)umax);
}
double Random::real(double min, double max)
{
return real() * (max - min) + min;
}
void Random::uuid(char *str)
{
unsigned char buf[16];
fill(buf, sizeof(buf));
buf[6] &= 0x0f;
buf[6] |= 0x40;
buf[8] &= 0x3f;
buf[8] |= 0x80;
String::hexdump(buf, str, "4-2-2-2-6");
}
String Random::uuid(void)
{
char buf[38];
uuid(buf);
return String(buf);
}