Skip to content

Instantly share code, notes, and snippets.

@ZhenhangTung
Created August 8, 2017 08:36
Show Gist options
  • Save ZhenhangTung/0d96e73f1c89a77f4d70adb032420609 to your computer and use it in GitHub Desktop.
Save ZhenhangTung/0d96e73f1c89a77f4d70adb032420609 to your computer and use it in GitHub Desktop.
The code is in this question(https://stackoverflow.com/q/20655702/3970355). It's about how to load rsa key and do the sign and unsign.
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
)
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("Signature: %v\n", sig)
parser, perr := loadPublicKey("public.pem")
if perr != nil {
fmt.Errorf("could not sign request: %v", err)
}
err = parser.Unsign([]byte(toSign), signed)
if err != nil {
fmt.Errorf("could not sign request: %v", err)
}
fmt.Printf("Unsign error: %v\n", err)
}
// loadPrivateKey loads an parses a PEM encoded private key file.
func loadPublicKey(path string) (Unsigner, error) {
return parsePublicKey([]byte(`-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCFENGw33yGihy92pDjZQhl0C3
6rPJj+CvfSC8+q28hxA161QFNUd13wuCTUcq0Qd2qsBe/2hFyc2DCJJg0h1L78+6
Z4UMR7EOcpfdUE9Hf3m/hs+FUR45uBJeDK1HSFHD8bHKD6kv8FPGfJTotc+2xjJw
oYi+1hqp1fIekaxsyQIDAQAB
-----END PUBLIC KEY-----`))
}
// 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) {
return parsePrivateKey([]byte(`-----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-----`))
}
// 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, sig []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 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)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment