add signing and verifying of messages
With this it is possible to sign a message with a private key and verify it with a public key. The only problem is, that it is currently not compatible with openssl yet.
This commit is contained in:
parent
43384bab59
commit
68167a5891
18
main.go
18
main.go
|
@ -28,10 +28,11 @@ func main() {
|
|||
case "create-private": create_private_key()
|
||||
case "create-cert-sign": create_sign_request()
|
||||
case "create-public": create_public_key()
|
||||
case "help": print_modules()
|
||||
case "info": info_on_file()
|
||||
case "sign-request": sign_request()
|
||||
case "sign-input": sign_input()
|
||||
case "help": print_modules()
|
||||
case "info": info_on_file()
|
||||
case "sign-request": sign_request()
|
||||
case "sign-input": sign_input()
|
||||
case "verify-signature": verify_signature()
|
||||
default: crash_with_help(1, "Command not supported!")
|
||||
}
|
||||
}
|
||||
|
@ -43,9 +44,10 @@ func sign_request() {}
|
|||
|
||||
// open stream for given path
|
||||
func open_output_stream(path string) (io.WriteCloser, error) {
|
||||
if path == "STDOUT" {
|
||||
return os.Stdout, nil
|
||||
} else {
|
||||
switch path {
|
||||
case "STDOUT": return os.Stdout, nil
|
||||
case "STDERR": return os.Stderr, nil
|
||||
default:
|
||||
var err error
|
||||
output_stream, err := os.OpenFile(path, os.O_WRONLY | os.O_CREATE | os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
|
@ -65,6 +67,8 @@ where 'command' is one of:
|
|||
help show this help
|
||||
info get info on a file
|
||||
sign sign a certificate request
|
||||
sign-input sign a message with a private key
|
||||
verify-signature verify a signature
|
||||
`, filepath.Base(os.Args[0]))
|
||||
fmt.Println()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
// "crypto/ecdsa"
|
||||
// "crypto/rsa"
|
||||
)
|
||||
|
||||
type (
|
||||
SignInputFlags struct {
|
||||
Message string // the message to sign
|
||||
PrivateKeyPath string // path to the private key
|
||||
Output string // a path or stream to output the private key to
|
||||
|
||||
private_key crypto.Signer
|
||||
output_stream io.Writer // the output stream for the CSR
|
||||
}
|
||||
)
|
||||
|
||||
func sign_input() {
|
||||
flags := parse_sign_input_flags()
|
||||
flags.private_key = load_private_key(flags.PrivateKeyPath)
|
||||
|
||||
output_stream, err := open_output_stream(flags.Output)
|
||||
if err != nil {
|
||||
crash_with_help(2, fmt.Sprintf("Error when creating file %s: %s", flags.Output, err))
|
||||
}
|
||||
flags.output_stream = output_stream
|
||||
defer output_stream.Close()
|
||||
|
||||
if err := create_signature(flags); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Error when creating signature", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
|
||||
func parse_sign_input_flags() SignInputFlags {
|
||||
flags := SignInputFlags{}
|
||||
fs := flag.NewFlagSet("sign-input", flag.ExitOnError)
|
||||
fs.StringVar(&flags.PrivateKeyPath, "private-key", "", "path to the private key file")
|
||||
fs.StringVar(&flags.Output, "output", "STDOUT", "path where the generated signature should be stored")
|
||||
fs.StringVar(&flags.Message, "message", "", "the message to sign")
|
||||
fs.Parse(os.Args[2:])
|
||||
|
||||
return flags
|
||||
}
|
||||
|
||||
func create_signature(flags SignInputFlags) error {
|
||||
message := []byte(flags.Message)
|
||||
// compute sha256 of the message
|
||||
hash := sha256.New()
|
||||
length, _ := hash.Write(message)
|
||||
if length != len(message) { return errors.New("Error when creating hash over message!") }
|
||||
fmt.Println(hash.Sum(nil))
|
||||
|
||||
// create signature of the hash using the private key
|
||||
signature, err := flags.private_key.Sign(
|
||||
rand.Reader,
|
||||
hash.Sum([]byte("")),
|
||||
nil,
|
||||
)
|
||||
if err != nil { return err }
|
||||
fmt.Println(signature)
|
||||
flags.output_stream.Write(signature)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
)
|
||||
|
||||
type (
|
||||
VerifySignatureFlags struct {
|
||||
Message string // the message to sign
|
||||
PublicKeyPath string // path to the private key
|
||||
Signature string // a path or stream to output the private key to
|
||||
}
|
||||
// struct to load the signature into (which is basically two bigint in byte form)
|
||||
Signature struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
)
|
||||
|
||||
func verify_signature() {
|
||||
flags := parse_verify_signature_flags()
|
||||
public_key, err := load_public_key_ecdsa(flags.PublicKeyPath)
|
||||
if err != nil {
|
||||
crash_with_help(2, fmt.Sprintf("Error when loading public key: %s", err))
|
||||
}
|
||||
signature, err := load_signature(flags.Signature)
|
||||
if err != nil {
|
||||
crash_with_help(2, fmt.Sprintf("Error when loading the signature: %s", err))
|
||||
}
|
||||
hash := sha256.New()
|
||||
hash.Write([]byte(flags.Message))
|
||||
|
||||
success := ecdsa.Verify(public_key, hash.Sum(nil), signature.R, signature.S)
|
||||
fmt.Println(success)
|
||||
}
|
||||
|
||||
// parse the parameters
|
||||
func parse_verify_signature_flags() VerifySignatureFlags {
|
||||
flags := VerifySignatureFlags{}
|
||||
fs := flag.NewFlagSet("verify-signature", flag.ExitOnError)
|
||||
fs.StringVar(&flags.PublicKeyPath, "public-key", "", "path to the public key file")
|
||||
fs.StringVar(&flags.Signature, "signature", "", "path where the signature file can be found")
|
||||
fs.StringVar(&flags.Message, "message", "", "the message to be validated")
|
||||
fs.Parse(os.Args[2:])
|
||||
|
||||
return flags
|
||||
}
|
||||
|
||||
// load the private key from pem file
|
||||
func load_public_key_ecdsa(path string) (*ecdsa.PublicKey, error) {
|
||||
public_key_file, err := os.Open(path)
|
||||
if err != nil { return nil, err }
|
||||
public_key_pem, err := ioutil.ReadAll(public_key_file)
|
||||
if err != nil { return nil, err }
|
||||
public_key_file.Close()
|
||||
|
||||
block, _ := pem.Decode(public_key_pem)
|
||||
if block.Type != TypeLabelPubKey {
|
||||
return nil, errors.New(fmt.Sprintf("No public key found in %s", path))
|
||||
}
|
||||
|
||||
public_key, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil { return nil, err }
|
||||
return public_key.(*ecdsa.PublicKey), nil
|
||||
}
|
||||
|
||||
// parse the signature from asn1 file
|
||||
func load_signature(path string) (*Signature, error) {
|
||||
signature_file, err := os.Open(path)
|
||||
if err != nil { return nil, err }
|
||||
signature_raw, err := ioutil.ReadAll(signature_file)
|
||||
if err != nil { return nil, err }
|
||||
signature_file.Close()
|
||||
|
||||
var signature Signature
|
||||
_, err = asn1.Unmarshal(signature_raw, &signature)
|
||||
if err != nil { return nil, err }
|
||||
return &signature, nil
|
||||
}
|
Loading…
Reference in New Issue