- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我尝试使用 PHP 制作应用程序,为某些文档创建 ECDSA 签名,并使用 Golang 应用程序验证该签名。
我使用由 openssl 工具生成的私钥。它是 prime256v1 曲线 key 。使用命令创建:
openssl ecparam -name prime256v1 -genkey -noout -out prime256v1-key.pem
在 PHP 中,我使用 openssl_sign 函数创建签名。
我用 Golang 验证签名的所有尝试都失败了。在 Golang 中使用 crypto/ecdsa、crypto/elliptic 包。
这是我的代码。
PHP
<?php
$stringtosign = "my test string to sign";
// Privcate key was geerated with openssl tool with the command
// openssl ecparam -name prime256v1 -genkey -noout -out prime256v1-key.pem
$cert = file_get_contents('prime256v1-key.pem');
$prkey = openssl_pkey_get_private($cert);
// we sign only hashes, because Golang lib can wok with hashes only
$stringtosign = md5($stringtosign);
// we generate 64 length signature (r and s 32 bytes length)
while(1) {
openssl_sign($stringtosign, $signature, $prkey, OPENSSL_ALGO_SHA256);
$rlen = ord(substr($signature,3,1));
$slen = ord(substr($signature,5+$rlen,1));
if ($slen != 32 || $rlen != 32) {
// try other signature if length is not 32 for both parts
continue;
}
$r = substr($signature,4,$rlen);
$s = substr($signature,6+$rlen,$slen);
$signature = $r.$s;
break;
}
openssl_free_key($prkey);
$signature = bin2hex($signature);
echo $signature."\n";
语言
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"math/big"
"crypto/x509"
"encoding/pem"
)
func main() {
stringtosign := "my test string to sign"
// This is outpur of PHP app. Signature generated by PHP openssl_sign
signature := "18d5c1d044a4a752ad91bc06499c72a590b2842b3d3b4c4b1086bfd0eea3e7eb5c06b77e15542e5ba944f3a1a613c24eabaefa4e2b2251bd8c9355bba4d14640"
// NOTE . Error verificaion is skipped here
// Privcate key was geerated with openssl tool with the command
// openssl ecparam -name prime256v1 -genkey -noout -out prime256v1-key.pem
prikeybytes, _ := ioutil.ReadFile("prime256v1-key.pem")
p, _ := pem.Decode(prikeybytes)
prikey, _ := x509.ParseECPrivateKey(p.Bytes)
signatureBytes, _ := hex.DecodeString(signature)
// make MD5 hash
h := md5.New()
io.WriteString(h, stringtosign)
data := h.Sum(nil)
// build key and verify data
r := big.Int{}
s := big.Int{}
// make signature numbers
sigLen := len(signatureBytes)
r.SetBytes(signatureBytes[:(sigLen / 2)])
s.SetBytes(signatureBytes[(sigLen / 2):])
curve := elliptic.P256()
// make public key from private key
x := big.Int{}
y := big.Int{}
x.SetBytes(prikey.PublicKey.X.Bytes())
y.SetBytes(prikey.PublicKey.Y.Bytes())
rawPubKey := ecdsa.PublicKey{Curve: curve, X: &x, Y: &y}
v := ecdsa.Verify(&rawPubKey, data, &r, &s)
if v {
fmt.Println("Success verify!")
return
}
fmt.Println(fmt.Sprintf("Signatire doed not match"))
}
我做错了什么?任何人都可以向我展示 Golang 验证用 PHP 创建的签名的工作示例吗?
我尝试在 openssl_sign 中使用不同版本而不是 OPENSSL_ALGO_SHA256 。试过 OPENSSL_ALGO_SHA1、OPENSSL_ALGO_SHA512
最佳答案
您的代码的问题似乎是,您在使用 OPENSSL_ALGO_SHA256
对其进行签名之前使用 MD5 对 PHP 中的字符串进行哈希处理,这会再次对您签名的内容(MD5 哈希)进行哈希处理,而在您的 Go 中程序,你只有这两个哈希中的第一个。要解决此问题,我将删除 PHP 代码中的 MD5
步骤,并将代码中的 h := md5.New()
行替换为您的签名使用的哈希算法(h := sha256.New()
在你的例子中)。
为了详细说明这些签名函数的作用,我首先想将签名和验证分解为以下步骤:
现在调用openssl_sign
在您的 PHP 代码中,执行所有签名步骤,同时调用 ecdsa.Verify
在 Go 中,只执行验证过程的第二步和第三步。这就是为什么它将散列作为第二个参数的原因。因此要验证签名,您必须自己实现第一个验证步骤,即生成哈希。
您在签名和验证时必须使用相同的哈希算法,因此您必须在您的 Go 代码中使用 SHA256 而不是 MD5(因为您使用 OPENSSL_ALGO_SHA256
签名),否则哈希值(通常)不匹配。
此外,我建议不要将 MD5 用于签名,因为它不再被认为是抗冲突的(哈希冲突是,当您有 2 个不同的字符串/文件/...具有相同的哈希值时)。有关更多详细信息,您可以查看 Wikipedia article on MD5 ,特别是“碰撞漏洞”部分。这是一个问题,因为具有相同 MD5 哈希的 2 条消息也将具有相同的签名,并且攻击者可以使用为其中一个字符串生成的签名来欺骗您认为另一个字符串已签名(因此信任它)。
此外,ecdsa.PrivateKey
可以给你对应的公钥,你可以调用ecdsa.Verify
像这样:
ecdsa.Verify(&prikey.PublicKey, data, &r, &s)
这为您省去了将所有数据从私钥复制到新对象的麻烦。
关于PHP 创建 ECDSA 签名并使用 Golang 验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52255715/
我得到了这个printHashKey函数,它运行良好。 fun printHashKey() { try { val info : PackageInfo = packageM
如何使用正确的签名 key 为我的 Android 应用包签名? 最佳答案 我尝试在此处和 this question 中使用多个答案, 但不知何故我收到了这个错误,因为我的 android/app/
我的 gradle 文件中有这个: android { signingConfigs { mySigningConfig { keyAlias 'the
请至少选择一个签名版本以在 Android Studio 2.3 中使用 现在在 Android Studio 中生成一个签名的 APK 时,它显示了两个选项(复选框),即 1. V1(Jar 签名)
我想表示一些标量值(例如整数或字符串)通过它的实际值或一些 NA 值,然后存储它们在集合中(例如列表)。目的是处理缺失值。 为此,我实现了一个签名 module type Scalar = sig
为什么这不完全有效? sum :: (Num a, Num b) => a -> b -> c sum a b = a + b 当然,错误消息与签名有关,但我仍然不明白原因。 Couldn't mat
谢谢帮助,我的问题是关于从下面的代码中收到的 ax 值? mov al,22h mov cl,0fdh imul cl 真机结果:ff9a 我的预期:00:9a(通过二进制相乘) 第一个数字是 22h
我有一个注释: import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.
我从对物体的思考中得出了一个术语。当我们扩展一个类时,扩展类将具有与父类相同的签名,因此术语 IS-A 来自...示例 class Foo{ } class Foo2 extends Foo{ } c
我需要在有符号整数和它们作为字节序列的内部表示之间进行转换。在 C 中,我使用的函数如下: unsigned char hibyte(unsigned short i) {return i>>8;}
我正在尝试使用给定的 RSA 参数对一些数据进行签名。 我给出了模数、指数、D、DP、DQ、P、Q 和 InverseQ。什么库或方法最容易使用来计算此签名。在 C# 中,一旦您提供参数,它们就会有一
这些签名之间有什么区别? T * f(T & identifier); T & f(T & identifier); T f(T & identifier); void f(T * identifie
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: Where and why do I have to put the “template” and “typ
我有一个签名,我需要在签名旁边添加图片。但我不确定 css 的确切程度和内容。目前它显示在文字下方,我应该把图片放在哪里?在相同的 tr 或 td 中?
查看 LinkedHashMap 的 JDK 源代码,我注意到这个类被声明为: public class LinkedHashMap extends HashMap im
背景:我继承了一个基于 linux 的嵌入式系统,其中包含一个 SMTP 代理和一些我不得不忍受的古怪限制。它位于 SMTP 客户端和服务器之间。当 SMTP 客户端连接时,代理会打开与服务器的连接,
这是 C++17 形式的规则 ([basic.lval]/8),但它在其他标准中看起来很相似(在 C++98 中是“lvalue”而不是“glvalue”): 8 If a program attem
我有一个注释: import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.
我即将开展一个项目,希望使用电子签名板使用 C# 捕获客户的签名、在设备上显示文本等。 现在,在我开始做进一步的研究之前,我想向你们征求一些意见/建议,我应该使用哪些设备.. 我现在的要求非常笼统:我
呢喃自己在心中开始扩张地盘,仿佛制式地广播了三次。 漾起的涟绮,用谈不上精腻的手段。 拒绝天亮,却又贪恋着贪恋多情的日光。 川流不息的画面是他们,而我的落幕停在右脚,它渴望着下台,而我只剩自言
我是一名优秀的程序员,十分优秀!