一尘不染

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

go

我试图让Java验证签名的SHA-1哈希,但是它一直返回false。我在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)
}

在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());
            }  
        }
    }

阅读 957

收藏
2020-07-02

共1个答案

一尘不染

在Java中,您无需在签名或验证消息之前对消息进行哈希处理。这意味着发送到sig.update的字节不应为hashBytes,而应为inputBytes。

2020-07-02