简体   繁体   English

在Java中验证在golang中生成的rsa.SignPKCS1v15签名

[英]Verify rsa.SignPKCS1v15 signature generated in golang in Java

I am trying to get Java to verify a signed SHA-1 hash but it keeps returning false.我试图让 Java 验证签名的 SHA-1 哈希,但它一直返回 false。 I have the following code in Go which generates an RSA Key Pair and signs and returns any message that hits the /sign endpoint along with the hex encoded hash and the public key modulus and exponent:我在 Go 中有以下代码,它生成一个 RSA 密钥对并签名并返回任何到达 /sign 端点的消息以及十六进制编码的散列和公钥模数和指数:

package main

import (
    "crypto"
    "crypto/rand"
    "crypto/rsa"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "strconv"
)

var PrivKey *rsa.PrivateKey

type Message struct {
    Message string `json:"message"`
}

func (msg *Message) Decode(r io.Reader) error {
    return json.NewDecoder(r).Decode(&msg)
}

type Signature struct {
    Hash      string `json:"hash"`
    Signature string `json:"signature"`
    N         string `json:"N"`
    E         string `json:"E"`
}

func hash(msg string) []byte {
    sh := crypto.SHA1.New()
    sh.Write([]byte(msg))
    hash := sh.Sum(nil)
    return hash
}

func SignWithKey(msg Message) Signature {
    hash := hash(msg.Message)
    bytes, err := rsa.SignPKCS1v15(rand.Reader, PrivKey, crypto.SHA1, hash)
    if err != nil {
        panic(err)
    }
    signature := hex.EncodeToString(bytes)
    sig := Signature{
        hex.EncodeToString(hash),
        signature,
        PrivKey.PublicKey.N.String(),
        strconv.Itoa(PrivKey.PublicKey.E),
    }
    return sig
}

func sign(w http.ResponseWriter, r *http.Request) {
    fmt.Println("/sign")
    var msg Message
    err := msg.Decode(r.Body)
    if err != nil {
        panic(err)
    }

    fmt.Println("Signing: " + msg.Message)
    signature := SignWithKey(msg)
    js, err := json.Marshal(signature)
    fmt.Println(string(js))

    w.Header().Set("Content-Type", "application/json")
    w.Write(js)
}

func LoadKeys() {
    // generate private key
    var err error
    PrivKey, err = rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
        fmt.Println(err)
    }
}

func main() {

    fmt.Println("Loading Keys")
    LoadKeys()
    fmt.Println("Keys Loaded")
    http.HandleFunc("/sign", sign)

    http.ListenAndServe(":8080", nil)
}

On the Java/Android side I have this code which after sending the relevant bits hits this function with the unparsed JSON object, but once it gets to the Signature verify part it always returns false:在 Java/Android 端,我有这个代码,它在发送相关位后使用未解析的 JSON 对象命中这个函数,但是一旦它到达签名验证部分,它总是返回 false:

protected void onPostExecute(String result) {
            if (result == null) {
                tv.setText("NULL");
                return;
            }
            JsonElement jelement = new JsonParser().parse(result);
            JsonObject jobject = jelement.getAsJsonObject();
            String signature = jobject.getAsJsonPrimitive("signature").getAsString();
            BigInteger N = jobject.getAsJsonPrimitive("N").getAsBigInteger();
            BigInteger E = jobject.getAsJsonPrimitive("E").getAsBigInteger();
            String hash = jobject.getAsJsonPrimitive("hash").getAsString();
            java.security.spec.RSAPublicKeySpec spec = new java.security.spec.RSAPublicKeySpec(N, E);

            try {
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                PublicKey pk = keyFactory.generatePublic(spec);

                MessageDigest digest = MessageDigest.getInstance("SHA1");
                byte[] inputBytes = msg.getBytes("UTF8");
                byte[] hashedBytes = digest.digest(inputBytes);

                Signature sig = Signature.getInstance("SHA1withRSA", "SC");
                sig.initVerify( pk );
                sig.update( hashedBytes );
                boolean ret = sig.verify( Hex.decode(signature) );
                if (ret) {
                    tv.setText(output + "Verified");
                } else {
                    tv.setText(output + "NOT VERIFIED");
                }
            }
            catch (Exception e) {
                Log.i("error", e.toString());
            }  
        }
    }

In Java you don't need to hash the message before signing or verifying it.在 Java 中,您不需要在签名或验证消息之前散列消息。 That means that the bytes being sent to sig.update shouldn't be hashedBytes, but the inputBytes.这意味着发送到 sig.update 的字节不应该是 hashedBytes,而是 inputBytes。

如果您不想在 Go 中对内容进行哈希处理而只对原始数据进行签名,则可以使用以下代码:

signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.Hash(0), []byte(message))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM