如何从签名邮件中恢复地址?
How to recover an address from the signed message?
我使用 Trust SDK 对消息和交易进行签名。
我恢复了这样的交易(Trust.signTransaction()
):
val tx = Geth.newTransactionFromRLP(Numeric.hexStringToByteArray(response.result))
其中 Geth
- 框架 (org.ethereum.geth),版本 1.8.11。
如何从签名消息 (Trust.signMessage()
) 中恢复数据(以及用户钱包的地址)?
Trust SDK 的开发者表示要查看'recovery'。但它是什么?框架?
非常感谢您。
我已经解决了问题。
1)需要使用这种方式:
signPersonalMessageCall = Trust.signPersonalMessage()
.message("my message to be signed")
.call(this)
2) 获取用户地址需要使用:
const val PERSONAL_MESSAGE_PREFIX = "\u0019Ethereum Signed Message:\n"
//...
fun recoverAddressFromSignature(message: String, signature: String): String? {
val prefix = PERSONAL_MESSAGE_PREFIX + message.length
val msgHash = Hash.sha3((prefix + message).toByteArray())
val signatureBytes = Numeric.hexStringToByteArray(signature)
var v = signatureBytes[64]
if (v < 27) {
v = (v + 27).toByte()
}
val sd = SignatureData(
v,
Arrays.copyOfRange(signatureBytes, 0, 32) as ByteArray,
Arrays.copyOfRange(signatureBytes, 32, 64) as ByteArray)
var addressRecovered: String? = null
// Iterate for each possible key to recover
for (i in 0..3) {
val publicKey = Sign.recoverFromSignature(
i,
ECDSASignature(BigInteger(1, sd.r), BigInteger(1, sd.s)),
msgHash)
if (publicKey != null) {
addressRecovered = "0x" + Keys.getAddress(publicKey)
Log.i(Core.APP_TAG, "*-*-* addressRecovered = $addressRecovered")
}
}
return addressRecovered
}
恢复的方法(在 Java)是从 here 抓取的。
这是我编写的实现,其工作方式与 JavaScript ethers.utils.verifyMessage(message, signature)
和 ethers.utils.recoverAddress(digest, signature)
方法完全相同。
EthersUtils.java
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import org.web3j.crypto.ECDSASignature;
import org.web3j.crypto.Hash;
import org.web3j.crypto.Keys;
import org.web3j.crypto.Sign;
import org.web3j.crypto.Sign.SignatureData;
import org.web3j.utils.Numeric;
public class EthersUtils {
private static final String MESSAGE_PREFIX = "\u0019Ethereum Signed Message:\n";
public static String verifyMessage(String message, String signature) {
return EthersUtils.recoverAddress(EthersUtils.hashMessage(message), signature);
}
public static String hashMessage(String message) {
return Hash.sha3(
Numeric.toHexStringNoPrefix(
(EthersUtils.MESSAGE_PREFIX + message.length() + message).getBytes(StandardCharsets.UTF_8)));
}
public static String recoverAddress(String digest, String signature) {
SignatureData signatureData = EthersUtils.getSignatureData(signature);
int header = 0;
for (byte b : signatureData.getV()) {
header = (header << 8) + (b & 0xFF);
}
if (header < 27 || header > 34) {
return null;
}
int recId = header - 27;
BigInteger key = Sign.recoverFromSignature(
recId,
new ECDSASignature(
new BigInteger(1, signatureData.getR()), new BigInteger(1, signatureData.getS())),
Numeric.hexStringToByteArray(digest));
if (key == null) {
return null;
}
return ("0x" + Keys.getAddress(key)).trim();
}
private static SignatureData getSignatureData(String signature) {
byte[] signatureBytes = Numeric.hexStringToByteArray(signature);
byte v = signatureBytes[64];
if (v < 27) {
v += 27;
}
byte[] r = (byte[]) Arrays.copyOfRange(signatureBytes, 0, 32);
byte[] s = (byte[]) Arrays.copyOfRange(signatureBytes, 32, 64);
return new SignatureData(v, r, s);
}
}
我使用 Trust SDK 对消息和交易进行签名。
我恢复了这样的交易(Trust.signTransaction()
):
val tx = Geth.newTransactionFromRLP(Numeric.hexStringToByteArray(response.result))
其中 Geth
- 框架 (org.ethereum.geth),版本 1.8.11。
如何从签名消息 (Trust.signMessage()
) 中恢复数据(以及用户钱包的地址)?
Trust SDK 的开发者表示要查看'recovery'。但它是什么?框架?
非常感谢您。
我已经解决了问题。
1)需要使用这种方式:
signPersonalMessageCall = Trust.signPersonalMessage()
.message("my message to be signed")
.call(this)
2) 获取用户地址需要使用:
const val PERSONAL_MESSAGE_PREFIX = "\u0019Ethereum Signed Message:\n"
//...
fun recoverAddressFromSignature(message: String, signature: String): String? {
val prefix = PERSONAL_MESSAGE_PREFIX + message.length
val msgHash = Hash.sha3((prefix + message).toByteArray())
val signatureBytes = Numeric.hexStringToByteArray(signature)
var v = signatureBytes[64]
if (v < 27) {
v = (v + 27).toByte()
}
val sd = SignatureData(
v,
Arrays.copyOfRange(signatureBytes, 0, 32) as ByteArray,
Arrays.copyOfRange(signatureBytes, 32, 64) as ByteArray)
var addressRecovered: String? = null
// Iterate for each possible key to recover
for (i in 0..3) {
val publicKey = Sign.recoverFromSignature(
i,
ECDSASignature(BigInteger(1, sd.r), BigInteger(1, sd.s)),
msgHash)
if (publicKey != null) {
addressRecovered = "0x" + Keys.getAddress(publicKey)
Log.i(Core.APP_TAG, "*-*-* addressRecovered = $addressRecovered")
}
}
return addressRecovered
}
恢复的方法(在 Java)是从 here 抓取的。
这是我编写的实现,其工作方式与 JavaScript ethers.utils.verifyMessage(message, signature)
和 ethers.utils.recoverAddress(digest, signature)
方法完全相同。
EthersUtils.java
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import org.web3j.crypto.ECDSASignature;
import org.web3j.crypto.Hash;
import org.web3j.crypto.Keys;
import org.web3j.crypto.Sign;
import org.web3j.crypto.Sign.SignatureData;
import org.web3j.utils.Numeric;
public class EthersUtils {
private static final String MESSAGE_PREFIX = "\u0019Ethereum Signed Message:\n";
public static String verifyMessage(String message, String signature) {
return EthersUtils.recoverAddress(EthersUtils.hashMessage(message), signature);
}
public static String hashMessage(String message) {
return Hash.sha3(
Numeric.toHexStringNoPrefix(
(EthersUtils.MESSAGE_PREFIX + message.length() + message).getBytes(StandardCharsets.UTF_8)));
}
public static String recoverAddress(String digest, String signature) {
SignatureData signatureData = EthersUtils.getSignatureData(signature);
int header = 0;
for (byte b : signatureData.getV()) {
header = (header << 8) + (b & 0xFF);
}
if (header < 27 || header > 34) {
return null;
}
int recId = header - 27;
BigInteger key = Sign.recoverFromSignature(
recId,
new ECDSASignature(
new BigInteger(1, signatureData.getR()), new BigInteger(1, signatureData.getS())),
Numeric.hexStringToByteArray(digest));
if (key == null) {
return null;
}
return ("0x" + Keys.getAddress(key)).trim();
}
private static SignatureData getSignatureData(String signature) {
byte[] signatureBytes = Numeric.hexStringToByteArray(signature);
byte v = signatureBytes[64];
if (v < 27) {
v += 27;
}
byte[] r = (byte[]) Arrays.copyOfRange(signatureBytes, 0, 32);
byte[] s = (byte[]) Arrays.copyOfRange(signatureBytes, 32, 64);
return new SignatureData(v, r, s);
}
}