Example #1
0
func main() {
	p, _ := new(big.Int).SetString("233970423115425145524320034830162017933", 10)
	groupOrder, _ := new(big.Int).SetString("233970423115425145498902418297807005944", 10)
	a := big.NewInt(-95051)
	b := big.NewInt(11279326)
	EC := dh.NewEllipticCurve(a, b, p)
	gx := big.NewInt(182)
	gy, _ := new(big.Int).SetString("85518893674295321206118380980485522083", 10)
	g := dh.NewEllipticCurveElement(EC, gx, gy)

	MC := dh.NewMontgomeryCurve(big.NewInt(534), big.NewInt(1), p)
	mg := dh.NewMontgomeryCurveElement(MC, big.NewInt(4))
	q, _ := new(big.Int).SetString("29246302889428143187362802287225875743", 10)
	GG := dh.NewGeneratedGroup(MC, mg, *q)

	twistOrder := new(big.Int).Mul(p, big.NewInt(2))
	twistOrder.Add(twistOrder, big.NewInt(2))
	twistOrder.Sub(twistOrder, groupOrder)

	factors := dh.FindFactors(twistOrder, twistOrder, q, MC)

	total := big.NewInt(1)

	for factor, _ := range factors {
		total.Mul(total, big.NewInt(factor))
	}

	// Find an element that is order=total. We will use this to guess which
	// of the one or two remainders for each small prime is correct.
	log.Printf("Finding an element of order %d...", total)
	pow := new(big.Int)
	pow.Div(twistOrder, total)
	var h dh.Element = nil
	for {
		h = MC.Pow(MC.Random(), pow)
		if h.Cmp(MC.Identity()) != 0 {
			bad := false
			for factor, _ := range factors {
				if MC.Pow(h, big.NewInt(factor)).Cmp(MC.Identity()) == 0 {
					bad = true
					break
				}
			}
			if !bad {
				log.Printf("%s^%d == %s", h, total, MC.Pow(h, total))
				break
			}
		}
	}

	d := dh.NewDiffieHellman(GG)
	mac := Alice(d, h)

	// Determine the possible remainders for each small prime. There are usually
	// two because (u, v) and (u, -v) are conflated by the ladder.
	type factorModuli struct {
		factor         int64
		possibleModuli []int64
	}
	smallFactorModuli := make([]*factorModuli, 0)
	for factor, h := range factors {
		fm := &factorModuli{factor, make([]int64, 0)}
		mac := Alice(d, h)
		log.Printf("Guessing the shared secret in the subgroup of order %d", factor)
		found := false
		for i := int64(0); i < factor; i++ {
			k := MC.Pow(h, big.NewInt(i))
			if hmac.Equal(mac, Sign(secretMessage, k)) {
				found = true
				fm.possibleModuli = append(fm.possibleModuli, i)
				if i != 0 {
					// If h^i = (u, v) then (u, -v) = (h^i)^-1 = h^-i
					fm.possibleModuli = append(fm.possibleModuli, factor-i)
				}
				break
			}
		}
		if !found {
			log.Fatal("Could not guess the shared secret")
		}
		smallFactorModuli = append(smallFactorModuli, fm)
	}

	// Figure out which one of the various choices for each small remainder is correct.
	// For each permutation:
	//  - use CRT to compute remainder x mod "total"
	//  - check if the saved MAC corresponds to h^x.
	indices := make([]int, len(smallFactorModuli))
	bigModuli := make([]*big.Int, 0)
	for {
		carry := true
		for i := 0; carry && i < len(indices); i++ {
			indices[i] = (indices[i] + 1) % len(smallFactorModuli[i].possibleModuli)
			carry = indices[i] == 0
		}
		moduli := make(map[int64]int64)
		for i, fm := range smallFactorModuli {
			moduli[fm.factor] = fm.possibleModuli[indices[i]]
		}
		// From Wikipedia CRT page
		x := new(big.Int)
		for n, a := range moduli {
			N := new(big.Int).Set(total)
			N.Div(N, big.NewInt(n))
			N.ModInverse(N, big.NewInt(n))
			N.Mul(N, total)
			N.Div(N, big.NewInt(n))
			N.Mul(N, big.NewInt(a))
			x.Add(x, N)
			x.Mod(x, total)
		}
		k := MC.Pow(h, x)
		if hmac.Equal(mac, Sign(secretMessage, k)) {
			log.Printf("x mod r may be %s [r = %s]", x, total)
			bigModuli = append(bigModuli, x)
			if x.Cmp(new(big.Int)) != 0 {
				// Again there are probably two answers, because
				// h^x = h^-x using the montgomery ladder.
				y := new(big.Int).Sub(total, x)
				log.Printf("x mod r may be %s [r = %s]", y, total)
				bigModuli = append(bigModuli, y)
			}
			break
		}
	}

	// We now have two possible remainders mod "total". For each of those,
	// use the kangaroo algorithm to try to guess the secret. Note that
	// the public key that Alice gives us will *also* correspond to two
	// different points (u, v) and (u, -v) so we need to try plugging both
	// of them in and see which one works.
	ch := make(chan bool)
	for _, x := range bigModuli {
		for _, negate := range []bool{true, false} {
			go func(x *big.Int, negate bool) {
				n := new(big.Int)
				n.Sub(q, x)

				// Convert to Weierstrass form so Op is implemented and so
				// we can specify which of the two collapsed points (u, v)
				// and (u, -v) to use for this trial.
				w1 := dh.Q60MontgomeryToWeierstrass(d.PublicKey(), EC)
				if negate {
					dh.NegateWeierstrass(w1, EC)
				}
				w2 := EC.Pow(g, n)
				hp := EC.Op(w1, w2)
				gp := EC.Pow(g, total)
				B := new(big.Int)
				B.Div(q, total)

				log.Printf("Searching for index of %s in 0..%d", hp, B.Int64())
				m := dh.Pollard(EC, gp, hp, 0, int(B.Int64()))
				if m == nil {
					log.Printf("The wild kangaroo escaped!")
					return
				} else {
					m.Mod(m, q)
					log.Printf("index = %s", m)
					check := EC.Pow(gp, m)
					log.Printf("%s^%d mod %s = %s", gp, m, p, check)
					if check.Cmp(hp) != 0 {
						log.Printf("ERROR! Expected %s but got %s", hp, check)
					}
				}

				m.Mul(m, total)
				x.Add(x, m)

				log.Printf("Predicted key: %d", x)
				log.Printf("%s", d)
				ch <- true
			}(x, negate)
		}
	}

	<-ch
}
Example #2
0
func main() {
	p, _ := new(big.Int).SetString("233970423115425145524320034830162017933", 10)
	a := big.NewInt(-95051)
	//a.Sub(p, a)
	b := big.NewInt(11279326)
	G := dh.NewEllipticCurve(a, b, p)

	gx := big.NewInt(182)
	gy, _ := new(big.Int).SetString("85518893674295321206118380980485522083", 10)
	g := dh.NewEllipticCurveElement(G, gx, gy)
	q, _ := new(big.Int).SetString("29246302889428143187362802287225875743", 10)
	GG := dh.NewGeneratedGroup(G, g, *q)

	d1 := dh.NewDiffieHellman(GG)
	d2 := dh.NewDiffieHellman(GG)

	fmt.Printf("=== PHASE I: TEST DIFFIE-HELLMAN WORKS ===\n")

	log.Printf("Alice's DH: %s", d1)
	log.Printf("Bob's DH: %s", d2)

	log.Printf("Bob's shared secret from Alice's public key: %s", d2.SharedSecret(d1.PublicKey()))
	log.Printf("Alice's shared secret from Bob's public key: %s", d1.SharedSecret(d2.PublicKey()))

	fmt.Printf("=== PHASE II: BREAK DIFFIE-HELLMAN ===\n")

	weakSubgroups := []dh.Group{
		dh.NewEllipticCurve(big.NewInt(-95051), big.NewInt(210), p),
		dh.NewEllipticCurve(big.NewInt(-95051), big.NewInt(504), p),
		dh.NewEllipticCurve(big.NewInt(-95051), big.NewInt(727), p),
	}
	weakSubgroupOrders := make([]*big.Int, 3)
	weakSubgroupOrders[0], _ = new(big.Int).SetString("233970423115425145550826547352470124412", 10)
	weakSubgroupOrders[1], _ = new(big.Int).SetString("233970423115425145544350131142039591210", 10)
	weakSubgroupOrders[2], _ = new(big.Int).SetString("233970423115425145545378039958152057148", 10)

	allFactors := make(map[int64]dh.Element)

	for i, SG := range weakSubgroups {
		order := weakSubgroupOrders[i]
		factors := dh.FindFactors(order, order, q, SG)
		for factor, h := range factors {
			if _, ok := allFactors[factor]; !ok {
				allFactors[factor] = h
			}
		}
	}

	moduli := make(map[int64]int64)
	total := big.NewInt(1)

	d := dh.NewDiffieHellman(GG)
	for factor, h := range allFactors {
		mac := Bob(d, h)
		log.Printf("Guessing the shared secret in the subgroup of order %d", factor)
		found := false
		for i := int64(1); i <= factor; i++ {
			k := G.Pow(h, big.NewInt(i))
			if hmac.Equal(mac, Sign(secretMessage, k)) {
				found = true
				moduli[factor] = i
				break
			}
		}
		if found {
			total.Mul(total, big.NewInt(factor))
			if total.Cmp(q) > 0 {
				log.Printf("Found enough moduli")
				break
			}
		} else {
			// This can happen if a prime factor of one of the weak subgroups' order
			// is a double divisor in another one's order.
			log.Printf("Could not guess the shared secret!")
		}
	}

	// From Wikipedia CRT page
	x := new(big.Int)
	for n, a := range moduli {
		N := new(big.Int).Set(total)
		N.Div(N, big.NewInt(n))
		N.ModInverse(N, big.NewInt(n))
		N.Mul(N, total)
		N.Div(N, big.NewInt(n))
		N.Mul(N, big.NewInt(a))
		x.Add(x, N)
		x.Mod(x, total)
	}
	log.Printf("Predicted key: %d", x)

	log.Printf("%s", d)
}