segwit support for SignMessage, VerifyMessage

pull/25/head
Pavol Rusnak 7 years ago
parent d8ad44f60a
commit b5f9a5738f
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D

@ -20,6 +20,7 @@
#include <string.h> #include <string.h>
#include "crypto.h" #include "crypto.h"
#include "sha2.h" #include "sha2.h"
#include "ripemd160.h"
#include "pbkdf2.h" #include "pbkdf2.h"
#include "aes.h" #include "aes.h"
#include "hmac.h" #include "hmac.h"
@ -109,7 +110,7 @@ int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin
} }
} }
int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) int cryptoMessageSign(const CoinType *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature)
{ {
SHA256_CTX ctx; SHA256_CTX ctx;
sha256_Init(&ctx); sha256_Init(&ctx);
@ -124,34 +125,48 @@ int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message
uint8_t pby; uint8_t pby;
int result = hdnode_sign_digest(node, hash, signature + 1, &pby, NULL); int result = hdnode_sign_digest(node, hash, signature + 1, &pby, NULL);
if (result == 0) { if (result == 0) {
signature[0] = 27 + pby + 4; switch (script_type) {
case InputScriptType_SPENDP2SHWITNESS:
// segwit-in-p2sh
signature[0] = 35 + pby;
break;
case InputScriptType_SPENDWITNESS:
// segwit
signature[0] = 39 + pby;
break;
default:
// p2pkh
signature[0] = 31 + pby;
break;
}
} }
return result; return result;
} }
int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature) int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature)
{ {
SHA256_CTX ctx; // check for invalid signature prefix
uint8_t pubkey[65], addr_raw[MAX_ADDR_RAW_SIZE], hash[32]; if (signature[0] < 27 || signature[0] > 43) {
return 1;
}
// calculate hash // calculate hash
SHA256_CTX ctx;
sha256_Init(&ctx); sha256_Init(&ctx);
sha256_Update(&ctx, (const uint8_t *)coin->signed_message_header, strlen(coin->signed_message_header)); sha256_Update(&ctx, (const uint8_t *)coin->signed_message_header, strlen(coin->signed_message_header));
uint8_t varint[5]; uint8_t varint[5];
uint32_t l = ser_length(message_len, varint); uint32_t l = ser_length(message_len, varint);
sha256_Update(&ctx, varint, l); sha256_Update(&ctx, varint, l);
sha256_Update(&ctx, message, message_len); sha256_Update(&ctx, message, message_len);
uint8_t hash[32];
sha256_Final(&ctx, hash); sha256_Final(&ctx, hash);
sha256_Raw(hash, 32, hash); sha256_Raw(hash, 32, hash);
uint8_t recid = signature[0] - 27; uint8_t recid = (signature[0] - 27) % 4;
if (recid >= 8) { bool compressed = signature[0] >= 31;
return 1;
}
bool compressed = (recid >= 4);
recid &= 3;
// check if signature verifies the digest and recover the public key // check if signature verifies the digest and recover the public key
uint8_t pubkey[65];
if (ecdsa_verify_digest_recover(&secp256k1, pubkey, signature + 1, hash, recid) != 0) { if (ecdsa_verify_digest_recover(&secp256k1, pubkey, signature + 1, hash, recid) != 0) {
return 3; return 3;
} }
@ -159,11 +174,35 @@ int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t mes
if (compressed) { if (compressed) {
pubkey[0] = 0x02 | (pubkey[64] & 1); pubkey[0] = 0x02 | (pubkey[64] & 1);
} }
// check if the address is correct // check if the address is correct
ecdsa_get_address_raw(pubkey, address_type, addr_raw); uint8_t addr_raw[MAX_ADDR_RAW_SIZE];
if (memcmp(addr_raw, address_raw, address_prefix_bytes_len(address_type) + 20) != 0) {
return 2; // p2pkh
if (signature[0] >= 27 && signature[0] <= 34) {
if (address_type != coin->address_type) {
return 4;
}
ecdsa_get_address_raw(pubkey, address_type, addr_raw);
if (memcmp(addr_raw, address_raw, address_prefix_bytes_len(address_type) + 20) != 0) {
return 2;
}
} else
// segwit-in-p2sh
if (signature[0] >= 35 && signature[0] <= 38) {
if (address_type != coin->address_type_p2sh) {
return 4;
}
ecdsa_get_address_segwit_p2sh_raw(pubkey, address_type, addr_raw);
if (memcmp(addr_raw, address_raw, address_prefix_bytes_len(address_type) + 20) != 0) {
return 2;
}
} else
// segwit
if (signature[0] >= 39 && signature[0] <= 42) {
return 2; // not supported yet
} }
return 0; return 0;
} }

@ -37,7 +37,7 @@ int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin
int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature);
int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); int cryptoMessageSign(const CoinType *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature);
int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature); int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature);

@ -795,9 +795,14 @@ void fsm_msgSignMessage(SignMessage *msg)
if (!node) return; if (!node) return;
layoutProgressSwipe(_("Signing"), 0); layoutProgressSwipe(_("Signing"), 0);
if (cryptoMessageSign(coin, node, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) { if (cryptoMessageSign(coin, node, msg->script_type, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) {
resp->has_address = true; resp->has_address = true;
hdnode_get_address(node, coin->address_type, resp->address, sizeof(resp->address)); hdnode_fill_public_key(node);
if (!compute_address(coin, msg->script_type, node, false, NULL, resp->address)) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing address"));
layoutHome();
return;
}
resp->has_signature = true; resp->has_signature = true;
resp->signature.size = 65; resp->signature.size = 65;
msg_write(MessageType_MessageType_MessageSignature, resp); msg_write(MessageType_MessageType_MessageSignature, resp);
@ -890,7 +895,7 @@ void fsm_msgSignIdentity(SignIdentity *msg)
uint8_t digest[64]; uint8_t digest[64];
sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest);
sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32); sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32);
result = cryptoMessageSign(&(coins[0]), node, digest, 64, resp->signature.bytes); result = cryptoMessageSign(&(coins[0]), node, InputScriptType_SPENDADDRESS, digest, 64, resp->signature.bytes);
} }
if (result == 0) { if (result == 0) {

@ -57,12 +57,12 @@ SignMessage.address_n max_count:8
SignMessage.message max_size:1024 SignMessage.message max_size:1024
SignMessage.coin_name max_size:17 SignMessage.coin_name max_size:17
VerifyMessage.address max_size:41 VerifyMessage.address max_size:60
VerifyMessage.signature max_size:65 VerifyMessage.signature max_size:65
VerifyMessage.message max_size:1024 VerifyMessage.message max_size:1024
VerifyMessage.coin_name max_size:17 VerifyMessage.coin_name max_size:17
MessageSignature.address max_size:41 MessageSignature.address max_size:60
MessageSignature.signature max_size:65 MessageSignature.signature max_size:65
EthereumSignMessage.address_n max_count:8 EthereumSignMessage.address_n max_count:8
@ -97,7 +97,7 @@ DecryptMessage skip_message:true
# deprecated # deprecated
DecryptedMessage skip_message:true DecryptedMessage skip_message:true
# DecryptedMessage.address max_size:41 # DecryptedMessage.address max_size:60
# DecryptedMessage.message max_size:1024 # DecryptedMessage.message max_size:1024
CipherKeyValue.address_n max_count:8 CipherKeyValue.address_n max_count:8
@ -133,7 +133,7 @@ SignIdentity.challenge_hidden max_size:256
SignIdentity.challenge_visual max_size:256 SignIdentity.challenge_visual max_size:256
SignIdentity.ecdsa_curve_name max_size:32 SignIdentity.ecdsa_curve_name max_size:32
SignedIdentity.address max_size:41 SignedIdentity.address max_size:60
SignedIdentity.public_key max_size:33 SignedIdentity.public_key max_size:33
SignedIdentity.signature max_size:65 SignedIdentity.signature max_size:65

@ -595,7 +595,7 @@ typedef struct {
typedef struct _MessageSignature { typedef struct _MessageSignature {
bool has_address; bool has_address;
char address[41]; char address[60];
bool has_signature; bool has_signature;
MessageSignature_signature_t signature; MessageSignature_signature_t signature;
} MessageSignature; } MessageSignature;
@ -729,7 +729,7 @@ typedef struct {
typedef struct _SignedIdentity { typedef struct _SignedIdentity {
bool has_address; bool has_address;
char address[41]; char address[60];
bool has_public_key; bool has_public_key;
SignedIdentity_public_key_t public_key; SignedIdentity_public_key_t public_key;
bool has_signature; bool has_signature;
@ -767,7 +767,7 @@ typedef struct {
typedef struct _VerifyMessage { typedef struct _VerifyMessage {
bool has_address; bool has_address;
char address[41]; char address[60];
bool has_signature; bool has_signature;
VerifyMessage_signature_t signature; VerifyMessage_signature_t signature;
bool has_message; bool has_message;
@ -1192,8 +1192,8 @@ extern const pb_field_t DebugLinkFlashErase_fields[2];
#define WordRequest_size 6 #define WordRequest_size 6
#define WordAck_size 14 #define WordAck_size 14
#define SignMessage_size 1100 #define SignMessage_size 1100
#define VerifyMessage_size 1156 #define VerifyMessage_size 1175
#define MessageSignature_size 110 #define MessageSignature_size 129
#define CipherKeyValue_size 1358 #define CipherKeyValue_size 1358
#define CipheredKeyValue_size 1027 #define CipheredKeyValue_size 1027
#define SignTx_size 43 #define SignTx_size 43
@ -1206,7 +1206,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2];
#define EthereumVerifyMessage_size 1116 #define EthereumVerifyMessage_size 1116
#define EthereumMessageSignature_size 89 #define EthereumMessageSignature_size 89
#define SignIdentity_size (558 + IdentityType_size) #define SignIdentity_size (558 + IdentityType_size)
#define SignedIdentity_size 145 #define SignedIdentity_size 164
#define GetECDHSessionKey_size (107 + IdentityType_size) #define GetECDHSessionKey_size (107 + IdentityType_size)
#define ECDHSessionKey_size 67 #define ECDHSessionKey_size 67
#define SetU2FCounter_size 6 #define SetU2FCounter_size 6

@ -124,16 +124,7 @@ bool compute_address(const CoinType *coin,
if (!coin->has_address_type_p2sh) { if (!coin->has_address_type_p2sh) {
return 0; return 0;
} }
prelen = address_prefix_bytes_len(coin->address_type_p2sh); ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, address, MAX_ADDR_SIZE);
raw[0] = 0; // version byte
raw[1] = 20; // push 20 bytes
ecdsa_get_pubkeyhash(node->public_key, raw + 2);
sha256_Raw(raw, 22, digest);
address_write_prefix_bytes(coin->address_type_p2sh, raw);
ripemd160(digest, 32, raw + prelen);
if (!base58_encode_check(raw, prelen + 20, address, MAX_ADDR_SIZE)) {
return 0;
}
} else { } else {
ecdsa_get_address(node->public_key, coin->address_type, address, MAX_ADDR_SIZE); ecdsa_get_address(node->public_key, coin->address_type, address, MAX_ADDR_SIZE);
} }

@ -1 +1 @@
Subproject commit cfe8f39cd436bf98e864775a9131e81e554e7bf1 Subproject commit dfdb4d2d766506e9f54dd2c69c5e664fe4e39304
Loading…
Cancel
Save