gopaque

package
v0.0.0-...-8180617 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 6, 2019 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package gopaque implements the OPAQUE protocol. The OPAQUE protocol, described as of this writing in the RFC draft at https://tools.ietf.org/html/draft-krawczyk-cfrg-opaque-01, is a protocol that allows a user with a password to register and authenticate with a server without ever giving that server the password. It uses the OPAQUE password authenticated key exchange (PAKE) which uses derived keys for registration authentication. A high-level introduction to OPAQUE (and PAKEs in general) is available at https://blog.cryptographyengineering.com/2018/10/19/lets-talk-about-pake/.

This implementation uses the https://github.com/dedis/kyber crypto library. The implementation is intentionally very extensible and exposed, but sensible default implementations are provided for every abstraction. The registration and authentication flows are below, followed by a couple of code examples clarifying usage.

Warning

This was developed by a hobbyist, not a cryptographer. The code has not been reviewed for accuracy or security. No care was taken to obfuscate the errors or prevent timing attacks. Only use after reviewing the code and understanding the implications.

Registration Flow

OPAQUE registration is a 3-message process starting with the user where a user registers with the server. The only input a user needs is the password and after registration, the server has the info to perform authentication.

The steps for a user are:

1 - Create a NewUserRegister with the user ID

2 - Call Init with the password and send the resulting UserRegisterInit to the server

3 - Receive the server's ServerRegisterInit

4 - Call Complete with the server's ServerRegisterInit and send the resulting UserRegisterComplete to the server

The steps for a server are:

1 - Receive the user's UserRegisterInit

2 - Create a NewServerRegister with a private key

3 - Call Init with the user's UserRegisterInit and send the resulting ServerRegisterInit to the user

4 - Receive the user's UserRegisterComplete

5 - Call Complete with the user's UserRegisterComplete and persist the resulting ServerRegisterComplete

Authentication Flow

OPAQUE authentication is intended to be used in conjunction with a key exchange protocol to authenticate a user. Gopaque supports either an external key exchange protocol or one embedded into the auth process. The pure OPAQUE part of the flow is only a 2-message process, but validation with a key exchange often adds a third message. The steps below assume the key exchange is embedded in the auth process instead of being external.

The steps for a user are:

1 - Create a NewUserAuth with an embedded key exchange

2 - Call Init with the password and send the resulting UserAuthInit to the server

3 - Receive the server's ServerAuthComplete

4 - Call Complete with the server's ServerAuthComplete. The resulting UserAuthFinish has user and server key information. This would be the last step if we were not using an embedded key exchange. Since we are, take the resulting UserAuthComplete and send it to the server.

The steps for a server are:

1 - Receive the user's UserAuthInit

2 - Create a NewServerAuth with an embedded key exchange

3 - Call Complete with the user's UserAuthInit and persisted ServerRegisterComplete and send the resulting ServerAuthComplete to the user. This would be the last step if we were not using an embedded key exchange.

4 - Receive the user's UserAuthComplete

5 - Call Finish with the user's UserAuthComplete

Example (Simple)

This simple example doesn't marshal the messages, it just sends them.

crypto := gopaque.CryptoDefault
// Registration first...create user side and server side
userReg := gopaque.NewUserRegister(crypto, []byte("user foo"), nil)
serverReg := gopaque.NewServerRegister(crypto, crypto.NewKey(nil))
// Do the registration steps
userRegInit := userReg.Init([]byte("password foo"))
serverRegInit := serverReg.Init(userRegInit)
userRegComplete := userReg.Complete(serverRegInit)
serverRegComplete := serverReg.Complete(userRegComplete)
// XXX: Here is where serverRegComplete would be persisted on the server.

// Now that we are registered, do an auth. We are using an embedded key
// exchange here instead of having our own externally which means we have
// one extra "Finish" step. Note, in other cases we might hold on to the
// created key exchange so we can get things like the shared secret.
userAuth := gopaque.NewUserAuth(crypto, []byte("user foo"), gopaque.NewKeyExchangeSigma(crypto))
serverAuth := gopaque.NewServerAuth(crypto, gopaque.NewKeyExchangeSigma(crypto))
// Do the auth
userAuthInit, err := userAuth.Init([]byte("password foo"))
panicIfErr(err)
// XXX: Here is where serverRegComplete would be looked up by userAuthInit.UserID.
serverAuthComplete, err := serverAuth.Complete(userAuthInit, serverRegComplete)
panicIfErr(err)
userAuthFinish, userAuthComplete, err := userAuth.Complete(serverAuthComplete)
panicIfErr(err)
err = serverAuth.Finish(userAuthComplete)
panicIfErr(err)

// Might as well check that the user key is the same as orig
if !userReg.PrivateKey().Equal(userAuthFinish.UserPrivateKey) {
	panic("Key mismatch")
}
Output:

Example (WithConnPipe)

This example is a more complex example showing marshalling and using separate user and server-side connections.

package main

import (
	"encoding/binary"
	"fmt"
	"io"
	"net"

	"github.com/cretz/gopaque/gopaque"
	"go.dedis.ch/kyber"
)

// This example is a more complex example showing marshalling and using separate
// user and server-side connections.
func main() {
	// Create already-connected user/server pipe and a bool to tell when closed
	userConn, serverConn := net.Pipe()
	defer userConn.Close()
	serverClosed := false
	defer func() {
		serverClosed = true
		serverConn.Close()
	}()

	// Run the server
	go func() {
		if err := RunServer(serverConn); err != nil && !serverClosed {
			fmt.Printf("Server failed: %v\n", err)
		}
	}()

	// Register a user. The returned key is just for checking later for this
	// example. In general there is no reason to keep it around as it's sent
	// back on auth.
	key, err := UserSideRegister(userConn, "myuser", "mypass")
	if err != nil {
		panic(err)
	}

	// Now auth the user. We are ignoring the returned key exchange info here
	// but could capture it and use it's shared secret if we wanted.
	authInfo, _, err := UserSideAuth(userConn, "myuser", "mypass")
	if err != nil {
		panic(err)
	}

	// Confirm the key pair is what we registered with
	if !key.Equal(authInfo.UserPrivateKey) {
		panic("Invalid key")
	}

}

var crypto = gopaque.CryptoDefault

func UserSideRegister(c net.Conn, username, password string) (kyber.Scalar, error) {
	// Create a registration session
	userReg := gopaque.NewUserRegister(crypto, []byte(username), nil)

	// Create init message and send it over
	if err := sendMessage(c, 'r', userReg.Init([]byte(password))); err != nil {
		return nil, err
	}

	// Receive the server message
	var serverInit gopaque.ServerRegisterInit
	if err := recvMessage(c, &serverInit); err != nil {
		return nil, err
	}

	// Create user complete message and send it over, then we're done
	return userReg.PrivateKey(), sendMessage(c, 'r', userReg.Complete(&serverInit))
}

func UserSideAuth(c net.Conn, username, password string) (*gopaque.UserAuthFinish, *gopaque.KeyExchangeSigma, error) {
	// Create auth session w/ built in key exchange
	kex := gopaque.NewKeyExchangeSigma(crypto)
	userAuth := gopaque.NewUserAuth(crypto, []byte(username), kex)

	// Create init message and send it over
	if userInit, err := userAuth.Init([]byte(password)); err != nil {
		return nil, nil, err
	} else if err = sendMessage(c, 'a', userInit); err != nil {
		return nil, nil, err
	}

	// Receive the server message
	var serverComplete gopaque.ServerAuthComplete
	if err := recvMessage(c, &serverComplete); err != nil {
		return nil, nil, err
	}

	// Verify user side and since we embedded a key exchange, there is one last
	// message to send to the server.
	if userFinish, userComplete, err := userAuth.Complete(&serverComplete); err != nil {
		return nil, nil, err
	} else if err = sendMessage(c, 'a', userComplete); err != nil {
		return nil, nil, err
	} else {
		return userFinish, kex, nil
	}
}

func RunServer(c net.Conn) error {
	// This stores the registered users
	registeredUsers := map[string]*gopaque.ServerRegisterComplete{}
	// Create a key pair for our server
	key := crypto.NewKey(nil)
	// Run forever handling register and auth
	for {
		// Get the next user message
		msgType, msgBytes, err := recvMessageBytes(c)
		if err != nil {
			return err
		}
		// Handle different message types
		switch msgType {
		// Handle registration...
		case 'r':
			if regComplete, err := ServerSideRegister(c, key, msgBytes); err != nil {
				return err
			} else if username := string(regComplete.UserID); registeredUsers[username] != nil {
				return fmt.Errorf("Username '%v' already exists", username)
			} else {
				registeredUsers[username] = regComplete
			}
			// Handle auth...
		case 'a':
			if err := ServerSideAuth(c, msgBytes, registeredUsers); err != nil {
				return err
			}
		default:
			return fmt.Errorf("Unknown message type: %v", msgType)
		}
	}
}

func ServerSideRegister(c net.Conn, key kyber.Scalar, userInitBytes []byte) (*gopaque.ServerRegisterComplete, error) {
	// Create the registration session
	serverReg := gopaque.NewServerRegister(crypto, key)
	// Unmarshal user init, create server init, and send back
	var userInit gopaque.UserRegisterInit
	if err := userInit.FromBytes(crypto, userInitBytes); err != nil {
		return nil, err
	} else if err = sendMessage(c, 'r', serverReg.Init(&userInit)); err != nil {
		return nil, err
	}
	// Get back the user complete and complete things ourselves
	var userComplete gopaque.UserRegisterComplete
	if err := recvMessage(c, &userComplete); err != nil {
		return nil, err
	}
	return serverReg.Complete(&userComplete), nil
}

func ServerSideAuth(c net.Conn, userInitBytes []byte, registeredUsers map[string]*gopaque.ServerRegisterComplete) error {
	// Create the server auth w/ an embedded key exchange. We could store this
	// key exchange if we wanted access to the shared secret afterwards.
	serverAuth := gopaque.NewServerAuth(crypto, gopaque.NewKeyExchangeSigma(crypto))
	// Parse the user init bytes
	var userInit gopaque.UserAuthInit
	if err := userInit.FromBytes(crypto, userInitBytes); err != nil {
		return err
	}
	// Load up the registration info
	regComplete := registeredUsers[string(userInit.UserID)]
	if regComplete == nil {
		return fmt.Errorf("Username not found")
	}
	// Complete the auth and send it back
	if serverComplete, err := serverAuth.Complete(&userInit, regComplete); err != nil {
		return err
	} else if err = sendMessage(c, 'a', serverComplete); err != nil {
		return err
	}
	// Since we are using an embedded key exchange, we have one more step which
	// receives another user message and validates it.
	var userComplete gopaque.UserAuthComplete
	if err := recvMessage(c, &userComplete); err != nil {
		return err
	}
	return serverAuth.Finish(&userComplete)
}

// Below is just a very simple, insecure conn messager

func sendMessage(c net.Conn, msgType byte, msg gopaque.Marshaler) error {
	if msgBytes, err := msg.ToBytes(); err != nil {
		return err
	} else if _, err = c.Write([]byte{msgType}); err != nil {
		return err
	} else if err = binary.Write(c, binary.BigEndian, uint32(len(msgBytes))); err != nil {
		return err
	} else if _, err = c.Write(msgBytes); err != nil {
		return err
	}
	return nil
}

func recvMessage(c net.Conn, msg gopaque.Marshaler) error {
	if _, msgBytes, err := recvMessageBytes(c); err != nil {
		return err
	} else {
		return msg.FromBytes(crypto, msgBytes)
	}
}

func recvMessageBytes(c net.Conn) (msgType byte, msg []byte, err error) {
	typeAndSize := make([]byte, 5)
	if _, err = io.ReadFull(c, typeAndSize); err == nil {
		msgType = typeAndSize[0]
		msg = make([]byte, binary.BigEndian.Uint32(typeAndSize[1:]))
		_, err = io.ReadFull(c, msg)
	}
	return
}
Output:

Index

Examples

Constants

This section is empty.

Variables

CryptoStandardDefault is the recommended default CryptoStandard impl.

View Source
var DeriveKeyArgonDefault = &DeriveKeyArgon{
	Time:    1,
	Memory:  64 * 1024,
	Threads: 4,
}

DeriveKeyArgonDefault is the recommended DeriveKeyArgon impl.

View Source
var KyberSuiteDefault = suites.MustFind("Ed25519")

KyberSuiteDefault is the recommended default kyber.Suite impl. This uses the Ed25519 suite which, based on reading, should satisfy the prime-order requirement.

Functions

func DeriveKeyHKDF

func DeriveKeyHKDF(c Crypto, priv kyber.Scalar, info []byte) kyber.Scalar

DeriveKeyHKDF builds a key for the given parent key and info using HKDF (RFC 5869). This function can be set as the CryptoStandard.KeyDeriver field.

func OPRFServerStep2

func OPRFServerStep2(crypto Crypto, alpha kyber.Point, k kyber.Scalar) (v kyber.Point, beta kyber.Point)

OPRFServerStep2 is executed on the server side with alpha from user step 1 and a "k" value that's usually either randomly generated on registration or looked up on auth.

func OPRFUserStep1

func OPRFUserStep1(crypto Crypto, x []byte) (r kyber.Scalar, alpha kyber.Point)

OPRFUserStep1 is executed on the user side and builds values to pass to server from the given x (usually a password).

func OPRFUserStep3

func OPRFUserStep3(crypto Crypto, x []byte, r kyber.Scalar, v kyber.Point, beta kyber.Point) (out []byte)

OPRFUserStep3 is executed on the client side with the original x and r from user step 1. The v and beta values are from server step 2. The result is the PRF output that can be re-obtained deterministically going through the steps again. It is often used to derive keys from.

Types

type AuthEncrypter

type AuthEncrypter interface {
	// AuthEncrypt performs an encryption of the given plain bytes
	// authenticated with the given key. It satisfies the OPAQUE requirement
	// for "key committing" meaning it's infeasible to have the same result
	// able to be decrypted successfully by different keys.
	AuthEncrypt(priv kyber.Scalar, plain []byte) ([]byte, error)

	// AuthDecrypt decrypts what was encrypted with AuthEncrypt with the same
	// key.
	AuthDecrypt(priv kyber.Scalar, enc []byte) ([]byte, error)
}

AuthEncrypter provides authenticated encryption/decryption that satisfies OPAQUE requirements.

type Crypto

Crypto is the abstraction of all needed features for OPAQUE.

var CryptoDefault Crypto = CryptoStandardDefault

CryptoDefault is the recommended default Crypto impl.

type CryptoStandard

type CryptoStandard struct {
	suites.Suite
	KeyDeriver func(c Crypto, priv kyber.Scalar, info []byte) kyber.Scalar
	Signer
}

CryptoStandard implements Crypto with a given suite + key deriver + signer and using basic implementations of other features.

func (*CryptoStandard) AuthDecrypt

func (c *CryptoStandard) AuthDecrypt(priv kyber.Scalar, enc []byte) ([]byte, error)

AuthDecrypt implements Crypto.AuthDecrypt.

func (*CryptoStandard) AuthEncrypt

func (c *CryptoStandard) AuthEncrypt(priv kyber.Scalar, plain []byte) ([]byte, error)

AuthEncrypt implements Crypto.AuthEncrypt.

func (*CryptoStandard) DeriveKey

func (c *CryptoStandard) DeriveKey(priv kyber.Scalar, info []byte) kyber.Scalar

DeriveKey implements KeyDeriver.DeriveKey. It just defers to the KeyDeriver function.

func (*CryptoStandard) HashToPoint

func (c *CryptoStandard) HashToPoint(msg []byte) kyber.Point

HashToPoint implements PointHasher.HashToPoint.

func (*CryptoStandard) NewKey

func (c *CryptoStandard) NewKey(stream cipher.Stream) kyber.Scalar

NewKey implements KeyGenerator.NewKey.

func (*CryptoStandard) NewKeyFromReader

func (c *CryptoStandard) NewKeyFromReader(r io.Reader) kyber.Scalar

NewKeyFromReader implements KeyGenerator.NewKeyFromReader.

type DeriveKeyArgon

type DeriveKeyArgon struct {
	Time    uint32
	Memory  uint32
	Threads uint8
}

DeriveKeyArgon holds parameters to use for Argon-based key derivation. See the DeriveKey method for more information.

func (*DeriveKeyArgon) DeriveKey

func (d *DeriveKeyArgon) DeriveKey(c Crypto, priv kyber.Scalar, info []byte) kyber.Scalar

DeriveKey creates a hash of info and uses that as the Argon salt value w/ the key's private bytes as the Argon password to deterministically derive a seed. That seed is then used in NewKeyFromReader.

type ErrUnmarshalMoreData

type ErrUnmarshalMoreData struct {
	// Left is the number of bytes not handled.
	Left int
}

ErrUnmarshalMoreData is when there is more data after unmarshalling.

func (*ErrUnmarshalMoreData) Error

func (e *ErrUnmarshalMoreData) Error() string

type KeyDeriver

type KeyDeriver interface {
	// DeriveKey creates a deterministic private key for the given parent
	// private key and an "info" discriminator.
	DeriveKey(priv kyber.Scalar, info []byte) kyber.Scalar
}

KeyDeriver provides DeriveKey to create deterministic keys from other keys.

type KeyExchange

type KeyExchange interface {
	// UserKeyExchange1 runs on the user side and returns the first key exchange
	// value to send to server (or nil if there is none).
	UserKeyExchange1() (Marshaler, error)

	// ServerKeyExchange2 runs on the server side and is given both the result
	// of UserKeyExchange1 (if any) and the server registration info for the
	// user. It returns the value to send back to the user (or nil if there is
	// none).
	ServerKeyExchange2(ke1 Marshaler, info *KeyExchangeInfo) (Marshaler, error)

	// UserKeyExchange3 runs on the user side and is given both the result of
	// ServerKeyExchange2 (if any) and the decoded user info. It returns the
	// value sent back to the server. If the result is nil, this is only a
	// 2-message key exchange instead of a 3-message one and no more steps are
	// done.
	UserKeyExchange3(ke2 Marshaler, info *KeyExchangeInfo) (Marshaler, error)

	// ServerKeyExchange4 runs on the server side and is given the result of
	// UserKeyExchange3. It is not called if there was no result from
	// UserKeyExchange3.
	ServerKeyExchange4(ke3 Marshaler) error

	// NewKeyExchangeMessage just instantiates the message instance for the
	// result of the given step number (1-3).
	NewKeyExchangeMessage(step int) (Marshaler, error)
}

KeyExchange describes a 2-step or 3-step key exchange. Although implementations can be used manually, they can also be used embedded into OPAQUE authentication via NewUserAuth and NewServerAuth. Exchanges that are only 2-step can return nil from UserKeyExchange3, otherwise the exchange is considered 3-step.

While implementers will implement all methods, callers should only call the User* or Server* methods depending on which side they are on. The key exchange should be created for each use and never reused.

type KeyExchangeInfo

type KeyExchangeInfo struct {
	UserID         []byte
	MyPrivateKey   kyber.Scalar
	TheirPublicKey kyber.Point
}

KeyExchangeInfo is the info given from the OPAQUE process.

type KeyExchangeSigma

type KeyExchangeSigma struct {
	// Info is the OPAQUE info given during either ServerKeyExchange2 or
	// UserKeyExchange3.
	Info *KeyExchangeInfo
	// SharedSecret is the Diffie-Hellman secret derived from this side's
	// ephemeral private key and the other side's ephemeral public key. It is
	// set during either ServerKeyExchange2 or UserKeyExchange3.
	SharedSecret kyber.Point
	// contains filtered or unexported fields
}

KeyExchangeSigma is a KeyExchange implementation using the 3-step SIGMA-I protocol as mentioned in the OPAQUE RFC.

func NewKeyExchangeSigma

func NewKeyExchangeSigma(crypto Crypto) *KeyExchangeSigma

NewKeyExchangeSigma creates the SIGMA KeyExchange with the given crypto.

func (*KeyExchangeSigma) NewKeyExchangeMessage

func (k *KeyExchangeSigma) NewKeyExchangeMessage(step int) (Marshaler, error)

NewKeyExchangeMessage implements KeyExchange.NewKeyExchangeMessage.

func (*KeyExchangeSigma) ServerKeyExchange2

func (k *KeyExchangeSigma) ServerKeyExchange2(ke1 Marshaler, info *KeyExchangeInfo) (Marshaler, error)

ServerKeyExchange2 implements KeyExchange.ServerKeyExchange2.

func (*KeyExchangeSigma) ServerKeyExchange4

func (k *KeyExchangeSigma) ServerKeyExchange4(ke3 Marshaler) error

ServerKeyExchange4 implements KeyExchange.ServerKeyExchange4.

func (*KeyExchangeSigma) UserKeyExchange1

func (k *KeyExchangeSigma) UserKeyExchange1() (Marshaler, error)

UserKeyExchange1 implements KeyExchange.UserKeyExchange1.

func (*KeyExchangeSigma) UserKeyExchange3

func (k *KeyExchangeSigma) UserKeyExchange3(ke2 Marshaler, info *KeyExchangeInfo) (Marshaler, error)

UserKeyExchange3 implements KeyExchange.UserKeyExchange3.

type KeyExchangeSigmaMsg1

type KeyExchangeSigmaMsg1 struct {
	UserExchangePublicKey kyber.Point
}

KeyExchangeSigmaMsg1 is the first exchange message sent from the user to the server. It implements Marshaler and is exposed only for debugging.

func (*KeyExchangeSigmaMsg1) FromBytes

func (k *KeyExchangeSigmaMsg1) FromBytes(c Crypto, data []byte) (err error)

FromBytes implements Marshaler.FromBytes.

func (*KeyExchangeSigmaMsg1) ToBytes

func (k *KeyExchangeSigmaMsg1) ToBytes() ([]byte, error)

ToBytes implements Marshaler.ToBytes.

type KeyExchangeSigmaMsg2

type KeyExchangeSigmaMsg2 struct {
	ServerExchangePublicKey kyber.Point
	ServerExchangeSig       []byte
	ServerExchangeMac       []byte
}

KeyExchangeSigmaMsg2 is the second exchange message sent from the server to the server. It implements Marshaler and is exposed only for debugging.

func (*KeyExchangeSigmaMsg2) FromBytes

func (k *KeyExchangeSigmaMsg2) FromBytes(c Crypto, data []byte) (err error)

FromBytes implements Marshaler.FromBytes.

func (*KeyExchangeSigmaMsg2) ToBytes

func (k *KeyExchangeSigmaMsg2) ToBytes() ([]byte, error)

ToBytes implements Marshaler.ToBytes.

type KeyExchangeSigmaMsg3

type KeyExchangeSigmaMsg3 struct {
	UserExchangeSig []byte
	UserExchangeMac []byte
}

KeyExchangeSigmaMsg3 is the third exchange message sent from the user to the server. It implements Marshaler and is exposed only for debugging.

func (*KeyExchangeSigmaMsg3) FromBytes

func (k *KeyExchangeSigmaMsg3) FromBytes(c Crypto, data []byte) (err error)

FromBytes implements Marshaler.FromBytes.

func (*KeyExchangeSigmaMsg3) ToBytes

func (k *KeyExchangeSigmaMsg3) ToBytes() ([]byte, error)

ToBytes implements Marshaler.ToBytes.

type KeyGenerator

type KeyGenerator interface {
	// NewKey creates a new key from the given stream. If the stream is nil, the
	// underlying crypto random stream is used.
	NewKey(stream cipher.Stream) kyber.Scalar

	// NewKeyFromReader creates a new key for the given reader. This simply
	// wraps a io.Reader into a cipher.Stream and calls NewKey. If the reader is
	// nil, the crypto random stream is used.
	NewKeyFromReader(r io.Reader) kyber.Scalar
}

KeyGenerator generates keys from a given stream or reader. It shares the NewKey signature with go.dedis.ch/kyber/util/key.Generator.

type Marshaler

type Marshaler interface {
	// ToBytes converts this to a byte slice. If successful should always have
	// at least one byte.
	ToBytes() ([]byte, error)

	// FromBytes populates this from a byte slice. This can return
	// ErrUnmarshalMoreData if the data is too big.
	FromBytes(Crypto, []byte) error
}

Marshaler is implemented by any message that can be marshaled to/from bytes.

type PointHasher

type PointHasher interface {
	// HashToPoint hashes the given msg to a point.
	HashToPoint(msg []byte) kyber.Point
}

PointHasher provides HashToPoint to create points from the hash of messages.

type ServerAuth

type ServerAuth struct {
	// contains filtered or unexported fields
}

ServerAuth is the server-side authentication session for a registered user. The Complete step takes a user message and gives a message that can be sent back. This should be interspersed with a key exchange which can be embedded or external, see NewServerAuth. If key exchange is embedded and there is a UserAuthComplete, it should be passed to Finish to complete with the embedded key exchange. Otherwise, Finish is not necessary.

This should be created each auth attempt and never reused.

func NewServerAuth

func NewServerAuth(crypto Crypto, embeddedKeyExchange KeyExchange) *ServerAuth

NewServerAuth creates a new auth session for a user. The auth should run alongside a key exchange. If embeddedKeyExchange is nil, the key exchange is expected to be done by the caller with these messages embedded within. If there is an embeddedKeyExchange and it is a 3-step one (meaning there is a UserAuthComplete given back) then Finish should be called. Otherwise, Finish is not necessary.

func (*ServerAuth) Complete

Complete combines the received UserAuthInit information with the stored ServerRegisterComplete information to produce the authentication info to give back to the user. If there is no embedded key exchange or it is only a 2-step exchange, this is the last call required. Otherwise, Finish must be called to complete the auth. If there is no embedded key exchange, error is always nil.

func (*ServerAuth) Finish

func (s *ServerAuth) Finish(u *UserAuthComplete) error

Finish simply validates the given user auth complete. This can only be called if there is an embedded key exchange and it is a 3-step exchange. Otherwise, Complete is the last OPAQUE step and the caller can use it in an external key exchange.

type ServerAuthComplete

type ServerAuthComplete struct {
	ServerPublicKey kyber.Point

	EnvU                        []byte
	V                           kyber.Point
	Beta                        kyber.Point
	EmbeddedKeyExchangeMessage2 []byte
}

ServerAuthComplete is the resulting info from ServerAuth to send back to the user. It implements Marshaler.

func (*ServerAuthComplete) FromBytes

func (s *ServerAuthComplete) FromBytes(c Crypto, data []byte) (err error)

FromBytes implements Marshaler.FromBytes. This can return ErrUnmarshalMoreData if the data is too big.

func (*ServerAuthComplete) ToBytes

func (s *ServerAuthComplete) ToBytes() ([]byte, error)

ToBytes implements Marshaler.ToBytes.

type ServerRegister

type ServerRegister struct {
	// contains filtered or unexported fields
}

ServerRegister is the server-side session for registration with a user. This should be created for each user registration and never reused. Once created via NewServerRegister, Init should be called with the value from the user side and then the result should be passed back to the user. The user-side's next value should be passed to Complete and the results of Complete should be stored by the server.

func NewServerRegister

func NewServerRegister(crypto Crypto, privateKey kyber.Scalar) *ServerRegister

NewServerRegister creates a ServerRegister with the given key. The key can be the same as used for other registrations.

func (*ServerRegister) Complete

Complete takes the last info from the user and returns a st of data that must be stored by the server.

func (*ServerRegister) Init

Init is called with the first data received from the user side. The response should be sent back to the user.

type ServerRegisterComplete

type ServerRegisterComplete struct {
	UserID []byte
	// Same as given originally, can be global
	ServerPrivateKey kyber.Scalar
	UserPublicKey    kyber.Point
	EnvU             []byte
	KU               kyber.Scalar
}

ServerRegisterComplete is the completed set of data that should be stored by the server on successful registration.

type ServerRegisterInit

type ServerRegisterInit struct {
	ServerPublicKey kyber.Point
	V               kyber.Point
	Beta            kyber.Point
}

ServerRegisterInit is the result of Init to be passed to the user. It implements Marshaler.

func (*ServerRegisterInit) FromBytes

func (s *ServerRegisterInit) FromBytes(c Crypto, data []byte) (err error)

FromBytes implements Marshaler.FromBytes. This can return ErrUnmarshalMoreData if the data is too big.

func (*ServerRegisterInit) ToBytes

func (s *ServerRegisterInit) ToBytes() ([]byte, error)

ToBytes implements Marshaler.ToBytes.

type Signer

type Signer interface {
	// Sign signs the given msg with the given priv key.
	Sign(priv kyber.Scalar, msg []byte) ([]byte, error)

	// Verify verifies the given sig for the given msg was signed by the private
	// key for the given pub key. If verification fails, the error is non-nil.
	Verify(pub kyber.Point, msg, sig []byte) error
}

Signer supports signing and verification.

type SignerSchnorr

type SignerSchnorr struct {
	schnorr.Suite
}

SignerSchnorr implement Signer for Schnorr signatures.

func (*SignerSchnorr) Sign

func (s *SignerSchnorr) Sign(priv kyber.Scalar, msg []byte) ([]byte, error)

Sign implements Signer.Sign.

func (*SignerSchnorr) Verify

func (s *SignerSchnorr) Verify(pub kyber.Point, msg, sig []byte) error

Verify implements Signer.Verify.

type UserAuth

type UserAuth struct {
	// contains filtered or unexported fields
}

UserAuth is the user-side authentication session for a registered user. The Init step gives a message that can be sent to the server and the response can be given to Complete to complete the authentication. Both the message sent from Init and received from the server are should interspersed in an existing key exchange. The key exchange can be embedded or external, see NewUserAuth.

This should be created each auth attempt and never reused.

func NewUserAuth

func NewUserAuth(crypto Crypto, userID []byte, embeddedKeyExchange KeyExchange) *UserAuth

NewUserAuth creates a new auth session for the given userID. The auth should run alongside a key exchange. If embeddedKeyExchange is nil, the key exchange is expected to be done by the caller with these messages embedded within. This means Complete will not return a message to send back to the server since OPAQUE only requires the two steps. If embeddedKeyExchange is not nil, the key exchange will be done as part of the auth here and shipped alongside the messages. If the key exchange is a 3-step then Complete will provide a message to send back to the server.

func (*UserAuth) Complete

Complete takes the server's complete information and decrypts it and returns the user auth information as UserAuthFinish. If there is an embedded key exchange and it's a 3-step one (meaning KeyExchange.UserKeyExchange3 returns a value), then a UserAuthComplete record is returned to send back to the server for completion. Otherwise, the UserAuthComplete is nil and there are no more steps. If there is no embedded key exchange, the external key exchange performed by the caller may do more after this.

func (*UserAuth) Init

func (u *UserAuth) Init(password []byte) (*UserAuthInit, error)

Init creates the first set of data to send to the server from the given password. Error is always nil if there is no embedded key exchange.

type UserAuthComplete

type UserAuthComplete struct {
	EmbeddedKeyExchangeMessage3 []byte
}

UserAuthComplete is sent back to the server to complete auth if needed. It implements Marshaler.

func (*UserAuthComplete) FromBytes

func (u *UserAuthComplete) FromBytes(c Crypto, data []byte) (err error)

FromBytes implements Marshaler.FromBytes. This can return ErrUnmarshalMoreData if the data is too big.

func (*UserAuthComplete) ToBytes

func (u *UserAuthComplete) ToBytes() ([]byte, error)

ToBytes implements Marshaler.ToBytes.

type UserAuthFinish

type UserAuthFinish struct {
	UserPrivateKey  kyber.Scalar
	ServerPublicKey kyber.Point
}

UserAuthFinish is the completed information for use once auth is done.

type UserAuthInit

type UserAuthInit struct {
	UserID []byte

	Alpha                       kyber.Point
	EmbeddedKeyExchangeMessage1 []byte
}

UserAuthInit is the set of data to pass to the server after calling UserAuth.Init. It implements Marshaler.

func (*UserAuthInit) FromBytes

func (u *UserAuthInit) FromBytes(c Crypto, data []byte) (err error)

FromBytes implements Marshaler.FromBytes. This can return ErrUnmarshalMoreData if the data is too big.

func (*UserAuthInit) ToBytes

func (u *UserAuthInit) ToBytes() ([]byte, error)

ToBytes implements Marshaler.ToBytes.

type UserRegister

type UserRegister struct {
	// contains filtered or unexported fields
}

UserRegister is the user-side session for registration with a server. This should be created for each server registration and never reused. Once created via NewUserRegister, Init can be called with a password that will return a value that can be sent to the server. The value that the server returns can then be used for Complete. The resulting value from Complete is then passed back to the server to complete registration.

func NewUserRegister

func NewUserRegister(crypto Crypto, userID []byte, privateKey kyber.Scalar) *UserRegister

NewUserRegister creates a registration session for the given userID. If privateKey is nil (recommended), it is generated. A key should never be reused on different registrations.

func (*UserRegister) Complete

Complete is called after receiving the server init results. The result of this call should be passed back to the server.

func (*UserRegister) Init

func (u *UserRegister) Init(password []byte) *UserRegisterInit

Init creates an init message for the password.

func (*UserRegister) PrivateKey

func (u *UserRegister) PrivateKey() kyber.Scalar

PrivateKey gives the key used during registration. This is often generated on NewUserRegister. It is rarely needed because it comes back on authenticate as well.

type UserRegisterComplete

type UserRegisterComplete struct {
	UserPublicKey kyber.Point
	EnvU          []byte
}

UserRegisterComplete is the set of data to pass to the server after calling Complete. It implements Marshaler.

func (*UserRegisterComplete) FromBytes

func (u *UserRegisterComplete) FromBytes(c Crypto, data []byte) (err error)

FromBytes implements Marshaler.FromBytes. This can return ErrUnmarshalMoreData if the data is too big.

func (*UserRegisterComplete) ToBytes

func (u *UserRegisterComplete) ToBytes() ([]byte, error)

ToBytes implements Marshaler.ToBytes.

type UserRegisterInit

type UserRegisterInit struct {
	UserID []byte
	Alpha  kyber.Point
}

UserRegisterInit is the set of data to pass to the server after calling UserRegister.Init. It implements Marshaler.

func (*UserRegisterInit) FromBytes

func (u *UserRegisterInit) FromBytes(c Crypto, data []byte) (err error)

FromBytes implements Marshaler.FromBytes. This can return ErrUnmarshalMoreData if the data is too big.

func (*UserRegisterInit) ToBytes

func (u *UserRegisterInit) ToBytes() ([]byte, error)

ToBytes implements Marshaler.ToBytes.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL