在GO中使用RSA-SHA进行签名和解码

时间:2013-12-18 10:33:14

标签: encryption go signing

我正在尝试签名字符串,然后用公钥验证它。我的验证结果为空。我做错了什么?

    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看起来像这样:

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

并且public.pem:

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

感谢。

1 个答案:

答案 0 :(得分:7)

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

需要对界面和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)
}

以下是验证的操场示例:http://play.golang.org/p/bzpD7Pa9mr

还做了一些修改以避免ioutils。