enclave_encrypt

package module
v0.0.0-...-99157af Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2024 License: Apache-2.0 Imports: 13 Imported by: 0

README

Enclave One Shot Encryption

This package hosts a set of primitives for sending and encrypting message from a user to an enclave or vice versa.

N.B. Neither the client or the server should ever be reused to send/receive more then one message. We want to avoid the recipient target key being used more then once in order to improve forward secrecy; see security profile section for more details.

Terms

  • Encapsulated ("Encapped") Key - the public key of the sender used for ECDH.
  • Target Key Pair - the key pair of the receiver that the sender encrypts to the public key of. Only one message should ever be encrypted to the public key.
  • Server - a server inside of the enclave; normally an enclave application.
  • Client - a client outside of the enclave; normally a turnkey end user.
  • Enclave Auth Key Pair - a key pair derived from the quorum master seed specifically for the purpose of authentication with clients.

Overview

This protocol builds on top of the HPKE standard (RFC 9180) by adding recipient pre-flight authentication so the client can verify it is sending ciphertext to a turnkey controlled enclave and the enclave can verify its sending ciphertext to the correct client. See the security profile section more details.

HPKE Configuration

KEM: KEM_P256_HKDF_SHA256 KDF: KDF_HKDF_SHA256 AEAD: AEAD_AES256GCM INFO: b"turnkey_hpke" ADDITIONAL ASSOCIATED DATA: EncappedPublicKey||ReceiverPublicKey

Protocol

Server to Client
  1. Client generates target pair and sends clientTargetPub key to server. The authenticity of the clientTargetPub is assumed to have been verified by the Ump policy engine.
  2. Server computes ciphertext, serverEncappedPub = ENCRYPT(plaintext, clientTargetPub) and clears clientTargetPub from memory.
  3. Server computes serverEncappedPub_sig_enclaveAuthPriv = SIGN(serverEncappedPub, enclaveAuthPriv).
  4. Server sends (ciphertext, serverEncappedPub, serverEncappedPub_sig_enclaveAuthPriv) to client.
  5. Client runs VERIFY(serverEncappedPub, serverEncappedPub_sig_enclaveAuthPriv).
  6. Client recovers plaintext by computing DECRYPT(ciphertext, serverEncappedPub, clientTargetPriv) and the client target pair is cleared from memory. If the target pair is used multiple times we increase the count of messages that an attacker with the compromised target private key can decrypt.

Note there is no mechanism to prevent a faulty client from resubmitting the same target public key.

Client to Server
  1. Client sends request to server for target key.
  2. Server generates server target pair and computes serverTargetPub_sig_enclaveAuthPriv = SIGN(serverTargetPub, enclaveAuthPriv).
  3. Server sends (serverTargetPub, serverTargetPub_sig_enclaveAuthPriv) to client.
  4. Client runs VERIFY(serverTargetPub, serverTargetPub_sig_enclaveAuthPriv).
  5. Client computes ciphertext, clientEncappedPub = ENCRYPT(plaintext, serverTargetPub) and clears serverTargetPub from memory.
  6. Client sends (ciphertext, clientEncappedPub) to server and the client is cleared from memory.
  7. Server assumes the authenticity of clientEncappedPub has been verified by the Ump policy engine.
  8. Server recovers plaintext by computing DECRYPT(ciphertext, clientEncappedPub, clientTargetPriv) and server target pair is cleared from memory. If the target pair is used multiple times we increase the count of messages that an attacker with the compromised target private key can decrypt.

Security profile

  • Receiver pre-flight authentication: we achieve recipient authentication for both the server and client:
    • Client to Server: client verifies that the server's target key is signed by the enclaveAuth key.
    • Server to Client: server relies on upstream checks by Ump + activity signing scheme to enforce rules that guarantee authenticity of the clients target key. Specifically, when the client "sends" clientTargetPub it actually submits a signed payload (activity), and that payload must be signed with an existing credential persisted in org data.
  • Forward secrecy: the underlying HPKE spec does not provide forward secrecy on the recipient side since the target key can be long lived. To improve forward secrecy we specify that the a target key should only be used once by the sender and receiver.
  • Sender authentication: we use OpMode Base and forgo authentication that the sender possessed a given KEM private key. In order for this to be taken advantage of, an attacker would need to compromise the receivers target private key, intercept the message, decrypt it, and then re-encrypt with different plaintext. In our use case, if the attacker intercepts the receivers target private key, everything is already broken so the extra level of authentication is not necessary. Read more about HPKE asymmetric authentication here.

Documentation

Index

Constants

View Source
const (
	// Consult the rust implementations README for how these should be configured.
	// See [here](../../../rust/enclave_encrypt/README.md#hpke-configuration)
	KemId           hpke.KEM  = hpke.KEM_P256_HKDF_SHA256
	KdfId           hpke.KDF  = hpke.KDF_HKDF_SHA256
	AeadId          hpke.AEAD = hpke.AEAD_AES256GCM
	TurnkeyHpkeInfo string    = "turnkey_hpke"
	DataVersion     string    = "v1.0.0"
)

Variables

This section is empty.

Functions

func P256Sign

func P256Sign(privateKey *ecdsa.PrivateKey, msg []byte) ([]byte, error)

Sign the given `msg`.

func P256Verify

func P256Verify(publicKey *ecdsa.PublicKey, msg []byte, signature []byte) bool

Verify the given signature over `msg` with `publicKey`.

func ToEcdsaPublic

func ToEcdsaPublic(publicBytes []byte) (*ecdsa.PublicKey, error)

Takes a byte slice and returns a ECDSA public key

func ValidateChecksum

func ValidateChecksum(payload []byte) error

Validates that a payload has a valid checksum in the last four bytes.

Types

type Bytes

type Bytes []byte

func (Bytes) MarshalJSON

func (bytes Bytes) MarshalJSON() ([]byte, error)

func (*Bytes) UnmarshalJSON

func (bytes *Bytes) UnmarshalJSON(data []byte) error

type ClientSendMsg

type ClientSendMsg struct {
	// We assume this public key can be trusted because the request went through
	// checks in the policy engine.
	EncappedPublic *Bytes `json:"encappedPublic,omitempty"`
	// The encrypted message.
	Ciphertext *Bytes `json:"ciphertext,omitempty"`
}

Message from the client with encapsulated key and ciphertext.

type EnclaveEncryptClient

type EnclaveEncryptClient struct {
	// contains filtered or unexported fields
}

An instance of the client side for enclave encrypt protocol. This should only be used for either a SINGLE send or a single receive.

func NewEnclaveEncryptClient

func NewEnclaveEncryptClient(enclaveAuthKey *ecdsa.PublicKey) (*EnclaveEncryptClient, error)

Create a client from the quorum public key.

func NewEnclaveEncryptClientFromTargetKey

func NewEnclaveEncryptClientFromTargetKey(enclaveAuthKey *ecdsa.PublicKey, targetPrivateKey kem.PrivateKey) (*EnclaveEncryptClient, error)

Create a client from the quorum public key and target key pair.

func (*EnclaveEncryptClient) AuthDecrypt

func (c *EnclaveEncryptClient) AuthDecrypt(payload string) (plaintext []byte, err error)

Decrypt a base58-encoded payload from the server. This is used in email authentication and email recovery flows.

func (*EnclaveEncryptClient) Decrypt

func (c *EnclaveEncryptClient) Decrypt(bundleBytes Bytes, organizationId string) (plaintext []byte, err error)

Decrypts a bundle. This is used in private key and wallet export flows. In the export flow for example, `bundleBytes` represents the bytes of the received bundle and contains the ciphertext of the exported wallet or private key. Note: for v1 bundles this function extracts the organizationId fields from the signed data bytes, verifies its integrity, and verifies that its match with the (user-) provided `organizationId`. For v0 bundles, `organizationId` is irrelevant.

func (*EnclaveEncryptClient) Encrypt

func (c *EnclaveEncryptClient) Encrypt(plaintext Bytes, bundleBytes Bytes, organizationId string, userId string) (*ClientSendMsg, error)

Encrypt some plaintext to the given server, using `enclaveMsgBytes`. In the import flow for example, `bundleBytes` represents the bytes of the received bundle. Note: for v1 bundles this function extracts organizationId and userId fields from the signed data bytes, verifies their integrity, and verifies that they match with the (user-) provided `organizationId` and `userId` params. To decrypt v0 bundles, `organizationId` and `userId` are irrelevant and can be set to empty strings.

func (*EnclaveEncryptClient) TargetPublic

func (c *EnclaveEncryptClient) TargetPublic() ([]byte, error)

Get this clients target public key.

type EnclaveEncryptServer

type EnclaveEncryptServer struct {
	// contains filtered or unexported fields
}

func NewEnclaveEncryptServer

func NewEnclaveEncryptServer(enclaveAuthKey *ecdsa.PrivateKey, organizationId string, userId *string) (EnclaveEncryptServer, error)

This should be the quorum signing secret derived from the quorum master seed.

func NewEnclaveEncryptServerFromTargetKey

func NewEnclaveEncryptServerFromTargetKey(enclaveAuthKey *ecdsa.PrivateKey, targetPrivateKey *kem.PrivateKey, organizationId string, userId *string) (EnclaveEncryptServer, error)

Create a server from the enclave quorum public key and the target key.

func (*EnclaveEncryptServer) AuthEncrypt

func (s *EnclaveEncryptServer) AuthEncrypt(clientTarget []byte, plaintext []byte) (string, error)

Relevant for usage with auth activities: Email Auth, Email Recovery.

func (*EnclaveEncryptServer) Encrypt

func (s *EnclaveEncryptServer) Encrypt(clientTarget []byte, plaintext []byte) (*ServerSendMsgV1, error)

Encrypt `plaintext` to the `clientTarget` key.

func (*EnclaveEncryptServer) IntoEnclaveServerRecv

func (s *EnclaveEncryptServer) IntoEnclaveServerRecv() EnclaveEncryptServerRecv

Get the server receiving type.

func (*EnclaveEncryptServer) PublishTarget

func (s *EnclaveEncryptServer) PublishTarget() (*ServerTargetMsgV1, error)

Return the servers encryption target key and a signature over it from the quorum key.

type EnclaveEncryptServerRecv

type EnclaveEncryptServerRecv struct {
	// contains filtered or unexported fields
}

func (*EnclaveEncryptServerRecv) Decrypt

func (s *EnclaveEncryptServerRecv) Decrypt(msg ClientSendMsg) ([]byte, error)

Decrypt a message from a client that encrypted to this server instance target key. Relevant for usage with auth activities: Email Auth, Email Recovery.

type ServerMsg

type ServerMsg struct {
	// Version of the data.
	Version *string `json:"version,omitempty"`
}

type ServerSendData

type ServerSendData struct {
	// Encapsulation key used to generate the ciphertext.
	EncappedPublic Bytes `json:"encappedPublic"`
	// Ciphertext from the server.
	Ciphertext Bytes `json:"ciphertext"`
	// Organization making the request.
	OrganizationId string `json:"organizationId"`
}

Data object from the server with the encapsulated public key, ciphertext, and organization ID.

type ServerSendMsgV0

type ServerSendMsgV0 struct {
	// Encapsulation key used to generate the ciphertext.
	EncappedPublic *Bytes `json:"encappedPublic,omitempty"`
	// Quorum key signature over the encapsulation key.
	EncappedPublicSignature *Bytes `json:"encappedPublicSignature,omitempty"`
	// Ciphertext from the server.
	Ciphertext *Bytes `json:"ciphertext,omitempty"`
}

Message from the server with encapsulated key, quorum key signature over encapsulated key and ciphertext.

type ServerSendMsgV1

type ServerSendMsgV1 struct {
	// Version of the data.
	Version string `json:"version"`
	// Data sent by the enclave
	Data Bytes `json:"data"`
	// Enclave quorum key signature over the data.
	DataSignature Bytes `json:"dataSignature"`
	// Enclave quorum key public key.
	EnclaveQuorumPublic Bytes `json:"enclaveQuorumPublic"`
}

Message from the server with data, the data's version, enclave quorum key, and the enclave quorum key signature over the data.

type ServerTargetData

type ServerTargetData struct {
	// Target public key for client to encrypt to.
	TargetPublic Bytes `json:"targetPublic"`
	// Organization making the request.
	OrganizationId string `json:"organizationId"`
	// User making the request.
	UserId string `json:"userId"`
}

Data object from the server with the target public key, organization ID, and an optional user ID field.

type ServerTargetMsgV0

type ServerTargetMsgV0 struct {
	// Target public key for client to encrypt to.
	TargetPublic Bytes `json:"targetPublic"`
	// Signature over the servers public target key.
	TargetPublicSignature Bytes `json:"targetPublicSignature"`
}

Message from the server with a encryption target key and a quorum key signature over it.

type ServerTargetMsgV1

type ServerTargetMsgV1 struct {
	// Version of the data.
	Version string `json:"version"`
	// Data sent and signed by the enclave.
	Data Bytes `json:"data"`
	// Enclave quorum key signature over the data.
	DataSignature Bytes `json:"dataSignature"`
	// Enclave quorum key public key.
	EnclaveQuorumPublic Bytes `json:"enclaveQuorumPublic"`
}

Message from the server with data, the data's version, enclave quorum key, and the enclave quorum key signature over the data.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL