Hush Full Node software. We were censored from Github, this is where all development happens now. https://hush.is
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

302 lines
9.2 KiB

// Copyright (c) 2016-2020 The Hush developers
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "include/cJSON.h"
#include "include/sha256.h"
#include "asn/asn_application.h"
#include "cryptoconditions.h"
#include "internal.h"
static unsigned char encoding_table[] = {'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', '+', '/'};
static unsigned char *decoding_table = NULL;
static int mod_table[] = {0, 2, 1};
void build_decoding_table() {
decoding_table = calloc(1,256);
for (int i = 0; i < 64; i++)
decoding_table[(unsigned char) encoding_table[i]] = i;
}
unsigned char *base64_encode(const unsigned char *data, size_t input_length) {
size_t output_length = 4 * ((input_length + 2) / 3);
unsigned char *encoded_data = calloc(1,output_length + 1);
if (encoded_data == NULL) return NULL;
for (int i = 0, j = 0; i < input_length;) {
uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
}
int strip = mod_table[input_length % 3];
for (int i = 0; i < strip; i++)
encoded_data[output_length - 1 - i] = '\0';
// make sure there's a null termination for string protocol
encoded_data[output_length] = '\0';
// url safe
for (int i=0; i<output_length; i++) {
if (encoded_data[i] == '/') encoded_data[i] = '_';
if (encoded_data[i] == '+') encoded_data[i] = '-';
}
return encoded_data;
}
unsigned char *base64_decode(const unsigned char *data_,
size_t *output_length) {
if (decoding_table == NULL) build_decoding_table();
size_t input_length = strlen(data_);
int rem = input_length % 4;
unsigned char *data = calloc(1,input_length + (4-rem));
strcpy(data, data_);
// for unpadded b64
if (0 != rem) {
for (int i=0; i<4-rem; i++) {
data[input_length + i] = '=';
}
input_length += 4-rem;
}
// for URL safe
for (int i=0; i<input_length; i++) {
if (data[i] == '-') data[i] = '+';
if (data[i] == '_') data[i] = '/';
}
*output_length = input_length / 4 * 3;
if (data[input_length - 1] == '=') (*output_length)--;
if (data[input_length - 2] == '=') (*output_length)--;
unsigned char *decoded_data = calloc(1,*output_length);
if (decoded_data == NULL) return NULL;
for (int i = 0, j = 0; i < input_length;) {
uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
uint32_t triple = (sextet_a << 3 * 6)
+ (sextet_b << 2 * 6)
+ (sextet_c << 1 * 6)
+ (sextet_d << 0 * 6);
if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
}
return decoded_data;
}
void base64_cleanup() {
free(decoding_table);
decoding_table = 0;
}
void dumpStr(unsigned char *str, size_t len) {
if (-1 == len) len = strlen(str);
fprintf(stderr, "len:%i ", (int)len);
for (int i=0; i<len; i++) {
if (isprint(str[i])) {
fprintf(stderr, "%c", str[i]);
} else {
fprintf(stderr, "\\x%02x", str[i] & 0xff);
//fprintf(stderr, "\\%u", str[i] & 0xff);
}
}
fprintf(stderr, "\n");
}
int checkString(const cJSON *value, char *key, char *err) {
if (value == NULL) {
sprintf(err, "%s is required", key);
return 0;
}
if (!cJSON_IsString(value)) {
sprintf(err, "%s must be a string", key);
return 0;
}
return 1;
}
int checkDecodeBase64(const cJSON *value, char *key, char *err, unsigned char **data, size_t *size) {
if (!checkString(value, key, err))
return 0;
*data = base64_decode(value->valuestring, size);
if (!*data) {
sprintf(err, "%s must be valid base64 string", key);
return 0;
}
return 1;
}
int jsonGetBase64(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size)
{
cJSON *item = cJSON_GetObjectItem(params, key);
if (!item) {
sprintf(err, "%s is required", key);
return 0;
}
return checkDecodeBase64(item, key, err, data, size);
}
int jsonGetBase64Optional(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size) {
cJSON *item = cJSON_GetObjectItem(params, key);
if (!item) {
return 1;
}
return checkDecodeBase64(item, key, err, data, size);
}
void jsonAddBase64(cJSON *params, char *key, unsigned char *bin, size_t size) {
unsigned char *b64 = base64_encode(bin, size);
cJSON_AddItemToObject(params, key, cJSON_CreateString(b64));
free(b64);
}
void hashFingerprintContents(asn_TYPE_descriptor_t *asnType, void *fp, uint8_t *out) {
unsigned char buf[BUF_SIZE];
asn_enc_rval_t rc = der_encode_to_buffer(asnType, fp, buf, BUF_SIZE);
ASN_STRUCT_FREE(*asnType, fp);
if (rc.encoded < 1) {
fprintf(stderr, "Encoding fingerprint failed\n");
return;
}
sha256(buf, rc.encoded, out);
}
char* cc_hex_encode(const uint8_t *bin, size_t len)
{
char* hex = calloc(1,len*2+1);
if (bin == NULL) return hex;
char map[16] = "0123456789ABCDEF";
for (int i=0; i<len; i++) {
hex[i*2] = map[bin[i] >> 4];
hex[i*2+1] = map[bin[i] & 0x0F];
}
hex[len*2] = '\0';
return hex;
}
uint8_t* cc_hex_decode(const char* hex)
{
size_t len = strlen(hex);
if (len % 2 == 1) return NULL;
uint8_t* bin = calloc(1, len/2);
for (int i=0; i<len; i++) {
char c = hex[i];
if (c <= 57) c -= 48;
else if (c <= 70) c -= 55;
else if (c <= 102) c -= 87;
if (c < 0 || c > 15) goto ERR;
bin[i/2] += c << (i%2 ? 0 : 4);
}
return bin;
ERR:
free(bin);
return NULL;
}
bool checkDecodeHex(const cJSON *value, char *key, char *err, unsigned char **data, size_t *size) {
if (!checkString(value, key, err))
return 0;
*data = cc_hex_decode(value->valuestring);
if (!*data) {
sprintf(err, "%s must be valid hex string", key);
return 0;
}
*size = strlen(value->valuestring) / 2;
return 1;
}
bool jsonGetHex(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size)
{
cJSON *item = cJSON_GetObjectItem(params, key);
if (!item) {
sprintf(err, "%s is required", key);
return 0;
}
return checkDecodeHex(item, key, err, data, size);
}
void jsonAddHex(cJSON *params, char *key, unsigned char *bin, size_t size) {
unsigned char *hex = cc_hex_encode(bin, size);
cJSON_AddItemToObject(params, key, cJSON_CreateString(hex));
free(hex);
}
int jsonGetHexOptional(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size) {
cJSON *item = cJSON_GetObjectItem(params, key);
if (!item) {
return 1;
}
return checkDecodeHex(item, key, err, data, size);
}