drqefnd544707688 2014-08-12 09:37
浏览 664

关于VerifyPKCS1v15(base64和rsa检查)

Given "notify" ,"publicKey" and "sign" , it doesnt pass the VerifyPKCS1v15 in go . That 's mycode , is there something wrong ?

  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)
        }
    }  

P.S. This is php code, and it'll pass with the same data.

<?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";
}
?>
  • 写回答

1条回答 默认 最新

  • dqwh26750 2014-08-12 15:17
    关注

    You appear to have several different problems in your code.

    1. There is no need to truncate the data to 128 characters in your PHP code as you are not doing the same in your go code. This discrepancy will cause the bytes to be different and therefore the computed signatures to be different.

    2. You are using the openssl_public_decrypt function to sign the data. While this does work in theory it's error prone. You are also using a public-key to sign the data, which is wrong - only private-keys can sign. It's much better to use PHP's openssl_sign function.

    Another source of error could be your signing code that uses the private key, which is not shown here.

    PHP's and Go's public key cryptography should be entirely compatible. To test this I've created the following identical signing scripts in both PHP and 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);
    

    And the same thing in Go:

    package main
    
    import (
        "crypto"
        "crypto/rand"
        "crypto/rsa"
        "crypto/sha1"
        "crypto/x509"
        "encoding/base64"
        "encoding/pem"
        "fmt"
        "log"
    )
    
    const (
        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-----`
    )
    
    func main() {
    
        // Parse private key into rsa.PrivateKey
        PEMBlock, _ := pem.Decode([]byte(privKeyPEM))
        if PEMBlock == nil {
            log.Fatal("Could not parse Private Key PEM")
        }
        if PEMBlock.Type != "RSA PRIVATE KEY" {
            log.Fatal("Found wrong key type")
        }
        privkey, err := x509.ParsePKCS1PrivateKey(PEMBlock.Bytes)
        if err != nil {
            log.Fatal(err)
        }
    
        // Compute the sha1
        h := sha1.New()
        h.Write([]byte(data))
    
        // Sign the data
        signature, err := rsa.SignPKCS1v15(rand.Reader, privkey, crypto.SHA1, h.Sum(nil))
        if err != nil {
            log.Fatal(err)
        }
    
        // Print the results
        fmt.Print(base64.StdEncoding.EncodeToString(signature))
    }
    

    You can verify that these do, indeed, produce the same output and sign the same data in the same way.

    We can also use both PHP and Go to verify the signatures. Here are a set of PHP and Go scripts that will both read a signature from standard input and verify it.

    <?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
    "; // it worked!
      exit(0);
    }
    else if ($ok == 0) {
      exit("Signature verification failed");
    }
    else {
      exit("Error verifying signature");
    }
    

    And the same verification code in Go:

    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")
    }
    

    We can mix and match these different scripts together and verify that PHP and Go are indeed fully compatible:

    $ 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
    
    评论

报告相同问题?

悬赏问题

  • ¥20 怎么在stm32门禁成品上增加记录功能
  • ¥15 Source insight编写代码后使用CCS5.2版本import之后,代码跳到注释行里面
  • ¥50 NT4.0系统 STOP:0X0000007B
  • ¥15 想问一下stata17中这段代码哪里有问题呀
  • ¥15 flink cdc无法实时同步mysql数据
  • ¥100 有人会搭建GPT-J-6B框架吗?有偿
  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 解riccati方程组