|
|
|
/***************************************************************************
|
|
|
|
** $Id: crypto.cpp,v 1.11 2008/07/31 19:56:26 hoganrobert Exp $
|
|
|
|
* Copyright (C) 2006 - 2008 Robert Hogan *
|
|
|
|
* robert@roberthogan.net *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* This program 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 General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program; if not, write to the *
|
|
|
|
* Free Software Foundation, Inc., *
|
|
|
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* In addition, as a special exception, the copyright holders give
|
|
|
|
* permission to link the code of portions of this program with the
|
|
|
|
* OpenSSL library under certain conditions as described in each
|
|
|
|
* individual source file, and distribute linked combinations
|
|
|
|
* including the two.
|
|
|
|
* You must obey the GNU General Public License in all respects
|
|
|
|
* for all of the code used other than OpenSSL. If you modify
|
|
|
|
* file(s) with this exception, you may extend this exception to your
|
|
|
|
* version of the file(s), but you are not obligated to do so. If you
|
|
|
|
* do not wish to do so, delete this exception statement from your
|
|
|
|
* version. If you delete this exception statement from all source
|
|
|
|
* files in the program, then also delete it here.
|
|
|
|
***************************************************************************/
|
|
|
|
/* Copyright (c) 2001 Matej Pfajfar.
|
|
|
|
* Copyright (c) 2001-2004, Roger Dingledine.
|
|
|
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. */
|
|
|
|
/* See Tor LICENSE for licensing information */
|
|
|
|
/* $Id: crypto.cpp,v 1.11 2008/07/31 19:56:26 hoganrobert Exp $ */
|
|
|
|
#include <string.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include "crypto.h"
|
|
|
|
#include "../config.h"
|
|
|
|
|
|
|
|
#ifndef USE_OPENSSL
|
|
|
|
#include <gnutls/gnutls.h>
|
|
|
|
#include <gcrypt.h>
|
|
|
|
#else
|
|
|
|
#include <openssl/err.h>
|
|
|
|
#include <openssl/rsa.h>
|
|
|
|
#include <openssl/pem.h>
|
|
|
|
#include <openssl/evp.h>
|
|
|
|
#include <openssl/rand.h>
|
|
|
|
#include <openssl/opensslv.h>
|
|
|
|
#include <openssl/bn.h>
|
|
|
|
#include <openssl/dh.h>
|
|
|
|
#include <openssl/rsa.h>
|
|
|
|
#include <openssl/dh.h>
|
|
|
|
#include <openssl/conf.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/fcntl.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
/* random numbers */
|
|
|
|
|
|
|
|
/* This is how much entropy OpenSSL likes to add right now, so maybe it will
|
|
|
|
* work for us too. */
|
|
|
|
#define ADD_ENTROPY 32
|
|
|
|
|
|
|
|
|
|
|
|
typedef TQMap<TQString, TQString> servermap;
|
|
|
|
servermap serverTofp_identity;
|
|
|
|
servermap fp_identityToServer;
|
|
|
|
|
|
|
|
/** Intermediate information about the digest of a stream of data. */
|
|
|
|
struct crypto_digest_env_t {
|
|
|
|
#ifndef USE_OPENSSL
|
|
|
|
gcry_md_hd_t d;
|
|
|
|
#else
|
|
|
|
SHA_CTX d;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void clearServers()
|
|
|
|
{
|
|
|
|
serverTofp_identity.clear();
|
|
|
|
fp_identityToServer.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString fp_identity(const TQString &server)
|
|
|
|
{
|
|
|
|
|
|
|
|
return serverTofp_identity[server];
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString server(const TQString &fp_identity)
|
|
|
|
{
|
|
|
|
|
|
|
|
return fp_identityToServer[fp_identity];
|
|
|
|
}
|
|
|
|
|
|
|
|
void storeServer(const TQString &server,const TQString &fp_identity)
|
|
|
|
{
|
|
|
|
|
|
|
|
serverTofp_identity[server] = fp_identity;
|
|
|
|
fp_identityToServer[fp_identity] = server;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TQString getFPDigestFromFP(const TQString &fp)
|
|
|
|
{
|
|
|
|
char identity64[BASE64_DIGEST_LEN+1];
|
|
|
|
char digest[DIGEST_LEN];
|
|
|
|
TQString FP = fp;
|
|
|
|
FP.replace("$","");
|
|
|
|
|
|
|
|
base16_decode(digest, DIGEST_LEN, FP, strlen(FP));
|
|
|
|
digest_to_base64(identity64, digest);
|
|
|
|
return identity64;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString getNickNameFromFPDigest(const TQString &fpdigest)
|
|
|
|
{
|
|
|
|
|
|
|
|
return fp_identityToServer[fpdigest];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString getNickNameFromFP(const TQString &fp)
|
|
|
|
{
|
|
|
|
TQString fpdigest = getFPDigestFromFP(fp);
|
|
|
|
|
|
|
|
return fp_identityToServer[fpdigest];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TQString getFPFromNickName(const TQString &nickname)
|
|
|
|
{
|
|
|
|
char buf[256];
|
|
|
|
char hexdigest[HEX_DIGEST_LEN+1];
|
|
|
|
|
|
|
|
TQString fp = serverTofp_identity[nickname];
|
|
|
|
|
|
|
|
if (fp.isEmpty())
|
|
|
|
return TQString();
|
|
|
|
if (!digest_from_base64(buf, fp))
|
|
|
|
base16_encode(hexdigest, HEX_DIGEST_LEN+1, buf, DIGEST_LEN);
|
|
|
|
|
|
|
|
return hexdigest;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString getFPFromFPDigest(const TQString &fp)
|
|
|
|
{
|
|
|
|
char buf[256];
|
|
|
|
char hexdigest[HEX_DIGEST_LEN+1];
|
|
|
|
|
|
|
|
digest_from_base64(buf, fp);
|
|
|
|
base16_encode(hexdigest, HEX_DIGEST_LEN+1, buf, DIGEST_LEN);
|
|
|
|
|
|
|
|
return hexdigest;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Seed OpenSSL's random number generator with bytes from the
|
|
|
|
* operating system. Return 0 on success, -1 on failure.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
crypto_seed_rng(void)
|
|
|
|
{
|
|
|
|
char buf[ADD_ENTROPY];
|
|
|
|
int rand_poll_status;
|
|
|
|
|
|
|
|
/* local variables */
|
|
|
|
static const char *filenames[] = {
|
|
|
|
"/dev/srandom", "/dev/urandom", "/dev/random", NULL
|
|
|
|
};
|
|
|
|
int fd;
|
|
|
|
int i, n;
|
|
|
|
|
|
|
|
rand_poll_status = 0;
|
|
|
|
|
|
|
|
for (i = 0; filenames[i]; ++i) {
|
|
|
|
fd = open(filenames[i], O_RDONLY, 0);
|
|
|
|
if (fd<0) continue;
|
|
|
|
n = read_all(fd, buf, sizeof(buf), 0);
|
|
|
|
close(fd);
|
|
|
|
if (n != sizeof(buf)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#ifndef USE_OPENSSL
|
|
|
|
gcry_create_nonce(buf, sizeof(buf));
|
|
|
|
#else
|
|
|
|
RAND_seed(buf, sizeof(buf));
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rand_poll_status ? 0 : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Write n bytes of strong random data to <b>to</b>. Return 0 on
|
|
|
|
* success, -1 on failure.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
crypto_rand(char *to, size_t n)
|
|
|
|
{
|
|
|
|
assert(to);
|
|
|
|
#ifndef USE_OPENSSL
|
|
|
|
gcry_randomize((unsigned char*)to,n,GCRY_STRONG_RANDOM);
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
int r;
|
|
|
|
r = RAND_bytes((unsigned char*)to, n);
|
|
|
|
return (r == 1) ? 0 : -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return a pseudorandom integer, chosen uniformly from the values
|
|
|
|
* between 0 and max-1. */
|
|
|
|
int
|
|
|
|
crypto_rand_int(unsigned int max)
|
|
|
|
{
|
|
|
|
unsigned int val;
|
|
|
|
unsigned int cutoff;
|
|
|
|
assert(max < UINT_MAX);
|
|
|
|
assert(max > 0); /* don't div by 0 */
|
|
|
|
|
|
|
|
/* We ignore any values that are >= 'cutoff,' to avoid biasing the
|
|
|
|
* distribution with clipping at the upper end of unsigned int's
|
|
|
|
* range.
|
|
|
|
*/
|
|
|
|
cutoff = UINT_MAX - (UINT_MAX%max);
|
|
|
|
while (1) {
|
|
|
|
crypto_rand((char*)&val, sizeof(val));
|
|
|
|
if (val < cutoff)
|
|
|
|
return val % max;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Generates a pseudorandom string of length <b>len</b> containing printable
|
|
|
|
* ASCII characters from the range '!' (0x21) to '~' (0x7e). */
|
|
|
|
TQString
|
|
|
|
crypto_rand_string(int len)
|
|
|
|
{
|
|
|
|
TQString str;
|
|
|
|
Q_ASSERT(len >= 0);
|
|
|
|
|
|
|
|
for (int i = 0; i < len; i++)
|
|
|
|
str += TQChar('!' + crypto_rand_int('~'-'!'+1));
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Read from <b>fd</b> to <b>buf</b>, until we get <b>count</b> bytes
|
|
|
|
* or reach the end of the file. <b>isSocket</b> must be 1 if fd
|
|
|
|
* was returned by socket() or accept(), and 0 if fd was returned by
|
|
|
|
* open(). Return the number of bytes read, or -1 on error. Only use
|
|
|
|
* if fd is a blocking fd. */
|
|
|
|
int
|
|
|
|
read_all(int fd, char *buf, size_t count, int isSocket)
|
|
|
|
{
|
|
|
|
size_t numread = 0;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
if (count > SIZE_T_CEILING)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
while (numread != count) {
|
|
|
|
if (isSocket)
|
|
|
|
result = recv(fd, buf+numread, count-numread, 0);
|
|
|
|
else
|
|
|
|
result = read(fd, buf+numread, count-numread);
|
|
|
|
if (result<0)
|
|
|
|
return -1;
|
|
|
|
else if (result == 0)
|
|
|
|
break;
|
|
|
|
numread += result;
|
|
|
|
}
|
|
|
|
return numread;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
digest_from_base64(char *digest, const char *d64)
|
|
|
|
{
|
|
|
|
|
|
|
|
char buf_in[BASE64_DIGEST_LEN+3];
|
|
|
|
char buf[256];
|
|
|
|
if (strlen(d64) != BASE64_DIGEST_LEN)
|
|
|
|
return -1;
|
|
|
|
memcpy(buf_in, d64, BASE64_DIGEST_LEN);
|
|
|
|
#ifndef USE_OPENSSL
|
|
|
|
memcpy(buf_in+BASE64_DIGEST_LEN, "=\0", 2);
|
|
|
|
if (base64_decode(buf, sizeof(buf), buf_in, strlen(buf_in)) != DIGEST_LEN)
|
|
|
|
return -1;
|
|
|
|
#else
|
|
|
|
memcpy(buf_in+BASE64_DIGEST_LEN, "=\n\0", 3);
|
|
|
|
if (base64_decode(buf, sizeof(buf), buf_in, strlen(buf_in)) != DIGEST_LEN)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
memcpy(digest, buf, DIGEST_LEN);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
base64_decode(char *dest, size_t destlen, const char *src, size_t srclen)
|
|
|
|
{
|
|
|
|
|
|
|
|
#ifndef USE_OPENSSL
|
|
|
|
// gnutls_datum_t data_in;
|
|
|
|
base64_decodestate state;
|
|
|
|
#else
|
|
|
|
EVP_ENCODE_CTX ctx;
|
|
|
|
int len;
|
|
|
|
#endif
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* 64 bytes of input -> *up to* 48 bytes of output.
|
|
|
|
Plus one more byte, in case I'm wrong.
|
|
|
|
*/
|
|
|
|
if (destlen < ((srclen/64)+1)*49)
|
|
|
|
return -1;
|
|
|
|
if (destlen > SIZE_T_CEILING)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
#ifndef USE_OPENSSL
|
|
|
|
/* data_in.data = (unsigned char*)src;
|
|
|
|
data_in.size = srclen;*/
|
|
|
|
base64_init_decodestate(&state);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef USE_OPENSSL
|
|
|
|
// if (gnutls_srp_base64_decode(&data_in, dest, &destlen)
|
|
|
|
// == GNUTLS_E_SHORT_MEMORY_BUFFER)
|
|
|
|
// kdDebug() << "error decoding " << endl;
|
|
|
|
// kdDebug() << "decoded " << dest << "len" << destlen << endl;
|
|
|
|
|
|
|
|
ret = base64_decode_block(src, srclen, dest, &state);
|
|
|
|
return ret;
|
|
|
|
#else
|
|
|
|
EVP_DecodeInit(&ctx);
|
|
|
|
EVP_DecodeUpdate(&ctx, (unsigned char*)dest, &len,
|
|
|
|
(unsigned char*)src, srclen);
|
|
|
|
EVP_DecodeFinal(&ctx, (unsigned char*)dest, &ret);
|
|
|
|
ret += len;
|
|
|
|
return ret;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
digest_to_base64(char *d64, const char *digest)
|
|
|
|
{
|
|
|
|
char buf[256];
|
|
|
|
base64_encode(buf, sizeof(buf), digest, DIGEST_LEN);
|
|
|
|
buf[BASE64_DIGEST_LEN] = '\0';
|
|
|
|
memcpy(d64, buf, BASE64_DIGEST_LEN+1);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
base64_encode(char *dest, size_t destlen, const char *src, size_t srclen)
|
|
|
|
{
|
|
|
|
#ifndef USE_OPENSSL
|
|
|
|
// gnutls_datum_t data_in;
|
|
|
|
base64_encodestate state;
|
|
|
|
#else
|
|
|
|
EVP_ENCODE_CTX ctx;
|
|
|
|
int len;
|
|
|
|
#endif
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
|
|
/* 48 bytes of input -> 64 bytes of output plus newline.
|
|
|
|
Plus one more byte, in case I'm wrong.
|
|
|
|
*/
|
|
|
|
if (destlen < ((srclen/48)+1)*66)
|
|
|
|
return -1;
|
|
|
|
if (destlen > SIZE_T_CEILING)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
#ifndef USE_OPENSSL
|
|
|
|
/* data_in.data = (unsigned char*)src;
|
|
|
|
data_in.size = srclen;*/
|
|
|
|
base64_init_encodestate(&state);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef USE_OPENSSL
|
|
|
|
// gnutls_srp_base64_encode(&data_in, dest, &destlen);
|
|
|
|
// kdDebug() << "encoded " << dest << "len" << destlen << endl;
|
|
|
|
// return destlen;
|
|
|
|
ret = base64_encode_block(src, srclen, dest, &state);
|
|
|
|
ret += base64_encode_blockend(dest+ret, &state);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
#else
|
|
|
|
EVP_EncodeInit(&ctx);
|
|
|
|
EVP_EncodeUpdate(&ctx, (unsigned char*)dest, &len,
|
|
|
|
(unsigned char*)src, srclen);
|
|
|
|
EVP_EncodeFinal(&ctx, (unsigned char*)(dest+len), &ret);
|
|
|
|
ret += len;
|
|
|
|
return ret;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char HEX_DIGITS[] = "0123456789ABCDEFabcdef";
|
|
|
|
|
|
|
|
static int hex_decode_digit(char c)
|
|
|
|
{
|
|
|
|
const char *cp;
|
|
|
|
int n;
|
|
|
|
cp = strchr(HEX_DIGITS, c);
|
|
|
|
if (!cp)
|
|
|
|
return -1;
|
|
|
|
n = cp-HEX_DIGITS;
|
|
|
|
if (n<=15)
|
|
|
|
return n; /* digit or uppercase */
|
|
|
|
else
|
|
|
|
return n-6; /* lowercase */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
base16_encode(char *dest, size_t destlen, const char *src, size_t srclen)
|
|
|
|
{
|
|
|
|
const char *end;
|
|
|
|
char *cp;
|
|
|
|
|
|
|
|
assert(destlen >= srclen*2+1);
|
|
|
|
assert(destlen < SIZE_T_CEILING);
|
|
|
|
|
|
|
|
cp = dest;
|
|
|
|
end = src+srclen;
|
|
|
|
while (src<end) {
|
|
|
|
sprintf(cp,"%02X",*(const uint8_t*)src);
|
|
|
|
++src;
|
|
|
|
cp += 2;
|
|
|
|
}
|
|
|
|
*cp = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
base16_decode(char *dest, size_t destlen, const char *src, size_t srclen)
|
|
|
|
{
|
|
|
|
const char *end;
|
|
|
|
int v1,v2;
|
|
|
|
if ((srclen % 2) != 0)
|
|
|
|
return -1;
|
|
|
|
if (destlen < srclen/2 || destlen > SIZE_T_CEILING)
|
|
|
|
return -1;
|
|
|
|
end = src+srclen;
|
|
|
|
while (src<end) {
|
|
|
|
v1 = hex_decode_digit(*src);
|
|
|
|
v2 = hex_decode_digit(*(src+1));
|
|
|
|
if (v1<0||v2<0)
|
|
|
|
return -1;
|
|
|
|
*(uint8_t*)dest = (v1<<4)|v2;
|
|
|
|
++dest;
|
|
|
|
src+=2;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Deallocate a digest object.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
crypto_free_digest_env(crypto_digest_env_t *digest)
|
|
|
|
{
|
|
|
|
free(digest);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Allocate and return a new digest object.
|
|
|
|
*/
|
|
|
|
crypto_digest_env_t *
|
|
|
|
crypto_new_digest_env(void)
|
|
|
|
{
|
|
|
|
crypto_digest_env_t *r;
|
|
|
|
r = (crypto_digest_env_t *)malloc(sizeof(crypto_digest_env_t));
|
|
|
|
|
|
|
|
#ifndef USE_OPENSSL
|
|
|
|
gcry_md_open(&r->d,GCRY_MD_SHA1, 0);
|
|
|
|
#else
|
|
|
|
SHA1_Init(&r->d);
|
|
|
|
#endif
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Compute the hash of the data that has been passed to the digest
|
|
|
|
* object; write the first out_len bytes of the result to <b>out</b>.
|
|
|
|
* <b>out_len</b> must be \<= DIGEST_LEN.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
crypto_digest_get_digest(crypto_digest_env_t *digest,
|
|
|
|
char *out, size_t out_len)
|
|
|
|
{
|
|
|
|
|
|
|
|
#ifdef USE_OPENSSL
|
|
|
|
static unsigned char r[DIGEST_LEN];
|
|
|
|
#else
|
|
|
|
unsigned char* r;
|
|
|
|
#endif
|
|
|
|
assert(digest);
|
|
|
|
assert(out);
|
|
|
|
assert(out_len <= DIGEST_LEN);
|
|
|
|
#ifdef USE_OPENSSL
|
|
|
|
SHA_CTX tmpctx;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef USE_OPENSSL
|
|
|
|
r = gcry_md_read(digest->d, GCRY_MD_SHA1);
|
|
|
|
memcpy(out, r, out_len);
|
|
|
|
gcry_md_close(digest->d);
|
|
|
|
#else
|
|
|
|
/* memcpy into a temporary ctx, since SHA1_Final clears the context */
|
|
|
|
memcpy(&tmpctx, &digest->d, sizeof(SHA_CTX));
|
|
|
|
SHA1_Final(r, &tmpctx);
|
|
|
|
memcpy(out, r, out_len);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Add <b>len</b> bytes from <b>data</b> to the digest object.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
crypto_digest_add_bytes(crypto_digest_env_t *digest, const char *data,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
assert(digest);
|
|
|
|
assert(data);
|
|
|
|
/* Using the SHA1_*() calls directly means we don't support doing
|
|
|
|
* sha1 in hardware. But so far the delay of getting the question
|
|
|
|
* to the hardware, and hearing the answer, is likely higher than
|
|
|
|
* just doing it ourselves. Hashes are fast.
|
|
|
|
*/
|
|
|
|
#ifndef USE_OPENSSL
|
|
|
|
gcry_md_write(digest->d, data, len);
|
|
|
|
#else
|
|
|
|
SHA1_Update(&digest->d, (void*)data, len);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Implement RFC2440-style iterated-salted S2K conversion: convert the
|
|
|
|
* <b>secret_len</b>-byte <b>secret</b> into a <b>key_out_len</b> byte
|
|
|
|
* <b>key_out</b>. As in RFC2440, the first 8 bytes of s2k_specifier
|
|
|
|
* are a salt; the 9th byte describes how much iteration to do.
|
|
|
|
* Does not support <b>key_out_len</b> > DIGEST_LEN.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
secret_to_key(char *key_out, size_t key_out_len, const char *secret,
|
|
|
|
size_t secret_len, const char *s2k_specifier)
|
|
|
|
{
|
|
|
|
crypto_digest_env_t *d;
|
|
|
|
uint8_t c;
|
|
|
|
size_t count;
|
|
|
|
char *tmp;
|
|
|
|
assert(key_out_len < SIZE_T_CEILING);
|
|
|
|
|
|
|
|
#define EXPBIAS 6
|
|
|
|
c = s2k_specifier[8];
|
|
|
|
count = ((uint32_t)16 + (c & 15)) << ((c >> 4) + EXPBIAS);
|
|
|
|
#undef EXPBIAS
|
|
|
|
|
|
|
|
assert(key_out_len <= DIGEST_LEN);
|
|
|
|
|
|
|
|
d = crypto_new_digest_env();
|
|
|
|
tmp = (char *)malloc(8+secret_len);
|
|
|
|
memcpy(tmp,s2k_specifier,8);
|
|
|
|
memcpy(tmp+8,secret,secret_len);
|
|
|
|
secret_len += 8;
|
|
|
|
while (count) {
|
|
|
|
if (count >= secret_len) {
|
|
|
|
crypto_digest_add_bytes(d, tmp, secret_len);
|
|
|
|
count -= secret_len;
|
|
|
|
} else {
|
|
|
|
crypto_digest_add_bytes(d, tmp, count);
|
|
|
|
count = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
crypto_digest_get_digest(d, key_out, key_out_len);
|
|
|
|
free(tmp);
|
|
|
|
crypto_free_digest_env(d);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Entry point for password hashing: take the desired password from
|
|
|
|
* the command line, and print its salted hash to stdout. **/
|
|
|
|
TQString hashPassword(const char* secret)
|
|
|
|
{
|
|
|
|
|
|
|
|
char output[256];
|
|
|
|
char key[S2K_SPECIFIER_LEN+DIGEST_LEN];
|
|
|
|
|
|
|
|
crypto_rand(key, S2K_SPECIFIER_LEN-1);
|
|
|
|
key[S2K_SPECIFIER_LEN-1] = (uint8_t)96; /* Hash 64 K of data. */
|
|
|
|
secret_to_key(key+S2K_SPECIFIER_LEN, DIGEST_LEN,
|
|
|
|
secret, strlen(secret),
|
|
|
|
key);
|
|
|
|
base16_encode(output, sizeof(output), key, sizeof(key));
|
|
|
|
kdDebug() << output << endl;
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
cdecoder.c - c source to a base64 decoding algorithm implementation
|
|
|
|
|
|
|
|
This is part of the libb64 project, and has been placed in the public domain.
|
|
|
|
For details, see http://sourceforge.net/projects/libb64
|
|
|
|
*/
|
|
|
|
|
|
|
|
int base64_decode_value(char value_in)
|
|
|
|
{
|
|
|
|
static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
|
|
|
|
static const char decoding_size = sizeof(decoding);
|
|
|
|
value_in -= 43;
|
|
|
|
if (value_in < 0 || value_in > decoding_size) return -1;
|
|
|
|
return decoding[(int)value_in];
|
|
|
|
}
|
|
|
|
|
|
|
|
void base64_init_decodestate(base64_decodestate* state_in)
|
|
|
|
{
|
|
|
|
state_in->step = step_a;
|
|
|
|
state_in->plainchar = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in)
|
|
|
|
{
|
|
|
|
const char* codechar = code_in;
|
|
|
|
char* plainchar = plaintext_out;
|
|
|
|
char fragment;
|
|
|
|
|
|
|
|
*plainchar = state_in->plainchar;
|
|
|
|
|
|
|
|
switch (state_in->step)
|
|
|
|
{
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
case step_a:
|
|
|
|
do {
|
|
|
|
if (codechar == code_in+length_in)
|
|
|
|
{
|
|
|
|
state_in->step = step_a;
|
|
|
|
state_in->plainchar = *plainchar;
|
|
|
|
return plainchar - plaintext_out;
|
|
|
|
}
|
|
|
|
fragment = (char)base64_decode_value(*codechar++);
|
|
|
|
} while (fragment < 0);
|
|
|
|
*plainchar = (fragment & 0x03f) << 2;
|
|
|
|
case step_b:
|
|
|
|
do {
|
|
|
|
if (codechar == code_in+length_in)
|
|
|
|
{
|
|
|
|
state_in->step = step_b;
|
|
|
|
state_in->plainchar = *plainchar;
|
|
|
|
return plainchar - plaintext_out;
|
|
|
|
}
|
|
|
|
fragment = (char)base64_decode_value(*codechar++);
|
|
|
|
} while (fragment < 0);
|
|
|
|
*plainchar++ |= (fragment & 0x030) >> 4;
|
|
|
|
*plainchar = (fragment & 0x00f) << 4;
|
|
|
|
case step_c:
|
|
|
|
do {
|
|
|
|
if (codechar == code_in+length_in)
|
|
|
|
{
|
|
|
|
state_in->step = step_c;
|
|
|
|
state_in->plainchar = *plainchar;
|
|
|
|
return plainchar - plaintext_out;
|
|
|
|
}
|
|
|
|
fragment = (char)base64_decode_value(*codechar++);
|
|
|
|
} while (fragment < 0);
|
|
|
|
*plainchar++ |= (fragment & 0x03c) >> 2;
|
|
|
|
*plainchar = (fragment & 0x003) << 6;
|
|
|
|
case step_d:
|
|
|
|
do {
|
|
|
|
if (codechar == code_in+length_in)
|
|
|
|
{
|
|
|
|
state_in->step = step_d;
|
|
|
|
state_in->plainchar = *plainchar;
|
|
|
|
return plainchar - plaintext_out;
|
|
|
|
}
|
|
|
|
fragment = (char)base64_decode_value(*codechar++);
|
|
|
|
} while (fragment < 0);
|
|
|
|
*plainchar++ |= (fragment & 0x03f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* control should not reach here */
|
|
|
|
return plainchar - plaintext_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
cencoder.c - c source to a base64 encoding algorithm implementation
|
|
|
|
|
|
|
|
This is part of the libb64 project, and has been placed in the public domain.
|
|
|
|
For details, see http://sourceforge.net/projects/libb64
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
const int CHARS_PER_LINE = 72;
|
|
|
|
|
|
|
|
void base64_init_encodestate(base64_encodestate* state_in)
|
|
|
|
{
|
|
|
|
state_in->step = step_A;
|
|
|
|
state_in->result = 0;
|
|
|
|
state_in->stepcount = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char base64_encode_value(char value_in)
|
|
|
|
{
|
|
|
|
static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
if (value_in > 63) return '=';
|
|
|
|
return encoding[(int)value_in];
|
|
|
|
}
|
|
|
|
|
|
|
|
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
|
|
|
|
{
|
|
|
|
const char* plainchar = plaintext_in;
|
|
|
|
const char* const plaintextend = plaintext_in + length_in;
|
|
|
|
char* codechar = code_out;
|
|
|
|
char result;
|
|
|
|
char fragment;
|
|
|
|
|
|
|
|
result = state_in->result;
|
|
|
|
|
|
|
|
switch (state_in->step)
|
|
|
|
{
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
case step_A:
|
|
|
|
if (plainchar == plaintextend)
|
|
|
|
{
|
|
|
|
state_in->result = result;
|
|
|
|
state_in->step = step_A;
|
|
|
|
return codechar - code_out;
|
|
|
|
}
|
|
|
|
fragment = *plainchar++;
|
|
|
|
result = (fragment & 0x0fc) >> 2;
|
|
|
|
*codechar++ = base64_encode_value(result);
|
|
|
|
result = (fragment & 0x003) << 4;
|
|
|
|
case step_B:
|
|
|
|
if (plainchar == plaintextend)
|
|
|
|
{
|
|
|
|
state_in->result = result;
|
|
|
|
state_in->step = step_B;
|
|
|
|
return codechar - code_out;
|
|
|
|
}
|
|
|
|
fragment = *plainchar++;
|
|
|
|
result |= (fragment & 0x0f0) >> 4;
|
|
|
|
*codechar++ = base64_encode_value(result);
|
|
|
|
result = (fragment & 0x00f) << 2;
|
|
|
|
case step_C:
|
|
|
|
if (plainchar == plaintextend)
|
|
|
|
{
|
|
|
|
state_in->result = result;
|
|
|
|
state_in->step = step_C;
|
|
|
|
return codechar - code_out;
|
|
|
|
}
|
|
|
|
fragment = *plainchar++;
|
|
|
|
result |= (fragment & 0x0c0) >> 6;
|
|
|
|
*codechar++ = base64_encode_value(result);
|
|
|
|
result = (fragment & 0x03f) >> 0;
|
|
|
|
*codechar++ = base64_encode_value(result);
|
|
|
|
|
|
|
|
++(state_in->stepcount);
|
|
|
|
if (state_in->stepcount == CHARS_PER_LINE/4)
|
|
|
|
{
|
|
|
|
*codechar++ = '\n';
|
|
|
|
state_in->stepcount = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* control should not reach here */
|
|
|
|
return codechar - code_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
|
|
|
|
{
|
|
|
|
char* codechar = code_out;
|
|
|
|
|
|
|
|
switch (state_in->step)
|
|
|
|
{
|
|
|
|
case step_B:
|
|
|
|
*codechar++ = base64_encode_value(state_in->result);
|
|
|
|
/* *codechar++ = '=';
|
|
|
|
*codechar++ = '=';*/
|
|
|
|
break;
|
|
|
|
case step_C:
|
|
|
|
*codechar++ = base64_encode_value(state_in->result);
|
|
|
|
/* *codechar++ = '=';*/
|
|
|
|
break;
|
|
|
|
case step_A:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* *codechar++ = '\n';*/
|
|
|
|
|
|
|
|
return codechar - code_out;
|
|
|
|
}
|