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)encryptedSharedSecretneeds to be sent to the server.clientCtxcan be used to encrypt/decrypt messages exchanged with the server.- The last parameter is an optional pre-shared key (
Psktype).
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)serverCtxcan be used to encrypt/decrypt messages exchanged with the client- The last parameter is an optional pre-shared key (
Psktype).
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)