From 39e78573812d623beb68bb835ec4a96b4e199ccf Mon Sep 17 00:00:00 2001 From: Ameer Ghani Date: Tue, 20 Oct 2026 15:02:33 -0500 Subject: [PATCH] goodkey: rsa: detect n = p^2 --- goodkey/good_key.go | 9 +++++++-- goodkey/good_key_test.go | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/goodkey/good_key.go b/goodkey/good_key.go index d8efd703ddc..604414f69c1 100644 --- a/goodkey/good_key.go +++ b/goodkey/good_key.go @@ -379,6 +379,12 @@ func checkSmallPrimes(i *big.Int) bool { // independently from a uniform random distribution. Basically, if we can factor // the key this easily, so can anyone else. func checkPrimeFactorsTooClose(n *big.Int, rounds int) error { + // Trivial case: n = p^2 + sqrt := new(big.Int).Sqrt(n) + if new(big.Int).Mul(sqrt, sqrt).Cmp(n) == 0 { + return fmt.Errorf("public modulus n = pq factored in 1 rounds into p: %s and q: %s", sqrt, sqrt) + } + // Pre-allocate some big numbers that we'll use a lot down below. one := big.NewInt(1) bb := new(big.Int) @@ -396,8 +402,7 @@ func checkPrimeFactorsTooClose(n *big.Int, rounds int) error { // first integer greater than the square root of n. Unfortunately, big.Int's // built-in square root function takes the floor, so we have to add one to get // the ceil. - a := new(big.Int) - a.Sqrt(n).Add(a, one) + a := new(big.Int).Add(sqrt, one) // We calculate b2 to see if it is a perfect square (i.e. b^2), and therefore // b is an integer. Specifically, b2 = a^2 - n. diff --git a/goodkey/good_key_test.go b/goodkey/good_key_test.go index 133b6ac11ef..d8b6df8918e 100644 --- a/goodkey/good_key_test.go +++ b/goodkey/good_key_test.go @@ -353,6 +353,12 @@ func TestCheckPrimeFactorsTooClose(t *testing.T) { q: "155536235030272749691472293262418471207550926406427515178205576891522284497518443889075039382254334975506248481615035474816604875321501901699955105345417152355947783063521554077194367454070647740704883461064399268622437721385112646454393005862535727615809073410746393326688230040267160616554768771412289114113", expectRounds: 1, }, + { + name: "p squared (2048 bit, 1 round)", + p: "155536235030272749691472293262418471207550926406427515178205576891522284497518443889075039382254334975506248481615035474816604875321501901699955105345417152355947783063521554077194367454070647740704883461064399268622437721385112646454393005862535727615809073410746393326688230040267160616554768771412289114449", + q: "155536235030272749691472293262418471207550926406427515178205576891522284497518443889075039382254334975506248481615035474816604875321501901699955105345417152355947783063521554077194367454070647740704883461064399268622437721385112646454393005862535727615809073410746393326688230040267160616554768771412289114449", + expectRounds: 1, + }, { // These factors come from a real innsbruck printer in the wild with a // broken key generation mechanism.