mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-20 10:12:15 +01:00
Move formatting functions around.
The base64 and base32 functions used to be in crypto.c; crypto_format.h had no header; some general-purpose functions were in crypto_curve25519.c. This patch makes a {crypto,util}_format.[ch], and puts more functions there. Small modules are beautiful!
This commit is contained in:
parent
8c83e8cec0
commit
347fe449fe
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "util_format.h"
|
||||||
#include "address.h"
|
#include "address.h"
|
||||||
#include "torlog.h"
|
#include "torlog.h"
|
||||||
#include "container.h"
|
#include "container.h"
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
#include "crypto_curve25519.h"
|
#include "crypto_curve25519.h"
|
||||||
#include "crypto_ed25519.h"
|
#include "crypto_ed25519.h"
|
||||||
|
#include "crypto_format.h"
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0)
|
#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0)
|
||||||
#error "We require OpenSSL >= 1.0.0"
|
#error "We require OpenSSL >= 1.0.0"
|
||||||
@ -62,6 +63,7 @@
|
|||||||
#include "container.h"
|
#include "container.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "sandbox.h"
|
#include "sandbox.h"
|
||||||
|
#include "util_format.h"
|
||||||
|
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
/* Android's OpenSSL seems to have removed all of its Engine support. */
|
/* Android's OpenSSL seems to have removed all of its Engine support. */
|
||||||
@ -2541,487 +2543,6 @@ smartlist_shuffle(smartlist_t *sl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BASE64_OPENSSL_LINELEN 64
|
|
||||||
|
|
||||||
/** Return the Base64 encoded size of <b>srclen</b> bytes of data in
|
|
||||||
* bytes.
|
|
||||||
*
|
|
||||||
* If <b>flags</b>&BASE64_ENCODE_MULTILINE is true, return the size
|
|
||||||
* of the encoded output as multiline output (64 character, `\n' terminated
|
|
||||||
* lines).
|
|
||||||
*/
|
|
||||||
size_t
|
|
||||||
base64_encode_size(size_t srclen, int flags)
|
|
||||||
{
|
|
||||||
size_t enclen;
|
|
||||||
tor_assert(srclen < INT_MAX);
|
|
||||||
|
|
||||||
if (srclen == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
enclen = ((srclen - 1) / 3) * 4 + 4;
|
|
||||||
if (flags & BASE64_ENCODE_MULTILINE) {
|
|
||||||
size_t remainder = enclen % BASE64_OPENSSL_LINELEN;
|
|
||||||
enclen += enclen / BASE64_OPENSSL_LINELEN;
|
|
||||||
if (remainder)
|
|
||||||
enclen++;
|
|
||||||
}
|
|
||||||
tor_assert(enclen < INT_MAX && enclen > srclen);
|
|
||||||
return enclen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Internal table mapping 6 bit values to the Base64 alphabet. */
|
|
||||||
static const char base64_encode_table[64] = {
|
|
||||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
|
||||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
|
||||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
|
||||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
|
||||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
|
||||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
|
||||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
|
||||||
'4', '5', '6', '7', '8', '9', '+', '/'
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Base64 encode <b>srclen</b> bytes of data from <b>src</b>. Write
|
|
||||||
* the result into <b>dest</b>, if it will fit within <b>destlen</b>
|
|
||||||
* bytes. Return the number of bytes written on success; -1 if
|
|
||||||
* destlen is too short, or other failure.
|
|
||||||
*
|
|
||||||
* If <b>flags</b>&BASE64_ENCODE_MULTILINE is true, return encoded
|
|
||||||
* output in multiline format (64 character, `\n' terminated lines).
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
base64_encode(char *dest, size_t destlen, const char *src, size_t srclen,
|
|
||||||
int flags)
|
|
||||||
{
|
|
||||||
const unsigned char *usrc = (unsigned char *)src;
|
|
||||||
const unsigned char *eous = usrc + srclen;
|
|
||||||
char *d = dest;
|
|
||||||
uint32_t n = 0;
|
|
||||||
size_t linelen = 0;
|
|
||||||
size_t enclen;
|
|
||||||
int n_idx = 0;
|
|
||||||
|
|
||||||
if (!src || !dest)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* Ensure that there is sufficient space, including the NUL. */
|
|
||||||
enclen = base64_encode_size(srclen, flags);
|
|
||||||
if (destlen < enclen + 1)
|
|
||||||
return -1;
|
|
||||||
if (destlen > SIZE_T_CEILING)
|
|
||||||
return -1;
|
|
||||||
if (enclen > INT_MAX)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
memset(dest, 0, enclen);
|
|
||||||
|
|
||||||
/* XXX/Yawning: If this ends up being too slow, this can be sped up
|
|
||||||
* by separating the multiline format case and the normal case, and
|
|
||||||
* processing 48 bytes of input at a time when newlines are desired.
|
|
||||||
*/
|
|
||||||
#define ENCODE_CHAR(ch) \
|
|
||||||
STMT_BEGIN \
|
|
||||||
*d++ = ch; \
|
|
||||||
if (flags & BASE64_ENCODE_MULTILINE) { \
|
|
||||||
if (++linelen % BASE64_OPENSSL_LINELEN == 0) { \
|
|
||||||
linelen = 0; \
|
|
||||||
*d++ = '\n'; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
STMT_END
|
|
||||||
|
|
||||||
#define ENCODE_N(idx) \
|
|
||||||
ENCODE_CHAR(base64_encode_table[(n >> ((3 - idx) * 6)) & 0x3f])
|
|
||||||
|
|
||||||
#define ENCODE_PAD() ENCODE_CHAR('=')
|
|
||||||
|
|
||||||
/* Iterate over all the bytes in src. Each one will add 8 bits to the
|
|
||||||
* value we're encoding. Accumulate bits in <b>n</b>, and whenever we
|
|
||||||
* have 24 bits, batch them into 4 bytes and flush those bytes to dest.
|
|
||||||
*/
|
|
||||||
for ( ; usrc < eous; ++usrc) {
|
|
||||||
n = (n << 8) | *usrc;
|
|
||||||
if ((++n_idx) == 3) {
|
|
||||||
ENCODE_N(0);
|
|
||||||
ENCODE_N(1);
|
|
||||||
ENCODE_N(2);
|
|
||||||
ENCODE_N(3);
|
|
||||||
n_idx = 0;
|
|
||||||
n = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (n_idx) {
|
|
||||||
case 0:
|
|
||||||
/* 0 leftover bits, no pading to add. */
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
/* 8 leftover bits, pad to 12 bits, write the 2 6-bit values followed
|
|
||||||
* by 2 padding characters.
|
|
||||||
*/
|
|
||||||
n <<= 4;
|
|
||||||
ENCODE_N(2);
|
|
||||||
ENCODE_N(3);
|
|
||||||
ENCODE_PAD();
|
|
||||||
ENCODE_PAD();
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
/* 16 leftover bits, pad to 18 bits, write the 3 6-bit values followed
|
|
||||||
* by 1 padding character.
|
|
||||||
*/
|
|
||||||
n <<= 2;
|
|
||||||
ENCODE_N(1);
|
|
||||||
ENCODE_N(2);
|
|
||||||
ENCODE_N(3);
|
|
||||||
ENCODE_PAD();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* Something went catastrophically wrong. */
|
|
||||||
tor_fragile_assert();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef ENCODE_N
|
|
||||||
#undef ENCODE_PAD
|
|
||||||
#undef ENCODE_CHAR
|
|
||||||
|
|
||||||
/* Multiline output always includes at least one newline. */
|
|
||||||
if (flags & BASE64_ENCODE_MULTILINE && linelen != 0)
|
|
||||||
*d++ = '\n';
|
|
||||||
|
|
||||||
tor_assert(d - dest == (ptrdiff_t)enclen);
|
|
||||||
|
|
||||||
*d++ = '\0'; /* NUL terminate the output. */
|
|
||||||
|
|
||||||
return (int) enclen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** As base64_encode, but do not add any internal spaces or external padding
|
|
||||||
* to the output stream. */
|
|
||||||
int
|
|
||||||
base64_encode_nopad(char *dest, size_t destlen,
|
|
||||||
const uint8_t *src, size_t srclen)
|
|
||||||
{
|
|
||||||
int n = base64_encode(dest, destlen, (const char*) src, srclen, 0);
|
|
||||||
if (n <= 0)
|
|
||||||
return n;
|
|
||||||
tor_assert((size_t)n < destlen && dest[n] == 0);
|
|
||||||
char *in, *out;
|
|
||||||
in = out = dest;
|
|
||||||
while (*in) {
|
|
||||||
if (*in == '=' || *in == '\n') {
|
|
||||||
++in;
|
|
||||||
} else {
|
|
||||||
*out++ = *in++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*out = 0;
|
|
||||||
|
|
||||||
tor_assert(out - dest <= INT_MAX);
|
|
||||||
|
|
||||||
return (int)(out - dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** As base64_decode, but do not require any padding on the input */
|
|
||||||
int
|
|
||||||
base64_decode_nopad(uint8_t *dest, size_t destlen,
|
|
||||||
const char *src, size_t srclen)
|
|
||||||
{
|
|
||||||
if (srclen > SIZE_T_CEILING - 4)
|
|
||||||
return -1;
|
|
||||||
char *buf = tor_malloc(srclen + 4);
|
|
||||||
memcpy(buf, src, srclen+1);
|
|
||||||
size_t buflen;
|
|
||||||
switch (srclen % 4)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
default:
|
|
||||||
buflen = srclen;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
tor_free(buf);
|
|
||||||
return -1;
|
|
||||||
case 2:
|
|
||||||
memcpy(buf+srclen, "==", 3);
|
|
||||||
buflen = srclen + 2;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
memcpy(buf+srclen, "=", 2);
|
|
||||||
buflen = srclen + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int n = base64_decode((char*)dest, destlen, buf, buflen);
|
|
||||||
tor_free(buf);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef BASE64_OPENSSL_LINELEN
|
|
||||||
|
|
||||||
/** @{ */
|
|
||||||
/** Special values used for the base64_decode_table */
|
|
||||||
#define X 255
|
|
||||||
#define SP 64
|
|
||||||
#define PAD 65
|
|
||||||
/** @} */
|
|
||||||
/** Internal table mapping byte values to what they represent in base64.
|
|
||||||
* Numbers 0..63 are 6-bit integers. SPs are spaces, and should be
|
|
||||||
* skipped. Xs are invalid and must not appear in base64. PAD indicates
|
|
||||||
* end-of-string. */
|
|
||||||
static const uint8_t base64_decode_table[256] = {
|
|
||||||
X, X, X, X, X, X, X, X, X, SP, SP, SP, X, SP, X, X, /* */
|
|
||||||
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
|
||||||
SP, X, X, X, X, X, X, X, X, X, X, 62, X, X, X, 63,
|
|
||||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, X, X, X, PAD, X, X,
|
|
||||||
X, 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, X, X, X, X, X,
|
|
||||||
X, 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, X, X, X, X, X,
|
|
||||||
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
|
||||||
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
|
||||||
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
|
||||||
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
|
||||||
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
|
||||||
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
|
||||||
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
|
||||||
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Base64 decode <b>srclen</b> bytes of data from <b>src</b>. Write
|
|
||||||
* the result into <b>dest</b>, if it will fit within <b>destlen</b>
|
|
||||||
* bytes. Return the number of bytes written on success; -1 if
|
|
||||||
* destlen is too short, or other failure.
|
|
||||||
*
|
|
||||||
* NOTE 1: destlen is checked conservatively, as though srclen contained no
|
|
||||||
* spaces or padding.
|
|
||||||
*
|
|
||||||
* NOTE 2: This implementation does not check for the correct number of
|
|
||||||
* padding "=" characters at the end of the string, and does not check
|
|
||||||
* for internal padding characters.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
base64_decode(char *dest, size_t destlen, const char *src, size_t srclen)
|
|
||||||
{
|
|
||||||
const char *eos = src+srclen;
|
|
||||||
uint32_t n=0;
|
|
||||||
int n_idx=0;
|
|
||||||
char *dest_orig = dest;
|
|
||||||
|
|
||||||
/* Max number of bits == srclen*6.
|
|
||||||
* Number of bytes required to hold all bits == (srclen*6)/8.
|
|
||||||
* Yes, we want to round down: anything that hangs over the end of a
|
|
||||||
* byte is padding. */
|
|
||||||
if (destlen < (srclen*3)/4)
|
|
||||||
return -1;
|
|
||||||
if (destlen > SIZE_T_CEILING)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
memset(dest, 0, destlen);
|
|
||||||
|
|
||||||
/* Iterate over all the bytes in src. Each one will add 0 or 6 bits to the
|
|
||||||
* value we're decoding. Accumulate bits in <b>n</b>, and whenever we have
|
|
||||||
* 24 bits, batch them into 3 bytes and flush those bytes to dest.
|
|
||||||
*/
|
|
||||||
for ( ; src < eos; ++src) {
|
|
||||||
unsigned char c = (unsigned char) *src;
|
|
||||||
uint8_t v = base64_decode_table[c];
|
|
||||||
switch (v) {
|
|
||||||
case X:
|
|
||||||
/* This character isn't allowed in base64. */
|
|
||||||
return -1;
|
|
||||||
case SP:
|
|
||||||
/* This character is whitespace, and has no effect. */
|
|
||||||
continue;
|
|
||||||
case PAD:
|
|
||||||
/* We've hit an = character: the data is over. */
|
|
||||||
goto end_of_loop;
|
|
||||||
default:
|
|
||||||
/* We have an actual 6-bit value. Append it to the bits in n. */
|
|
||||||
n = (n<<6) | v;
|
|
||||||
if ((++n_idx) == 4) {
|
|
||||||
/* We've accumulated 24 bits in n. Flush them. */
|
|
||||||
*dest++ = (n>>16);
|
|
||||||
*dest++ = (n>>8) & 0xff;
|
|
||||||
*dest++ = (n) & 0xff;
|
|
||||||
n_idx = 0;
|
|
||||||
n = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end_of_loop:
|
|
||||||
/* If we have leftover bits, we need to cope. */
|
|
||||||
switch (n_idx) {
|
|
||||||
case 0:
|
|
||||||
default:
|
|
||||||
/* No leftover bits. We win. */
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
/* 6 leftover bits. That's invalid; we can't form a byte out of that. */
|
|
||||||
return -1;
|
|
||||||
case 2:
|
|
||||||
/* 12 leftover bits: The last 4 are padding and the first 8 are data. */
|
|
||||||
*dest++ = n >> 4;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
/* 18 leftover bits: The last 2 are padding and the first 16 are data. */
|
|
||||||
*dest++ = n >> 10;
|
|
||||||
*dest++ = n >> 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
tor_assert((dest-dest_orig) <= (ssize_t)destlen);
|
|
||||||
tor_assert((dest-dest_orig) <= INT_MAX);
|
|
||||||
|
|
||||||
return (int)(dest-dest_orig);
|
|
||||||
}
|
|
||||||
#undef X
|
|
||||||
#undef SP
|
|
||||||
#undef PAD
|
|
||||||
|
|
||||||
/** Base64 encode DIGEST_LINE bytes from <b>digest</b>, remove the trailing =
|
|
||||||
* characters, and store the nul-terminated result in the first
|
|
||||||
* BASE64_DIGEST_LEN+1 bytes of <b>d64</b>. */
|
|
||||||
/* XXXX unify with crypto_format.c code */
|
|
||||||
int
|
|
||||||
digest_to_base64(char *d64, const char *digest)
|
|
||||||
{
|
|
||||||
char buf[256];
|
|
||||||
base64_encode(buf, sizeof(buf), digest, DIGEST_LEN, 0);
|
|
||||||
buf[BASE64_DIGEST_LEN] = '\0';
|
|
||||||
memcpy(d64, buf, BASE64_DIGEST_LEN+1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
|
|
||||||
* trailing newline or = characters), decode it and store the result in the
|
|
||||||
* first DIGEST_LEN bytes at <b>digest</b>. */
|
|
||||||
/* XXXX unify with crypto_format.c code */
|
|
||||||
int
|
|
||||||
digest_from_base64(char *digest, const char *d64)
|
|
||||||
{
|
|
||||||
if (base64_decode(digest, DIGEST_LEN, d64, strlen(d64)) == DIGEST_LEN)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Base64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the
|
|
||||||
* trailing = characters, and store the nul-terminated result in the first
|
|
||||||
* BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>. */
|
|
||||||
/* XXXX unify with crypto_format.c code */
|
|
||||||
int
|
|
||||||
digest256_to_base64(char *d64, const char *digest)
|
|
||||||
{
|
|
||||||
char buf[256];
|
|
||||||
base64_encode(buf, sizeof(buf), digest, DIGEST256_LEN, 0);
|
|
||||||
buf[BASE64_DIGEST256_LEN] = '\0';
|
|
||||||
memcpy(d64, buf, BASE64_DIGEST256_LEN+1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
|
|
||||||
* trailing newline or = characters), decode it and store the result in the
|
|
||||||
* first DIGEST256_LEN bytes at <b>digest</b>. */
|
|
||||||
/* XXXX unify with crypto_format.c code */
|
|
||||||
int
|
|
||||||
digest256_from_base64(char *digest, const char *d64)
|
|
||||||
{
|
|
||||||
if (base64_decode(digest, DIGEST256_LEN, d64, strlen(d64)) == DIGEST256_LEN)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Implements base32 encoding as in RFC 4648. Limitation: Requires
|
|
||||||
* that srclen*8 is a multiple of 5.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
base32_encode(char *dest, size_t destlen, const char *src, size_t srclen)
|
|
||||||
{
|
|
||||||
unsigned int i, v, u;
|
|
||||||
size_t nbits = srclen * 8, bit;
|
|
||||||
|
|
||||||
tor_assert(srclen < SIZE_T_CEILING/8);
|
|
||||||
tor_assert((nbits%5) == 0); /* We need an even multiple of 5 bits. */
|
|
||||||
tor_assert((nbits/5)+1 <= destlen); /* We need enough space. */
|
|
||||||
tor_assert(destlen < SIZE_T_CEILING);
|
|
||||||
|
|
||||||
for (i=0,bit=0; bit < nbits; ++i, bit+=5) {
|
|
||||||
/* set v to the 16-bit value starting at src[bits/8], 0-padded. */
|
|
||||||
v = ((uint8_t)src[bit/8]) << 8;
|
|
||||||
if (bit+5<nbits) v += (uint8_t)src[(bit/8)+1];
|
|
||||||
/* set u to the 5-bit value at the bit'th bit of src. */
|
|
||||||
u = (v >> (11-(bit%8))) & 0x1F;
|
|
||||||
dest[i] = BASE32_CHARS[u];
|
|
||||||
}
|
|
||||||
dest[i] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Implements base32 decoding as in RFC 4648. Limitation: Requires
|
|
||||||
* that srclen*5 is a multiple of 8. Returns 0 if successful, -1 otherwise.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
base32_decode(char *dest, size_t destlen, const char *src, size_t srclen)
|
|
||||||
{
|
|
||||||
/* XXXX we might want to rewrite this along the lines of base64_decode, if
|
|
||||||
* it ever shows up in the profile. */
|
|
||||||
unsigned int i;
|
|
||||||
size_t nbits, j, bit;
|
|
||||||
char *tmp;
|
|
||||||
nbits = srclen * 5;
|
|
||||||
|
|
||||||
tor_assert(srclen < SIZE_T_CEILING / 5);
|
|
||||||
tor_assert((nbits%8) == 0); /* We need an even multiple of 8 bits. */
|
|
||||||
tor_assert((nbits/8) <= destlen); /* We need enough space. */
|
|
||||||
tor_assert(destlen < SIZE_T_CEILING);
|
|
||||||
|
|
||||||
memset(dest, 0, destlen);
|
|
||||||
|
|
||||||
/* Convert base32 encoded chars to the 5-bit values that they represent. */
|
|
||||||
tmp = tor_malloc_zero(srclen);
|
|
||||||
for (j = 0; j < srclen; ++j) {
|
|
||||||
if (src[j] > 0x60 && src[j] < 0x7B) tmp[j] = src[j] - 0x61;
|
|
||||||
else if (src[j] > 0x31 && src[j] < 0x38) tmp[j] = src[j] - 0x18;
|
|
||||||
else if (src[j] > 0x40 && src[j] < 0x5B) tmp[j] = src[j] - 0x41;
|
|
||||||
else {
|
|
||||||
log_warn(LD_BUG, "illegal character in base32 encoded string");
|
|
||||||
tor_free(tmp);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Assemble result byte-wise by applying five possible cases. */
|
|
||||||
for (i = 0, bit = 0; bit < nbits; ++i, bit += 8) {
|
|
||||||
switch (bit % 40) {
|
|
||||||
case 0:
|
|
||||||
dest[i] = (((uint8_t)tmp[(bit/5)]) << 3) +
|
|
||||||
(((uint8_t)tmp[(bit/5)+1]) >> 2);
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
dest[i] = (((uint8_t)tmp[(bit/5)]) << 6) +
|
|
||||||
(((uint8_t)tmp[(bit/5)+1]) << 1) +
|
|
||||||
(((uint8_t)tmp[(bit/5)+2]) >> 4);
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
dest[i] = (((uint8_t)tmp[(bit/5)]) << 4) +
|
|
||||||
(((uint8_t)tmp[(bit/5)+1]) >> 1);
|
|
||||||
break;
|
|
||||||
case 24:
|
|
||||||
dest[i] = (((uint8_t)tmp[(bit/5)]) << 7) +
|
|
||||||
(((uint8_t)tmp[(bit/5)+1]) << 2) +
|
|
||||||
(((uint8_t)tmp[(bit/5)+2]) >> 3);
|
|
||||||
break;
|
|
||||||
case 32:
|
|
||||||
dest[i] = (((uint8_t)tmp[(bit/5)]) << 5) +
|
|
||||||
((uint8_t)tmp[(bit/5)+1]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memwipe(tmp, 0, srclen);
|
|
||||||
tor_free(tmp);
|
|
||||||
tmp = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the <b>sz</b> bytes of data stored at <b>mem</b>, setting them to
|
* Destroy the <b>sz</b> bytes of data stored at <b>mem</b>, setting them to
|
||||||
* the value <b>byte</b>.
|
* the value <b>byte</b>.
|
||||||
|
@ -278,26 +278,6 @@ struct smartlist_t;
|
|||||||
void *smartlist_choose(const struct smartlist_t *sl);
|
void *smartlist_choose(const struct smartlist_t *sl);
|
||||||
void smartlist_shuffle(struct smartlist_t *sl);
|
void smartlist_shuffle(struct smartlist_t *sl);
|
||||||
|
|
||||||
#define BASE64_ENCODE_MULTILINE 1
|
|
||||||
size_t base64_encode_size(size_t srclen, int flags);
|
|
||||||
int base64_encode(char *dest, size_t destlen, const char *src, size_t srclen,
|
|
||||||
int flags);
|
|
||||||
int base64_decode(char *dest, size_t destlen, const char *src, size_t srclen);
|
|
||||||
int base64_encode_nopad(char *dest, size_t destlen,
|
|
||||||
const uint8_t *src, size_t srclen);
|
|
||||||
int base64_decode_nopad(uint8_t *dest, size_t destlen,
|
|
||||||
const char *src, size_t srclen);
|
|
||||||
|
|
||||||
/** Characters that can appear (case-insensitively) in a base32 encoding. */
|
|
||||||
#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567"
|
|
||||||
void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen);
|
|
||||||
int base32_decode(char *dest, size_t destlen, const char *src, size_t srclen);
|
|
||||||
|
|
||||||
int digest_to_base64(char *d64, const char *digest);
|
|
||||||
int digest_from_base64(char *digest, const char *d64);
|
|
||||||
int digest256_to_base64(char *d64, const char *digest);
|
|
||||||
int digest256_from_base64(char *digest, const char *d64);
|
|
||||||
|
|
||||||
/** OpenSSL-based utility functions. */
|
/** OpenSSL-based utility functions. */
|
||||||
void memwipe(void *mem, uint8_t byte, size_t sz);
|
void memwipe(void *mem, uint8_t byte, size_t sz);
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "container.h"
|
#include "container.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
#include "crypto_curve25519.h"
|
#include "crypto_curve25519.h"
|
||||||
|
#include "crypto_format.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "torlog.h"
|
#include "torlog.h"
|
||||||
|
|
||||||
@ -160,106 +161,6 @@ curve25519_keypair_generate(curve25519_keypair_t *keypair_out,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Write the <b>datalen</b> bytes from <b>data</b> to the file named
|
|
||||||
* <b>fname</b> in the tagged-data format. This format contains a
|
|
||||||
* 32-byte header, followed by the data itself. The header is the
|
|
||||||
* NUL-padded string "== <b>typestring</b>: <b>tag</b> ==". The length
|
|
||||||
* of <b>typestring</b> and <b>tag</b> must therefore be no more than
|
|
||||||
* 24.
|
|
||||||
**/
|
|
||||||
int
|
|
||||||
crypto_write_tagged_contents_to_file(const char *fname,
|
|
||||||
const char *typestring,
|
|
||||||
const char *tag,
|
|
||||||
const uint8_t *data,
|
|
||||||
size_t datalen)
|
|
||||||
{
|
|
||||||
char header[32];
|
|
||||||
smartlist_t *chunks = smartlist_new();
|
|
||||||
sized_chunk_t ch0, ch1;
|
|
||||||
int r = -1;
|
|
||||||
|
|
||||||
memset(header, 0, sizeof(header));
|
|
||||||
if (tor_snprintf(header, sizeof(header),
|
|
||||||
"== %s: %s ==", typestring, tag) < 0)
|
|
||||||
goto end;
|
|
||||||
ch0.bytes = header;
|
|
||||||
ch0.len = 32;
|
|
||||||
ch1.bytes = (const char*) data;
|
|
||||||
ch1.len = datalen;
|
|
||||||
smartlist_add(chunks, &ch0);
|
|
||||||
smartlist_add(chunks, &ch1);
|
|
||||||
|
|
||||||
r = write_chunks_to_file(fname, chunks, 1, 0);
|
|
||||||
|
|
||||||
end:
|
|
||||||
smartlist_free(chunks);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Read a tagged-data file from <b>fname</b> into the
|
|
||||||
* <b>data_out_len</b>-byte buffer in <b>data_out</b>. Check that the
|
|
||||||
* typestring matches <b>typestring</b>; store the tag into a newly allocated
|
|
||||||
* string in <b>tag_out</b>. Return -1 on failure, and the number of bytes of
|
|
||||||
* data on success. Preserves the errno from reading the file. */
|
|
||||||
ssize_t
|
|
||||||
crypto_read_tagged_contents_from_file(const char *fname,
|
|
||||||
const char *typestring,
|
|
||||||
char **tag_out,
|
|
||||||
uint8_t *data_out,
|
|
||||||
ssize_t data_out_len)
|
|
||||||
{
|
|
||||||
char prefix[33];
|
|
||||||
char *content = NULL;
|
|
||||||
struct stat st;
|
|
||||||
ssize_t r = -1;
|
|
||||||
size_t st_size = 0;
|
|
||||||
int saved_errno = 0;
|
|
||||||
|
|
||||||
*tag_out = NULL;
|
|
||||||
st.st_size = 0;
|
|
||||||
content = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
|
|
||||||
if (! content) {
|
|
||||||
saved_errno = errno;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
if (st.st_size < 32 || st.st_size > 32 + data_out_len) {
|
|
||||||
saved_errno = EINVAL;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
st_size = (size_t)st.st_size;
|
|
||||||
|
|
||||||
memcpy(prefix, content, 32);
|
|
||||||
prefix[32] = 0;
|
|
||||||
/* Check type, extract tag. */
|
|
||||||
if (strcmpstart(prefix, "== ") || strcmpend(prefix, " ==") ||
|
|
||||||
! tor_mem_is_zero(prefix+strlen(prefix), 32-strlen(prefix))) {
|
|
||||||
saved_errno = EINVAL;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmpstart(prefix+3, typestring) ||
|
|
||||||
3+strlen(typestring) >= 32 ||
|
|
||||||
strcmpstart(prefix+3+strlen(typestring), ": ")) {
|
|
||||||
saved_errno = EINVAL;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
*tag_out = tor_strndup(prefix+5+strlen(typestring),
|
|
||||||
strlen(prefix)-8-strlen(typestring));
|
|
||||||
|
|
||||||
memcpy(data_out, content+32, st_size-32);
|
|
||||||
r = st_size - 32;
|
|
||||||
|
|
||||||
end:
|
|
||||||
if (content)
|
|
||||||
memwipe(content, 0, st_size);
|
|
||||||
tor_free(content);
|
|
||||||
if (saved_errno)
|
|
||||||
errno = saved_errno;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** DOCDOC */
|
/** DOCDOC */
|
||||||
int
|
int
|
||||||
curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair,
|
curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair,
|
||||||
|
@ -72,18 +72,6 @@ int curve25519_public_from_base64(curve25519_public_key_t *pkey,
|
|||||||
int curve25519_public_to_base64(char *output,
|
int curve25519_public_to_base64(char *output,
|
||||||
const curve25519_public_key_t *pkey);
|
const curve25519_public_key_t *pkey);
|
||||||
|
|
||||||
int crypto_write_tagged_contents_to_file(const char *fname,
|
|
||||||
const char *typestring,
|
|
||||||
const char *tag,
|
|
||||||
const uint8_t *data,
|
|
||||||
size_t datalen);
|
|
||||||
|
|
||||||
ssize_t crypto_read_tagged_contents_from_file(const char *fname,
|
|
||||||
const char *typestring,
|
|
||||||
char **tag_out,
|
|
||||||
uint8_t *data_out,
|
|
||||||
ssize_t data_out_len);
|
|
||||||
|
|
||||||
void curve25519_set_impl_params(int use_ed);
|
void curve25519_set_impl_params(int use_ed);
|
||||||
void curve25519_init(void);
|
void curve25519_init(void);
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "crypto_curve25519.h"
|
#include "crypto_curve25519.h"
|
||||||
#include "crypto_ed25519.h"
|
#include "crypto_ed25519.h"
|
||||||
|
#include "crypto_format.h"
|
||||||
#include "torlog.h"
|
#include "torlog.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
@ -88,21 +88,6 @@ int ed25519_public_blind(ed25519_public_key_t *out,
|
|||||||
const ed25519_public_key_t *inp,
|
const ed25519_public_key_t *inp,
|
||||||
const uint8_t *param);
|
const uint8_t *param);
|
||||||
|
|
||||||
/* XXXX move these to crypto_format.h */
|
|
||||||
#define ED25519_BASE64_LEN 43
|
|
||||||
int ed25519_public_from_base64(ed25519_public_key_t *pkey,
|
|
||||||
const char *input);
|
|
||||||
int ed25519_public_to_base64(char *output,
|
|
||||||
const ed25519_public_key_t *pkey);
|
|
||||||
|
|
||||||
/* XXXX move these to crypto_format.h */
|
|
||||||
#define ED25519_SIG_BASE64_LEN 86
|
|
||||||
|
|
||||||
int ed25519_signature_from_base64(ed25519_signature_t *sig,
|
|
||||||
const char *input);
|
|
||||||
int ed25519_signature_to_base64(char *output,
|
|
||||||
const ed25519_signature_t *sig);
|
|
||||||
|
|
||||||
/* XXXX read encrypted, write encrypted. */
|
/* XXXX read encrypted, write encrypted. */
|
||||||
|
|
||||||
int ed25519_seckey_write_to_file(const ed25519_secret_key_t *seckey,
|
int ed25519_seckey_write_to_file(const ed25519_secret_key_t *seckey,
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
/* Copyright (c) 2012-2015, The Tor Project, Inc. */
|
/* Copyright (c) 2001, Matej Pfajfar.
|
||||||
|
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||||
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||||
|
* Copyright (c) 2007-2015, The Tor Project, Inc. */
|
||||||
/* See LICENSE for licensing information */
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
/* Formatting and parsing code for crypto-related data structures. */
|
/* Formatting and parsing code for crypto-related data structures. */
|
||||||
@ -7,12 +10,115 @@
|
|||||||
#ifdef HAVE_SYS_STAT_H
|
#ifdef HAVE_SYS_STAT_H
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include "container.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
#include "crypto_curve25519.h"
|
#include "crypto_curve25519.h"
|
||||||
#include "crypto_ed25519.h"
|
#include "crypto_ed25519.h"
|
||||||
|
#include "crypto_format.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "util_format.h"
|
||||||
#include "torlog.h"
|
#include "torlog.h"
|
||||||
|
|
||||||
|
/** Write the <b>datalen</b> bytes from <b>data</b> to the file named
|
||||||
|
* <b>fname</b> in the tagged-data format. This format contains a
|
||||||
|
* 32-byte header, followed by the data itself. The header is the
|
||||||
|
* NUL-padded string "== <b>typestring</b>: <b>tag</b> ==". The length
|
||||||
|
* of <b>typestring</b> and <b>tag</b> must therefore be no more than
|
||||||
|
* 24.
|
||||||
|
**/
|
||||||
|
int
|
||||||
|
crypto_write_tagged_contents_to_file(const char *fname,
|
||||||
|
const char *typestring,
|
||||||
|
const char *tag,
|
||||||
|
const uint8_t *data,
|
||||||
|
size_t datalen)
|
||||||
|
{
|
||||||
|
char header[32];
|
||||||
|
smartlist_t *chunks = smartlist_new();
|
||||||
|
sized_chunk_t ch0, ch1;
|
||||||
|
int r = -1;
|
||||||
|
|
||||||
|
memset(header, 0, sizeof(header));
|
||||||
|
if (tor_snprintf(header, sizeof(header),
|
||||||
|
"== %s: %s ==", typestring, tag) < 0)
|
||||||
|
goto end;
|
||||||
|
ch0.bytes = header;
|
||||||
|
ch0.len = 32;
|
||||||
|
ch1.bytes = (const char*) data;
|
||||||
|
ch1.len = datalen;
|
||||||
|
smartlist_add(chunks, &ch0);
|
||||||
|
smartlist_add(chunks, &ch1);
|
||||||
|
|
||||||
|
r = write_chunks_to_file(fname, chunks, 1, 0);
|
||||||
|
|
||||||
|
end:
|
||||||
|
smartlist_free(chunks);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read a tagged-data file from <b>fname</b> into the
|
||||||
|
* <b>data_out_len</b>-byte buffer in <b>data_out</b>. Check that the
|
||||||
|
* typestring matches <b>typestring</b>; store the tag into a newly allocated
|
||||||
|
* string in <b>tag_out</b>. Return -1 on failure, and the number of bytes of
|
||||||
|
* data on success. Preserves the errno from reading the file. */
|
||||||
|
ssize_t
|
||||||
|
crypto_read_tagged_contents_from_file(const char *fname,
|
||||||
|
const char *typestring,
|
||||||
|
char **tag_out,
|
||||||
|
uint8_t *data_out,
|
||||||
|
ssize_t data_out_len)
|
||||||
|
{
|
||||||
|
char prefix[33];
|
||||||
|
char *content = NULL;
|
||||||
|
struct stat st;
|
||||||
|
ssize_t r = -1;
|
||||||
|
size_t st_size = 0;
|
||||||
|
int saved_errno = 0;
|
||||||
|
|
||||||
|
*tag_out = NULL;
|
||||||
|
st.st_size = 0;
|
||||||
|
content = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
|
||||||
|
if (! content) {
|
||||||
|
saved_errno = errno;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (st.st_size < 32 || st.st_size > 32 + data_out_len) {
|
||||||
|
saved_errno = EINVAL;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
st_size = (size_t)st.st_size;
|
||||||
|
|
||||||
|
memcpy(prefix, content, 32);
|
||||||
|
prefix[32] = 0;
|
||||||
|
/* Check type, extract tag. */
|
||||||
|
if (strcmpstart(prefix, "== ") || strcmpend(prefix, " ==") ||
|
||||||
|
! tor_mem_is_zero(prefix+strlen(prefix), 32-strlen(prefix))) {
|
||||||
|
saved_errno = EINVAL;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmpstart(prefix+3, typestring) ||
|
||||||
|
3+strlen(typestring) >= 32 ||
|
||||||
|
strcmpstart(prefix+3+strlen(typestring), ": ")) {
|
||||||
|
saved_errno = EINVAL;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
*tag_out = tor_strndup(prefix+5+strlen(typestring),
|
||||||
|
strlen(prefix)-8-strlen(typestring));
|
||||||
|
|
||||||
|
memcpy(data_out, content+32, st_size-32);
|
||||||
|
r = st_size - 32;
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (content)
|
||||||
|
memwipe(content, 0, st_size);
|
||||||
|
tor_free(content);
|
||||||
|
if (saved_errno)
|
||||||
|
errno = saved_errno;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
curve25519_public_to_base64(char *output,
|
curve25519_public_to_base64(char *output,
|
||||||
const curve25519_public_key_t *pkey)
|
const curve25519_public_key_t *pkey)
|
||||||
@ -104,3 +210,57 @@ ed25519_signature_from_base64(ed25519_signature_t *sig,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Base64 encode DIGEST_LINE bytes from <b>digest</b>, remove the trailing =
|
||||||
|
* characters, and store the nul-terminated result in the first
|
||||||
|
* BASE64_DIGEST_LEN+1 bytes of <b>d64</b>. */
|
||||||
|
/* XXXX unify with crypto_format.c code */
|
||||||
|
int
|
||||||
|
digest_to_base64(char *d64, const char *digest)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
base64_encode(buf, sizeof(buf), digest, DIGEST_LEN, 0);
|
||||||
|
buf[BASE64_DIGEST_LEN] = '\0';
|
||||||
|
memcpy(d64, buf, BASE64_DIGEST_LEN+1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
|
||||||
|
* trailing newline or = characters), decode it and store the result in the
|
||||||
|
* first DIGEST_LEN bytes at <b>digest</b>. */
|
||||||
|
/* XXXX unify with crypto_format.c code */
|
||||||
|
int
|
||||||
|
digest_from_base64(char *digest, const char *d64)
|
||||||
|
{
|
||||||
|
if (base64_decode(digest, DIGEST_LEN, d64, strlen(d64)) == DIGEST_LEN)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Base64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the
|
||||||
|
* trailing = characters, and store the nul-terminated result in the first
|
||||||
|
* BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>. */
|
||||||
|
/* XXXX unify with crypto_format.c code */
|
||||||
|
int
|
||||||
|
digest256_to_base64(char *d64, const char *digest)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
base64_encode(buf, sizeof(buf), digest, DIGEST256_LEN, 0);
|
||||||
|
buf[BASE64_DIGEST256_LEN] = '\0';
|
||||||
|
memcpy(d64, buf, BASE64_DIGEST256_LEN+1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
|
||||||
|
* trailing newline or = characters), decode it and store the result in the
|
||||||
|
* first DIGEST256_LEN bytes at <b>digest</b>. */
|
||||||
|
/* XXXX unify with crypto_format.c code */
|
||||||
|
int
|
||||||
|
digest256_from_base64(char *digest, const char *d64)
|
||||||
|
{
|
||||||
|
if (base64_decode(digest, DIGEST256_LEN, d64, strlen(d64)) == DIGEST256_LEN)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
46
src/common/crypto_format.h
Normal file
46
src/common/crypto_format.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/* Copyright (c) 2001, Matej Pfajfar.
|
||||||
|
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||||
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||||
|
* Copyright (c) 2007-2015, The Tor Project, Inc. */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
#ifndef TOR_CRYPTO_FORMAT_H
|
||||||
|
#define TOR_CRYPTO_FORMAT_H
|
||||||
|
|
||||||
|
#include "testsupport.h"
|
||||||
|
#include "torint.h"
|
||||||
|
#include "crypto_ed25519.h"
|
||||||
|
|
||||||
|
int crypto_write_tagged_contents_to_file(const char *fname,
|
||||||
|
const char *typestring,
|
||||||
|
const char *tag,
|
||||||
|
const uint8_t *data,
|
||||||
|
size_t datalen);
|
||||||
|
|
||||||
|
ssize_t crypto_read_tagged_contents_from_file(const char *fname,
|
||||||
|
const char *typestring,
|
||||||
|
char **tag_out,
|
||||||
|
uint8_t *data_out,
|
||||||
|
ssize_t data_out_len);
|
||||||
|
|
||||||
|
#define ED25519_BASE64_LEN 43
|
||||||
|
int ed25519_public_from_base64(ed25519_public_key_t *pkey,
|
||||||
|
const char *input);
|
||||||
|
int ed25519_public_to_base64(char *output,
|
||||||
|
const ed25519_public_key_t *pkey);
|
||||||
|
|
||||||
|
/* XXXX move these to crypto_format.h */
|
||||||
|
#define ED25519_SIG_BASE64_LEN 86
|
||||||
|
|
||||||
|
int ed25519_signature_from_base64(ed25519_signature_t *sig,
|
||||||
|
const char *input);
|
||||||
|
int ed25519_signature_to_base64(char *output,
|
||||||
|
const ed25519_signature_t *sig);
|
||||||
|
|
||||||
|
int digest_to_base64(char *d64, const char *digest);
|
||||||
|
int digest_from_base64(char *digest, const char *d64);
|
||||||
|
int digest256_to_base64(char *d64, const char *digest);
|
||||||
|
int digest256_from_base64(char *digest, const char *d64);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -68,6 +68,7 @@ LIBOR_A_SOURCES = \
|
|||||||
src/common/log.c \
|
src/common/log.c \
|
||||||
src/common/memarea.c \
|
src/common/memarea.c \
|
||||||
src/common/util.c \
|
src/common/util.c \
|
||||||
|
src/common/util_format.c \
|
||||||
src/common/util_process.c \
|
src/common/util_process.c \
|
||||||
src/common/sandbox.c \
|
src/common/sandbox.c \
|
||||||
src/common/workqueue.c \
|
src/common/workqueue.c \
|
||||||
@ -122,6 +123,7 @@ COMMONHEADERS = \
|
|||||||
src/common/crypto.h \
|
src/common/crypto.h \
|
||||||
src/common/crypto_curve25519.h \
|
src/common/crypto_curve25519.h \
|
||||||
src/common/crypto_ed25519.h \
|
src/common/crypto_ed25519.h \
|
||||||
|
src/common/crypto_format.h \
|
||||||
src/common/crypto_pwbox.h \
|
src/common/crypto_pwbox.h \
|
||||||
src/common/crypto_s2k.h \
|
src/common/crypto_s2k.h \
|
||||||
src/common/di_ops.h \
|
src/common/di_ops.h \
|
||||||
@ -135,6 +137,7 @@ COMMONHEADERS = \
|
|||||||
src/common/torlog.h \
|
src/common/torlog.h \
|
||||||
src/common/tortls.h \
|
src/common/tortls.h \
|
||||||
src/common/util.h \
|
src/common/util.h \
|
||||||
|
src/common/util_format.h \
|
||||||
src/common/util_process.h \
|
src/common/util_process.h \
|
||||||
src/common/workqueue.h
|
src/common/workqueue.h
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "sandbox.h"
|
#include "sandbox.h"
|
||||||
#include "backtrace.h"
|
#include "backtrace.h"
|
||||||
#include "util_process.h"
|
#include "util_process.h"
|
||||||
|
#include "util_format.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
@ -1211,91 +1212,6 @@ tor_parse_uint64(const char *s, int base, uint64_t min,
|
|||||||
CHECK_STRTOX_RESULT();
|
CHECK_STRTOX_RESULT();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Encode the <b>srclen</b> bytes at <b>src</b> in a NUL-terminated,
|
|
||||||
* uppercase hexadecimal string; store it in the <b>destlen</b>-byte buffer
|
|
||||||
* <b>dest</b>.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
base16_encode(char *dest, size_t destlen, const char *src, size_t srclen)
|
|
||||||
{
|
|
||||||
const char *end;
|
|
||||||
char *cp;
|
|
||||||
|
|
||||||
tor_assert(destlen >= srclen*2+1);
|
|
||||||
tor_assert(destlen < SIZE_T_CEILING);
|
|
||||||
|
|
||||||
cp = dest;
|
|
||||||
end = src+srclen;
|
|
||||||
while (src<end) {
|
|
||||||
*cp++ = "0123456789ABCDEF"[ (*(const uint8_t*)src) >> 4 ];
|
|
||||||
*cp++ = "0123456789ABCDEF"[ (*(const uint8_t*)src) & 0xf ];
|
|
||||||
++src;
|
|
||||||
}
|
|
||||||
*cp = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Helper: given a hex digit, return its value, or -1 if it isn't hex. */
|
|
||||||
static INLINE int
|
|
||||||
hex_decode_digit_(char c)
|
|
||||||
{
|
|
||||||
switch (c) {
|
|
||||||
case '0': return 0;
|
|
||||||
case '1': return 1;
|
|
||||||
case '2': return 2;
|
|
||||||
case '3': return 3;
|
|
||||||
case '4': return 4;
|
|
||||||
case '5': return 5;
|
|
||||||
case '6': return 6;
|
|
||||||
case '7': return 7;
|
|
||||||
case '8': return 8;
|
|
||||||
case '9': return 9;
|
|
||||||
case 'A': case 'a': return 10;
|
|
||||||
case 'B': case 'b': return 11;
|
|
||||||
case 'C': case 'c': return 12;
|
|
||||||
case 'D': case 'd': return 13;
|
|
||||||
case 'E': case 'e': return 14;
|
|
||||||
case 'F': case 'f': return 15;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Helper: given a hex digit, return its value, or -1 if it isn't hex. */
|
|
||||||
int
|
|
||||||
hex_decode_digit(char c)
|
|
||||||
{
|
|
||||||
return hex_decode_digit_(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Given a hexadecimal string of <b>srclen</b> bytes in <b>src</b>, decode it
|
|
||||||
* and store the result in the <b>destlen</b>-byte buffer at <b>dest</b>.
|
|
||||||
* Return 0 on success, -1 on failure. */
|
|
||||||
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;
|
|
||||||
|
|
||||||
memset(dest, 0, destlen);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Allocate and return a new string representing the contents of <b>s</b>,
|
/** Allocate and return a new string representing the contents of <b>s</b>,
|
||||||
* surrounded by quotes and using standard C escapes.
|
* surrounded by quotes and using standard C escapes.
|
||||||
*
|
*
|
||||||
|
@ -264,10 +264,6 @@ void smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern,
|
|||||||
va_list args)
|
va_list args)
|
||||||
CHECK_PRINTF(2, 0);
|
CHECK_PRINTF(2, 0);
|
||||||
|
|
||||||
int hex_decode_digit(char c);
|
|
||||||
void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen);
|
|
||||||
int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen);
|
|
||||||
|
|
||||||
/* Time helpers */
|
/* Time helpers */
|
||||||
long tv_udiff(const struct timeval *start, const struct timeval *end);
|
long tv_udiff(const struct timeval *start, const struct timeval *end);
|
||||||
long tv_mdiff(const struct timeval *start, const struct timeval *end);
|
long tv_mdiff(const struct timeval *start, const struct timeval *end);
|
||||||
|
528
src/common/util_format.c
Normal file
528
src/common/util_format.c
Normal file
@ -0,0 +1,528 @@
|
|||||||
|
/* Copyright (c) 2001, Matej Pfajfar.
|
||||||
|
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||||
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||||
|
* Copyright (c) 2007-2015, The Tor Project, Inc. */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
#include "orconfig.h"
|
||||||
|
#include "torlog.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "util_format.h"
|
||||||
|
#include "torint.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/** Implements base32 encoding as in RFC 4648. Limitation: Requires
|
||||||
|
* that srclen*8 is a multiple of 5.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
base32_encode(char *dest, size_t destlen, const char *src, size_t srclen)
|
||||||
|
{
|
||||||
|
unsigned int i, v, u;
|
||||||
|
size_t nbits = srclen * 8, bit;
|
||||||
|
|
||||||
|
tor_assert(srclen < SIZE_T_CEILING/8);
|
||||||
|
tor_assert((nbits%5) == 0); /* We need an even multiple of 5 bits. */
|
||||||
|
tor_assert((nbits/5)+1 <= destlen); /* We need enough space. */
|
||||||
|
tor_assert(destlen < SIZE_T_CEILING);
|
||||||
|
|
||||||
|
for (i=0,bit=0; bit < nbits; ++i, bit+=5) {
|
||||||
|
/* set v to the 16-bit value starting at src[bits/8], 0-padded. */
|
||||||
|
v = ((uint8_t)src[bit/8]) << 8;
|
||||||
|
if (bit+5<nbits) v += (uint8_t)src[(bit/8)+1];
|
||||||
|
/* set u to the 5-bit value at the bit'th bit of src. */
|
||||||
|
u = (v >> (11-(bit%8))) & 0x1F;
|
||||||
|
dest[i] = BASE32_CHARS[u];
|
||||||
|
}
|
||||||
|
dest[i] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Implements base32 decoding as in RFC 4648. Limitation: Requires
|
||||||
|
* that srclen*5 is a multiple of 8. Returns 0 if successful, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
base32_decode(char *dest, size_t destlen, const char *src, size_t srclen)
|
||||||
|
{
|
||||||
|
/* XXXX we might want to rewrite this along the lines of base64_decode, if
|
||||||
|
* it ever shows up in the profile. */
|
||||||
|
unsigned int i;
|
||||||
|
size_t nbits, j, bit;
|
||||||
|
char *tmp;
|
||||||
|
nbits = srclen * 5;
|
||||||
|
|
||||||
|
tor_assert(srclen < SIZE_T_CEILING / 5);
|
||||||
|
tor_assert((nbits%8) == 0); /* We need an even multiple of 8 bits. */
|
||||||
|
tor_assert((nbits/8) <= destlen); /* We need enough space. */
|
||||||
|
tor_assert(destlen < SIZE_T_CEILING);
|
||||||
|
|
||||||
|
memset(dest, 0, destlen);
|
||||||
|
|
||||||
|
/* Convert base32 encoded chars to the 5-bit values that they represent. */
|
||||||
|
tmp = tor_malloc_zero(srclen);
|
||||||
|
for (j = 0; j < srclen; ++j) {
|
||||||
|
if (src[j] > 0x60 && src[j] < 0x7B) tmp[j] = src[j] - 0x61;
|
||||||
|
else if (src[j] > 0x31 && src[j] < 0x38) tmp[j] = src[j] - 0x18;
|
||||||
|
else if (src[j] > 0x40 && src[j] < 0x5B) tmp[j] = src[j] - 0x41;
|
||||||
|
else {
|
||||||
|
log_warn(LD_BUG, "illegal character in base32 encoded string");
|
||||||
|
tor_free(tmp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assemble result byte-wise by applying five possible cases. */
|
||||||
|
for (i = 0, bit = 0; bit < nbits; ++i, bit += 8) {
|
||||||
|
switch (bit % 40) {
|
||||||
|
case 0:
|
||||||
|
dest[i] = (((uint8_t)tmp[(bit/5)]) << 3) +
|
||||||
|
(((uint8_t)tmp[(bit/5)+1]) >> 2);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
dest[i] = (((uint8_t)tmp[(bit/5)]) << 6) +
|
||||||
|
(((uint8_t)tmp[(bit/5)+1]) << 1) +
|
||||||
|
(((uint8_t)tmp[(bit/5)+2]) >> 4);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
dest[i] = (((uint8_t)tmp[(bit/5)]) << 4) +
|
||||||
|
(((uint8_t)tmp[(bit/5)+1]) >> 1);
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
dest[i] = (((uint8_t)tmp[(bit/5)]) << 7) +
|
||||||
|
(((uint8_t)tmp[(bit/5)+1]) << 2) +
|
||||||
|
(((uint8_t)tmp[(bit/5)+2]) >> 3);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
dest[i] = (((uint8_t)tmp[(bit/5)]) << 5) +
|
||||||
|
((uint8_t)tmp[(bit/5)+1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(tmp, 0, srclen); /* on the heap, this should be safe */
|
||||||
|
tor_free(tmp);
|
||||||
|
tmp = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BASE64_OPENSSL_LINELEN 64
|
||||||
|
|
||||||
|
/** Return the Base64 encoded size of <b>srclen</b> bytes of data in
|
||||||
|
* bytes.
|
||||||
|
*
|
||||||
|
* If <b>flags</b>&BASE64_ENCODE_MULTILINE is true, return the size
|
||||||
|
* of the encoded output as multiline output (64 character, `\n' terminated
|
||||||
|
* lines).
|
||||||
|
*/
|
||||||
|
size_t
|
||||||
|
base64_encode_size(size_t srclen, int flags)
|
||||||
|
{
|
||||||
|
size_t enclen;
|
||||||
|
tor_assert(srclen < INT_MAX);
|
||||||
|
|
||||||
|
if (srclen == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
enclen = ((srclen - 1) / 3) * 4 + 4;
|
||||||
|
if (flags & BASE64_ENCODE_MULTILINE) {
|
||||||
|
size_t remainder = enclen % BASE64_OPENSSL_LINELEN;
|
||||||
|
enclen += enclen / BASE64_OPENSSL_LINELEN;
|
||||||
|
if (remainder)
|
||||||
|
enclen++;
|
||||||
|
}
|
||||||
|
tor_assert(enclen < INT_MAX && enclen > srclen);
|
||||||
|
return enclen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Internal table mapping 6 bit values to the Base64 alphabet. */
|
||||||
|
static const char base64_encode_table[64] = {
|
||||||
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||||
|
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||||
|
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||||
|
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||||
|
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||||
|
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||||
|
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||||
|
'4', '5', '6', '7', '8', '9', '+', '/'
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Base64 encode <b>srclen</b> bytes of data from <b>src</b>. Write
|
||||||
|
* the result into <b>dest</b>, if it will fit within <b>destlen</b>
|
||||||
|
* bytes. Return the number of bytes written on success; -1 if
|
||||||
|
* destlen is too short, or other failure.
|
||||||
|
*
|
||||||
|
* If <b>flags</b>&BASE64_ENCODE_MULTILINE is true, return encoded
|
||||||
|
* output in multiline format (64 character, `\n' terminated lines).
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
base64_encode(char *dest, size_t destlen, const char *src, size_t srclen,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
const unsigned char *usrc = (unsigned char *)src;
|
||||||
|
const unsigned char *eous = usrc + srclen;
|
||||||
|
char *d = dest;
|
||||||
|
uint32_t n = 0;
|
||||||
|
size_t linelen = 0;
|
||||||
|
size_t enclen;
|
||||||
|
int n_idx = 0;
|
||||||
|
|
||||||
|
if (!src || !dest)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Ensure that there is sufficient space, including the NUL. */
|
||||||
|
enclen = base64_encode_size(srclen, flags);
|
||||||
|
if (destlen < enclen + 1)
|
||||||
|
return -1;
|
||||||
|
if (destlen > SIZE_T_CEILING)
|
||||||
|
return -1;
|
||||||
|
if (enclen > INT_MAX)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memset(dest, 0, enclen);
|
||||||
|
|
||||||
|
/* XXX/Yawning: If this ends up being too slow, this can be sped up
|
||||||
|
* by separating the multiline format case and the normal case, and
|
||||||
|
* processing 48 bytes of input at a time when newlines are desired.
|
||||||
|
*/
|
||||||
|
#define ENCODE_CHAR(ch) \
|
||||||
|
STMT_BEGIN \
|
||||||
|
*d++ = ch; \
|
||||||
|
if (flags & BASE64_ENCODE_MULTILINE) { \
|
||||||
|
if (++linelen % BASE64_OPENSSL_LINELEN == 0) { \
|
||||||
|
linelen = 0; \
|
||||||
|
*d++ = '\n'; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
STMT_END
|
||||||
|
|
||||||
|
#define ENCODE_N(idx) \
|
||||||
|
ENCODE_CHAR(base64_encode_table[(n >> ((3 - idx) * 6)) & 0x3f])
|
||||||
|
|
||||||
|
#define ENCODE_PAD() ENCODE_CHAR('=')
|
||||||
|
|
||||||
|
/* Iterate over all the bytes in src. Each one will add 8 bits to the
|
||||||
|
* value we're encoding. Accumulate bits in <b>n</b>, and whenever we
|
||||||
|
* have 24 bits, batch them into 4 bytes and flush those bytes to dest.
|
||||||
|
*/
|
||||||
|
for ( ; usrc < eous; ++usrc) {
|
||||||
|
n = (n << 8) | *usrc;
|
||||||
|
if ((++n_idx) == 3) {
|
||||||
|
ENCODE_N(0);
|
||||||
|
ENCODE_N(1);
|
||||||
|
ENCODE_N(2);
|
||||||
|
ENCODE_N(3);
|
||||||
|
n_idx = 0;
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (n_idx) {
|
||||||
|
case 0:
|
||||||
|
/* 0 leftover bits, no pading to add. */
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
/* 8 leftover bits, pad to 12 bits, write the 2 6-bit values followed
|
||||||
|
* by 2 padding characters.
|
||||||
|
*/
|
||||||
|
n <<= 4;
|
||||||
|
ENCODE_N(2);
|
||||||
|
ENCODE_N(3);
|
||||||
|
ENCODE_PAD();
|
||||||
|
ENCODE_PAD();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
/* 16 leftover bits, pad to 18 bits, write the 3 6-bit values followed
|
||||||
|
* by 1 padding character.
|
||||||
|
*/
|
||||||
|
n <<= 2;
|
||||||
|
ENCODE_N(1);
|
||||||
|
ENCODE_N(2);
|
||||||
|
ENCODE_N(3);
|
||||||
|
ENCODE_PAD();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Something went catastrophically wrong. */
|
||||||
|
tor_fragile_assert();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef ENCODE_N
|
||||||
|
#undef ENCODE_PAD
|
||||||
|
#undef ENCODE_CHAR
|
||||||
|
|
||||||
|
/* Multiline output always includes at least one newline. */
|
||||||
|
if (flags & BASE64_ENCODE_MULTILINE && linelen != 0)
|
||||||
|
*d++ = '\n';
|
||||||
|
|
||||||
|
tor_assert(d - dest == (ptrdiff_t)enclen);
|
||||||
|
|
||||||
|
*d++ = '\0'; /* NUL terminate the output. */
|
||||||
|
|
||||||
|
return (int) enclen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** As base64_encode, but do not add any internal spaces or external padding
|
||||||
|
* to the output stream. */
|
||||||
|
int
|
||||||
|
base64_encode_nopad(char *dest, size_t destlen,
|
||||||
|
const uint8_t *src, size_t srclen)
|
||||||
|
{
|
||||||
|
int n = base64_encode(dest, destlen, (const char*) src, srclen, 0);
|
||||||
|
if (n <= 0)
|
||||||
|
return n;
|
||||||
|
tor_assert((size_t)n < destlen && dest[n] == 0);
|
||||||
|
char *in, *out;
|
||||||
|
in = out = dest;
|
||||||
|
while (*in) {
|
||||||
|
if (*in == '=' || *in == '\n') {
|
||||||
|
++in;
|
||||||
|
} else {
|
||||||
|
*out++ = *in++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*out = 0;
|
||||||
|
|
||||||
|
tor_assert(out - dest <= INT_MAX);
|
||||||
|
|
||||||
|
return (int)(out - dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** As base64_decode, but do not require any padding on the input */
|
||||||
|
int
|
||||||
|
base64_decode_nopad(uint8_t *dest, size_t destlen,
|
||||||
|
const char *src, size_t srclen)
|
||||||
|
{
|
||||||
|
if (srclen > SIZE_T_CEILING - 4)
|
||||||
|
return -1;
|
||||||
|
char *buf = tor_malloc(srclen + 4);
|
||||||
|
memcpy(buf, src, srclen+1);
|
||||||
|
size_t buflen;
|
||||||
|
switch (srclen % 4)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
buflen = srclen;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
tor_free(buf);
|
||||||
|
return -1;
|
||||||
|
case 2:
|
||||||
|
memcpy(buf+srclen, "==", 3);
|
||||||
|
buflen = srclen + 2;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
memcpy(buf+srclen, "=", 2);
|
||||||
|
buflen = srclen + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int n = base64_decode((char*)dest, destlen, buf, buflen);
|
||||||
|
tor_free(buf);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef BASE64_OPENSSL_LINELEN
|
||||||
|
|
||||||
|
/** @{ */
|
||||||
|
/** Special values used for the base64_decode_table */
|
||||||
|
#define X 255
|
||||||
|
#define SP 64
|
||||||
|
#define PAD 65
|
||||||
|
/** @} */
|
||||||
|
/** Internal table mapping byte values to what they represent in base64.
|
||||||
|
* Numbers 0..63 are 6-bit integers. SPs are spaces, and should be
|
||||||
|
* skipped. Xs are invalid and must not appear in base64. PAD indicates
|
||||||
|
* end-of-string. */
|
||||||
|
static const uint8_t base64_decode_table[256] = {
|
||||||
|
X, X, X, X, X, X, X, X, X, SP, SP, SP, X, SP, X, X, /* */
|
||||||
|
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
||||||
|
SP, X, X, X, X, X, X, X, X, X, X, 62, X, X, X, 63,
|
||||||
|
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, X, X, X, PAD, X, X,
|
||||||
|
X, 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, X, X, X, X, X,
|
||||||
|
X, 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, X, X, X, X, X,
|
||||||
|
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
||||||
|
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
||||||
|
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
||||||
|
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
||||||
|
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
||||||
|
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
||||||
|
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
||||||
|
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Base64 decode <b>srclen</b> bytes of data from <b>src</b>. Write
|
||||||
|
* the result into <b>dest</b>, if it will fit within <b>destlen</b>
|
||||||
|
* bytes. Return the number of bytes written on success; -1 if
|
||||||
|
* destlen is too short, or other failure.
|
||||||
|
*
|
||||||
|
* NOTE 1: destlen is checked conservatively, as though srclen contained no
|
||||||
|
* spaces or padding.
|
||||||
|
*
|
||||||
|
* NOTE 2: This implementation does not check for the correct number of
|
||||||
|
* padding "=" characters at the end of the string, and does not check
|
||||||
|
* for internal padding characters.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
base64_decode(char *dest, size_t destlen, const char *src, size_t srclen)
|
||||||
|
{
|
||||||
|
const char *eos = src+srclen;
|
||||||
|
uint32_t n=0;
|
||||||
|
int n_idx=0;
|
||||||
|
char *dest_orig = dest;
|
||||||
|
|
||||||
|
/* Max number of bits == srclen*6.
|
||||||
|
* Number of bytes required to hold all bits == (srclen*6)/8.
|
||||||
|
* Yes, we want to round down: anything that hangs over the end of a
|
||||||
|
* byte is padding. */
|
||||||
|
if (destlen < (srclen*3)/4)
|
||||||
|
return -1;
|
||||||
|
if (destlen > SIZE_T_CEILING)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memset(dest, 0, destlen);
|
||||||
|
|
||||||
|
/* Iterate over all the bytes in src. Each one will add 0 or 6 bits to the
|
||||||
|
* value we're decoding. Accumulate bits in <b>n</b>, and whenever we have
|
||||||
|
* 24 bits, batch them into 3 bytes and flush those bytes to dest.
|
||||||
|
*/
|
||||||
|
for ( ; src < eos; ++src) {
|
||||||
|
unsigned char c = (unsigned char) *src;
|
||||||
|
uint8_t v = base64_decode_table[c];
|
||||||
|
switch (v) {
|
||||||
|
case X:
|
||||||
|
/* This character isn't allowed in base64. */
|
||||||
|
return -1;
|
||||||
|
case SP:
|
||||||
|
/* This character is whitespace, and has no effect. */
|
||||||
|
continue;
|
||||||
|
case PAD:
|
||||||
|
/* We've hit an = character: the data is over. */
|
||||||
|
goto end_of_loop;
|
||||||
|
default:
|
||||||
|
/* We have an actual 6-bit value. Append it to the bits in n. */
|
||||||
|
n = (n<<6) | v;
|
||||||
|
if ((++n_idx) == 4) {
|
||||||
|
/* We've accumulated 24 bits in n. Flush them. */
|
||||||
|
*dest++ = (n>>16);
|
||||||
|
*dest++ = (n>>8) & 0xff;
|
||||||
|
*dest++ = (n) & 0xff;
|
||||||
|
n_idx = 0;
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end_of_loop:
|
||||||
|
/* If we have leftover bits, we need to cope. */
|
||||||
|
switch (n_idx) {
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
/* No leftover bits. We win. */
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
/* 6 leftover bits. That's invalid; we can't form a byte out of that. */
|
||||||
|
return -1;
|
||||||
|
case 2:
|
||||||
|
/* 12 leftover bits: The last 4 are padding and the first 8 are data. */
|
||||||
|
*dest++ = n >> 4;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
/* 18 leftover bits: The last 2 are padding and the first 16 are data. */
|
||||||
|
*dest++ = n >> 10;
|
||||||
|
*dest++ = n >> 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
tor_assert((dest-dest_orig) <= (ssize_t)destlen);
|
||||||
|
tor_assert((dest-dest_orig) <= INT_MAX);
|
||||||
|
|
||||||
|
return (int)(dest-dest_orig);
|
||||||
|
}
|
||||||
|
#undef X
|
||||||
|
#undef SP
|
||||||
|
#undef PAD
|
||||||
|
|
||||||
|
/** Encode the <b>srclen</b> bytes at <b>src</b> in a NUL-terminated,
|
||||||
|
* uppercase hexadecimal string; store it in the <b>destlen</b>-byte buffer
|
||||||
|
* <b>dest</b>.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
base16_encode(char *dest, size_t destlen, const char *src, size_t srclen)
|
||||||
|
{
|
||||||
|
const char *end;
|
||||||
|
char *cp;
|
||||||
|
|
||||||
|
tor_assert(destlen >= srclen*2+1);
|
||||||
|
tor_assert(destlen < SIZE_T_CEILING);
|
||||||
|
|
||||||
|
cp = dest;
|
||||||
|
end = src+srclen;
|
||||||
|
while (src<end) {
|
||||||
|
*cp++ = "0123456789ABCDEF"[ (*(const uint8_t*)src) >> 4 ];
|
||||||
|
*cp++ = "0123456789ABCDEF"[ (*(const uint8_t*)src) & 0xf ];
|
||||||
|
++src;
|
||||||
|
}
|
||||||
|
*cp = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Helper: given a hex digit, return its value, or -1 if it isn't hex. */
|
||||||
|
static INLINE int
|
||||||
|
hex_decode_digit_(char c)
|
||||||
|
{
|
||||||
|
switch (c) {
|
||||||
|
case '0': return 0;
|
||||||
|
case '1': return 1;
|
||||||
|
case '2': return 2;
|
||||||
|
case '3': return 3;
|
||||||
|
case '4': return 4;
|
||||||
|
case '5': return 5;
|
||||||
|
case '6': return 6;
|
||||||
|
case '7': return 7;
|
||||||
|
case '8': return 8;
|
||||||
|
case '9': return 9;
|
||||||
|
case 'A': case 'a': return 10;
|
||||||
|
case 'B': case 'b': return 11;
|
||||||
|
case 'C': case 'c': return 12;
|
||||||
|
case 'D': case 'd': return 13;
|
||||||
|
case 'E': case 'e': return 14;
|
||||||
|
case 'F': case 'f': return 15;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Helper: given a hex digit, return its value, or -1 if it isn't hex. */
|
||||||
|
int
|
||||||
|
hex_decode_digit(char c)
|
||||||
|
{
|
||||||
|
return hex_decode_digit_(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Given a hexadecimal string of <b>srclen</b> bytes in <b>src</b>, decode it
|
||||||
|
* and store the result in the <b>destlen</b>-byte buffer at <b>dest</b>.
|
||||||
|
* Return 0 on success, -1 on failure. */
|
||||||
|
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;
|
||||||
|
|
||||||
|
memset(dest, 0, destlen);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
33
src/common/util_format.h
Normal file
33
src/common/util_format.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/* Copyright (c) 2001, Matej Pfajfar.
|
||||||
|
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||||
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||||
|
* Copyright (c) 2007-2015, The Tor Project, Inc. */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
#ifndef TOR_UTIL_FORMAT_H
|
||||||
|
#define TOR_UTIL_FORMAT_H
|
||||||
|
|
||||||
|
#include "testsupport.h"
|
||||||
|
#include "torint.h"
|
||||||
|
|
||||||
|
#define BASE64_ENCODE_MULTILINE 1
|
||||||
|
size_t base64_encode_size(size_t srclen, int flags);
|
||||||
|
int base64_encode(char *dest, size_t destlen, const char *src, size_t srclen,
|
||||||
|
int flags);
|
||||||
|
int base64_decode(char *dest, size_t destlen, const char *src, size_t srclen);
|
||||||
|
int base64_encode_nopad(char *dest, size_t destlen,
|
||||||
|
const uint8_t *src, size_t srclen);
|
||||||
|
int base64_decode_nopad(uint8_t *dest, size_t destlen,
|
||||||
|
const char *src, size_t srclen);
|
||||||
|
|
||||||
|
/** Characters that can appear (case-insensitively) in a base32 encoding. */
|
||||||
|
#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567"
|
||||||
|
void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen);
|
||||||
|
int base32_decode(char *dest, size_t destlen, const char *src, size_t srclen);
|
||||||
|
|
||||||
|
int hex_decode_digit(char c);
|
||||||
|
void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen);
|
||||||
|
int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -6,6 +6,7 @@
|
|||||||
#include "orconfig.h"
|
#include "orconfig.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
|
#include "crypto_format.h"
|
||||||
#include "di_ops.h"
|
#include "di_ops.h"
|
||||||
#include "ht.h"
|
#include "ht.h"
|
||||||
#include "keypin.h"
|
#include "keypin.h"
|
||||||
@ -13,6 +14,7 @@
|
|||||||
#include "torint.h"
|
#include "torint.h"
|
||||||
#include "torlog.h"
|
#include "torlog.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "util_format.h"
|
||||||
|
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -81,6 +81,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
|
#include "crypto_format.h"
|
||||||
#include "tortls.h"
|
#include "tortls.h"
|
||||||
#include "torlog.h"
|
#include "torlog.h"
|
||||||
#include "container.h"
|
#include "container.h"
|
||||||
@ -92,6 +93,7 @@
|
|||||||
#include "crypto_curve25519.h"
|
#include "crypto_curve25519.h"
|
||||||
#include "crypto_ed25519.h"
|
#include "crypto_ed25519.h"
|
||||||
#include "tor_queue.h"
|
#include "tor_queue.h"
|
||||||
|
#include "util_format.h"
|
||||||
|
|
||||||
/* These signals are defined to help handle_control_signal work.
|
/* These signals are defined to help handle_control_signal work.
|
||||||
*/
|
*/
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "torlog.h"
|
#include "torlog.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
#include "address.h"
|
#include "address.h"
|
||||||
|
#include "util_format.h"
|
||||||
|
|
||||||
#define IDENTITY_KEY_BITS 3072
|
#define IDENTITY_KEY_BITS 3072
|
||||||
#define SIGNING_KEY_BITS 2048
|
#define SIGNING_KEY_BITS 2048
|
||||||
|
Loading…
Reference in New Issue
Block a user