Created
May 31, 2019 20:59
-
-
Save DazWilkin/a9f253fe1121ad78bd5283557bc0437d to your computer and use it in GitHub Desktop.
Google Cloud KMS & Tink
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "context" | |
| "crypto/ecdsa" | |
| "crypto/sha256" | |
| "crypto/x509" | |
| "encoding/asn1" | |
| "encoding/pem" | |
| "errors" | |
| "flag" | |
| "fmt" | |
| "log" | |
| "math/big" | |
| "encoding/base64" | |
| cloudkms "cloud.google.com/go/kms/apiv1" | |
| kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1" | |
| ) | |
| var ( | |
| project = flag.String("project", "", "Project ID") | |
| location = flag.String("location", "", "Keyring Location") | |
| keyring = flag.String("keyring", "", "Keyring ID") | |
| key = flag.String("key", "", "Key ID") | |
| msg = flag.String("message", "", "Message") | |
| ) | |
| // Google-provided sample functions | |
| // https://cloud.google.com/kms/docs/create-validate-signatures#create_signature | |
| func signAsymmetric(keyName string, message []byte) ([]byte, error) { | |
| ctx := context.Background() | |
| client, err := cloudkms.NewKeyManagementClient(ctx) | |
| if err != nil { | |
| return nil, err | |
| } | |
| digest := sha256.New() | |
| digest.Write(message) | |
| req := &kmspb.AsymmetricSignRequest{ | |
| Name: keyName, | |
| Digest: &kmspb.Digest{ | |
| Digest: &kmspb.Digest_Sha256{ | |
| Sha256: digest.Sum(nil), | |
| }, | |
| }, | |
| } | |
| // Call the API. | |
| rsp, err := client.AsymmetricSign(ctx, req) | |
| if err != nil { | |
| return nil, fmt.Errorf("asymmetric sign request failed: %+v", err) | |
| } | |
| return rsp.Signature, nil | |
| } | |
| func verifySignatureEC(keyName string, signature, message []byte) error { | |
| ctx := context.Background() | |
| client, err := cloudkms.NewKeyManagementClient(ctx) | |
| if err != nil { | |
| return err | |
| } | |
| // Retrieve the public key from KMS. | |
| response, err := client.GetPublicKey(ctx, &kmspb.GetPublicKeyRequest{Name: keyName}) | |
| if err != nil { | |
| return fmt.Errorf("failed to fetch public key: %+v", err) | |
| } | |
| // Parse the key. | |
| block, _ := pem.Decode([]byte(response.Pem)) | |
| abstractKey, err := x509.ParsePKIXPublicKey(block.Bytes) | |
| if err != nil { | |
| return fmt.Errorf("failed to parse public key: %+v", err) | |
| } | |
| ecKey, ok := abstractKey.(*ecdsa.PublicKey) | |
| if !ok { | |
| return fmt.Errorf("key '%s' is not EC", keyName) | |
| } | |
| // Verify Elliptic Curve signature. | |
| var parsedSig struct{ R, S *big.Int } | |
| _, err = asn1.Unmarshal(signature, &parsedSig) | |
| if err != nil { | |
| return fmt.Errorf("failed to parse signature bytes: %+v", err) | |
| } | |
| hash := sha256.New() | |
| hash.Write(message) | |
| digest := hash.Sum(nil) | |
| if !ecdsa.Verify(ecKey, digest, parsedSig.R, parsedSig.S) { | |
| return errors.New("signature verification failed") | |
| } | |
| return nil | |
| } | |
| func main() { | |
| flag.Parse() | |
| log.Printf("Message:\n%s\n", *msg) | |
| keyName := fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/1", *project, *location, *keyring, *key) | |
| message := []byte(*msg) | |
| // Owner Signs | |
| signature, err := signAsymmetric(keyName, message) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| encodedSig := base64.StdEncoding.EncodeToString(signature) | |
| log.Printf("Encoded:\n%s\n", encodedSig) | |
| // Prover Verifies | |
| if err := verifySignatureEC(keyName, signature, message); err != nil { | |
| log.Fatal(err) | |
| } | |
| log.Println("Message verified.") | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment