|
|
@ -24,6 +24,7 @@ |
|
|
|
#include <assert.h> |
|
|
|
#include <string.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <inttypes.h> |
|
|
|
|
|
|
|
#include <openssl/bn.h> |
|
|
|
#include <openssl/ecdsa.h> |
|
|
@ -215,138 +216,6 @@ static void vg_encode_address(const EC_POINT *ppoint, const EC_GROUP *pgroup, |
|
|
|
vg_b58_encode_check(binres, sizeof(binres), result); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* ASCII <-> Base64 conversion as described in RFC1421. |
|
|
|
* |
|
|
|
* Copyright 2006-2010 Willy Tarreau <w@1wt.eu> |
|
|
|
* Copyright 2009-2010 Krzysztof Piotr Oledzki <ole@ans.pl> |
|
|
|
* |
|
|
|
* 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. |
|
|
|
* |
|
|
|
*/ |
|
|
|
#define B64BASE '#' /** arbitrary chosen base value */ |
|
|
|
#define B64CMIN '+' |
|
|
|
#define B64CMAX 'z' |
|
|
|
#define B64PADV 64 /** Base64 chosen special pad value */ |
|
|
|
|
|
|
|
const char base64tab[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
|
|
|
const char base64rev[] = "b###cXYZ[\\]^_`a###d###$%&'()*+,-./0123456789:;<=######>?@ABCDEFGHIJKLMNOPQRSTUVW"; |
|
|
|
|
|
|
|
/** Encodes <ilen> bytes from <in> to <out> for at most <olen> chars (including |
|
|
|
* the trailing zero). Returns the number of bytes written. No check is made |
|
|
|
* for <in> or <out> to be NULL. Returns negative value if <olen> is too short |
|
|
|
* to accept <ilen>. 4 output bytes are produced for 1 to 3 input bytes. |
|
|
|
*/ |
|
|
|
static int base64_encode(char *in, int ilen, char *out, int olen) { |
|
|
|
int convlen; |
|
|
|
|
|
|
|
convlen = ((ilen + 2) / 3) * 4; |
|
|
|
|
|
|
|
if (convlen >= olen) |
|
|
|
return -1; |
|
|
|
|
|
|
|
/** we don't need to check olen anymore */ |
|
|
|
while (ilen >= 3) { |
|
|
|
out[0] = base64tab[(((unsigned char)in[0]) >> 2)]; |
|
|
|
out[1] = base64tab[(((unsigned char)in[0] & 0x03) << 4) | (((unsigned char)in[1]) >> 4)]; |
|
|
|
out[2] = base64tab[(((unsigned char)in[1] & 0x0F) << 2) | (((unsigned char)in[2]) >> 6)]; |
|
|
|
out[3] = base64tab[(((unsigned char)in[2] & 0x3F))]; |
|
|
|
out += 4; |
|
|
|
in += 3; ilen -= 3; |
|
|
|
} |
|
|
|
|
|
|
|
if (!ilen) { |
|
|
|
out[0] = '\0'; |
|
|
|
} else { |
|
|
|
out[0] = base64tab[((unsigned char)in[0]) >> 2]; |
|
|
|
if (ilen == 1) { |
|
|
|
out[1] = base64tab[((unsigned char)in[0] & 0x03) << 4]; |
|
|
|
out[2] = '='; |
|
|
|
} else { |
|
|
|
out[1] = base64tab[(((unsigned char)in[0] & 0x03) << 4) | |
|
|
|
(((unsigned char)in[1]) >> 4)]; |
|
|
|
out[2] = base64tab[((unsigned char)in[1] & 0x0F) << 2]; |
|
|
|
} |
|
|
|
out[3] = '='; |
|
|
|
out[4] = '\0'; |
|
|
|
} |
|
|
|
|
|
|
|
return convlen; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Decodes <ilen> bytes from <in> to <out> for at most <olen> chars. |
|
|
|
* Returns the number of bytes converted. No check is made for |
|
|
|
* <in> or <out> to be NULL. Returns -1 if <in> is invalid or ilen |
|
|
|
* has wrong size, -2 if <olen> is too short. |
|
|
|
* 1 to 3 output bytes are produced for 4 input bytes. |
|
|
|
*/ |
|
|
|
static int base64_decode(const char *in, size_t ilen, char *out, size_t olen) { |
|
|
|
|
|
|
|
unsigned char t[4]; |
|
|
|
signed char b; |
|
|
|
int convlen = 0, i = 0, pad = 0; |
|
|
|
|
|
|
|
if (ilen % 4) |
|
|
|
return -1; |
|
|
|
|
|
|
|
if (olen < ilen / 4 * 3) |
|
|
|
return -2; |
|
|
|
|
|
|
|
while (ilen) { |
|
|
|
|
|
|
|
/** if (*p < B64CMIN || *p > B64CMAX) */ |
|
|
|
b = (signed char)*in - B64CMIN; |
|
|
|
if ((unsigned char)b > (B64CMAX-B64CMIN)) |
|
|
|
return -1; |
|
|
|
|
|
|
|
b = base64rev[b] - B64BASE - 1; |
|
|
|
|
|
|
|
/** b == -1: invalid character */ |
|
|
|
if (b < 0) |
|
|
|
return -1; |
|
|
|
|
|
|
|
/** padding has to be continous */ |
|
|
|
if (pad && b != B64PADV) |
|
|
|
return -1; |
|
|
|
|
|
|
|
/** valid padding: "XX==" or "XXX=", but never "X===" or "====" */ |
|
|
|
if (pad && i < 2) |
|
|
|
return -1; |
|
|
|
|
|
|
|
if (b == B64PADV) |
|
|
|
pad++; |
|
|
|
|
|
|
|
t[i++] = b; |
|
|
|
|
|
|
|
if (i == 4) { |
|
|
|
/** |
|
|
|
* WARNING: we allow to write little more data than we |
|
|
|
* should, but the checks from the beginning of the |
|
|
|
* functions guarantee that we can safely do that. |
|
|
|
*/ |
|
|
|
|
|
|
|
/** xx000000 xx001111 xx111122 xx222222 */ |
|
|
|
out[convlen] = ((t[0] << 2) + (t[1] >> 4)); |
|
|
|
out[convlen+1] = ((t[1] << 4) + (t[2] >> 2)); |
|
|
|
out[convlen+2] = ((t[2] << 6) + (t[3] >> 0)); |
|
|
|
|
|
|
|
convlen += 3-pad; |
|
|
|
|
|
|
|
pad = i = 0; |
|
|
|
} |
|
|
|
|
|
|
|
in++; |
|
|
|
ilen--; |
|
|
|
} |
|
|
|
|
|
|
|
return convlen; |
|
|
|
} |
|
|
|
|
|
|
|
static size_t write_compact_size(const uint64_t val, uint8_t *dest) { |
|
|
|
if (val < 0xfd) { |
|
|
|
*dest++ = (unsigned char)val; |
|
|
@ -572,7 +441,7 @@ static int isCompressedAddress(const char *priv_key_b58, const char *address) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
static int sign_message(char *signature, size_t signature_size, |
|
|
|
static int sign_message(uint8_t *signature_65, |
|
|
|
const uint8_t *msg, const size_t msg_len, |
|
|
|
const char *priv_key_b58, int is_compressed_pubkey) { |
|
|
|
EC_KEY *pkey = NULL; |
|
|
@ -650,11 +519,8 @@ static int sign_message(char *signature, size_t signature_size, |
|
|
|
BN_bn2bin(sig->r, sigbuf + 33 - (nBitsR+7)/8); |
|
|
|
BN_bn2bin(sig->s, sigbuf + 65 - (nBitsS+7)/8); |
|
|
|
|
|
|
|
// convent to base64 |
|
|
|
if (base64_encode((char *)sigbuf, sizeof(sigbuf), |
|
|
|
signature, (int)signature_size) != -1) { |
|
|
|
fOK = 1; |
|
|
|
} |
|
|
|
memcpy(signature_65, sigbuf, 65); |
|
|
|
fOK = 1; |
|
|
|
} |
|
|
|
|
|
|
|
error: |
|
|
@ -666,25 +532,21 @@ error: |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int bitcoin_sign_message(char *signature, size_t signature_size, |
|
|
|
int bitcoin_sign_message(unsigned char *buf_65, |
|
|
|
const void *msg, const size_t msg_len, |
|
|
|
const char *priv_key_b58, const char *address) { |
|
|
|
int is_compressed = isCompressedAddress(priv_key_b58, address); |
|
|
|
return sign_message(signature, signature_size, (uint8_t *)msg, msg_len, |
|
|
|
return sign_message(buf_65, (uint8_t *)msg, msg_len, |
|
|
|
priv_key_b58, is_compressed); |
|
|
|
} |
|
|
|
|
|
|
|
int bitcoin_verify_message(const char *address, const char *sig_b64, |
|
|
|
int bitcoin_verify_message(const char *address, const unsigned char *sig, |
|
|
|
const void *msg, const size_t msglen) { |
|
|
|
EC_KEY *pkey = EC_KEY_new_by_curve_name(NID_secp256k1); |
|
|
|
uint8_t hash[32] = {0}; |
|
|
|
char ecprot[128] = {0}; |
|
|
|
uint8_t sig[128] = {0}; // sig is 65 bytes, but base64 decode need more |
|
|
|
int fOK = 0; |
|
|
|
|
|
|
|
// decode base64 |
|
|
|
base64_decode(sig_b64, strlen(sig_b64), (char *)sig, sizeof(sig)); |
|
|
|
|
|
|
|
// message double sha256 |
|
|
|
dsha265_message(hash, msg, msglen); |
|
|
|
|
|
|
|