tuf/scheme/ecdsa_sha256.go (111 lines of code) (raw):

/* Copyright 2018 Google Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package scheme import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/sha256" "crypto/x509" "encoding/asn1" "encoding/hex" "encoding/json" "encoding/pem" "fmt" "io/ioutil" "math/big" "github.com/GoogleCloudPlatform/runtimes-common/tuf/constants" "github.com/GoogleCloudPlatform/runtimes-common/tuf/types" ) type ECDSA struct { *ecdsa.PrivateKey KeyType types.KeyScheme } type ecdsaSignature struct { R, S *big.Int } func NewECDSA() *ECDSA { privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil } return &ECDSA{ PrivateKey: privateKey, KeyType: constants.ECDSA256Scheme, } } func (ecdsaKey *ECDSA) encode() (string, string, error) { x509Encoded, err := x509.MarshalECPrivateKey(ecdsaKey.PrivateKey) if err != nil { return "", "", err } pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: x509Encoded}) x509EncodedPub, err := x509.MarshalPKIXPublicKey(&ecdsaKey.PrivateKey.PublicKey) if err != nil { return "", "", err } pemEncodedPub := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: x509EncodedPub}) return string(pemEncoded), string(pemEncodedPub), nil } func (ecdsaKey *ECDSA) decode(pemEncoded string) error { block, _ := pem.Decode([]byte(pemEncoded)) privateKey, err := x509.ParseECPrivateKey(block.Bytes) if err != nil { return err } ecdsaKey.PrivateKey = privateKey ecdsaKey.KeyType = constants.ECDSA256Scheme return nil } func (ecdsaKey *ECDSA) Store(filename string) error { privateKey, publicKey, err := ecdsaKey.encode() schemeKey := SchemeKey{ PrivateKey: privateKey, PublicKey: publicKey, KeyType: ecdsaKey.KeyType, } jsonBytes, err := json.Marshal(schemeKey) if err != nil { return err } return ioutil.WriteFile(filename, jsonBytes, 0644) } func (ecdsaKey *ECDSA) Sign(signedMetadata interface{}) (string, error) { // Convert signedMetadata to bytes. b, err := json.Marshal(signedMetadata) if err != nil { return "", err } // Calculate hash of string using SHA256 algo because only first 32 bytes are verified. sha256Sum := sha256.Sum256(b) r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey.PrivateKey, sha256Sum[0:]) if err != nil { return "", err } // Use asn1.Marshall as json.Unmarshal cannot unmarshall big ints. out, marshalError := asn1.Marshal(ecdsaSignature{r, s}) return hex.EncodeToString(out), marshalError } func (ecdsaKey *ECDSA) Verify(signingstring string, signature string) bool { // Decode the hex String. decSignatureString, err := hex.DecodeString(signature) if err != nil { return false } es := ecdsaSignature{} _, err = asn1.Unmarshal([]byte(decSignatureString), &es) if err != nil { return false } // Calculate hash of string using SHA256 algo sha256Sum := sha256.Sum256([]byte(signingstring)) // Verify the signature return ecdsa.Verify(&ecdsaKey.PublicKey, sha256Sum[0:], es.R, es.S) } func (ecdsaKey *ECDSA) GetPublicKey() string { _, publicKey, _ := ecdsaKey.encode() return publicKey } func (ecdsaKey *ECDSA) GetKeyId() types.KeyId { var bytes = sha256.Sum256([]byte(ecdsaKey.GetPublicKey())) var b = bytes[0:] return types.KeyId(fmt.Sprintf("%x", b)) } func (ecdsaKey *ECDSA) GetKeyIdHashAlgo() []types.HashAlgo { return []types.HashAlgo{constants.SHA256} } func (ecdsaKey *ECDSA) GetScheme() types.KeyScheme { return constants.ECDSA256Scheme }