+

web3登录签名实现

签名验证

Posted by Coozw on 2022-08-30
Words 650 and Reading Time 3 Minutes
Viewed Times

区块链登录签名验证

Vue端实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const EtheremUtil = require("ethereumjs-util");
import Web3 from "web3";
var sourceData = ""; // 签名的消息体
var privateKey = ""; // 区块链私钥
/* 根据私钥推导出公钥和地址 */
var publicKey = EtheremUtil.privateToPublic(
new Buffer(this.privateKey, "hex")
);
console.log(publicKey)
var address = "0x" + EtheremUtil.publicToAddress(publicKey).toString("hex");
console.log(address)

var paramSha3 = Web3.utils.sha3(sourceData, {encoding: 'hex'});
var privateBuffer = Buffer.from(this.privateKey, "hex");
var ecsign = EtheremUtil.ecsign(Buffer.from(Web3.utils.hexToBytes(paramSha3)), privateBuffer);
console.log("R", EtheremUtil.bufferToHex(ecsign.r));
console.log("S", EtheremUtil.bufferToHex(ecsign.s));
console.log("V", EtheremUtil.bufferToHex(ecsign.v));
var sign = EtheremUtil.bufferToHex(ecsign.r) + EtheremUtil.bufferToHex(ecsign.s) + EtheremUtil.bufferToHex(ecsign.v);
sign = sign.replace(new RegExp("0x", "gm"), '');
console.log(sign);

Java端实现验签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
    String signData = jo.getJSONArray("sign").getString(jo.getJSONArray("sign").size() - 1);
// 客户端传过来的key
String pubKK = Web3EcRecovHelper.VerifySigner(signData, paramHash);
String publicKeyNoPrefix = pubKK;
if (publicKeyNoPrefix.startsWith("0x")) {
publicKeyNoPrefix = publicKeyNoPrefix.replaceAll("0x", "");
}
String hash = Hash.sha3(publicKeyNoPrefix);
addUid = hash.substring(hash.length() - 40);
public static String getParamsHash(String strBody) throws UnsupportedEncodingException {
String hexStrBody = Numeric.toHexString(strBody.getBytes("utf-8"));
String paramHash = Hash.sha3(hexStrBody);
return paramHash;
}

public static String VerifySigner(String rsv, String messageHash) throws Exception {
try {

if (rsv.startsWith("0x")) {
rsv = rsv.replace("0x", "");
}

if (rsv == null || rsv.length() != 130) {
throw new Exception("数据无效或被篡改!");
}
ECDSASignature sig = new ECDSASignature(
Numeric.toBigInt(rsv.substring(0, 64)),
Numeric.toBigInt(rsv.substring(64, 128)));

int v = Numeric.toBigInt("0x" + rsv.substring(128)).intValue() - 27;
BigInteger k = Sign.recoverFromSignature(v, sig, Numeric.hexStringToByteArray(messageHash));
// strings.add(k.toString(16));
return k.toString(16);

} catch (Exception e) {
throw new Exception("数据无效或被篡改!");
}
}

PHP端实现验签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
依赖
php-ecrecover
web3.pnp
require './php-sdk/web3p/autoload.php';
require './php-sdk/php-ecrecover/autoload.php';
require_once './php-sdk/php-ecrecover/CryptoCurrencyPHP/Signature.class.php';
require_once './php-sdk/php-ecrecover/CryptoCurrencyPHP/SECp256k1.class.php';
require_once './php-sdk/php-ecrecover/CryptoCurrencyPHP/PointMathGMP.class.php';

use kornrunner\Keccak;
use Signature;
use Think\Controller;
use Web3\Utils;
$web3Utils = new Utils();
// $hexStrBody = $web3Utils::toHex($msg);
$paramHash = $web3Utils::sha3($msg);
// $arr['code'] = 0;
// $arr['msg'] = $paramHash;
// $this->ajaxReturn($arr, "json");
// 解析出区块链地址
$addUid = $this->VerifySigner('0x' . $sign, $paramHash);
private function VerifySigner($signed, $hex)
{
$rHex = substr($signed, 2, 64);
$sHex = substr($signed, 66, 64);
$vValue = hexdec(substr($signed, 130, 2));
$messageHex = substr($hex, 2);
$messageByteArray = unpack('C*', hex2bin($messageHex));
$messageGmp = gmp_init("0x" . $messageHex);
$r = $rHex; //hex string without 0x
$s = $sHex; //hex string without 0x
$v = $vValue; //27 or 28

//with hex2bin it gives the same byte array as the javascript
$rByteArray = unpack('C*', hex2bin($r));
$sByteArray = unpack('C*', hex2bin($s));
$rGmp = gmp_init("0x" . $r);
$sGmp = gmp_init("0x" . $s);

if ($v != 27 && $v != 28) {
$v += 27;
}

$recovery = $v - 27;
if ($recovery !== 0 && $recovery !== 1) {
throw new Exception('Invalid signature v value');
}

$publicKey = Signature::recoverPublicKey($rGmp, $sGmp, $messageGmp, $recovery);
$publicKeyString = $publicKey["x"] . $publicKey["y"];

return '0x' . substr($this->keccak256(hex2bin($publicKeyString)), -40);

}

...

...

00:00
00:00