○ 介绍
签名延展性指的是:网络中的任何中继节点,不需要获取对应交易的私钥, 而修改该交易签名的能力。而ECDSA自身的签名延展性是指其自身具有延展性,因为内部S的负值不会使签名无效。这意味着如果在签名中没有加入限制条件,攻击者可以为相同的数据创建第二有效的签名,从而发生“双花”。
● 原理
ECDSA 签名由r与s两部分组成,两者都是256-bit数字,在ssecp256k1(y2 = x3 + 7(mod p))曲线上(其中 p 是一个非常大的素数),两者都是256-bit数字。这通常表示为元组 [r, s]。
在签署交易时,我们会创建一个随机的临时私钥以包含在签名中。然后,使用这个临时私钥点在 Secp256k1 椭圆曲线上生成一个对应的点 P,将该公钥点的 X 坐标用作我们的 r 值,而s = (z+re)/k。但椭圆曲线上实际上有两个点具有此 X 值:P1 和 P2。
○ 实例
本实例来自Mr Steal Yo Crypto CTF
链接:
https://mrstealyocrypto.xyz/malleable/index.html
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract TreasureVault {
bytes32 public immutable DOMAIN_SEPARATOR;
bytes32 public constant TYPEHASH = keccak256("SendFundsWithAuth(uint256 amount,uint256 nonce)");
mapping(bytes32 => bool) usedHash;
address public immutable owner;
constructor() {
owner = msg.sender;
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
),
keccak256(bytes("TreasureVault")),
keccak256(bytes("1")),
getChainid(),
address(this)
)
);
}
receive() external payable {}
function sendFundsWithAuth(
uint256 amount,
uint256 nonce,
uint8 v,
bytes32 r,
bytes32 s
) external {
require(tx.origin == msg.sender,'EOA');
bytes32 structHash = keccak256(abi.encode(TYPEHASH, amount, nonce));
bytes32 digest = keccak256(abi.encodePacked("x19x01", DOMAIN_SEPARATOR, structHash));
address signatory = ecrecover(digest, v, r, s);
require(signatory == owner,'invalid sig');
bytes32 signatureHash = keccak256(abi.encodePacked(v, r, s));
require(!usedHash[signatureHash],'sig reuse');
usedHash[signatureHash]=true;
(bool success,) = payable(msg.sender).call{value:amount}('');
require(success);
}
function removeFunds() external {
require(msg.sender == owner,'invalid caller');
(bool success,) = payable(msg.sender).call{value:address(this).balance}('');
require(success);
}
function getChainid() public view returns (uint256) {
return block.chainid;
}
}
在此合约中,调用方可以指定其签名的 v、r 和 s 值,以验证自己是所有者并转移资金。但是由于ECDSA 签名的内在延展性,因此攻击者可以修改s = bytes32
( uint256(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141) – uint256(s) );
并使用对应的v,从而将相同的金额转移给自己。
● 引用说明
引用链接:
https://www.derpturkey.com/inherent-malleability-of-ecdsa-signatures/
作者:于文杰
编辑:舒婷
原文始发于微信公众号(ChainSecLabs):由ECDSA签名延展性产生的重放