Browse Source

API: More closely follow the API used by the reference package.

Basically, when it's not possible to return a randomized shared secret
due to extremely malformed input, RNG failures, or whatever, panic.

This isn't the most friendly thing, but things such as validating input
lengths and not trying to mix and match ParameterSets doesn't feel like
unreasonable demands to place on the calling code.
Yawning Angel 1 year ago
parent
commit
ec6c3bfa93
2 changed files with 37 additions and 21 deletions
  1. 8 3
      kem.go
  2. 29 18
      kex.go

+ 8 - 3
kem.go

@@ -21,6 +21,10 @@ var (
 	// an invalid size.
 	ErrInvalidKeySize = errors.New("kyber: invalid key size")
 
+	// ErrInvalidCipherTextSize is the error thrown via a panic when a byte
+	// serialized ciphertext is an invalid size.
+	ErrInvalidCipherTextSize = errors.New("kyber: invalid ciphertext size")
+
 	// ErrInvalidPrivateKey is the error returned when a byte serialized
 	// private key is malformed.
 	ErrInvalidPrivateKey = errors.New("kyber: invalid private key")
@@ -127,7 +131,7 @@ func (p *ParameterSet) GenerateKeyPair(rng io.Reader) (*PublicKey, *PrivateKey,
 func (pk *PublicKey) KEMEncrypt(rng io.Reader) (cipherText []byte, sharedSecret []byte, err error) {
 	var buf [SymSize]byte
 	if _, err = io.ReadFull(rng, buf[:]); err != nil {
-		return
+		return nil, nil, err
 	}
 	buf = sha3.Sum256(buf[:]) // Don't release system RNG output
 
@@ -152,13 +156,14 @@ func (pk *PublicKey) KEMEncrypt(rng io.Reader) (cipherText []byte, sharedSecret
 // Kyber key encapsulation mechanism.
 //
 // On success fail will be 0, otherwise fail will be set to -1 and
-// sharedSecret will contain a randomized value.
+// sharedSecret will contain a randomized value.  Providing a cipher text
+// that is obviously malformed (too large/small) will result in a panic.
 func (sk *PrivateKey) KEMDecrypt(cipherText []byte) (sharedSecret []byte, fail int) {
 	var buf [2 * SymSize]byte
 
 	p := sk.PublicKey.p
 	if len(cipherText) != p.CipherTextSize() {
-		return nil, -1
+		panic(ErrInvalidCipherTextSize)
 	}
 	p.indcpaDecrypt(buf[:SymSize], cipherText, sk.sk)
 

+ 29 - 18
kex.go

@@ -8,11 +8,22 @@
 package kyber
 
 import (
+	"errors"
 	"io"
 
 	"golang.org/x/crypto/sha3"
 )
 
+var (
+	// ErrInvalidMessageSize is the error thrown via a panic when a initator
+	// or responder message is an invalid size.
+	ErrInvalidMessageSize = errors.New("kyber: invalid message size")
+
+	// ErrParameterSetMismatch is the error thrown via a panic when there
+	// is a mismatch between parameter sets.
+	ErrParameterSetMismatch = errors.New("kyber: parameter set mismatch")
+)
+
 // UAKEInitiatorMessageSize returns the size of the initiator UAKE message
 // in bytes.
 func (p *ParameterSet) UAKEInitiatorMessageSize() int {
@@ -80,21 +91,20 @@ func (pk *PublicKey) NewUAKEInitiatorState(rng io.Reader) (*UAKEInitiatorState,
 // a initiator UAKE message.
 //
 // On success fail will be 0, otherwise fail will be set to -1 and
-// sharedSecret will contain a randomized value.
+// sharedSecret will contain a randomized value.  Providing a malformed
+// initator message will result in a panic.
 func (sk *PrivateKey) UAKEResponderShared(rng io.Reader, recv []byte) (message, sharedSecret []byte, fail int) {
 	p := sk.PublicKey.p
 	pkLen := p.PublicKeySize()
 
-	fail = -1
-
 	// Deserialize the peer's ephemeral public key.
 	if len(recv) != p.UAKEInitiatorMessageSize() {
-		return
+		panic(ErrInvalidMessageSize)
 	}
 	rawPk, ct := recv[:pkLen], recv[pkLen:]
 	pk, err := p.PublicKeyFromBytes(rawPk)
 	if err != nil {
-		return
+		panic(err)
 	}
 
 	xof := sha3.NewShake256()
@@ -102,7 +112,7 @@ func (sk *PrivateKey) UAKEResponderShared(rng io.Reader, recv []byte) (message,
 
 	message, tk, err = pk.KEMEncrypt(rng)
 	if err != nil {
-		return
+		panic(err)
 	}
 	xof.Write(tk)
 
@@ -140,16 +150,17 @@ type AKEInitiatorState struct {
 // message, and long term initiator private key.
 //
 // On success fail will be 0, otherwise fail will be set to -1 and
-// sharedSecret will contain a randomized value.
+// sharedSecret will contain a randomized value.   Providing a malformed
+// responder message, or a private key that uses a different ParamterSet
+// than the AKEInitiatorState will result in a panic.
 func (s *AKEInitiatorState) Shared(recv []byte, initiatorPrivateKey *PrivateKey) (sharedSecret []byte, fail int) {
 	p := s.eSk.PublicKey.p
-	fail = -1
 
 	if initiatorPrivateKey.PublicKey.p != p {
-		return
+		panic(ErrParameterSetMismatch)
 	}
 	if len(recv) != p.AKEResponderMessageSize() {
-		return
+		panic(ErrInvalidMessageSize)
 	}
 	ctLen := p.CipherTextSize()
 
@@ -192,25 +203,25 @@ func (pk *PublicKey) NewAKEInitiatorState(rng io.Reader) (*AKEInitiatorState, er
 // a initiator AKE message and long term initiator public key.
 //
 // On success fail will be 0, otherwise fail will be set to -1 and
-// sharedSecret will contain a randomized value.
+// sharedSecret will contain a randomized value.  Providing a malformed
+// initiator message, or a public key that uses a different ParamterSet
+// than the PrivateKey will result in a panic.
 func (sk *PrivateKey) AKEResponderShared(rng io.Reader, recv []byte, peerPublicKey *PublicKey) (message, sharedSecret []byte, fail int) {
 	p := sk.PublicKey.p
 	pkLen := p.PublicKeySize()
 
-	fail = -1
-
 	if peerPublicKey.p != p {
-		return
+		panic(ErrParameterSetMismatch)
 	}
 
 	// Deserialize the peer's ephemeral public key.
 	if len(recv) != p.AKEInitiatorMessageSize() {
-		return
+		panic(ErrInvalidMessageSize)
 	}
 	rawPk, ct := recv[:pkLen], recv[pkLen:]
 	pk, err := p.PublicKeyFromBytes(rawPk)
 	if err != nil {
-		return
+		panic(err)
 	}
 
 	message = make([]byte, 0, p.AKEResponderMessageSize())
@@ -220,14 +231,14 @@ func (sk *PrivateKey) AKEResponderShared(rng io.Reader, recv []byte, peerPublicK
 
 	tmp, tk, err = pk.KEMEncrypt(rng)
 	if err != nil {
-		return
+		panic(err)
 	}
 	xof.Write(tk)
 	message = append(message, tmp...)
 
 	tmp, tk, err = peerPublicKey.KEMEncrypt(rng)
 	if err != nil {
-		return
+		panic(err)
 	}
 	xof.Write(tk)
 	message = append(message, tmp...)