简体   繁体   中英

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. 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:

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:

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. That means that the bytes being sent to sig.update shouldn't be hashedBytes, but the inputBytes.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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