Example #1
0
File: hmac.c Project: aido/picocoin
void hmac_sha256(const void *key_p, const uint32_t keylen, const void *msg_p, const uint32_t msglen, uint8_t *hmac)
{
	const uint8_t *key = key_p;
	const uint8_t *msg = msg_p;
	int i;
	uint8_t buf[SHA256_BLOCK_LENGTH], o_key_pad[SHA256_BLOCK_LENGTH], i_key_pad[SHA256_BLOCK_LENGTH];
	SHA256_CTX ctx;

	memset(buf, 0, SHA256_BLOCK_LENGTH);
	if (keylen > SHA256_BLOCK_LENGTH) {
		sha256_Raw(key, keylen, buf);
	} else {
		memcpy(buf, key, keylen);
	}

	for (i = 0; i < SHA256_BLOCK_LENGTH; i++) {
		o_key_pad[i] = buf[i] ^ 0x5c;
		i_key_pad[i] = buf[i] ^ 0x36;
	}

	sha256_Init(&ctx);
	sha256_Update(&ctx, i_key_pad, SHA256_BLOCK_LENGTH);
	sha256_Update(&ctx, msg, msglen);
	sha256_Final(buf, &ctx);

	sha256_Init(&ctx);
	sha256_Update(&ctx, o_key_pad, SHA256_BLOCK_LENGTH);
	sha256_Update(&ctx, buf, SHA256_DIGEST_LENGTH);
	sha256_Final(hmac, &ctx);
	MEMSET_BZERO(buf, sizeof(buf));
	MEMSET_BZERO(o_key_pad, sizeof(o_key_pad));
	MEMSET_BZERO(i_key_pad, sizeof(i_key_pad));
}
Example #2
0
void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, const HDNode *_root)
{
	inputs_count = _inputs_count;
	outputs_count = _outputs_count;
	coin = _coin;
	root = _root;

	idx1 = 0;
	to_spend = 0;
	spending = 0;
	change_spend = 0;
	memset(&input, 0, sizeof(TxInputType));
	memset(&resp, 0, sizeof(TxRequest));

	signing = true;

	multisig_fp_set = false;
	multisig_fp_mismatch = false;

	tx_init(&to, inputs_count, outputs_count, version, lock_time, false);
	sha256_Init(&tc);
	sha256_Update(&tc, (const uint8_t *)&inputs_count, sizeof(inputs_count));
	sha256_Update(&tc, (const uint8_t *)&outputs_count, sizeof(outputs_count));
	sha256_Update(&tc, (const uint8_t *)&version, sizeof(version));
	sha256_Update(&tc, (const uint8_t *)&lock_time, sizeof(lock_time));

	raw_tx_status = NOT_PARSING;

	send_req_1_input();
}
Example #3
0
void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen,
                         uint32_t *opad_digest, uint32_t *ipad_digest) {
  static CONFIDENTIAL uint32_t key_pad[SHA256_BLOCK_LENGTH / sizeof(uint32_t)];

  memzero(key_pad, sizeof(key_pad));
  if (keylen > SHA256_BLOCK_LENGTH) {
    static CONFIDENTIAL SHA256_CTX context;
    sha256_Init(&context);
    sha256_Update(&context, key, keylen);
    sha256_Final(&context, (uint8_t *)key_pad);
  } else {
    memcpy(key_pad, key, keylen);
  }

  /* compute o_key_pad and its digest */
  for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) {
    uint32_t data;
#if BYTE_ORDER == LITTLE_ENDIAN
    REVERSE32(key_pad[i], data);
#else
    data = key_pad[i];
#endif
    key_pad[i] = data ^ 0x5c5c5c5c;
  }
  sha256_Transform(sha256_initial_hash_value, key_pad, opad_digest);

  /* convert o_key_pad to i_key_pad and compute its digest */
  for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) {
    key_pad[i] = key_pad[i] ^ 0x5c5c5c5c ^ 0x36363636;
  }
  sha256_Transform(sha256_initial_hash_value, key_pad, ipad_digest);
  memzero(key_pad, sizeof(key_pad));
}
Example #4
0
void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac) {
  sha256_Final(&(hctx->ctx), hmac);
  sha256_Init(&(hctx->ctx));
  sha256_Update(&(hctx->ctx), hctx->o_key_pad, SHA256_BLOCK_LENGTH);
  sha256_Update(&(hctx->ctx), hmac, SHA256_DIGEST_LENGTH);
  sha256_Final(&(hctx->ctx), hmac);
  memzero(hctx, sizeof(HMAC_SHA256_CTX));
}
Example #5
0
void lisk_message_hash(const uint8_t *message, size_t message_len,
                       uint8_t hash[32]) {
  SHA256_CTX ctx;
  sha256_Init(&ctx);
  sha256_Update(&ctx, (const uint8_t *)"\x15" "Lisk Signed Message:\n", 22);
  uint8_t varint[5];
  uint32_t l = ser_length(message_len, varint);
  sha256_Update(&ctx, varint, l);
  sha256_Update(&ctx, message, message_len);
  sha256_Final(&ctx, hash);
  sha256_Raw(hash, 32, hash);
}
Example #6
0
logdb_log_db* logdb_new_internal()
{
    logdb_log_db* db;
    db = calloc(1, sizeof(*db));
    db->mem_mapper = NULL;
    db->cache_head = NULL;
    db->hashlen = kLOGDB_DEFAULT_HASH_LEN;
    db->version = kLOGDB_DEFAULT_VERSION;
    db->support_flags = 0; /* reserved for future changes */
    sha256_Init(&db->hashctx);

    return db;
}
Example #7
0
void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key,
                      const uint32_t keylen) {
  static CONFIDENTIAL uint8_t i_key_pad[SHA256_BLOCK_LENGTH];
  memzero(i_key_pad, SHA256_BLOCK_LENGTH);
  if (keylen > SHA256_BLOCK_LENGTH) {
    sha256_Raw(key, keylen, i_key_pad);
  } else {
    memcpy(i_key_pad, key, keylen);
  }
  for (int i = 0; i < SHA256_BLOCK_LENGTH; i++) {
    hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c;
    i_key_pad[i] ^= 0x36;
  }
  sha256_Init(&(hctx->ctx));
  sha256_Update(&(hctx->ctx), i_key_pad, SHA256_BLOCK_LENGTH);
  memzero(i_key_pad, sizeof(i_key_pad));
}
Example #8
0
/*
 * memory_firmware_hash() - SHA256 hash of firmware (meta and application)
 *
 * INPUT
 *     - hash: buffer to be filled with hash
 * OUTPUT
 *     none
 */
int memory_firmware_hash(uint8_t *hash)
{
#ifndef EMULATOR
    SHA256_CTX ctx;
    uint32_t codelen = *((uint32_t *)FLASH_META_CODELEN);

    if(codelen <= FLASH_APP_LEN)
    {
        sha256_Init(&ctx);
        sha256_Update(&ctx, (const uint8_t *)META_MAGIC_STR, META_MAGIC_SIZE);
        sha256_Update(&ctx, (const uint8_t *)FLASH_META_CODELEN,
                      FLASH_META_DESC_LEN - META_MAGIC_SIZE);
        sha256_Update(&ctx, (const uint8_t *)FLASH_APP_START, codelen);
        sha256_Final(&ctx, hash);
        return SHA256_DIGEST_LENGTH;
    }
    else
    {
        return 0;
    }
#else
    return 0;
#endif
}
Example #9
0
void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) {
  lisk_update_raw_tx(node, msg);

  if (msg->has_transaction) {
    SHA256_CTX ctx;
    sha256_Init(&ctx);

    switch (msg->transaction.type) {
      case LiskTransactionType_Transfer:
        layoutRequireConfirmTx(msg->transaction.recipient_id,
                               msg->transaction.amount);
        break;
      case LiskTransactionType_RegisterDelegate:
        layoutRequireConfirmDelegateRegistration(&msg->transaction.asset);
        break;
      case LiskTransactionType_CastVotes:
        layoutRequireConfirmCastVotes(&msg->transaction.asset);
        break;
      case LiskTransactionType_RegisterSecondPassphrase:
        layoutLiskPublicKey(msg->transaction.asset.signature.public_key.bytes);
        break;
      case LiskTransactionType_RegisterMultisignatureAccount:
        layoutRequireConfirmMultisig(&msg->transaction.asset);
        break;
      default:
        fsm_sendFailure(FailureType_Failure_DataError,
                        _("Invalid transaction type"));
        layoutHome();
        break;
    }
    if (!protectButton((msg->transaction.type ==
                                LiskTransactionType_RegisterSecondPassphrase
                            ? ButtonRequestType_ButtonRequest_PublicKey
                            : ButtonRequestType_ButtonRequest_SignTx),
                       false)) {
      fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled");
      layoutHome();
      return;
    }

    layoutRequireConfirmFee(msg->transaction.fee, msg->transaction.amount);
    if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
      fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled");
      layoutHome();
      return;
    }
    layoutProgressSwipe(_("Signing transaction"), 0);

    sha256_Update(&ctx, (const uint8_t *)&msg->transaction.type, 1);

    lisk_hashupdate_uint32(&ctx, msg->transaction.timestamp);

    sha256_Update(&ctx, msg->transaction.sender_public_key.bytes, 32);

    if (msg->transaction.has_requester_public_key) {
      sha256_Update(&ctx, msg->transaction.requester_public_key.bytes,
                    msg->transaction.requester_public_key.size);
    }

    uint64_t recipient_id = 0;
    if (msg->transaction.has_recipient_id &&
        msg->transaction.recipient_id[0] != 0) {
      // parse integer from lisk address ("123L" -> 123)
      for (size_t i = 0; i < strlen(msg->transaction.recipient_id) - 1; i++) {
        if (msg->transaction.recipient_id[i] < '0' ||
            msg->transaction.recipient_id[i] > '9') {
          fsm_sendFailure(FailureType_Failure_DataError,
                          _("Invalid recipient_id"));
          layoutHome();
          return;
        }
        recipient_id *= 10;
        recipient_id += (msg->transaction.recipient_id[i] - '0');
      }
    }
    lisk_hashupdate_uint64_be(&ctx, recipient_id);
    lisk_hashupdate_uint64_le(&ctx, msg->transaction.amount);

    lisk_hashupdate_asset(&ctx, msg->transaction.type, &msg->transaction.asset);

    // if signature exist calculate second signature
    if (msg->transaction.has_signature) {
      sha256_Update(&ctx, msg->transaction.signature.bytes,
                    msg->transaction.signature.size);
    }

    uint8_t hash[32];
    sha256_Final(&ctx, hash);
    ed25519_sign(hash, 32, node->private_key, &node->public_key[1],
                 resp->signature.bytes);

    resp->has_signature = true;
    resp->signature.size = 64;
  }
}
Example #10
0
void reset_entropy(const uint8_t *ext_entropy, uint32_t len)
{
    if(!awaiting_entropy)
    {
        fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Reset mode");
        return;
    }

    SHA256_CTX ctx;
    sha256_Init(&ctx);
    sha256_Update(&ctx, int_entropy, 32);
    sha256_Update(&ctx, ext_entropy, len);
    sha256_Final(int_entropy, &ctx);

    const char *temp_mnemonic = mnemonic_from_data(int_entropy, strength / 8);

    memset(int_entropy, 0, 32);
    awaiting_entropy = false;

    /*
     * Format mnemonic for user review
     */
    uint32_t word_count = 0, current_page = 0, page_count;
    char *tok;
    char tokened_mnemonic[TOKENED_MNEMONIC_BUF];
    char mnemonic_by_screen[MAX_PAGES][MNEMONIC_BY_SCREEN_BUF];
    char formatted_mnemonic[MAX_PAGES][FORMATTED_MNEMONIC_BUF];
    char mnemonic_display[FORMATTED_MNEMONIC_BUF];
    char formatted_word[MAX_WORD_LEN + ADDITIONAL_WORD_PAD];

    strlcpy(tokened_mnemonic, temp_mnemonic, TOKENED_MNEMONIC_BUF);

    tok = strtok(tokened_mnemonic, " ");

    while(tok)
    {
        snprintf(formatted_word, MAX_WORD_LEN + ADDITIONAL_WORD_PAD, "%lu.%s",
                 (unsigned long)(word_count + 1), tok);

        /* Check that we have enough room on display to show word */
        snprintf(mnemonic_display, FORMATTED_MNEMONIC_BUF, "%s   %s",
                 formatted_mnemonic[current_page], formatted_word);

        if(calc_str_line(get_body_font(), mnemonic_display, BODY_WIDTH) > 3)
        {
            page_count++;
            current_page++;

            snprintf(mnemonic_display, FORMATTED_MNEMONIC_BUF, "%s   %s",
                 formatted_mnemonic[current_page], formatted_word);
        }


        strlcpy(formatted_mnemonic[current_page], mnemonic_display,
                FORMATTED_MNEMONIC_BUF);

        /* Save mnemonic for each screen */
        if(strlen(mnemonic_by_screen[current_page]) == 0)
        {
            strlcpy(mnemonic_by_screen[current_page], tok, MNEMONIC_BY_SCREEN_BUF);
        }
        else
        {
            strlcat(mnemonic_by_screen[current_page], " ", MNEMONIC_BY_SCREEN_BUF);
            strlcat(mnemonic_by_screen[current_page], tok, MNEMONIC_BY_SCREEN_BUF);
        }

        tok = strtok(NULL, " ");
        word_count++;
    }

    /* Have user confirm mnemonic is sets of 12 words */
    for(page_count = current_page + 1, current_page = 0; current_page < page_count; current_page++)
    {
        char title[MEDIUM_STR_BUF] = "Recovery Sentence";

        /* make current screen mnemonic available via debuglink */
        strlcpy(current_words, mnemonic_by_screen[current_page], MNEMONIC_BY_SCREEN_BUF);

        if(page_count > 1)
        {
            /* snprintf: 20 + 10 (%d) + 1 (NULL) = 31 */
            snprintf(title, MEDIUM_STR_BUF, "Recovery Sentence %lu/%lu", current_page + 1, page_count);
        }

        if(!confirm(ButtonRequestType_ButtonRequest_ConfirmWord, title, "%s",
                    formatted_mnemonic[current_page]))
        {
            fsm_sendFailure(FailureType_Failure_ActionCancelled, "Reset cancelled");
            storage_reset();
            go_home();
            return;
        }
    }

    /* Save mnemonic */
    storage_set_mnemonic(temp_mnemonic);
    storage_commit();

    fsm_sendSuccess("Device reset");
    go_home();
}
Example #11
0
void signing_txack(TransactionType *tx)
{
	if (!signing) {
		fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Signing mode");
		go_home();
		return;
	}

	int co;
	memset(&resp, 0, sizeof(TxRequest));

	switch (signing_stage) {
		case STAGE_REQUEST_1_INPUT:
			/* compute multisig fingerprint */
			/* (if all input share the same fingerprint, outputs having the same fingerprint will be considered as change outputs) */
			if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG) {
				if (tx->inputs[0].has_multisig && !multisig_fp_mismatch) {
					if (multisig_fp_set) {
						uint8_t h[32];
						if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), h) == 0) {
							fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint");
							signing_abort();
							return;
						}
						if (memcmp(multisig_fp, h, 32) != 0) {
							multisig_fp_mismatch = true;
						}
					} else {
						if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), multisig_fp) == 0) {
							fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint");
							signing_abort();
							return;
						}
						multisig_fp_set = true;
					}
				}
			} else { // InputScriptType_SPENDADDRESS
				multisig_fp_mismatch = true;
			}
			sha256_Update(&tc, (const uint8_t *)tx->inputs, sizeof(TxInputType));
			memcpy(&input, tx->inputs, sizeof(TxInputType));
			send_req_2_prev_meta();
			return;
		case STAGE_REQUEST_2_PREV_META:
			tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, false);
			idx2 = 0;
			send_req_2_prev_input();
			return;
		case STAGE_REQUEST_2_PREV_INPUT:
			if (!tx_serialize_input_hash(&tp, tx->inputs)) {
				fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input");
				signing_abort();
				return;
			}
			if (idx2 < tp.inputs_len - 1) {
				idx2++;
				send_req_2_prev_input();
			} else {
				idx2 = 0;
				send_req_2_prev_output();
			}
			return;
		case STAGE_REQUEST_2_PREV_OUTPUT:
			if (!tx_serialize_output_hash(&tp, tx->bin_outputs)) {
				fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output");
				signing_abort();
				return;
			}
			if (idx2 == input.prev_index) {
				to_spend += tx->bin_outputs[0].amount;
			}
			if (idx2 < tp.outputs_len - 1) {
				/* Check prevtx of next input */
				idx2++;
				send_req_2_prev_output();
			} else {
				/* Check next output */
				tx_hash_final(&tp, hash, true);
				if (memcmp(hash, input.prev_hash.bytes, 32) != 0) {
					fsm_sendFailure(FailureType_Failure_Other, "Encountered invalid prevhash");
					signing_abort();
					return;
				}
				if (idx1 < inputs_count - 1) {
					idx1++;
					send_req_1_input();
				} else {
					idx1 = 0;
					send_req_3_output();
				}
			}
			return;
		case STAGE_REQUEST_3_OUTPUT:
		{
			/* Downloaded output idx1 the first time.
			 *  Add it to transaction check
			 *  Ask for permission.
			 */
			bool is_change = false;

			if (tx->outputs[0].script_type == OutputScriptType_PAYTOMULTISIG &&
			    tx->outputs[0].has_multisig &&
			    multisig_fp_set && !multisig_fp_mismatch) {
				uint8_t h[32];
				if (cryptoMultisigFingerprint(&(tx->outputs[0].multisig), h) == 0) {
					fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint");
					signing_abort();
					return;
				}
				if (memcmp(multisig_fp, h, 32) == 0) {
					is_change = true;
				}
                        } else {
                            if(tx->outputs[0].has_address_type) {
                                if(check_valid_output_address(tx->outputs) == false) {
                                    fsm_sendFailure(FailureType_Failure_Other, "Invalid output address type");
                                    signing_abort();
                                    return;
                                }

                                if(tx->outputs[0].script_type == OutputScriptType_PAYTOADDRESS &&
                                        tx->outputs[0].address_n_count > 0 &&
                                        tx->outputs[0].address_type == OutputAddressType_CHANGE) {
                                    is_change = true;
                                }
                            }
                            else if(tx->outputs[0].script_type == OutputScriptType_PAYTOADDRESS &&
                                    tx->outputs[0].address_n_count > 0) {
                                is_change = true;
                            }
                        }

			if (is_change) {
				if (change_spend == 0) { // not set
					change_spend = tx->outputs[0].amount;
				} else {
					fsm_sendFailure(FailureType_Failure_Other, "Only one change output allowed");
					signing_abort();
					return;
			    }
			}

			spending += tx->outputs[0].amount;
			co = compile_output(coin, root, tx->outputs, &bin_output, !is_change);

			if (co < 0) {
				fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user");
				signing_abort();
				return;
			} else if (co == 0) {
				fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output");
				signing_abort();
				return;
			}
			sha256_Update(&tc, (const uint8_t *)&bin_output, sizeof(TxOutputBinType));
			if (idx1 < outputs_count - 1) {
				idx1++;
				send_req_3_output();
			} else {
                            sha256_Final(hash_check, &tc);
                            // check fees
                            if (spending > to_spend) {
                                fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds");
		                        signing_abort();
                                return;
                            }
                            uint64_t fee = to_spend - spending;
                            uint32_t tx_est_size = transactionEstimateSizeKb(inputs_count, outputs_count);
                            char total_amount_str[32];
		            char fee_str[32];

		            coin_amnt_to_str(coin, fee, fee_str, sizeof(fee_str));

                            if(fee > (uint64_t)tx_est_size * coin->maxfee_kb) {
			        if (!confirm(ButtonRequestType_ButtonRequest_FeeOverThreshold,
		                        "Confirm Fee", "%s", fee_str)) {
		                    fsm_sendFailure(FailureType_Failure_ActionCancelled, "Fee over threshold. Signing cancelled.");
		                    signing_abort();
		                    return;
		                }

                            }
                            // last confirmation
                            coin_amnt_to_str(coin, to_spend - change_spend, total_amount_str, sizeof(total_amount_str));

		            if(!confirm_transaction(total_amount_str, fee_str))
		            {
		                fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user");
		                signing_abort();
		                return;
		            }
		            // Everything was checked, now phase 2 begins and the transaction is signed.
		            layout_simple_message("Signing Transaction...");

			    idx1 = 0;
			    idx2 = 0;
			    send_req_4_input();
			}
			return;
		}
		case STAGE_REQUEST_4_INPUT:
			if (idx2 == 0) {
				tx_init(&ti, inputs_count, outputs_count, version, lock_time, true);
				sha256_Init(&tc);
				sha256_Update(&tc, (const uint8_t *)&inputs_count, sizeof(inputs_count));
				sha256_Update(&tc, (const uint8_t *)&outputs_count, sizeof(outputs_count));
				sha256_Update(&tc, (const uint8_t *)&version, sizeof(version));
				sha256_Update(&tc, (const uint8_t *)&lock_time, sizeof(lock_time));
				memset(privkey, 0, 32);
				memset(pubkey, 0, 33);
			}
			sha256_Update(&tc, (const uint8_t *)tx->inputs, sizeof(TxInputType));
			if (idx2 == idx1) {
				memcpy(&input, tx->inputs, sizeof(TxInputType));
				memcpy(&node, root, sizeof(HDNode));
				if (hdnode_private_ckd_cached(&node, tx->inputs[0].address_n, tx->inputs[0].address_n_count) == 0) {
					fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key");
					signing_abort();
					return;
				}
				if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG) {
					if (!tx->inputs[0].has_multisig) {
						fsm_sendFailure(FailureType_Failure_Other, "Multisig info not provided");
						signing_abort();
						return;
					}
					tx->inputs[0].script_sig.size = compile_script_multisig(&(tx->inputs[0].multisig), tx->inputs[0].script_sig.bytes);
				} else { // SPENDADDRESS
					ecdsa_get_pubkeyhash(node.public_key, hash);
					tx->inputs[0].script_sig.size = compile_script_sig(coin->address_type, hash, tx->inputs[0].script_sig.bytes);
				}
				if (tx->inputs[0].script_sig.size == 0) {
					fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input");
					signing_abort();
					return;
				}
				memcpy(privkey, node.private_key, 32);
				memcpy(pubkey, node.public_key, 33);
			} else {
				tx->inputs[0].script_sig.size = 0;
			}
			if (!tx_serialize_input_hash(&ti, tx->inputs)) {
				fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input");
				signing_abort();
				return;
			}
			if (idx2 < inputs_count - 1) {
				idx2++;
				send_req_4_input();
			} else {
				idx2 = 0;
				send_req_4_output();
			}
			return;
		case STAGE_REQUEST_4_OUTPUT:
			co = compile_output(coin, root, tx->outputs, &bin_output, false);
			if (co < 0) {
				fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user");
				signing_abort();
				return;
			} else if (co == 0) {
				fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output");
				signing_abort();
				return;
			}
			sha256_Update(&tc, (const uint8_t *)&bin_output, sizeof(TxOutputBinType));
			if (!tx_serialize_output_hash(&ti, &bin_output)) {
				fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output");
				signing_abort();
				return;
			}
			if (idx2 < outputs_count - 1) {
				idx2++;
				send_req_4_output();
			} else {
				sha256_Final(hash, &tc);
				if (memcmp(hash, hash_check, 32) != 0) {
					fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing");
					signing_abort();
					return;
				}
				tx_hash_final(&ti, hash, false);
				resp.has_serialized = true;
				resp.serialized.has_signature_index = true;
				resp.serialized.signature_index = idx1;
				resp.serialized.has_signature = true;
				resp.serialized.has_serialized_tx = true;
				ecdsa_sign_digest(&secp256k1, privkey, hash, sig, 0);
				resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes);
				if (input.script_type == InputScriptType_SPENDMULTISIG) {
					if (!input.has_multisig) {
						fsm_sendFailure(FailureType_Failure_Other, "Multisig info not provided");
						signing_abort();
						return;
					}
					// fill in the signature
					int pubkey_idx = cryptoMultisigPubkeyIndex(&(input.multisig), pubkey);
					if (pubkey_idx < 0) {
						fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script");
						signing_abort();
						return;
					}
					memcpy(input.multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size);
					input.multisig.signatures[pubkey_idx].size = resp.serialized.signature.size;
					input.script_sig.size = serialize_script_multisig(&(input.multisig), input.script_sig.bytes);
					if (input.script_sig.size == 0) {
						fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize multisig script");
						signing_abort();
						return;
					}
				} else { // SPENDADDRESS
					input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, input.script_sig.bytes);
				}
				resp.serialized.serialized_tx.size = tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes);

				if (idx1 < inputs_count - 1) {
					idx1++;
					idx2 = 0;
					send_req_4_input();
				} else {
					idx1 = 0;
					send_req_5_output();
				}
			}
			return;
		case STAGE_REQUEST_5_OUTPUT:
			if (compile_output(coin, root, tx->outputs, &bin_output,false) <= 0) {
				fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output");
				signing_abort();
				return;
			}
			resp.has_serialized = true;
			resp.serialized.has_serialized_tx = true;
			resp.serialized.serialized_tx.size = tx_serialize_output(&to, &bin_output, resp.serialized.serialized_tx.bytes);
			if (idx1 < outputs_count - 1) {
				idx1++;
				send_req_5_output();
			} else {
				send_req_finished();
				signing_abort();
			}
			return;
	}

	fsm_sendFailure(FailureType_Failure_Other, "Signing error");
	signing_abort();
}
Example #12
0
void reset_entropy(const uint8_t *ext_entropy, uint32_t len)
{
    if (!awaiting_entropy) {
        fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Reset mode");
        return;
    }
    SHA256_CTX ctx;
    sha256_Init(&ctx);
    sha256_Update(&ctx, int_entropy, 32);
    sha256_Update(&ctx, ext_entropy, len);
    sha256_Final(int_entropy, &ctx);
    strlcpy(storage.mnemonic, mnemonic_from_data(int_entropy, strength / 8), sizeof(storage.mnemonic));
    memset(int_entropy, 0, 32);
    awaiting_entropy = false;

    int pass, word_pos, i = 0, j;

    for (pass = 0; pass < 2; pass++) {
        i = 0;
        for (word_pos = 1; word_pos <= (int)strength/32*3; word_pos++) {
            // copy current_word
            j = 0;
            while (storage.mnemonic[i] != ' ' && storage.mnemonic[i] != 0 && j + 1 < (int)sizeof(current_word)) {
                current_word[j] = storage.mnemonic[i];
                i++;
                j++;
            }
            current_word[j] = 0;
            if (storage.mnemonic[i] != 0) i++;
            char desc[] = "##th word is:";
            if (word_pos < 10) {
                desc[0] = ' ';
            } else {
                desc[0] = '0' + word_pos / 10;
            }
            desc[1] = '0' + word_pos % 10;
            if (word_pos == 1 || word_pos == 21) {
                desc[2] = 's';
                desc[3] = 't';
            } else if (word_pos == 2 || word_pos == 22) {
                desc[2] = 'n';
                desc[3] = 'd';
            } else if (word_pos == 3 || word_pos == 23) {
                desc[2] = 'r';
                desc[3] = 'd';
            }
            if (word_pos == (int)strength/32*3) { // last word
                if (pass == 1) {
                    layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Finish", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL);
                } else {
                    layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Again", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL);
                }
            } else {
                if (pass == 1) {
                    layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL);
                } else {
                    layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL);
                }
            }
            if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) {
                storage_reset();
                layoutHome();
                return;
            }
        }
    }

    storage.has_mnemonic = true;
    storage_commit();
    fsm_sendSuccess("Device reset");
    layoutHome();
}