Esempio n. 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
}
Esempio n. 2
0
func main() {
	fmt.Printf("=== PHASE I: TEST ALGORITHM ===\n")
	pi := new(big.Int)
	pi.SetString("11470374874925275658116663507232161402086650258453896274534991676898999262641581519101074740642369848233294239851519212341844337347119899874391456329785623", 10)
	gi := new(big.Int)
	gi.SetString("622952335333961296978159266084741085889881358738459939978290179936063635566740258555167783009058567397963466103140082647486611657350811560630587013183357", 10)
	q := new(big.Int)
	q.SetString("335062023296420808191071248367701059461", 10)
	G := dh.NewFiniteGroup(*pi)
	g := dh.NewFiniteElement(G, *gi)
	GG := dh.NewGeneratedGroup(G, g, *q)

	targets := []string{
		"7760073848032689505395005705677365876654629189298052775754597607446617558600394076764814236081991643094239886772481052254010323780165093955236429914607119",
		"9388897478013399550694114614498790691034187453089355259602614074132918843899833277397448144245883225611726912025846772975325932794909655215329941809013733",
	}

	hi := new(big.Int)
	a := 0
	upperBounds := []int{1 << 20, 1 << 40}

	for i, hs := range targets {
		hi.SetString(hs, 10)
		b := upperBounds[i]

		h := dh.NewFiniteElement(G, *hi)

		log.Printf("Searching for discrete log of %s", h)
		x := dh.Pollard(GG, g, h, a, b)
		if x == nil {
			log.Printf("The wild kangaroo escaped!")
		} else {
			x.Mod(x, q)
			log.Printf("discrete log = %s", x)
			check := GG.Pow(g, x)
			log.Printf("%s^%d mod %s == %s", g, x, pi, GG.Pow(g, x))
			if check.Cmp(h) != 0 {
				log.Printf("ERROR! Expected %s but got %s", h, check)
			}
		}
	}

	fmt.Printf("\n=== PHASE II: APPLY WITH COFACTOR ATTACK ===\n")
	factors := dh.FindCoFactors(q, pi, G)

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

	d := dh.NewDiffieHellman(GG)
	for factor, h := range factors {
		total.Mul(total, big.NewInt(factor))
		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)) {
				//log.Printf("%d^%d", elt, i)
				found = true
				moduli[factor] = i
				break
			}
		}
		if !found {
			panic("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("x mod r = %s [r = %s]", x, total)

	n := new(big.Int)
	n.Sub(q, x)

	hp := GG.Op(d.PublicKey(), GG.Pow(g, n))
	gp := GG.Pow(g, total)
	B := new(big.Int)
	B.Div(q, total)

	log.Printf("Searching for discrete log of %s", hp)
	m := dh.Pollard(GG, gp, hp, 0, int(B.Int64()))
	if m == nil {
		log.Printf("The wild kangaroo escaped!")
	} else {
		m.Mod(m, q)
		log.Printf("discrete log = %s", m)
		check := GG.Pow(gp, m)
		log.Printf("%s^%d mod %s == %s", gp, m, pi, GG.Pow(gp, m))
		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)
}