Skip to content

Commit

Permalink
Update OPRF (#49)
Browse files Browse the repository at this point in the history
* update OPRF

Signed-off-by: bytemare <[email protected]>

* some adaptations to identifiers

Signed-off-by: bytemare <[email protected]>

* update vectors and fuzzing tests

Signed-off-by: bytemare <[email protected]>

* update deps

Signed-off-by: bytemare <[email protected]>

---------

Signed-off-by: bytemare <[email protected]>
  • Loading branch information
bytemare authored Feb 8, 2023
1 parent ddd30b6 commit 7dd75ce
Show file tree
Hide file tree
Showing 22 changed files with 416 additions and 313 deletions.
9 changes: 5 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ module github.com/bytemare/opaque
go 1.19

require (
github.com/bytemare/crypto v0.3.3
github.com/bytemare/crypto v0.4.1
github.com/bytemare/hash v0.1.3
github.com/bytemare/ksf v0.1.0
)

require (
filippo.io/nistec v0.0.0-20220513155737-c4b6d02e738c // indirect
filippo.io/edwards25519 v1.0.0 // indirect
filippo.io/nistec v0.0.0-20220825075812-a82cab4ea6f0 // indirect
github.com/bytemare/hash2curve v0.1.2 // indirect
github.com/gtank/ristretto255 v0.1.2 // indirect
golang.org/x/crypto v0.4.0 // indirect
golang.org/x/sys v0.3.0 // indirect
golang.org/x/crypto v0.5.0 // indirect
golang.org/x/sys v0.5.0 // indirect
)
18 changes: 10 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
filippo.io/nistec v0.0.0-20220513155737-c4b6d02e738c h1:x4epP2lA8b5UYoIFjcVpN+MfJQeX5M5Yilmc1VH0YDw=
filippo.io/nistec v0.0.0-20220513155737-c4b6d02e738c/go.mod h1:84fxC9mi+MhC2AERXI4LSa8cmSVOzrFikg6hZ4IfCyw=
github.com/bytemare/crypto v0.3.3 h1:/zKg0KGDW/AZbLpS7VDMmGTjwkfr3fZzSfVZEliVCFE=
github.com/bytemare/crypto v0.3.3/go.mod h1:l4WGLrTDFQSxSrbB3d1DknkMe26M3IJHos66ZMAsrE8=
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
filippo.io/nistec v0.0.0-20220825075812-a82cab4ea6f0 h1:infQBtlEPAdRCqMIoddLS8K27zaaz05FLnrXskk0TtE=
filippo.io/nistec v0.0.0-20220825075812-a82cab4ea6f0/go.mod h1:84fxC9mi+MhC2AERXI4LSa8cmSVOzrFikg6hZ4IfCyw=
github.com/bytemare/crypto v0.4.1 h1:XqbZHc0wuDHJMSRFgF3JLx8ROQmgSkdGKkiDk4br8Xg=
github.com/bytemare/crypto v0.4.1/go.mod h1:O/pUglImCf2zLj7Ii1FZAaDb4hEV5jcEZCgXVRx4blQ=
github.com/bytemare/hash v0.1.3 h1:E2v/+gqvLTjaR8W2JdhqaB2L9161yFBlSXDnYEyMt94=
github.com/bytemare/hash v0.1.3/go.mod h1:5WJSSK+ftRTLt9fOMHT+S4eXTTAb0Uz+NJJZKHLKovM=
github.com/bytemare/hash2curve v0.1.2 h1:V/TSdU/WsfYS3Bk73ap+odLCOOm2/B02rKE8lb91djI=
Expand All @@ -10,7 +12,7 @@ github.com/bytemare/ksf v0.1.0 h1:t0VobAtBVSb1SyX1RltuZ+c4gVVHLKQnUN5oYd3o3qc=
github.com/bytemare/ksf v0.1.0/go.mod h1:wKBp7KmpY482R8lOfcGFh01MsJEU0vZHw8qFEMzNoRU=
github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc=
github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o=
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
2 changes: 1 addition & 1 deletion internal/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ type Configuration struct {
MAC *Mac
Hash *Hash
KSF *KSF
OPRF oprf.Identifier
Context []byte
NonceLen int
EnvelopeSize int
OPRFPointLength int
AkePointLength int
Group group.Group
OPRF oprf.Ciphersuite
}

// RandomBytes returns random bytes of length len (wrapper for crypto/rand).
Expand Down
2 changes: 1 addition & 1 deletion internal/keyrecovery/keyrec.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (

func deriveAuthKeyPair(conf *internal.Configuration, randomizedPwd, nonce []byte) (*group.Scalar, *group.Element) {
seed := conf.KDF.Expand(randomizedPwd, encoding.SuffixString(nonce, tag.ExpandPrivateKey), internal.SeedLength)
sk := oprf.Ciphersuite(conf.Group).DeriveKey(seed, []byte(tag.DerivePrivateKey))
sk := oprf.IDFromGroup(conf.Group).DeriveKey(seed, []byte(tag.DerivePrivateKey))

return sk, conf.Group.Base().Multiply(sk)
}
Expand Down
4 changes: 2 additions & 2 deletions internal/oprf/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ var errInvalidInput = errors.New("invalid input - OPRF input deterministically m
// Client implements the OPRF client and holds its state.
type Client struct {
blind *group.Scalar
Identifier
input []byte
Ciphersuite
}

// Blind masks the input.
Expand All @@ -49,7 +49,7 @@ func (c *Client) hashTranscript(input, unblinded []byte) []byte {
encElement := encoding.EncodeVector(unblinded)
encDST := []byte(tag.OPRFFinalize)

return c.Ciphersuite.hash(encInput, encElement, encDST)
return c.Identifier.hash(encInput, encElement, encDST)
}

// Finalize terminates the OPRF by unblinding the evaluation and hashing the transcript.
Expand Down
113 changes: 71 additions & 42 deletions internal/oprf/oprf.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,62 +12,70 @@ package oprf

import (
"crypto"
"fmt"

group "github.com/bytemare/crypto"

"github.com/bytemare/opaque/internal/encoding"
"github.com/bytemare/opaque/internal/tag"
)

const maxDeriveKeyPairTries = 255

// base identifies the OPRF non-verifiable, base, mode, encoded on one byte: base = I2OSP(0, 1).
var base = []byte{0}

// Ciphersuite identifies the OPRF compatible cipher suite to be used.
type Ciphersuite group.Group
// Identifier of the OPRF compatible cipher suite to be used.
type Identifier string

const (
// RistrettoSha512 is the OPRF cipher suite of the Ristretto255 group and SHA-512.
RistrettoSha512 = Ciphersuite(group.Ristretto255Sha512)
// Ristretto255Sha512 is the OPRF cipher suite of the Ristretto255 group and SHA-512.
Ristretto255Sha512 Identifier = "ristretto255-SHA512"

// Decaf448Sha512 is the OPRF cipher suite of the Decaf448 group and SHA-512.
// decaf448Sha512 Identifier = "decaf448-SHAKE256".

// P256Sha256 is the OPRF cipher suite of the NIST P-256 group and SHA-256.
P256Sha256 = Ciphersuite(group.P256Sha256)
P256Sha256 Identifier = "P256-SHA256"

// P384Sha384 is the OPRF cipher suite of the NIST P-384 group and SHA-384.
P384Sha384 = Ciphersuite(group.P384Sha384)
P384Sha384 Identifier = "P384-SHA384"

// P521Sha512 is the OPRF cipher suite of the NIST P-512 group and SHA-512.
P521Sha512 = Ciphersuite(group.P521Sha512)
P521Sha512 Identifier = "P521-SHA512"

nbIDs = 4
maxDeriveKeyPairTries = 255
)

var suiteToHash = make(map[group.Group]crypto.Hash, 4)
var (
suites = make(map[group.Group]Identifier, nbIDs)
groups = make(map[Identifier]group.Group, nbIDs)
hashes = make(map[Identifier]crypto.Hash, nbIDs)
)

func init() {
RistrettoSha512.register(crypto.SHA512)
P256Sha256.register(crypto.SHA256)
P384Sha384.register(crypto.SHA384)
P521Sha512.register(crypto.SHA512)
}

func (c Ciphersuite) register(h crypto.Hash) {
suiteToHash[c.Group()] = h
Ristretto255Sha512.register(group.Ristretto255Sha512, crypto.SHA512)
P256Sha256.register(group.P256Sha256, crypto.SHA256)
P384Sha384.register(group.P384Sha384, crypto.SHA384)
P521Sha512.register(group.P521Sha512, crypto.SHA512)
}

func (c Ciphersuite) dst(prefix string) []byte {
return encoding.Concat([]byte(prefix), c.contextString())
func (i Identifier) register(g group.Group, h crypto.Hash) {
if g.Available() && h.Available() {
suites[g] = i
groups[i] = g
hashes[i] = h
} else {
panic(fmt.Sprintf("OPRF dependencies not available - Group: %v, Hash: %v", g.Available(), h.Available()))
}
}

func (c Ciphersuite) i2osp() []byte {
return []byte{0, byte(c)}
func (i Identifier) dst(prefix string) []byte {
return encoding.Concat([]byte(prefix), i.contextString())
}

func (c Ciphersuite) contextString() []byte {
return encoding.Concat3([]byte(tag.OPRF), base, c.i2osp())
func (i Identifier) contextString() []byte {
return encoding.Concatenate([]byte(tag.OPRFVersionPrefix), []byte(i))
}

func (c Ciphersuite) hash(input ...[]byte) []byte {
h := suiteToHash[c.Group()].New()
func (i Identifier) hash(input ...[]byte) []byte {
h := hashes[i].New()
h.Reset()

for _, i := range input {
Expand All @@ -77,20 +85,41 @@ func (c Ciphersuite) hash(input ...[]byte) []byte {
return h.Sum(nil)
}

// Available returns whether the Ciphersuite has been registered of not.
func (c Ciphersuite) Available() bool {
_, ok := suiteToHash[c.Group()]
return ok
// Available returns whether the Identifier has been registered of not.
func (i Identifier) Available() bool {
// Check for invalid identifiers
switch i {
case Ristretto255Sha512, P256Sha256, P384Sha384, P521Sha512:
break
default:
return false
}

// Check for unregistered groups and hashes
if _, ok := groups[i]; !ok {
return false
}

if _, ok := hashes[i]; !ok {
return false
}

return true
}

// IDFromGroup returns the OPRF identifier corresponding to the input group.
func IDFromGroup(g group.Group) Identifier {
return suites[g]
}

// Group returns the Group identifier for the cipher suite.
func (c Ciphersuite) Group() group.Group {
return group.Group(c)
func (i Identifier) Group() group.Group {
return groups[i]
}

// DeriveKey returns a scalar mapped from the input.
func (c Ciphersuite) DeriveKey(seed, info []byte) *group.Scalar {
dst := encoding.Concat([]byte(tag.DeriveKeyPairInternal), c.contextString())
func (i Identifier) DeriveKey(seed, info []byte) *group.Scalar {
dst := encoding.Concat([]byte(tag.DeriveKeyPairInternal), i.contextString())
deriveInput := encoding.Concat(seed, encoding.EncodeVector(info))

var counter uint8
Expand All @@ -101,18 +130,18 @@ func (c Ciphersuite) DeriveKey(seed, info []byte) *group.Scalar {
panic("DeriveKeyPairError")
}

s = c.Group().HashToScalar(encoding.Concat(deriveInput, []byte{counter}), dst)
s = i.Group().HashToScalar(encoding.Concat(deriveInput, []byte{counter}), dst)
counter++
}

return s
}

// Client returns an OPRF client.
func (c Ciphersuite) Client() *Client {
func (i Identifier) Client() *Client {
return &Client{
Ciphersuite: c,
input: nil,
blind: nil,
Identifier: i,
input: nil,
blind: nil,
}
}
2 changes: 1 addition & 1 deletion internal/oprf/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ import (
)

// Evaluate evaluates the blinded input with the given key.
func (c Ciphersuite) Evaluate(privateKey *group.Scalar, blindedElement *group.Element) *group.Element {
func (i Identifier) Evaluate(privateKey *group.Scalar, blindedElement *group.Element) *group.Element {
return blindedElement.Copy().Multiply(privateKey)
}
4 changes: 2 additions & 2 deletions internal/tag/strings.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ package tag
const (
// OPRF tags.

// OPRF is a string explicitly stating the version name.
OPRF = "VOPRF10-"
// OPRFVersionPrefix is a string explicitly stating the version name.
OPRFVersionPrefix = "OPRFV1-\x00-"

// DeriveKeyPairInternal is the internal DeriveKeyPair tag as defined in VOPRF.
DeriveKeyPairInternal = "DeriveKeyPair"
Expand Down
2 changes: 1 addition & 1 deletion message/credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type CredentialRequest struct {
}

// NewCredentialRequest returns a populated CredentialRequest.
func NewCredentialRequest(ciphersuite oprf.Ciphersuite, message *group.Element) *CredentialRequest {
func NewCredentialRequest(ciphersuite oprf.Identifier, message *group.Element) *CredentialRequest {
return &CredentialRequest{
BlindedMessage: message,
}
Expand Down
27 changes: 19 additions & 8 deletions opaque.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ func (g Group) Available() bool {
g == P521Sha512
}

// OPRF returns the OPRF Identifier used in the Ciphersuite.
func (g Group) OPRF() oprf.Identifier {
return oprf.IDFromGroup(g.Group())
}

// Group returns the EC Group used in the Ciphersuite.
func (g Group) Group() group.Group {
return group.Group(g)
}

const confLength = 6

var (
Expand Down Expand Up @@ -115,10 +125,14 @@ func (c *Configuration) KeyGen() (secretKey, publicKey []byte) {

// verify returns an error on the first non-compliant parameter, nil otherwise.
func (c *Configuration) verify() error {
if !c.OPRF.Available() || !oprf.Ciphersuite(c.OPRF).Available() {
if !c.OPRF.Available() || !c.OPRF.OPRF().Available() {
return errInvalidOPRFid
}

if !c.AKE.Available() || !c.AKE.Group().Available() {
return errInvalidAKEid
}

if !hash.Hashing(c.KDF).Available() {
return errInvalidKDFid
}
Expand All @@ -135,10 +149,6 @@ func (c *Configuration) verify() error {
return errInvalidKSFid
}

if !c.AKE.Available() || !group.Group(c.AKE).Available() {
return errInvalidAKEid
}

return nil
}

Expand All @@ -148,11 +158,12 @@ func (c *Configuration) toInternal() (*internal.Configuration, error) {
return nil, err
}

g := group.Group(c.AKE)
g := c.AKE.Group()
o := c.OPRF.OPRF()
mac := internal.NewMac(c.MAC)
ip := &internal.Configuration{
OPRF: oprf.Ciphersuite(c.OPRF),
OPRFPointLength: encoding.PointLength[group.Group(c.OPRF)],
OPRF: o,
OPRFPointLength: encoding.PointLength[o.Group()],
KDF: internal.NewKDF(c.KDF),
MAC: mac,
Hash: internal.NewHash(c.Hash),
Expand Down
Loading

0 comments on commit 7dd75ce

Please sign in to comment.