Documentation ¶
Index ¶
- Constants
- Variables
- type Dispatcher
- type ECDHPrivateKey
- type Error
- type InvalidSignatureError
- type NativeECDHKey
- type NativeSession
- func (b *NativeSession) Decrypt(nonce, ciphertext, associatedData, tag []byte) (plaintext []byte, err error)
- func (b *NativeSession) Encrypt(plaintext, associatedData []byte) (nonce, ciphertext, tag []byte, err error)
- func (b *NativeSession) LocalPublicBytes() []byte
- func (b *NativeSession) NewHMAC(label string) hash.Hash
- func (b *NativeSession) SessionInfoHMAC(id, challenge, encodedInfo []byte) ([]byte, error)
- type Peer
- type Session
- type Signer
- func ImportSessionInfo(private ECDHPrivateKey, verifierName, encodedInfo []byte, ...) (*Signer, error)
- func NewAuthenticatedSigner(private ECDHPrivateKey, verifierName, challenge, encodedInfo, tag []byte) (*Signer, error)
- func NewSigner(private ECDHPrivateKey, verifierName []byte, ...) (*Signer, error)
- func (s *Signer) AuthorizeHMAC(message *universal.RoutableMessage, expiresIn time.Duration) error
- func (s *Signer) Encrypt(message *universal.RoutableMessage, expiresIn time.Duration) error
- func (s *Signer) ExportSessionInfo() ([]byte, error)
- func (s *Signer) RemotePublicKeyBytes() []byte
- func (s *Signer) UpdateSessionInfo(info *signatures.SessionInfo) error
- func (s *Signer) UpdateSignedSessionInfo(challenge, encodedInfo, tag []byte) error
- type Verifier
- func (v *Verifier) SessionInfo() (*signatures.SessionInfo, error)
- func (v *Verifier) SetSessionInfo(challenge []byte, message *universal.RoutableMessage) error
- func (v *Verifier) SignedSessionInfo(challenge []byte) (encodedInfo, tag []byte, err error)
- func (v *Verifier) Verify(message *universal.RoutableMessage) (plaintext []byte, err error)
Examples ¶
Constants ¶
SharedKeySizeBytes is the length of the cryptographic key shared by a Signer and a Verifier.
Variables ¶
var ( // ErrInvalidPublicKey is an Error raised when a remote peer provides an invalid public key. ErrInvalidPublicKey = newError(errCodeBadParameter, "invalid public key") // ErrInvalidPrivateKey indicates the local peer tried to load an unsupported or malformed // private key. ErrInvalidPrivateKey = errors.New("invalid private key") )
var ( // ErrMetadataFieldTooLong indicates an authenticated field (such as a verifier name) is too // long to be compatible with the serialization format. ErrMetadataFieldTooLong = errors.New("metadata fields can't be more than 255 bytes long") )
Functions ¶
This section is empty.
Types ¶
type Dispatcher ¶
type Dispatcher struct {
ECDHPrivateKey
}
Dispatcher facilitates creating connections to multiple vehicles using the same ECDHPrivateKey.
Example ¶
const carCount = 10 const messagesPerCar = 5 var challenges [][]byte // Create dispatcher dispatcherPrivateKey, err := NewECDHPrivateKey(rand.Reader) if err != nil { panic(fmt.Sprintf("Failed to generate dispatcher key: %s", err)) } dispatcher := Dispatcher{dispatcherPrivateKey} // Initialize cars, provision dispatcher public key cars := make([]*Verifier, carCount) for i := 0; i < carCount; i++ { vin := []byte(fmt.Sprintf("%d", i)) VCSECKey, err := NewECDHPrivateKey(rand.Reader) var challenge [16]byte if _, err := rand.Read(challenge[:]); err != nil { panic(fmt.Sprintf("Failed to generate random challenge: %s", err)) } else { challenges = append(challenges, challenge[:]) } if err != nil { panic(fmt.Sprintf("Failed to generate car key: %s", err)) } cars[i], err = NewVerifier(VCSECKey, vin, universal.Domain_DOMAIN_VEHICLE_SECURITY, dispatcherPrivateKey.PublicBytes()) if err != nil { panic(fmt.Sprintf("Failed to initialize car: %s", err)) } } message := &universal.RoutableMessage{ ToDestination: &universal.Destination{ SubDestination: &universal.Destination_Domain{Domain: universal.Domain_DOMAIN_VEHICLE_SECURITY}, }, } for i := 0; i < carCount; i++ { // Fetch session info from vehicle sessionInfo, tag, err := cars[i].SignedSessionInfo(challenges[i]) if err != nil { panic(fmt.Sprintf("Error obtaining session info from car %d: %s", i, err)) } // Give it to the signer (dispatcher). The UUID used to fetch the // session info can be used as the challenge. connection, err := dispatcher.ConnectAuthenticated(cars[i].verifierName, challenges[i], sessionInfo, tag) if err != nil { panic(fmt.Sprintf("Error creating authenticated connection to car %d: %s", i, err)) } // Send several messages to vehicle using connection for j := 0; j < messagesPerCar; j++ { original := []byte(fmt.Sprintf("Message %d for car %d", j, i)) message.Payload = &universal.RoutableMessage_ProtobufMessageAsBytes{ProtobufMessageAsBytes: original} if err := connection.Encrypt(message, time.Minute); err != nil { panic(fmt.Sprintf("Failed to encrypt message: %s", err)) } // This won't happen if err above is nil, just here for illustrative purposes. if bytes.Equal(message.GetProtobufMessageAsBytes(), original) { panic("Message wasn't encrypted!") } if plaintext, err := cars[i].Verify(message); err != nil { panic(fmt.Sprintf("Decryption error :%s", err)) } else if !bytes.Equal(plaintext, original) { panic("Failed to recover original plaintext") } } }
Output:
func (*Dispatcher) Connect ¶
func (d *Dispatcher) Connect(verifierId []byte, sessionInfo *signatures.SessionInfo) (*Signer, error)
func (*Dispatcher) ConnectAuthenticated ¶
func (d *Dispatcher) ConnectAuthenticated(verifierId, challenge, encodedSessionInfo, tag []byte) (*Signer, error)
type ECDHPrivateKey ¶
type ECDHPrivateKey interface { Exchange(remotePublicBytes []byte) (Session, error) PublicBytes() []byte }
ECDHPrivateKey represents a local private key.
func LoadExternalECDHKey ¶
func LoadExternalECDHKey(filename string) (ECDHPrivateKey, error)
func NewECDHPrivateKey ¶
func NewECDHPrivateKey(rng io.Reader) (ECDHPrivateKey, error)
func UnmarshalECDHPrivateKey ¶
func UnmarshalECDHPrivateKey(privateScalar []byte) ECDHPrivateKey
type Error ¶
type Error struct { Code universal.MessageFault_E Info string }
Error represents a protocol-layer error.
type InvalidSignatureError ¶
type InvalidSignatureError struct { Code universal.MessageFault_E EncodedInfo []byte Tag []byte }
func (*InvalidSignatureError) Error ¶
func (e *InvalidSignatureError) Error() string
type NativeECDHKey ¶
type NativeECDHKey struct {
*ecdsa.PrivateKey
}
func (*NativeECDHKey) Exchange ¶
func (n *NativeECDHKey) Exchange(publicBytes []byte) (Session, error)
func (*NativeECDHKey) Public ¶
func (n *NativeECDHKey) Public() *ecdsa.PublicKey
func (*NativeECDHKey) PublicBytes ¶
func (n *NativeECDHKey) PublicBytes() []byte
type NativeSession ¶
type NativeSession struct {
// contains filtered or unexported fields
}
NativeSession implements the Session interface using native Go.
func (*NativeSession) Decrypt ¶
func (b *NativeSession) Decrypt(nonce, ciphertext, associatedData, tag []byte) (plaintext []byte, err error)
func (*NativeSession) Encrypt ¶
func (b *NativeSession) Encrypt(plaintext, associatedData []byte) (nonce, ciphertext, tag []byte, err error)
func (*NativeSession) LocalPublicBytes ¶
func (b *NativeSession) LocalPublicBytes() []byte
func (*NativeSession) SessionInfoHMAC ¶
func (b *NativeSession) SessionInfoHMAC(id, challenge, encodedInfo []byte) ([]byte, error)
type Peer ¶
type Peer struct {
// contains filtered or unexported fields
}
A Peer is the parent type for Signer and Verifier.
type Session ¶
type Session interface { // Returns the session info HMAC tag for encodedInfo. The challenge is a Signer-provided // anti-replay value. SessionInfoHMAC(id, challenge, encodedInfo []byte) ([]byte, error) // Encrypt plaintext and generate a tag that can be used to authenticate // the ciphertext and associated data. The tag and ciphertext are part of // the same slice, but returned separately for convenience. Encrypt(plaintext, associatedData []byte) (nonce, ciphertext, tag []byte, err error) // Authenticate a ciphertext and its associated data using the tag, then // decrypt it and return the plaintext. Decrypt(nonce, ciphertext, associatedData, tag []byte) (plaintext []byte, err error) // Return the encoded local public key. LocalPublicBytes() []byte // Returns a hash.Hash context that can be used as a KDF rooted in the shared secret. NewHMAC(label string) hash.Hash }
A Session allows encrypting/decrypting/authenticating data using a shared ECDH secret.
type Signer ¶
type Signer struct { Peer // contains filtered or unexported fields }
Signers encrypt messages that are decrypted and verified by a designated Verifier. (Technically speaking, the name is a misnomer since Signers use symmetric-key operations following ECDH key agreement.)
func ImportSessionInfo ¶
func ImportSessionInfo(private ECDHPrivateKey, verifierName, encodedInfo []byte, generatedAt time.Time) (*Signer, error)
ImportSessionInfo allows creation of a Signer with cached SessionInfo. This can be used to avoid a round trip with the Verifier.
func NewAuthenticatedSigner ¶
func NewAuthenticatedSigner(private ECDHPrivateKey, verifierName, challenge, encodedInfo, tag []byte) (*Signer, error)
NewAuthenticatedSigner creates a Signer from encoded and cryptographically verified session info.
func NewSigner ¶
func NewSigner(private ECDHPrivateKey, verifierName []byte, verifierInfo *signatures.SessionInfo) (*Signer, error)
NewSigner creates a Signer that sends authenticated messages to the Verifier named verifierName. In order to use this function, the client needs to obtain verifierInfo from the Verifier.
func (*Signer) AuthorizeHMAC ¶
AuthorizeHMAC adds an authentication tag to message.
This allows the recipient to verify the message has not been tampered with, but the payload is not encrypted. Unencrypted (but authenticated) messages are required for an HTTP API which relays messages to vehicles but needs to state in order to determine when a sequence of replies terminates. Sensitive data, such as live camera streams, is encrypted on the application layer.
func (*Signer) Encrypt ¶
Encrypt message's payload in-place. This method adds (authenticated) metadata to the message as well, including the provided expiration time.
func (*Signer) ExportSessionInfo ¶
ExportSessionInfo can be used to write session state to disk, allowing for later resumption using ImportSessionInfo.
func (*Signer) RemotePublicKeyBytes ¶
RemotePublicKeyBytes returns the Verifer's public key encoded without point compression.
func (*Signer) UpdateSessionInfo ¶
func (s *Signer) UpdateSessionInfo(info *signatures.SessionInfo) error
UpdateSessionInfo allows s to resync session state with a Verifier. A Verifier may include info in an authentication error message when the error may have resulted from a desync. The Signer can update its session info and then reattempt transmission.
func (*Signer) UpdateSignedSessionInfo ¶
UpdateSignedSessionInfo allows s to resync session state with a Verifier using cryptographically verified session state. See UpdateSessionInfo.
type Verifier ¶
type Verifier struct { Peer // contains filtered or unexported fields }
A Verifier checks the authenticity of commands sent by a Signer.
func NewVerifier ¶
func NewVerifier(private ECDHPrivateKey, id []byte, domain universal.Domain, signerPublicBytes []byte) (*Verifier, error)
NewVerifier returns a Verifier. Set domain to universal.Domain_DOMAIN_BROADCAST if the Verifier shouldn't enforce domain checking. The Verifier's domain must be known in advance by the Signer.
func (*Verifier) SessionInfo ¶
func (v *Verifier) SessionInfo() (*signatures.SessionInfo, error)
SessionInfo contains metadata used to prevent replay and similar attacks. A Signer must have the Verifier's SessionInfo on initialization.
func (*Verifier) SetSessionInfo ¶
func (v *Verifier) SetSessionInfo(challenge []byte, message *universal.RoutableMessage) error
SetSessionInfo attaches up-to-date session info to a message. This is useful when v encounters an error while authenticating a message and wishes to include session info in the error response, thereby allowing the Signer to resync.
func (*Verifier) SignedSessionInfo ¶
SignedSessionInfo returns a protobuf-encoded signatures.SessionInfo along with an authentication tag that a Signer may use to verify the info has not been tampered with.