openpgp/elgamal: prevent bad key from causing panic in Decrypt

If the mod inverse of the private key's P value does not exist,
return an error in Decrypt rather than panic.

Change-Id: Ia075a60108863b14ba98bb62364a17131423b819
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/573976
Reviewed-by: Filippo Valsorda <valsorda@google.com>
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/205502
Run-TryBot: Katie Hockman <katie@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
diff --git a/openpgp/elgamal/elgamal.go b/openpgp/elgamal/elgamal.go
index 73f4fe3..72a6a73 100644
--- a/openpgp/elgamal/elgamal.go
+++ b/openpgp/elgamal/elgamal.go
@@ -76,7 +76,9 @@
 // Bleichenbacher, Advances in Cryptology (Crypto '98),
 func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) {
 	s := new(big.Int).Exp(c1, priv.X, priv.P)
-	s.ModInverse(s, priv.P)
+	if s.ModInverse(s, priv.P) == nil {
+		return nil, errors.New("elgamal: invalid private key")
+	}
 	s.Mul(s, c2)
 	s.Mod(s, priv.P)
 	em := s.Bytes()
diff --git a/openpgp/elgamal/elgamal_test.go b/openpgp/elgamal/elgamal_test.go
index c4f99f5..9f0a854 100644
--- a/openpgp/elgamal/elgamal_test.go
+++ b/openpgp/elgamal/elgamal_test.go
@@ -47,3 +47,18 @@
 		t.Errorf("decryption failed, got: %x, want: %x", message2, message)
 	}
 }
+
+func TestDecryptBadKey(t *testing.T) {
+	priv := &PrivateKey{
+		PublicKey: PublicKey{
+			G: fromHex(generatorHex),
+			P: fromHex("2"),
+		},
+		X: fromHex("42"),
+	}
+	priv.Y = new(big.Int).Exp(priv.G, priv.X, priv.P)
+	c1, c2 := fromHex("8"), fromHex("8")
+	if _, err := Decrypt(priv, c1, c2); err == nil {
+		t.Errorf("unexpected success decrypting")
+	}
+}