Go 关于VerifyPKCS1v15(base64和rsa检查)

Go 关于VerifyPKCS1v15(base64和rsa检查),go,base64,rsa,Go,Base64,Rsa,给定“通知”、“公钥”和“签名”,它无法通过go中的验证PKCS1V15。那是mycode,有什么问题吗 package main import (

给定“通知”、“公钥”和“签名”,它无法通过go中的验证PKCS1V15。那是mycode,有什么问题吗

  package main
    import (                                                                                                                                                                     
        "crypto"
        "crypto/sha1"
        "crypto/rsa"
        "crypto/x509"
        "encoding/base64"
        "encoding/pem"
        "fmt"
    )
    func main() {
        notify := `YFSGlJTpNYakrZuZqZ55dcA5mVUb/JQBr3hdDjODsAVSdoVVytIagk9Wt0CD/uX+7jGL9pqev8/u0I0ZBKEmz5huXp8TdZSnskCZ7GTeHNW0VPJcW8OcBxAValA0jQSv2mBP+tc1r6mdvf66GEzhvgBfTnp3Sp7V3dijJ9bNstIDyrGm/BlByhcMr3UqXjTFJaui6t5TxvZhCuSV9sg+xVVA+sR3uFI78b5lKomg5Vu31EBZvXASlFfaOc4StltRUH2aSiRqjnbXe8dlRZO0Ih44htYs2QfehzeQnPHtTwNHUvtVIVcIdI/7j9yfy5es13QeIgfKghY/ENUnB2V7iA==`
        sign := `s8XIN2TyC5niX1HFPDXOQj2eRvhW2qMPOdDuuXlOspYhxkjxunV4Ytgcw8GXg761HSbk4e5QsgKpU+vM2ggLhYni2GfXhGBVj/P13B6JhMmdrucU8ktlaH+fJGUmc3rqGMU3qiQgNAh/8PV1BS/5li7qzXHc0tgKL1zRgeu1CVw=`
        notifyData, err := base64.StdEncoding.DecodeString(notify)
        if err != nil {
            fmt.Println("error1:", err)
            return
        }
        signData, err := base64.StdEncoding.DecodeString(sign)
        if err != nil {
            fmt.Println("error2:", err)
            return
        }
        publicKey := []byte(`-----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2kcrRvxURhFijDoPpqZ/IgPlA
    gppkKrek6wSrua1zBiGTwHI2f+YCa5vC1JEiIi9uw4srS0OSCB6kY3bP2DGJagBo
    Egj/rYAGjtYJxJrEiTxVs5/GfPuQBYmU0XAtPXFzciZy446VPJLHMPnmTALmIOR5
    Dddd1Zklod9IQBMjjwIDAQAB
    -----END PUBLIC KEY-----
    `)
        block, _ := pem.Decode(publicKey)
        if block == nil {
            fmt.Println("pem error :")
            return
        }
        public, err := x509.ParsePKIXPublicKey(block.Bytes)
        if err != nil {
            fmt.Println("public key error :", err)
            return
        }
        pub := public.(*rsa.PublicKey)
        fmt.Println(pub.N)

        h := sha1.New()
        h.Write([]byte(notifyData))
        digest := h.Sum(nil)

        err = rsa.VerifyPKCS1v15(pub, crypto.SHA1, digest, signData)
        if err == nil {
            fmt.Println("OK")
        } else {
            fmt.Println("verify fail", err)
        }
    }  
附言。 这是php代码,它将传递相同的数据

<?php                                                                                                                                                                        
$pubKey = "-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2kcrRvxURhFijDoPpqZ/IgPlA
gppkKrek6wSrua1zBiGTwHI2f+YCa5vC1JEiIi9uw4srS0OSCB6kY3bP2DGJagBo
Egj/rYAGjtYJxJrEiTxVs5/GfPuQBYmU0XAtPXFzciZy446VPJLHMPnmTALmIOR5
Dddd1Zklod9IQBMjjwIDAQAB
-----END PUBLIC KEY-----";
$pubRes = openssl_get_publickey($pubKey);
//通知数据
$notify_data = "YFSGlJTpNYakrZuZqZ55dcA5mVUb/JQBr3hdDjODsAVSdoVVytIagk9Wt0CD/uX+7jGL9pqev8/u0I0ZBKEmz5huXp8TdZSnskCZ7GTeHNW0VPJcW8OcBxAValA0jQSv2mBP+tc1r6mdvf66GEzhvgBfTnp3Sp7V3dijJ9bNstIDyrGm/BlByhcMr3UqXjTFJaui6t5TxvZhCuSV9sg+xVVA+sR3uFI78b5lKomg5Vu31EBZvXASlFfaOc4StltRUH2aSiRqjnbXe8dlRZO0Ih44htYs2QfehzeQnPHtTwNHUvtVIVcIdI/7j9yfy5es13QeIgfKghY/ENUnB2V7iA==";
//签名
$sign = "s8XIN2TyC5niX1HFPDXOQj2eRvhW2qMPOdDuuXlOspYhxkjxunV4Ytgcw8GXg761HSbk4e5QsgKpU+vM2ggLhYni2GfXhGBVj/P13B6JhMmdrucU8ktlaH+fJGUmc3rqGMU3qiQgNAh/8PV1BS/5li7qzXHc0tgKL1zRgeu1CVw=";
$data = base64_decode($notify_data);
$maxlength = 128;
$output = '';
while ($data) {
    $input = substr($data, 0, $maxlength);
    $data = substr($data, $maxlength);
    openssl_public_decrypt($input, $out, $pubRes, OPENSSL_PKCS1_PADDING);
    $output .= $out;
}
if (openssl_verify($output, base64_decode($sign), $pubRes)) {
    echo "success";
}else{
    echo "fail";
}
?>

您的代码中似乎有几个不同的问题

  • 在PHP代码中不需要将数据截断为128个字符,因为在go代码中不需要这样做。这种差异将导致字节不同,因此计算的签名也不同

  • 您正在使用
    openssl\u public\u decrypt
    函数对数据进行签名。虽然这在理论上是可行的,但它很容易出错。您还使用公钥对数据进行签名,这是错误的-只有私钥才能签名。最好使用PHP的
    openssl\u-sign
    函数

  • 另一个错误源可能是使用私钥的签名代码,此处未显示

    PHP和Go的公钥加密应该完全兼容。为了测试这一点,我在PHP和Go中创建了以下相同的签名脚本

    <?php
    
    $data = "TEST DATA TO COMPUTE";
    
    $privKeyPEM = "-----BEGIN RSA PRIVATE KEY-----
    MIIBOgIBAAJBAK3ADijXKw72+YbC5QKK2y7IosCp7rWOhTf8Ph07ZA0KjdbKtfL/
    7dmNKjSP6EkC/DJUWfZJNLIlGOtDLLA/AnsCAwEAAQJAQj9kJrZDuKT6ZyOQZfPD
    tobRZ1xjo93/dWU72bF3aHDo4ILMy2Kigy5yhZU0ZGjOuPv5eUOLRe/yxYQf6B5J
    AQIhANbhfZ4QJC8dLXAqcsxOXuLgztzbKixUre0gnhiVSd1hAiEAzv+sHJ4PMjKs
    Iuf6/nUI9XFgQQRd+NGRovyHRZC18VsCIAX7AKQFjvxAs6MLi2ZkR//IgfljoCjb
    snuHDN9iSEwBAiEAmAc1XCtGE+Mdg+GG+T3xn3pubDIN5oHcia0YmKIIzsMCIEy1
    fWM5cIJ9bAUExKB6MV8PF+9EjDvXzbSk1/Ycta8z
    -----END RSA PRIVATE KEY-----";
    
    // Parse private key
    $privkey = openssl_pkey_get_private($privKeyPEM);
    if (!$privkey) {
        exit("Could not parse private key");
    }
    
    // Compute the signature
    $signature = '';
    $ok = openssl_sign($data, $signature, $privkey, OPENSSL_ALGO_SHA1); //SHA1 of $data is computed automatically by this function
    if (!$ok) {
        exit("Could not compute signature");
    }
    
    // Print the output
    print base64_encode($signature);
    
    您可以验证它们是否确实生成相同的输出,并以相同的方式对相同的数据进行签名

    我们还可以使用PHP和Go来验证签名。下面是一组PHP和Go脚本,它们都将从标准输入读取签名并进行验证

    <?php  
    
    $data = "TEST DATA TO COMPUTE";
    
    $pubKeyPEM = "-----BEGIN PUBLIC KEY-----
    MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAK3ADijXKw72+YbC5QKK2y7IosCp7rWO
    hTf8Ph07ZA0KjdbKtfL/7dmNKjSP6EkC/DJUWfZJNLIlGOtDLLA/AnsCAwEAAQ==
    -----END PUBLIC KEY-----";
    
    // Parse public key
    $pubkey = openssl_pkey_get_public($pubKeyPEM);
    if (!$pubkey) {
        exit("Could not parse public key");
    }
    
    // Read the signature from stdin
    $stdin = file_get_contents("php://stdin");
    $signature = base64_decode($stdin);
    
    // Verify the signature
    $ok = openssl_verify($data, $signature, $pubkey, OPENSSL_ALGO_SHA1); //SHA1 of $data is computed automatically by this function
    if ($ok == 1) {
        print "OK\n"; // it worked!
      exit(0);
    }
    else if ($ok == 0) {
      exit("Signature verification failed");
    }
    else {
      exit("Error verifying signature");
    }
    
    我们可以混合和匹配这些不同的脚本,并验证PHP和Go确实完全兼容:

    $ go run go-sign.go | go run go-verify.go
    OK
    $ go run go-sign.go | php php-verify.php
    OK
    $ php php-sign.php | php php-verify.php
    OK
    $ php php-sign.php | go run go-verify.go
    OK
    

    请处理所有错误,例如pem.Decode。@Volker:pen.Decode不会返回错误谢谢。我知道我的问题在哪里。是的,php和go代码之间存在一些差异。我错过了围棋比赛。我想知道go在php中是什么样子的
    openssl\u public\u decrypt
    ?go与php的
    openssl\u public\u decrypt
    的等价物在这里()。但是,该函数未导出,因此无法直接使用。你的用例是什么?如果你真的想加密和解密数据,最好使用AES之类的对称密码。@phayes:那不太一样
    openssl\u public\u decrypt
    使用公钥解密。人们通常不想这样做,但因为PHP提供了一个函数,所以人们使用它。
    package main
    
    import (
        "crypto"
        "crypto/rsa"
        "crypto/sha1"
        "crypto/x509"
        "encoding/base64"
        "encoding/pem"
        "fmt"
        "io/ioutil"
        "log"
        "os"
    )
    
    const (
        data = "TEST DATA TO COMPUTE"
    
        pubKeyPEM = `-----BEGIN PUBLIC KEY-----
    MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAK3ADijXKw72+YbC5QKK2y7IosCp7rWO
    hTf8Ph07ZA0KjdbKtfL/7dmNKjSP6EkC/DJUWfZJNLIlGOtDLLA/AnsCAwEAAQ==
    -----END PUBLIC KEY-----`
    )
    
    func main() {
    
        // Parse public key into rsa.PublicKey
        PEMBlock, _ := pem.Decode([]byte(pubKeyPEM))
        if PEMBlock == nil {
            log.Fatal("Could not parse Public Key PEM")
        }
        if PEMBlock.Type != "PUBLIC KEY" {
            log.Fatal("Found wrong key type")
        }
        pubkey, err := x509.ParsePKIXPublicKey(PEMBlock.Bytes)
        if err != nil {
            log.Fatal(err)
        }
    
        // compute the sha1
        h := sha1.New()
        h.Write([]byte(data))
    
        // Read the signature from stdin
        b64 := base64.NewDecoder(base64.StdEncoding, os.Stdin)
        signature, err := ioutil.ReadAll(b64)
        if err != nil {
            log.Fatal(err)
        }
    
        // Verify
        err = rsa.VerifyPKCS1v15(pubkey.(*rsa.PublicKey), crypto.SHA1, h.Sum(nil), signature)
        if err != nil {
            log.Fatal(err)
        }
    
        // It verified!
        fmt.Println("OK")
    }
    
    $ go run go-sign.go | go run go-verify.go
    OK
    $ go run go-sign.go | php php-verify.php
    OK
    $ php php-sign.php | php php-verify.php
    OK
    $ php php-sign.php | go run go-verify.go
    OK