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.
suite, err := NewSuite(KemX25519HkdfSha256, KdfHkdfSha256, AeadAes128Gcm)
serverKp, err := ctx.GenerateKeyPair()
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.
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).
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.
The server can decrypt a ciphertext sent by the client:
decrypted, err := serverCtx.DecryptFromClient(ciphertext, nil)
Second parameter is optional associated data.
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.
The client can decrypt a ciphertext sent by the server:
decrypted, err := clientCtx.DecryptFromServer(ciphertext, nil)
Second parameter is optional associated data.
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)
The exporter secret can be obtained with the ExportedSecret()
function available both in the ServerContext
and ClientContext
structures:
exporter := serverCtx.ExporterSecret()
secret1, err := clientCtx.Export("description 1")
secret2, err := serverCtx.Export("description 2");
cipher, err := suite.NewRawCipher(key)