Signing and decoding with RSA-SHA in GO

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

Signing and decoding with RSA-SHA in GO

问题

我正在尝试对一个字符串进行签名,并使用公钥进行验证。但是我的验证结果为空。我做错了什么?

首先,你需要确保你的私钥和公钥文件的格式是正确的。私钥文件应该以"BEGIN RSA PRIVATE KEY"开头,以"END RSA PRIVATE KEY"结尾。公钥文件应该以"BEGIN PUBLIC KEY"开头,以"END PUBLIC KEY"结尾。

其次,你需要确保你的私钥和公钥文件是匹配的。也就是说,私钥是由对应的公钥生成的。

另外,你的代码中有一些错误。在main函数中,你应该使用fmt.Printf来打印错误信息,而不是使用fmt.Errorf。此外,在loadPublicKey函数中,你应该返回Unsigner类型的值,而不是返回Signer类型的值。

以下是修改后的代码:

package main

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"fmt"
	"io/ioutil"
)

func main() {
	signer, err := loadPrivateKey("private.pem")
	if err != nil {
		fmt.Printf("signer is damaged: %v\n", err)
		return
	}

	toSign := "date: Thu, 05 Jan 2012 21:31:40 GMT"

	signed, err := signer.Sign([]byte(toSign))
	if err != nil {
		fmt.Printf("could not sign request: %v\n", err)
		return
	}
	sig := base64.StdEncoding.EncodeToString(signed)
	fmt.Printf("Encoded: %v\n", sig)

	parser, perr := loadPublicKey("public.pem")
	if perr != nil {
		fmt.Printf("could not sign request: %v\n", err)
		return
	}
	unsigned, err := parser.Unsign(signed)
	if err != nil {
		fmt.Printf("could not sign request: %v\n", err)
		return
	}

	fmt.Printf("Decrypted: %v\n", base64.StdEncoding.EncodeToString(unsigned))
}

// loadPrivateKey loads and parses a PEM encoded private key file.
func loadPrivateKey(path string) (Signer, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	return parsePrivateKey(data)
}

// parsePrivateKey parses a PEM encoded private key.
func parsePrivateKey(pemBytes []byte) (Signer, error) {
	block, _ := pem.Decode(pemBytes)
	if block == nil {
		return nil, errors.New("ssh: no key found")
	}

	var rawkey interface{}
	switch block.Type {
	case "RSA PRIVATE KEY":
		rsa, err := x509.ParsePKCS1PrivateKey(block.Bytes)
		if err != nil {
			return nil, err
		}
		rawkey = rsa
	default:
		return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
	}
	return newSignerFromKey(rawkey)
}

// loadPublicKey loads and parses a PEM encoded public key file.
func loadPublicKey(path string) (Unsigner, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	return parsePublicKey(data)
}

// parsePublicKey parses a PEM encoded public key.
func parsePublicKey(pemBytes []byte) (Unsigner, error) {
	block, _ := pem.Decode(pemBytes)
	if block == nil {
		return nil, errors.New("ssh: no key found")
	}

	var rawkey interface{}
	switch block.Type {
	case "PUBLIC KEY":
		rsa, err := x509.ParsePKIXPublicKey(block.Bytes)
		if err != nil {
			return nil, err
		}
		rawkey = rsa
	default:
		return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
	}

	return newUnsignerFromKey(rawkey)
}

// A Signer can create signatures that verify against a public key.
type Signer interface {
	// Sign returns raw signature for the given data. This method
	// will apply the hash specified for the keytype to the data.
	Sign(data []byte) ([]byte, error)
}

// A Unsigner can verify signatures against a public key.
type Unsigner interface {
	// Unsign returns the original data for the given signature. This method
	// will apply the hash specified for the keytype to the signature.
	Unsign(signature []byte) ([]byte, error)
}

func newSignerFromKey(k interface{}) (Signer, error) {
	var sshKey Signer
	switch t := k.(type) {
	case *rsa.PrivateKey:
		sshKey = &rsaPrivateKey{t}
	default:
		return nil, fmt.Errorf("ssh: unsupported key type %T", k)
	}
	return sshKey, nil
}

func newUnsignerFromKey(k interface{}) (Unsigner, error) {
	var sshKey Unsigner
	switch t := k.(type) {
	case *rsa.PublicKey:
		sshKey = &rsaPublicKey{t}
	default:
		return nil, fmt.Errorf("ssh: unsupported key type %T", k)
	}
	return sshKey, nil
}

type rsaPublicKey struct {
	*rsa.PublicKey
}

type rsaPrivateKey struct {
	*rsa.PrivateKey
}

// Sign signs data with rsa-sha256.
func (r *rsaPrivateKey) Sign(data []byte) ([]byte, error) {
	h := sha256.New()
	h.Write(data)
	d := h.Sum(nil)
	return rsa.SignPKCS1v15(rand.Reader, r.PrivateKey, crypto.SHA256, d)
}

// Unsign verifies the signature and returns the original data.
func (r *rsaPublicKey) Unsign(signature []byte) ([]byte, error) {
	return rsa.DecryptPKCS1v15(rand.Reader, r.PublicKey, signature)
}

希望对你有帮助!

英文:

I'm trying to sign a string and later on verifying it with the public key. My verified result is empty. What am I doing wrong?

    package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
)
func main() {
signer, err := loadPrivateKey("private.pem");
if err != nil {
fmt.Errorf("signer is damaged: %v", err)
}
toSign := "date: Thu, 05 Jan 2012 21:31:40 GMT";
signed, err := signer.Sign([]byte(toSign))
if err != nil {
fmt.Errorf("could not sign request: %v", err)
}
sig := base64.StdEncoding.EncodeToString(signed)
fmt.Printf("Encoded: %v\n", sig)
parser, perr := loadPublicKey("public.pem");
if perr != nil {
fmt.Errorf("could not sign request: %v", err)
}
unsigned, err := parser.Unsign(signed);
if err != nil {
fmt.Errorf("could not sign request: %v", err)
}
fmt.Printf("Decrypted: %v\n", base64.StdEncoding.EncodeToString(unsigned))    
}
// loadPrivateKey loads an parses a PEM encoded private key file.
func loadPublicKey(path string) (Unsigner, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return parsePublicKey(data)
}
// parsePublicKey parses a PEM encoded private key.
func parsePublicKey(pemBytes []byte) (Unsigner, error) {
block, _ := pem.Decode(pemBytes)
if block == nil {
return nil, errors.New("ssh: no key found")
}
var rawkey interface{}
switch block.Type {
case "PUBLIC KEY":
rsa, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
rawkey = rsa
default:
return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
}
return newUnsignerFromKey(rawkey)
}
// loadPrivateKey loads an parses a PEM encoded private key file.
func loadPrivateKey(path string) (Signer, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return parsePrivateKey(data)
}
// parsePublicKey parses a PEM encoded private key.
func parsePrivateKey(pemBytes []byte) (Signer, error) {
block, _ := pem.Decode(pemBytes)
if block == nil {
return nil, errors.New("ssh: no key found")
}
var rawkey interface{}
switch block.Type {
case "RSA PRIVATE KEY":
rsa, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
rawkey = rsa
default:
return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
}
return newSignerFromKey(rawkey)
}
// A Signer is can create signatures that verify against a public key.
type Signer interface {
// Sign returns raw signature for the given data. This method
// will apply the hash specified for the keytype to the data.
Sign(data []byte) ([]byte, error)
}
// A Signer is can create signatures that verify against a public key.
type Unsigner interface {
// Sign returns raw signature for the given data. This method
// will apply the hash specified for the keytype to the data.
Unsign(data []byte) ([]byte, error)
}
func newSignerFromKey(k interface{}) (Signer, error) {
var sshKey Signer
switch t := k.(type) {
case *rsa.PrivateKey:
sshKey = &rsaPrivateKey{t}
default: 
return nil, fmt.Errorf("ssh: unsupported key type %T", k)
}
return sshKey, nil
}
func newUnsignerFromKey(k interface{}) (Unsigner, error) {
var sshKey Unsigner
switch t := k.(type) {
case *rsa.PublicKey:
sshKey = &rsaPublicKey{t}
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", k)
}
return sshKey, nil
}
type rsaPublicKey struct {
*rsa.PublicKey
}
type rsaPrivateKey struct {
*rsa.PrivateKey
}
// Sign signs data with rsa-sha256
func (r *rsaPrivateKey) Sign(data []byte) ([]byte, error) {
h := sha256.New()
h.Write(data)
d := h.Sum(nil)
return rsa.SignPKCS1v15(rand.Reader, r.PrivateKey, crypto.SHA256, d)
}
// Unsign encrypts data with rsa-sha256
func (r *rsaPublicKey) Unsign(message []byte) ([]byte, error) {  
return rsa.EncryptPKCS1v15(rand.Reader, r.PublicKey, message)        
}

private.pem looks like this:

-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDCFENGw33yGihy92pDjZQhl0C36rPJj+CvfSC8+q28hxA161QF
NUd13wuCTUcq0Qd2qsBe/2hFyc2DCJJg0h1L78+6Z4UMR7EOcpfdUE9Hf3m/hs+F
UR45uBJeDK1HSFHD8bHKD6kv8FPGfJTotc+2xjJwoYi+1hqp1fIekaxsyQIDAQAB
AoGBAJR8ZkCUvx5kzv+utdl7T5MnordT1TvoXXJGXK7ZZ+UuvMNUCdN2QPc4sBiA
QWvLw1cSKt5DsKZ8UETpYPy8pPYnnDEz2dDYiaew9+xEpubyeW2oH4Zx71wqBtOK
kqwrXa/pzdpiucRRjk6vE6YY7EBBs/g7uanVpGibOVAEsqH1AkEA7DkjVH28WDUg
f1nqvfn2Kj6CT7nIcE3jGJsZZ7zlZmBmHFDONMLUrXR/Zm3pR5m0tCmBqa5RK95u
412jt1dPIwJBANJT3v8pnkth48bQo/fKel6uEYyboRtA5/uHuHkZ6FQF7OUkGogc
mSJluOdc5t6hI1VsLn0QZEjQZMEOWr+wKSMCQQCC4kXJEsHAve77oP6HtG/IiEn7
kpyUXRNvFsDE0czpJJBvL/aRFUJxuRK91jhjC68sA7NsKMGg5OXb5I5Jj36xAkEA
gIT7aFOYBFwGgQAQkWNKLvySgKbAZRTeLBacpHMuQdl1DfdntvAyqpAZ0lY0RKmW
G6aFKaqQfOXKCyWoUiVknQJAXrlgySFci/2ueKlIE1QqIiLSZ8V8OlpFLRnb1pzI
7U1yQXnTAEFYM560yJlzUpOb1V4cScGd365tiSMvxLOvTA==
-----END RSA PRIVATE KEY-----

And public.pem:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCFENGw33yGihy92pDjZQhl0C3
6rPJj+CvfSC8+q28hxA161QFNUd13wuCTUcq0Qd2qsBe/2hFyc2DCJJg0h1L78+6
Z4UMR7EOcpfdUE9Hf3m/hs+FUR45uBJeDK1HSFHD8bHKD6kv8FPGfJTotc+2xjJw
oYi+1hqp1fIekaxsyQIDAQAB
-----END PUBLIC KEY-----

Thanks.

答案1

得分: 12

你的代码中的问题是Unsign尝试对签名进行编码,而不是使用它来验证原始消息。

需要对接口和Unsign进行一些更改:

// Unsign使用rsa-sha256签名验证消息
func (r *rsaPublicKey) Unsign(message []byte, sig []byte) error {
    h := sha256.New()
    h.Write(message)
    d := h.Sum(nil)
    return rsa.VerifyPKCS1v15(r.PublicKey, crypto.SHA256, d, sig)
}

这里有一个验证的playground示例:http://play.golang.org/p/bzpD7Pa9mr

还进行了一些修改以避免使用ioutils

英文:

The problem in your code is that Unsign tries to Encode the signature instead of using it to verify the original message.

There need to be changes made to the Interface and to Unsign:

// Unsign verifies the message using a rsa-sha256 signature
func (r *rsaPublicKey) Unsign(message []byte, sig []byte) error {
h := sha256.New()
h.Write(message)
d := h.Sum(nil)
return rsa.VerifyPKCS1v15(r.PublicKey, crypto.SHA256, d, sig)
}

Here is a playground example of verification: http://play.golang.org/p/bzpD7Pa9mr

Some modifications has also been made to avoid ioutils.

huangapple
  • 本文由 发表于 2013年12月18日 18:33:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/20655702.html
匿名

发表评论

匿名网友

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

确定