dnscrypt-proxy/vendor/github.com/jedisct1/go-hpke-compact/README.md

4.2 KiB

CI status Go Reference

HPKE-Compact

A compact HPKE implemention for Go

hpkecompact is a small implementation of the Hybrid Public Key Encryption (HPKE) draft.

It fits in a single file and only uses the Go standard library and x/crypto.

Suites are currently limited to X25519-HKDF-SHA256 / HKDF-SHA-256 / {AES-{128,256}-GCM, CHACHA20-POLY1305}; these are very likely to be the most commonly deployed ones for a forseable future.

Usage

Suite instantiation

suite, err := NewSuite(KemX25519HkdfSha256, KdfHkdfSha256, AeadAes128Gcm)

Key pair creation

serverKp, err := ctx.GenerateKeyPair()

Client: creation and encapsulation of the shared secret

A client initiates a connexion by sending an encrypted secret; a server accepts an encrypted secret from a client, and decrypts it, so that both parties can eventually agree on a shared secret.

clientCtx, encryptedSharedSecret, err :=
    suite.NewClientContext(serverKp.PublicKey, []byte("application name"), nil)
  • encryptedSharedSecret needs to be sent to the server.
  • clientCtx can be used to encrypt/decrypt messages exchanged with the server.
  • The last parameter is an optional pre-shared key (Psk type).

To improve misuse resistance, this implementation uses distinct types for the client and the server context: ClientContext for the client, and ServerContext for the server.

Server: decapsulation of the shared secret

serverCtx, err := suite.NewServerContext(encryptedSharedSecret,
    serverKp, []byte("application name"), nil)
  • serverCtx can be used to encrypt/decrypt messages exchanged with the client
  • The last parameter is an optional pre-shared key (Psk type).

Encryption of a message from the client to the server

A message can be encrypted by the client for the server:

ciphertext, err := clientCtx.EncryptToServer([]byte("message"), nil)

Nonces are automatically incremented, so it is safe to call this function multiple times within the same context.

Second parameter is optional associated data.

Decryption of a ciphertext received by the server

The server can decrypt a ciphertext sent by the client:

decrypted, err := serverCtx.DecryptFromClient(ciphertext, nil)

Second parameter is optional associated data.

Encryption of a message from the server to the client

A message can also be encrypted by the server for the client:

ciphertext, err := serverCtx.EncryptToClient([]byte("response"), nil)

Nonces are automatically incremented, so it is safe to call this function multiple times within the same context.

Second parameter is optional associated data.

Decryption of a ciphertext received by the client

The client can decrypt a ciphertext sent by the server:

decrypted, err := clientCtx.DecryptFromServer(ciphertext, nil)

Second parameter is optional associated data.

Authenticated modes

Authenticated modes, with or without a PSK are supported.

Just replace NewClientContext() with NewAuthenticatedClientContext() and NewServerContext() with NewAuthenticatedServerContext() for authentication.

clientKp, err := suite.GenerateKeyPair()
serverKp, err := suite.GenerateKeyPair()

clientCtx, encryptedSharedSecret, err := suite.NewAuthenticatedClientContext(
    clientKp, serverKp.PublicKey, []byte("app"), psk)

serverCtx, err := suite.NewAuthenticatedServerContext(
    clientKp.PublicKey, encryptedSharedSecret, serverKp, []byte("app"), psk)

Exporter secret

The exporter secret can be obtained with the ExportedSecret() function available both in the ServerContext and ClientContext structures:

exporter := serverCtx.ExporterSecret()

Key derivation

secret1, err := clientCtx.Export("description 1")
secret2, err := serverCtx.Export("description 2");

Access the raw cipher interface

cipher, err := suite.NewRawCipher(key)

That's it!