暗号化と署名の違いを最近知った若輩者なのですが、、ちょっと仕事でこのあたりのことを扱う必要が出てきたので、表題の通りのことをやってみました。
暗号化と署名について
暗号化と署名は対称じゃないよという話 あたりに目を通すとよいかと思います。こちらのエントリは結構前のものですが、とてもわかりやすかったです。
秘密鍵と公開鍵を準備する
$ openssl genrsa 1024 > private-key.pem
$ openssl rsa -pubout < private-key.pem > public-key.pem
実際に署名をつくって検証してみる
以下のコードで署名の作成と検証が実行できます。key へのパスはよしなに置換してください。
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha512"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"log"
)
func readPrivateKey(path string) (*rsa.PrivateKey, error) {
privateKeyData, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
privateKeyBlock, _ := pem.Decode(privateKeyData)
if privateKeyBlock == nil {
return nil, errors.New("invalid private key data")
}
if privateKeyBlock.Type != "RSA PRIVATE KEY" {
return nil, errors.New(fmt.Sprintf("invalid private key type : %s", privateKeyBlock.Type))
}
privateKey, err := x509.ParsePKCS1PrivateKey(privateKeyBlock.Bytes)
if err != nil {
return nil, err
}
return privateKey, err
}
func readPublicKey(path string) (*rsa.PublicKey, error) {
publicKeyData, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
publicKeyBlock, _ := pem.Decode(publicKeyData)
if publicKeyBlock == nil {
return nil, errors.New("invalid public key data")
}
if publicKeyBlock.Type != "PUBLIC KEY" {
return nil, errors.New(fmt.Sprintf("invalid public key type : %s", publicKeyBlock.Type))
}
publicKeyInterface, err := x509.ParsePKIXPublicKey(publicKeyBlock.Bytes)
if err != nil {
return nil, err
}
publicKey, ok := publicKeyInterface.(*rsa.PublicKey)
if !ok {
return nil, errors.New("not RSA public key")
}
return publicKey, nil
}
func main() {
// read private key
privateKey, err := readPrivateKey("/path/to/your/private-key.pem")
if err != nil {
log.Fatal(err)
}
// precompute
// ref. http://golang.org/pkg/crypto/rsa/#PrivateKey.Precompute
// Precompute performs some calculations that speed up private key operations in the future.
privateKey.Precompute()
// validate
// ref. http://golang.org/pkg/crypto/rsa/#PrivateKey.Validate
// Validate performs basic sanity checks on the key.
// It returns nil if the key is valid, or else an error describing a problem.
if err := privateKey.Validate(); err != nil {
log.Fatal(err)
}
// read public key
publicKey, err := readPublicKey("/path/to/your/public-key.pem")
if err != nil {
log.Fatal(err)
}
// generate token hash from token
hasher := sha512.New()
hasher.Write([]byte("token"))
hasher.Write([]byte("salt"))
tokenHash := hasher.Sum(nil)
// sign
signature, err := rsa.SignPSS(rand.Reader, privateKey, crypto.SHA512, tokenHash, nil)
if err != nil {
log.Fatal(err)
}
// verify
if err := rsa.VerifyPSS(publicKey, crypto.SHA512, tokenHash, signature, nil); err != nil {
log.Fatal(err)
}
log.Println("success")
}