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

huangapple go评论90阅读模式
英文:

Verify rsa.SignPKCS1v15 signature generated in golang in Java

问题

我正在尝试让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());
    }
}

请问有什么我可以帮助你的吗?

英文:

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

答案1

得分: 2

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

英文:

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.

答案2

得分: 0

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

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

If you don't want to hash the content in Go and just sign the raw data, you can use this code:

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

huangapple
  • 本文由 发表于 2015年4月3日 05:25:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/29422738.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定