Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use hash size as KSF output size, expose KSF parameters & salt in configuration #73

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

DJAndries
Copy link

A couple of changes to achieve interoperability with facebook/opaque-ke:

  • Use the configured hash size as the KSF output size (it seems that the Rust library does this, not sure if it's mentioned in the draft)
  • Allow configuration of KSF cost parameters & salt value

@DJAndries DJAndries requested a review from bytemare as a code owner November 5, 2024 00:09
Comment on lines +51 to +57
OPRF: opaque.RistrettoSha512,
KDF: crypto.SHA512,
MAC: crypto.SHA512,
Hash: crypto.SHA512,
KSF: opaque.KSFConfiguration{
Identifier: ksf.Argon2id,
},
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
OPRF: opaque.RistrettoSha512,
KDF: crypto.SHA512,
MAC: crypto.SHA512,
Hash: crypto.SHA512,
KSF: opaque.KSFConfiguration{
Identifier: ksf.Argon2id,
},
OPRF: opaque.RistrettoSha512,
KDF: crypto.SHA512,
MAC: crypto.SHA512,
Hash: crypto.SHA512,
KSF: opaque.KSFConfiguration{
Identifier: ksf.Argon2id,
},

Comment on lines +81 to +86
type KSFConfiguration struct {
Identifier ksf.Identifier `json:"identifier"`
Parameters []int `json:"parameters"`
Salt []byte `json:"salt"`
}

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type KSFConfiguration struct {
Identifier ksf.Identifier `json:"identifier"`
Parameters []int `json:"parameters"`
Salt []byte `json:"salt"`
}
type KSFConfiguration struct {
Parameters []int `json:"parameters"`
Salt []byte `json:"salt"`
Identifier ksf.Identifier `json:"identifier"`
}

aligns better in memory

Parameters []int `json:"parameters"`
Salt []byte `json:"salt"`
}

// Configuration represents an OPAQUE configuration. Note that OprfGroup and AKEGroup are recommended to be the same,
// as well as KDF, MAC, Hash should be the same.
type Configuration struct {
Context []byte
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Context []byte

Comment on lines +91 to +96
KDF crypto.Hash `json:"kdf"`
MAC crypto.Hash `json:"mac"`
Hash crypto.Hash `json:"hash"`
OPRF Group `json:"oprf"`
KSF KSFConfiguration `json:"ksf"`
AKE Group `json:"group"`
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
KDF crypto.Hash `json:"kdf"`
MAC crypto.Hash `json:"mac"`
Hash crypto.Hash `json:"hash"`
OPRF Group `json:"oprf"`
KSF KSFConfiguration `json:"ksf"`
AKE Group `json:"group"`
KSF KSFConfiguration `json:"ksf"`
Context []byte
KDF crypto.Hash `json:"kdf"`
MAC crypto.Hash `json:"mac"`
Hash crypto.Hash `json:"hash"`
OPRF Group `json:"oprf"`
KSF KSFConfiguration `json:"ksf"`
AKE Group `json:"group"`

memory alignement

var ksfEncodedParams []byte
for _, param := range c.KSF.Parameters {
ksfEncodedParams = append(ksfEncodedParams, encoding.I2OSP(param, 4)...)
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
}

@@ -228,21 +248,50 @@ func (c *Configuration) GetFakeRecord(credentialIdentifier []byte) (*ClientRecor

// DeserializeConfiguration decodes the input and returns a Parameter structure.
func DeserializeConfiguration(encoded []byte) (*Configuration, error) {
if len(encoded) < confLength+2 { // corresponds to the configuration length + 2-byte encoding of empty context
if len(encoded) < confIdsLength+2 { // corresponds to the configuration length + 2-byte encoding of empty context
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if len(encoded) < confIdsLength+2 { // corresponds to the configuration length + 2-byte encoding of empty context
if len(encoded) < confIdsLength+6 { // corresponds to the configuration length + 3*2-byte encoding of empty context and KSF parameters

return nil, internal.ErrConfigurationInvalidLength
}

ctx, _, err := encoding.DecodeVector(encoded[confLength:])
ctx, _, err := encoding.DecodeVector(encoded[confIdsLength:])
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ctx, _, err := encoding.DecodeVector(encoded[confIdsLength:])
ctx, offset, err := encoding.DecodeVector(encoded[confIdsLength:])

use the returned offset

Comment on lines +260 to +283
var ksfParams []int
ksfParamOffset := confIdsLength + 2 + len(ctx)

if len(encoded) >= ksfParamOffset+2 {
ksfEncodedParams, _, err := encoding.DecodeVector(encoded[ksfParamOffset:])
if err != nil {
return nil, fmt.Errorf("decoding the ksf configuration parameters: %w", err)
}
for i := 0; i < len(ksfEncodedParams); i += 4 {
ksfParams = append(ksfParams, encoding.OS2IP(ksfEncodedParams[i:i+4]))
}
}

var ksfSalt []byte
ksfSaltOffset := ksfParamOffset + 2 + (len(ksfParams) * 4)
if len(encoded) >= ksfSaltOffset+2 {
ksfSalt, _, err = encoding.DecodeVector(encoded[ksfSaltOffset:])
if err != nil {
return nil, fmt.Errorf("decoding the ksf salt: %w", err)
}
if len(ksfSalt) == 0 {
ksfSalt = nil
}
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var ksfParams []int
ksfParamOffset := confIdsLength + 2 + len(ctx)
if len(encoded) >= ksfParamOffset+2 {
ksfEncodedParams, _, err := encoding.DecodeVector(encoded[ksfParamOffset:])
if err != nil {
return nil, fmt.Errorf("decoding the ksf configuration parameters: %w", err)
}
for i := 0; i < len(ksfEncodedParams); i += 4 {
ksfParams = append(ksfParams, encoding.OS2IP(ksfEncodedParams[i:i+4]))
}
}
var ksfSalt []byte
ksfSaltOffset := ksfParamOffset + 2 + (len(ksfParams) * 4)
if len(encoded) >= ksfSaltOffset+2 {
ksfSalt, _, err = encoding.DecodeVector(encoded[ksfSaltOffset:])
if err != nil {
return nil, fmt.Errorf("decoding the ksf salt: %w", err)
}
if len(ksfSalt) == 0 {
ksfSalt = nil
}
}
offset += confIdsLength
ksfEncodedParams, offsetKSF, err := encoding.DecodeVector(encoded[offset:])
if err != nil {
return nil, fmt.Errorf("decoding the ksf configuration parameters: %w", err)
}
offset += offsetKSF
var ksfParams []int
for i := 0; i < len(ksfEncodedParams); i += 4 {
ksfParams = append(ksfParams, encoding.OS2IP(ksfEncodedParams[i:i+4]))
}
ksfSalt, _, err := encoding.DecodeVector(encoded[offset:])
if err != nil {
return nil, fmt.Errorf("decoding the ksf salt: %w", err)
}
if len(ksfSalt) == 0 {
ksfSalt = nil
}

we can use the offset argument returned by DecodeVector

Comment on lines -362 to -375
func TestDeserializeConfiguration_InvalidContextHeader(t *testing.T) {
d := opaque.DefaultConfiguration().Serialize()
d[7] = 3

expected := "decoding the configuration context: "
if _, err := opaque.DeserializeConfiguration(d); err == nil || !strings.HasPrefix(err.Error(), expected) {
t.Errorf(
"DeserializeConfiguration did not return the appropriate error for vector invalid header. want %q, got %q",
expected,
err,
)
}
}

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we should keep this error detection test.

@bytemare
Copy link
Owner

Hi @DJAndries ! Thank you for this PR, this is an excellent contribution :)
I'm sorry the delay, I haven't had time to get to this earlier.

I left some comments for some minor code changes.
I also believe we should keep the TestDeserializeConfiguration_InvalidContextHeader test function, but it would need some adaptation.

@bytemare
Copy link
Owner

Have you noticed other differences in Kevin's implementation that would be interesting to add here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants