#include "orconfig.h"
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#include "lib/container/smartlist.h"
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_digest.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/string/compat_string.h"
#include "lib/string/util_string.h"
#include "lib/string/printf.h"
#include "lib/encoding/binascii.h"
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
#include "lib/fs/files.h"
#include <string.h>
#include <errno.h>
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;
}
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;
if (strcmpstart(prefix, "== ") || strcmpend(prefix, " ==") ||
! fast_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;
}
void
curve25519_public_to_base64(char *output,
const curve25519_public_key_t *pkey, bool pad)
{
int n, expected_len;
if (pad) {
n = base64_encode(output, CURVE25519_BASE64_PADDED_LEN+1,
(const char*)pkey->public_key,
CURVE25519_PUBKEY_LEN, 0);
expected_len = CURVE25519_BASE64_PADDED_LEN;
} else {
n = base64_encode_nopad(output, CURVE25519_BASE64_PADDED_LEN+1,
(const uint8_t*)pkey->public_key,
CURVE25519_PUBKEY_LEN);
expected_len = CURVE25519_BASE64_LEN;
}
tor_assert(n == expected_len);
tor_assert(output[expected_len] == '\0');
}
int
curve25519_public_from_base64(curve25519_public_key_t *pkey,
const char *input)
{
size_t len = strlen(input);
if (len == CURVE25519_BASE64_LEN) {
return digest256_from_base64((char*)pkey->public_key, input);
} else if (len == CURVE25519_BASE64_PADDED_LEN) {
char buf[CURVE25519_BASE64_PADDED_LEN+1];
if (base64_decode(buf, sizeof(buf), input, len) != CURVE25519_PUBKEY_LEN)
return -1;
memcpy(pkey->public_key, buf, CURVE25519_PUBKEY_LEN);
return 0;
} else {
return -1;
}
}
const char *
ed25519_fmt(const ed25519_public_key_t *pkey)
{
static char formatted[ED25519_BASE64_LEN+1];
if (pkey) {
if (ed25519_public_key_is_zero(pkey)) {
strlcpy(formatted, "<unset>", sizeof(formatted));
} else {
ed25519_public_to_base64(formatted, pkey);
}
} else {
strlcpy(formatted, "<null>", sizeof(formatted));
}
return formatted;
}
int
ed25519_public_from_base64(ed25519_public_key_t *pkey,
const char *input)
{
return digest256_from_base64((char*)pkey->pubkey, input);
}
void
ed25519_public_to_base64(char *output,
const ed25519_public_key_t *pkey)
{
digest256_to_base64(output, (const char *)pkey->pubkey);
}
void
ed25519_signature_to_base64(char *output,
const ed25519_signature_t *sig)
{
char buf[256];
int n = base64_encode_nopad(buf, sizeof(buf), sig->sig, ED25519_SIG_LEN);
tor_assert(n == ED25519_SIG_BASE64_LEN);
tor_assert(buf[ED25519_SIG_BASE64_LEN] == '\0');
memcpy(output, buf, ED25519_SIG_BASE64_LEN+1);
}
int
ed25519_signature_from_base64(ed25519_signature_t *sig,
const char *input)
{
if (strlen(input) != ED25519_SIG_BASE64_LEN)
return -1;
char decoded[128];
int n = base64_decode(decoded, sizeof(decoded), input,
ED25519_SIG_BASE64_LEN);
if (n < 0 || n != ED25519_SIG_LEN)
return -1;
memcpy(sig->sig, decoded, ED25519_SIG_LEN);
return 0;
}
void
digest_to_base64(char *d64, const char *digest)
{
char buf[256];
int n = base64_encode_nopad(buf, sizeof(buf),
(const uint8_t *)digest, DIGEST_LEN);
tor_assert(n == BASE64_DIGEST_LEN);
tor_assert(buf[BASE64_DIGEST_LEN] == '\0');
memcpy(d64, buf, BASE64_DIGEST_LEN+1);
}
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;
}
void
digest256_to_base64(char *d64, const char *digest)
{
char buf[256];
int n = base64_encode_nopad(buf, sizeof(buf),
(const uint8_t *)digest, DIGEST256_LEN);
tor_assert(n == BASE64_DIGEST256_LEN);
tor_assert(buf[BASE64_DIGEST256_LEN] == '\0');
memcpy(d64, buf, BASE64_DIGEST256_LEN+1);
}
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;
}