Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
bytemare authored and bytemare committed Nov 21, 2020
1 parent a45864b commit 7858a4b
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 66 deletions.
19 changes: 9 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# CPace

CPace implements the CFRG recommended balanced Password Authentication Key Exchange.
CPace provides an easy to use CPace PAKE implementation to do secure mutual authentication based on passwords.

CPace implements https://datatracker.ietf.org/doc/draft-irtf-cfrg-cpace.

**!!! WARNING : THIS IMPLEMENTATION IS PROOF OF CONCEPT AND BASED ON THE LATEST INTERNET DRAFT.
THERE ARE ABSOLUTELY NO WARRANTIES. !!!**
Expand All @@ -12,7 +14,7 @@ Note: The registration of the secret password is not in the scope of the protoco

# Get it

go get github.com/bytemare/cpace
go get -u github.com/bytemare/cpace

# Use it

Expand All @@ -27,7 +29,7 @@ Messages are of type message.Kex, from the companion pake package. These message
<details>
<summary>Example:</summary>

```
```Go
serverID := []byte("server")
username := []byte("client")
password := []byte("password")
Expand Down Expand Up @@ -60,17 +62,14 @@ Messages are of type message.Kex, from the companion pake package. These message

# Under the hood

All cryptographic operations can be found in the pake package, which itself uses either the standard library or tested and proved external libraries.
The Ristretto255 group is used for the mathematical heavy lifting and performance.

Hash operations use SHA3 and Shake.

Default password key derivation is Argon2id.
All cryptographic operations can be found in the [cryptotools package](https://github.com/bytemare/cryptotools), which itself uses either the standard library or tested and proved external libraries.

# Deploy it

Don't, yet.

## Work on it

WIP
- Closely follow draft evolution
- More testing, with vectors, if available
- Fuzzing
33 changes: 15 additions & 18 deletions api.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// Package cpace provides an easy to use CPace implementation
package cpace

import (
Expand All @@ -16,35 +15,35 @@ import (
)

const (
Protocol = "CPace"
Version = "0.0.0"
protocol = "CPace"
version = "0.0.0"
maxIDLength = 1<<16 - 1
)

var errInternalKexAssertion = errors.New("internal: something went wrong in type assertion to Kex message")

// Parameters groups a party's input parameters
// Parameters groups a party's input parameters.
type Parameters struct {
// ID is own identity
// ID is own identity.
ID []byte

// PeerID identifies the remote peer
// PeerID identifies the remote peer.
PeerID []byte

// Secret is the shared secret, e.g. the password
// Secret is the shared secret, e.g. the password.
Secret []byte

// SID is the session identifier, a unique random byte array of at least 16 bytes
// SID is the session identifier, a unique random byte array of at least 16 bytes.
SID []byte

// AD
AD []byte

// Encoding specifies which encoding should be used for outgoing and incoming messages
// Encoding specifies which encoding should be used for outgoing and incoming messages.
Encoding encoding.Encoding
}

// CPace wraps the core CPace session and state info and enriches them with a more abstract API
// CPace wraps the core CPace session and state info and enriches them with a more abstract API.
type CPace struct {
session
state
Expand Down Expand Up @@ -84,7 +83,7 @@ func assembleCI(role pake.Role, id, peerID, ad []byte) ([]byte, error) {
}

func buildDST(identifier hashtogroup.Ciphersuite, in int) []byte {
return []byte(fmt.Sprintf("%s%s-%d", Protocol, identifier, in))
return []byte(fmt.Sprintf("%s%s-%d", protocol, identifier, in))
}

func newCPace(role pake.Role, parameters *Parameters, csp *cryptotools.Parameters) (*CPace, error) {
Expand Down Expand Up @@ -112,9 +111,7 @@ func newCPace(role pake.Role, parameters *Parameters, csp *cryptotools.Parameter
return nil, err
}

// meta := pake.MetaData()

pakeCore, err := pake.KeyExchange.New(Protocol, Version, parameters.Encoding, csp, role, parameters.PeerID)
pakeCore, err := pake.KeyExchange.New(protocol, version, parameters.Encoding, csp, role, parameters.PeerID)
if err != nil {
return nil, err
}
Expand All @@ -134,12 +131,12 @@ func newCPace(role pake.Role, parameters *Parameters, csp *cryptotools.Parameter
}, nil
}

// Client returns a new CPace client instance
// Client returns a new CPace client instance.
func Client(parameters *Parameters, csp *cryptotools.Parameters) (pake.Pake, error) {
return newCPace(pake.Initiator, parameters, csp)
}

// Server returns a new CPace server instance
// Server returns a new CPace server instance.
func Server(parameters *Parameters, csp *cryptotools.Parameters) (pake.Pake, error) {
return newCPace(pake.Responder, parameters, csp)
}
Expand Down Expand Up @@ -216,12 +213,12 @@ func (c *CPace) Authenticate(m []byte) ([]byte, error) {
return r.Encode(c.core.Encoding())
}

// SessionKey returns the session's intermediary secret session key
// SessionKey returns the session's intermediary secret session key.
func (c *CPace) SessionKey() []byte {
return c.iSessionKey
}

// EncodedParameters returns the 4-byte encoding of the ciphersuite parameters
// EncodedParameters returns the 4-byte encoding of the cipher suite parameters.
func (c *CPace) EncodedParameters() cryptotools.CiphersuiteEncoding {
return c.core.Crypto.Parameters.Encode()
}
Expand Down
38 changes: 8 additions & 30 deletions cpace.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// Package cpace provides an easy to use CPace implementation
package cpace

import (
Expand All @@ -14,20 +13,20 @@ const (
minSidLength = 16
)

// session holds the public, shared, session information
// session holds the public, shared, session information.
type session struct {
// role specifies whether the current instance is an initiator or responder
// role specifies whether the current instance is an initiator or responder.
role pake.Role

// sid session identifier, must be random and different for each session, and greater or equal than minSidLength bytes
// sid session identifier, must be random and different for each session, and greater or equal than minSidLength bytes.
sid []byte

// cid channel identifier, holds identities of parties and eventually additional data about the connection
// cid channel identifier, holds identities of parties and eventually additional data about the connection.
// cid = idA || idB || AD
cid []byte
}

// state is the CPace's internal state
// state is the CPace's internal state.
type state struct {
password []byte
publicElement []byte
Expand Down Expand Up @@ -65,7 +64,7 @@ func (c *CPace) publicPoint() error {
return nil
}

// intermediarySessionKey calculates the secret session key and stores it in internal state
// intermediarySessionKey calculates the secret session key and stores it in internal state.
func (c *CPace) intermediarySessionKey(peerElement []byte) error {
if len(peerElement) == 0 {
return errPeerElementNil
Expand All @@ -85,16 +84,14 @@ func (c *CPace) intermediarySessionKey(peerElement []byte) error {
return errPeerElementIdentity
}

// transcript := c.transcript(peerElement)
// c.ISessionKey = c.Core.Crypto.HKDF(k.Encode(), transcript, c.dsi2, 0)

c.buildKey(k.Bytes(), peerElement)

return err
}

func (c *CPace) buildKey(k, peerElement []byte) {
ee := make([]byte, 0, len(c.publicElement)+len(peerElement))

switch c.role {
case pake.Initiator:
ee = append(ee, c.publicElement...)
Expand All @@ -112,7 +109,7 @@ func (c *CPace) buildKey(k, peerElement []byte) {
c.iSessionKey = c.core.Crypto.Hash.Hash(0, in)
}

func (c *CPace) initiate() ([]byte, []byte, error) {
func (c *CPace) initiate() (pe, sid []byte, err error) {
if err := c.publicPoint(); err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -156,22 +153,3 @@ func (c *CPace) finish(peerElement []byte) error {

return nil
}

// transcript returns the protocol's transcript given the peer element
//func (c *CPace) transcript(peerElement []byte) []byte {
// transcript := make([]byte, 0, minSidLength+2*pointLength)
// transcript = append(transcript, c.sid...)
//
// switch c.role {
// case pake.Initiator:
// transcript = append(transcript, c.publicElement...)
// transcript = append(transcript, peerElement...)
// case pake.Responder:
// transcript = append(transcript, peerElement...)
// transcript = append(transcript, c.publicElement...)
// default:
// panic(errInternalInvalidRole)
// }
//
// return transcript
//}
2 changes: 1 addition & 1 deletion doc.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Package cpace provides an easy to use CPace implementation
// Package cpace provides an easy to use CPace PAKE implementation to do secure mutual authentication based on passwords.
//
// CPace implements the CFRG recommended balanced Password Authentication Key Exchange.
//
Expand Down
13 changes: 6 additions & 7 deletions errors.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// Package cpace provides an easy to use CPace implementation
package cpace

import (
Expand Down Expand Up @@ -29,40 +28,40 @@ func errorPeerData(err string) error {
return fmt.Errorf("%s : %w", errPrefixPeerData, errors.New(err))
}

// Setup errors
// Setup errors.
var (
errSetupSIDTooShort = errorSetup(fmt.Sprintf("session id is too short (< %d)", minSidLength))
errSetupLongID = errorSetup("id exceeds authorised length")
errSetupLongPeerID = errorSetup("peer ID exceeds authorised length")
errSetupLongAD = errorSetup("AD exceeds authorised length")
)

// Responder specific errors
// Responder specific errors.
var errRespNilMsg = errorImplementation("responder can't handle nil messages")

// Initiator specific errors
// Initiator specific errors.
var errInitReInit = errorImplementation("unexpected nil message - already initialised")

var (
errInitSIDInvalid = errorPeerData("session id received from peer is either nil or too short")
errInitSIDDifferent = errorPeerData("session id from received from peer is different")
)

// Errors resulting from invalid peer data
// Errors resulting from invalid peer data.
var (
errPeerEncoding = errorPeerData("decoding errored")
errPeerElementNil = errorPeerData("peer element is either nil or of size 0")
errPeerElementInvalid = errorPeerData("peer element yields error")
errPeerElementIdentity = errorPeerData("invalid peer message : identity element")
)

// Other errors
// Other errors.
var (
errInternalNoPublicPoint = errorImplementation("public point not set - not initiated ?")
errInternalUnexpectedMessage = errorImplementation("received message on unexpected stage")
)

// These are used in panics for internal inconsistencies, that should not occur
// These are used in panics for internal inconsistencies, that should not occur.
var (
errInternalInvalidRole = errorInternal("invalid role (should not happen)")
errInternalNoSID = errorInternal("session id is not set (should not happen)")
Expand Down

0 comments on commit 7858a4b

Please sign in to comment.