Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 47 additions & 6 deletions crypto/internal/bigmod/nat.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ package bigmod

import (
"errors"
"github.com/runZeroInc/excrypto/internal/byteorder"
"math/big"
"math/bits"

"github.com/runZeroInc/excrypto/internal/byteorder"
)

const (
Expand All @@ -25,8 +26,10 @@ type choice uint

func not(c choice) choice { return 1 ^ c }

const yes = choice(1)
const no = choice(0)
const (
yes = choice(1)
no = choice(0)
)

// ctMask is all 1s if on is yes, and all 0s otherwise.
func ctMask(on choice) uint { return -uint(on) }
Expand All @@ -53,8 +56,10 @@ type Nat struct {
// preallocTarget is the size in bits of the numbers used to implement the most
// common and most performant RSA key size. It's also enough to cover some of
// the operations of key sizes up to 4096.
const preallocTarget = 2048
const preallocLimbs = (preallocTarget + _W - 1) / _W
const (
preallocTarget = 2048
preallocLimbs = (preallocTarget + _W - 1) / _W
)

// NewNat returns a new nat with a size of zero, just like new(Nat), but with
// the preallocated capacity to hold a number of up to preallocTarget bits.
Expand Down Expand Up @@ -771,7 +776,43 @@ func (out *Nat) Exp(x *Nat, e []byte, m *Modulus) *Nat {
//
// The output will be resized to the size of m and overwritten. x must already
// be reduced modulo m. This leaks the exponent through timing side-channels.
func (out *Nat) ExpShortVarTime(x *Nat, e uint, m *Modulus) *Nat {
func (out *Nat) ExpShortVarTime(x *Nat, e *big.Int, m *Modulus) *Nat {
// For short exponents, precomputing a table and using a window like in Exp
// doesn't pay off. Instead, we do a simple conditional square-and-multiply
// chain, skipping the initial run of zeroes.
xR := NewNat().set(x).montgomeryRepresentation(m)
out.set(xR)

// Convert the big.Int exponent to binary representation
expBits := e.Bytes()
for i := 0; i < len(expBits); i++ {
byteVal := expBits[i]
for j := 7; j >= 0; j-- {
// Square the result
out.montgomeryMul(out, out, m)

// Multiply if the current bit is set
if (byteVal>>j)&1 == 1 {
out.montgomeryMul(out, xR, m)
}
}
}

resNew := out.montgomeryReduction(m)
resOld := out.ExpShortVarTimeOrig(x, uint(e.Uint64()), m)
if resNew.Equal(resOld) == no {
panic("XXX: bigmod: ExpShortVarTime produced different result than ExpShortVarTimeOrig")
}
return resNew
}

// ExpShortVarTime calculates out = x^e mod m.
//
// The output will be resized to the size of m and overwritten. x must already
// be reduced modulo m. This leaks the exponent through timing side-channels.
//
// m must be odd, or ExpShortVarTime will panic.
func (out *Nat) ExpShortVarTimeOrig(x *Nat, e uint, m *Modulus) *Nat {
// For short exponents, precomputing a table and using a window like in Exp
// doesn't pay off. Instead, we do a simple conditional square-and-multiply
// chain, skipping the initial run of zeroes.
Expand Down
12 changes: 8 additions & 4 deletions crypto/internal/bigmod/nat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,12 @@ func TestModulusAndNatSizes(t *testing.T) {
// modulus strips leading zeroes and nat does not.
m := modulusFromBytes([]byte{
0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff})
xb := []byte{0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
})
xb := []byte{
0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
}
natFromBytes(xb).ExpandFor(m) // must not panic for shrinking
NewNat().SetBytes(xb, m)
}
Expand Down Expand Up @@ -303,7 +306,8 @@ func TestExpShort(t *testing.T) {
m := modulusFromBytes([]byte{13})
x := &Nat{[]uint{3}}
out := &Nat{[]uint{0}}
out.ExpShortVarTime(x, 12, m)
e := big.NewInt(12)
out.ExpShortVarTime(x, e, m)
expected := &Nat{[]uint{1}}
if out.Equal(expected) != 1 {
t.Errorf("%+v != %+v", out, expected)
Expand Down
6 changes: 3 additions & 3 deletions crypto/json/rsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ type RSAPublicKey struct {
}

type auxRSAPublicKey struct {
Exponent int `json:"exponent"`
Modulus []byte `json:"modulus"`
Length int `json:"length"`
Exponent *big.Int `json:"exponent"`
Modulus []byte `json:"modulus"`
Length int `json:"length"`
}

// RSAClientParams are the TLS key exchange parameters for RSA keys.
Expand Down
2 changes: 1 addition & 1 deletion crypto/json/rsa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ var _ = Suite(&RSASuite{})
func (s *RSASuite) SetUpTest(c *C) {
s.pk4096 = new(RSAPublicKey)
s.pk4096.PublicKey = new(rsa.PublicKey)
s.pk4096.E = 65537
s.pk4096.E = big.NewInt(65537)
s.pk4096.N = big.NewInt(0).SetBytes(test4096Modulus)
}

Expand Down
7 changes: 3 additions & 4 deletions crypto/rsa/equal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
package rsa_test

import (
"testing"

"crypto/rand"
"testing"

"github.com/runZeroInc/excrypto/crypto"
"github.com/runZeroInc/excrypto/crypto/rsa"
Expand Down Expand Up @@ -37,10 +36,10 @@ func TestEqual(t *testing.T) {
t.Fatal(err)
}
if !public.Equal(decoded.(crypto.Signer).Public()) {
t.Errorf("public key is not equal to itself after decoding: %v", public)
t.Errorf("public key is not equal to itself after decoding: pre: %#v. post: %#v", public, decoded.(crypto.Signer).Public())
}
if !private.Equal(decoded) {
t.Errorf("private key is not equal to itself after decoding: %v", private)
t.Errorf("private key is not equal to itself after decoding: pre: %#v. post: %#v", private, decoded)
}

other, _ := rsa.GenerateKey(rand.Reader, 512)
Expand Down
7 changes: 3 additions & 4 deletions crypto/rsa/pss_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ import (
"bufio"
"bytes"
"compress/bzip2"
"crypto/rand"
"encoding/hex"
"math/big"
"os"
"strconv"
"strings"
"testing"

"crypto/rand"

"github.com/runZeroInc/excrypto/crypto"
. "github.com/runZeroInc/excrypto/crypto/rsa"
"github.com/runZeroInc/excrypto/crypto/sha1"
Expand Down Expand Up @@ -145,7 +144,7 @@ func TestPSSGolden(t *testing.T) {
continue
}
key.N = bigFromHex(nHex)
key.E = intFromHex(<-values)
key.E = bigFromHex(<-values)
// We don't care for d, p, q, dP, dQ or qInv.
for i := 0; i < 6; i++ {
<-values
Expand Down Expand Up @@ -202,7 +201,7 @@ func TestPSSNilOpts(t *testing.T) {
}

func TestPSSSigning(t *testing.T) {
var saltLengthCombinations = []struct {
saltLengthCombinations := []struct {
signSaltLength, verifySaltLength int
good bool
}{
Expand Down
43 changes: 26 additions & 17 deletions crypto/rsa/rsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,13 @@
package rsa

import (
"crypto/rand"
"errors"
"hash"
"io"
"math"
"math/big"

"crypto/rand"

"github.com/runZeroInc/excrypto/crypto"
"github.com/runZeroInc/excrypto/crypto/internal/bigmod"
"github.com/runZeroInc/excrypto/crypto/internal/boring"
Expand All @@ -50,7 +49,7 @@ var bigOne = big.NewInt(1)
// exponent E nor the precise bit size of N are similarly protected.
type PublicKey struct {
N *big.Int // modulus
E int // public exponent
E *big.Int // public exponent
}

// Any methods implemented on PublicKey might need to also be implemented on
Expand All @@ -68,7 +67,7 @@ func (pub *PublicKey) Equal(x crypto.PublicKey) bool {
if !ok {
return false
}
return bigIntEqual(pub.N, xx.N) && pub.E == xx.E
return bigIntEqual(pub.N, xx.N) && bigIntEqual(pub.E, xx.E)
}

// OAEPOptions is an interface for passing options to OAEP decryption using the
Expand All @@ -92,6 +91,8 @@ var (
errPublicExponentLarge = errors.New("crypto/rsa: public exponent too large")
)

/*
// The original checkPub() is disabled to enable wild values for E
// checkPub sanity checks the public key before we use it.
// We require pub.E to fit into a 32-bit integer so that we
// do not have different behavior depending on whether
Expand All @@ -101,12 +102,23 @@ func checkPub(pub *PublicKey) error {
if pub.N == nil {
return errPublicModulus
}

if pub.E < 2 {
return errPublicExponentSmall
}
if pub.E > 1<<31-1 {
return errPublicExponentLarge
}

return nil
}
*/

// checkPub provides minimal checks on the public key.
func checkPub(pub *PublicKey) error {
if pub.N == nil {
return errPublicModulus
}
return nil
}

Expand Down Expand Up @@ -256,7 +268,7 @@ func (priv *PrivateKey) Validate() error {
// exponent(ℤ/nℤ). It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1
// mod p. Thus a^de ≡ a mod n for all a coprime to n, as required.
congruence := new(big.Int)
de := new(big.Int).SetInt64(int64(priv.E))
de := new(big.Int).Set(priv.E)
de.Mul(de, priv.D)
for _, prime := range priv.Primes {
pminus1 := new(big.Int).Sub(prime, bigOne)
Expand Down Expand Up @@ -313,10 +325,6 @@ func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey
Dp := bbig.Dec(bDp)
Dq := bbig.Dec(bDq)
Qinv := bbig.Dec(bQinv)
e64 := E.Int64()
if !E.IsInt64() || int64(int(e64)) != e64 {
return nil, errors.New("crypto/rsa: generated key exponent too large")
}

mn, err := bigmod.NewModulusFromBig(N)
if err != nil {
Expand All @@ -334,7 +342,7 @@ func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey
key := &PrivateKey{
PublicKey: PublicKey{
N: N,
E: int(e64),
E: new(big.Int).Set(E),
},
D: D,
Primes: []*big.Int{P, Q},
Expand All @@ -352,7 +360,7 @@ func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey
}

priv := new(PrivateKey)
priv.E = 65537
priv.E = big.NewInt(65537)

if nprimes < 2 {
return nil, errors.New("crypto/rsa: GenerateMultiPrimeKey: nprimes must be >= 2")
Expand Down Expand Up @@ -426,7 +434,7 @@ NextSetOfPrimes:
}

priv.D = new(big.Int)
e := big.NewInt(int64(priv.E))
e := new(big.Int).Set(priv.E)
ok := priv.D.ModInverse(e, totient)

if ok != nil {
Expand Down Expand Up @@ -491,8 +499,7 @@ func encrypt(pub *PublicKey, plaintext []byte) ([]byte, error) {
if err != nil {
return nil, err
}
e := uint(pub.E)

e := new(big.Int).Set(pub.E)
return bigmod.NewNat().ExpShortVarTime(m, e, N).Bytes(N), nil
}

Expand Down Expand Up @@ -633,8 +640,10 @@ func (priv *PrivateKey) Precompute() {
}
}

const withCheck = true
const noCheck = false
const (
withCheck = true
noCheck = false
)

// decrypt performs an RSA decryption of ciphertext into out. If check is true,
// m^e is calculated and compared with ciphertext, in order to defend against
Expand Down Expand Up @@ -687,7 +696,7 @@ func decrypt(priv *PrivateKey, ciphertext []byte, check bool) ([]byte, error) {
}

if check {
c1 := bigmod.NewNat().ExpShortVarTime(m, uint(priv.E), N)
c1 := bigmod.NewNat().ExpShortVarTime(m, priv.E, N)
if c1.Equal(c) != 1 {
return nil, ErrDecryption
}
Expand Down
Loading