blob: 27078c7a3d8c80ab02daa9eadb700a58baeebb23 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file
package main
import (
"crypto/ecdsa"
"crypto/md5"
"crypto/x509"
"encoding"
"errors"
"fmt"
)
// hash identifies a cryptographic hash function approved for use in signature algorithms.
type hash string
const (
sha1Hash = hash("SHA1") // sha1 cryptographic hash function defined in RFC3174.
sha256Hash = hash("SHA256") // sha256 cryptographic hash function defined in FIPS 180-4.
sha384Hash = hash("SHA384") // sha384 cryptographic hash function defined in FIPS 180-2.
sha512Hash = hash("SHA512") // sha512 cryptographic hash function defined in FIPS 180-2.
)
// publicKey represents a public key using an unspecified algorithm.
//
// MarshalBinary returns the DER-encoded PKIX representation of the public key,
// while UnmarshalPublicKey creates a PublicKey object from the marshaled bytes.
//
// String returns a human-readable representation of the public key.
type publicKey interface {
encoding.BinaryMarshaler
fmt.Stringer
// hashFn returns a cryptographic hash function whose security strength is
// appropriate for creating message digests to sign with this public key.
// For example, an ECDSA public key with a 512-bit curve would require a
// 512-bit hash function, whilst a key with a 256-bit curve would be
// happy with a 256-bit hash function.
hashFn() hash
implementationsOnlyInThisPackage()
}
type ecdsaPublicKey struct {
key *ecdsa.PublicKey
}
func (pk *ecdsaPublicKey) MarshalBinary() ([]byte, error) { return x509.MarshalPKIXPublicKey(pk.key) }
func (pk *ecdsaPublicKey) String() string { return publicKeyString(pk) }
func (pk *ecdsaPublicKey) implementationsOnlyInThisPackage() {}
func (pk *ecdsaPublicKey) hashFn() hash {
if nbits := pk.key.Curve.Params().BitSize; nbits <= 160 {
return sha1Hash
} else if nbits <= 256 {
return sha256Hash
} else if nbits <= 384 {
return sha384Hash
} else {
return sha512Hash
}
}
func publicKeyString(pk publicKey) string {
bytes, err := pk.MarshalBinary()
if err != nil {
return fmt.Sprintf("<invalid public key: %v>", err)
}
const hextable = "0123456789abcdef"
h := md5.Sum(bytes)
var repr [md5.Size * 3]byte
for i, v := range h {
repr[i*3] = hextable[v>>4]
repr[i*3+1] = hextable[v&0x0f]
repr[i*3+2] = ':'
}
return string(repr[:len(repr)-1])
}
// unmarshalPublicKey returns a PublicKey object from the DER-encoded PKIX representation of it
// (typically obtianed via PublicKey.MarshalBinary).
func unmarshalPublicKey(bytes []byte) (publicKey, error) {
key, err := x509.ParsePKIXPublicKey(bytes)
if err != nil {
return nil, err
}
switch v := key.(type) {
case *ecdsa.PublicKey:
return &ecdsaPublicKey{v}, nil
default:
return nil, errors.New(fmt.Sprintf("Unrecognized key: %T", key))
}
}
// newECDSAPublicKey creates a publicKey object that uses the ECDSA algorithm and the provided ECDSA public key.
func newECDSAPublicKey(key *ecdsa.PublicKey) publicKey {
return &ecdsaPublicKey{key}
}