Skip to content

Commit

Permalink
Add more parameterization (#48)
Browse files Browse the repository at this point in the history
* add more parameterization

Signed-off-by: bytemare <3641580+bytemare@users.noreply.github.com>

* clean-up tests, update deps

Signed-off-by: bytemare <3641580+bytemare@users.noreply.github.com>

* clean up

Signed-off-by: bytemare <3641580+bytemare@users.noreply.github.com>

Signed-off-by: bytemare <3641580+bytemare@users.noreply.github.com>
  • Loading branch information
bytemare authored Dec 26, 2022
1 parent 13d6216 commit bf3e1f2
Show file tree
Hide file tree
Showing 27 changed files with 450 additions and 384 deletions.
11 changes: 7 additions & 4 deletions .github/.golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ linters:
- gofumpt
- goheader
- goimports
- gomnd
#- gomnd
- gomoddirectives
- gomodguard
- goprintffuncname
Expand Down Expand Up @@ -146,13 +146,16 @@ linters-settings:
gomnd:
checks:
- argument
- case
- condition
- operation
- return
- assign
ignored-functions:
- 'EncodeVectorLen'
- 'decodeVectorLen'
- 'encoding.I2OSP'
- 'encoding.OS2IP'
- 'make'
gosimple:
checks: [ "all" ]
Expand Down Expand Up @@ -243,7 +246,7 @@ issues:
max-issues-per-linter: 0
max-same-issues: 0

# Independently from option `exclude` we use default exclude patterns,
# Independently of option `exclude` we use default exclude patterns,
# it can be disabled by this option. To list all
# excluded by default patterns execute `golangci-lint run --help`.
# Default value for this option is true.
Expand All @@ -252,5 +255,5 @@ issues:
run:
tests: false

#output:
# format: github-actions
output:
format: github-actions
12 changes: 6 additions & 6 deletions .github/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
PACKAGES := $(shell go list ./...)
COMMIT := $(shell git rev-parse HEAD)

.PHONY: update
update:
@cd ../
Expand All @@ -10,7 +7,10 @@ update:
@echo "Updating Github Actions pins..."
@$(foreach file, $(wildcard workflows/*.yml), pin-github-action $(file);)
@echo "Updating linters..."
@go install -u mvdan.cc/gofumpt@latest github.com/daixiang0/gci github.com/segmentio/golines@latest golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest
@go install mvdan.cc/gofumpt@latest
@go install github.com/daixiang0/gci@latest
@go install github.com/segmentio/golines@latest
@go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest
@curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin

.PHONY: fmt
Expand All @@ -20,8 +20,8 @@ fmt:
@go fmt ../...
@golines -m 120 -t 4 -w ../
@gofumpt -w -extra ../
@gci write --Section Standard --Section Default --Section "Prefix($(shell go list -m))" ../
@fieldalignment ../...
@gci write -s Standard -s Default -s "Prefix($(shell go list -m))" ../
@fieldalignment -fix ../...

.PHONY: license
license:
Expand Down
156 changes: 112 additions & 44 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,73 +72,145 @@ func (c *Client) buildPRK(evaluation *group.Element) []byte {
return c.conf.KDF.Extract(nil, encoding.Concat(output, stretched))
}

// ClientRegistrationInitOptions enables setting internal client values for the client registration.
type ClientRegistrationInitOptions struct {
// OPRFBlind: optional
OPRFBlind *group.Scalar
}

func getClientRegistrationInitBlind(options []ClientRegistrationInitOptions) *group.Scalar {
if len(options) == 0 {
return nil
}

return options[0].OPRFBlind
}

// RegistrationInit returns a RegistrationRequest message blinding the given password.
func (c *Client) RegistrationInit(password []byte) *message.RegistrationRequest {
m := c.OPRF.Blind(password)
func (c *Client) RegistrationInit(
password []byte,
options ...ClientRegistrationInitOptions,
) *message.RegistrationRequest {
m := c.OPRF.Blind(password, getClientRegistrationInitBlind(options))

return &message.RegistrationRequest{
C: c.conf.OPRF,
BlindedMessage: m,
}
}

// RegistrationFinalizeWithNonce returns a RegistrationRecord message given the identities, server's
// RegistrationResponse, and the envelope nonce to be used.
// This function is primarily used for testing purposes and will most probably be removed at some point.
func (c *Client) RegistrationFinalizeWithNonce(
resp *message.RegistrationResponse,
clientIdentity, serverIdentity, envelopeNonce []byte,
) (upload *message.RegistrationRecord, exportKey []byte) {
return c.registrationFinalize(clientIdentity, serverIdentity, envelopeNonce, resp)
// ClientRegistrationFinalizeOptions enables setting optional client values for the client registration.
type ClientRegistrationFinalizeOptions struct {
// ClientIdentity: optional
ClientIdentity []byte
// ServerIdentity: optional
ServerIdentity []byte
// EnvelopeNonce : optional
EnvelopeNonce []byte
}

func initClientRegistrationFinalizeOptions(options []ClientRegistrationFinalizeOptions) *keyrecovery.Credentials {
if len(options) == 0 {
return &keyrecovery.Credentials{
ClientIdentity: nil,
ServerIdentity: nil,
EnvelopeNonce: nil,
}
}

return &keyrecovery.Credentials{
ClientIdentity: options[0].ClientIdentity,
ServerIdentity: options[0].ServerIdentity,
EnvelopeNonce: options[0].EnvelopeNonce,
}
}

// RegistrationFinalize returns a RegistrationRecord message given the identities and the server's RegistrationResponse.
func (c *Client) RegistrationFinalize(
resp *message.RegistrationResponse,
clientIdentity, serverIdentity []byte,
options ...ClientRegistrationFinalizeOptions,
) (record *message.RegistrationRecord, exportKey []byte) {
return c.registrationFinalize(clientIdentity, serverIdentity, nil, resp)
}

func (c *Client) registrationFinalize(
clientIdentity, serverIdentity, envelopeNonce []byte,
resp *message.RegistrationResponse,
) (upload *message.RegistrationRecord, exportKey []byte) {
creds2 := &keyrecovery.Credentials{
ClientIdentity: clientIdentity,
ServerIdentity: serverIdentity,
EnvelopeNonce: envelopeNonce,
MaskingNonce: nil,
}

credentials := initClientRegistrationFinalizeOptions(options)
randomizedPwd := c.buildPRK(resp.EvaluatedMessage)
maskingKey := c.conf.KDF.Expand(randomizedPwd, []byte(tag.MaskingKey), c.conf.KDF.Size())
envelope, clientPublicKey, exportKey := keyrecovery.Store(c.conf, randomizedPwd, resp.Pks, creds2)
envelope, clientPublicKey, exportKey := keyrecovery.Store(c.conf, randomizedPwd, resp.Pks, credentials)

return &message.RegistrationRecord{
G: c.conf.Group,
PublicKey: clientPublicKey,
MaskingKey: maskingKey,
Envelope: envelope.Serialize(),
}, exportKey
}

// ClientLoginInitOptions enables setting optional values for the session, which default to secure random values if not
// set.
type ClientLoginInitOptions struct {
// Blind: optional
Blind *group.Scalar
// EphemeralSecretKey: optional
EphemeralSecretKey *group.Scalar
// Nonce: optional
Nonce []byte
// NonceLength: optional
NonceLength uint
}

func (c ClientLoginInitOptions) get() (*group.Scalar, ake.Options) {
return c.Blind, ake.Options{
EphemeralSecretKey: c.EphemeralSecretKey,
Nonce: c.Nonce,
NonceLength: c.NonceLength,
}
}

func getClientLoginInitOptions(options []ClientLoginInitOptions) (*group.Scalar, ake.Options) {
if len(options) != 0 {
return options[0].get()
}

return nil, ake.Options{
EphemeralSecretKey: nil,
Nonce: nil,
NonceLength: internal.NonceLength,
}
}

// LoginInit initiates the authentication process, returning a KE1 message blinding the given password.
// clientInfo is optional client information sent in clear, and only authenticated in KE3.
func (c *Client) LoginInit(password []byte) *message.KE1 {
m := c.OPRF.Blind(password)
ke1 := c.Ake.Start(c.conf.Group)
func (c *Client) LoginInit(password []byte, options ...ClientLoginInitOptions) *message.KE1 {
blind, akeOptions := getClientLoginInitOptions(options)
m := c.OPRF.Blind(password, blind)
ke1 := c.Ake.Start(c.conf.Group, akeOptions)
ke1.CredentialRequest = message.NewCredentialRequest(c.conf.OPRF, m)
c.Ake.Ke1 = ke1.Serialize()

return ke1
}

// ClientLoginFinishOptions enables setting optional client values for the client registration.
type ClientLoginFinishOptions struct {
// ClientIdentity: optional
ClientIdentity []byte
// ServerIdentity: optional
ServerIdentity []byte
}

func initClientLoginFinishOptions(options []ClientLoginFinishOptions) *ake.Identities {
if len(options) == 0 {
return &ake.Identities{
ClientIdentity: nil,
ServerIdentity: nil,
}
}

return &ake.Identities{
ClientIdentity: options[0].ClientIdentity,
ServerIdentity: options[0].ServerIdentity,
}
}

// LoginFinish returns a KE3 message given the server's KE2 response message and the identities. If the idc
// or ids parameters are nil, the client and server's public keys are taken as identities for both.
func (c *Client) LoginFinish(
clientIdentity, serverIdentity []byte,
ke2 *message.KE2,
ke2 *message.KE2, options ...ClientLoginFinishOptions,
) (ke3 *message.KE3, exportKey []byte, err error) {
if len(c.Ake.Ke1) == 0 {
return nil, nil, errKe1Missing
Expand All @@ -149,6 +221,8 @@ func (c *Client) LoginFinish(
return nil, nil, errInvalidMaskedLength
}

identities := initClientLoginFinishOptions(options)

// Finalize the OPRF.
randomizedPwd := c.buildPRK(ke2.EvaluatedMessage)

Expand All @@ -165,23 +239,17 @@ func (c *Client) LoginFinish(
c.conf,
randomizedPwd,
serverPublicKeyBytes,
clientIdentity,
serverIdentity,
identities.ClientIdentity,
identities.ServerIdentity,
envelope)
if err != nil {
return nil, nil, fmt.Errorf("key recovery: %w", err)
}

// Finalize the AKE.
if clientIdentity == nil {
clientIdentity = encoding.SerializePoint(clientPublicKey, c.conf.Group)
}

if serverIdentity == nil {
serverIdentity = serverPublicKeyBytes
}
identities.SetIdentities(clientPublicKey, serverPublicKeyBytes)

ke3, err = c.Ake.Finalize(c.conf, clientIdentity, clientSecretKey, serverIdentity, serverPublicKey, ke2)
ke3, err = c.Ake.Finalize(c.conf, identities, clientSecretKey, serverPublicKey, ke2)
if err != nil {
return nil, nil, fmt.Errorf("finalizing AKE: %w", err)
}
Expand Down
10 changes: 2 additions & 8 deletions deserializer.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (d *Deserializer) RegistrationRequest(registrationRequest []byte) (*message
return nil, errInvalidBlindedData
}

return &message.RegistrationRequest{C: d.conf.OPRF, BlindedMessage: blindedMessage}, nil
return &message.RegistrationRequest{BlindedMessage: blindedMessage}, nil
}

func (d *Deserializer) registrationResponseLength() int {
Expand All @@ -70,8 +70,6 @@ func (d *Deserializer) RegistrationResponse(registrationResponse []byte) (*messa
}

return &message.RegistrationResponse{
C: d.conf.OPRF,
G: d.conf.Group,
EvaluatedMessage: evaluatedMessage,
Pks: pks,
}, nil
Expand All @@ -98,7 +96,6 @@ func (d *Deserializer) RegistrationRecord(record []byte) (*message.RegistrationR
}

return &message.RegistrationRecord{
G: d.conf.Group,
PublicKey: pku,
MaskingKey: maskingKey,
Envelope: env,
Expand All @@ -123,8 +120,7 @@ func (d *Deserializer) deserializeCredentialResponse(
return nil, errInvalidEvaluatedData
}

return message.NewCredentialResponse(d.conf.OPRF,
data,
return message.NewCredentialResponse(data,
input[d.conf.OPRFPointLength:d.conf.OPRFPointLength+d.conf.NonceLen],
input[d.conf.OPRFPointLength+d.conf.NonceLen:maxResponseLength]), nil
}
Expand Down Expand Up @@ -152,7 +148,6 @@ func (d *Deserializer) KE1(ke1 []byte) (*message.KE1, error) {
}

return &message.KE1{
G: d.conf.Group,
CredentialRequest: request,
NonceU: nonceU,
EpkU: epku,
Expand Down Expand Up @@ -194,7 +189,6 @@ func (d *Deserializer) KE2(ke2 []byte) (*message.KE2, error) {
}

return &message.KE2{
G: d.conf.Group,
CredentialResponse: cresp,
NonceS: nonceS,
EpkS: epks,
Expand Down
10 changes: 8 additions & 2 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,10 @@ func Example_registration() {

// The client produces its record and a client-only-known secret export_key, that the client can use for other purposes (e.g. encrypt
// information to store on the server, and that the server can't decrypt). We don't use in the example here.
record, _ := client.RegistrationFinalize(response, clientID, serverID)
record, _ := client.RegistrationFinalize(response, opaque.ClientRegistrationFinalizeOptions{
ClientIdentity: clientID,
ServerIdentity: serverID,
})
message3 = record.Serialize()
}

Expand Down Expand Up @@ -330,7 +333,10 @@ func Example_loginKeyExchange() {
}

// In this example, we don't use the secret export key. The client sends the serialized ke3 to the server.
ke3, _, err := client.LoginFinish(clientID, serverID, ke2)
ke3, _, err := client.LoginFinish(ke2, opaque.ClientLoginFinishOptions{
ClientIdentity: clientID,
ServerIdentity: serverID,
})
if err != nil {
log.Fatalln(err)
}
Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module github.com/bytemare/opaque

go 1.18
go 1.19

require (
github.com/bytemare/crypto v0.3.2
github.com/bytemare/crypto v0.3.3
github.com/bytemare/hash v0.1.3
github.com/bytemare/ksf v0.1.0
)
Expand All @@ -12,6 +12,6 @@ require (
filippo.io/nistec v0.0.0-20220513155737-c4b6d02e738c // indirect
github.com/bytemare/hash2curve v0.1.2 // indirect
github.com/gtank/ristretto255 v0.1.2 // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/sys v0.0.0-20220803195053-6e608f9ce704 // indirect
golang.org/x/crypto v0.4.0 // indirect
golang.org/x/sys v0.3.0 // indirect
)
Loading

0 comments on commit bf3e1f2

Please sign in to comment.