github.com/ericlagergren/ctb@v0.0.0-20220810041818-96749d9c394d/cmd/k/main.go (about)

     1  // Command k demonstrates breaking ECDSA private keys with weak,
     2  // leaked, or reused nonces.
     3  package main
     4  
     5  import (
     6  	"bytes"
     7  	"crypto/aes"
     8  	"crypto/cipher"
     9  	"crypto/ecdsa"
    10  	"crypto/elliptic"
    11  	"crypto/rand"
    12  	"crypto/sha256"
    13  	"crypto/sha512"
    14  	"errors"
    15  	"fmt"
    16  	"io"
    17  	"math/big"
    18  
    19  	l3 "github.com/elagergren/ctb/lll"
    20  	"golang.org/x/crypto/chacha20"
    21  )
    22  
    23  func init() {
    24  	curve := elliptic.P256()
    25  	M := []byte("hello, world!")
    26  	r, _ := new(big.Int).SetString("c5363ca0229aa1487026dc77c2abc09dba6b4dce6cc879a07afbe14122316c9a", 16)
    27  	s, _ := new(big.Int).SetString("6ae8ceeaa0661e3ba0fed6530b3a661c01c744009e833d44b87861b9b8e5320d", 16)
    28  	K, _ := new(big.Int).SetString("02020201fefefeff01445d62b55152b9866561ee015f71beb49fb020554e145f", 16)
    29  	N := curve.Params().N
    30  	e := hashToInt(H(M), curve)
    31  	reveal1(r, s, K, N, e)
    32  }
    33  
    34  func main() {
    35  	curve := elliptic.P256()
    36  	priv, err := ecdsa.GenerateKey(curve, rand.Reader)
    37  	if err != nil {
    38  		panic(err)
    39  	}
    40  	// fmt.Printf("leaked k #1: %x\n", leakK(priv, true))
    41  	// fmt.Printf("leaked k #2: %x\n", leakK(priv, false))
    42  	// fmt.Printf("reused k   : %x\n", reuseK(priv))
    43  	// fmt.Printf("actual     : %x\n", priv.D)
    44  
    45  	for i := 0; i < 1; i++ {
    46  		D := lattice(priv)
    47  		if D.Sign() != 0 {
    48  			fmt.Printf("#%d: LLL:       : %x\n", i, D)
    49  			break
    50  		}
    51  	}
    52  }
    53  
    54  func lattice(priv *ecdsa.PrivateKey) *big.Int {
    55  	curve := elliptic.P256()
    56  
    57  	priv = &(*priv)
    58  	priv.D, _ = new(big.Int).SetString("78820416530262976955738813433175776840628733537564602790902190607542488847122", 10)
    59  	priv.PublicKey.X, priv.PublicKey.Y = curve.ScalarBaseMult(priv.D.Bytes())
    60  
    61  	N := curve.Params().N
    62  
    63  	M1 := []byte("hello, world!")
    64  	M2 := []byte("!dlrow ,olleh")
    65  
    66  	h := sha256.New()
    67  	h.Write(M1)
    68  	hash1 := h.Sum(nil)
    69  	h.Reset()
    70  	h.Write(M2)
    71  	hash2 := h.Sum(nil)
    72  
    73  	const _W = 128
    74  	B := big.NewInt(1)
    75  	B.Lsh(B, _W)
    76  	Bm1 := big.NewInt(1)
    77  	Bm1.Lsh(Bm1, _W-1)
    78  	k1, _ := new(big.Int).SetString("152980802533694987400421914292345709688", 10)
    79  	k2, _ := new(big.Int).SetString("23479681102223137409793422985451094498", 10)
    80  	// k1, _ := rand.Int(rand.Reader, Bm1)
    81  	// k2, _ := rand.Int(rand.Reader, Bm1)
    82  
    83  	r1, s1, err := SignWithNonce(priv, hash1, k1)
    84  	if err != nil {
    85  		panic(err)
    86  	}
    87  	sm1 := new(big.Int).ModInverse(s1, N)
    88  	fmt.Println(r1)
    89  	fmt.Println(sm1)
    90  	r1s1 := new(big.Int).Mul(r1, sm1)
    91  	// r1s1.Mod(r1s1, N)
    92  
    93  	r2, s2, err := SignWithNonce(priv, hash2, k2)
    94  	if err != nil {
    95  		panic(err)
    96  	}
    97  	sm2 := new(big.Int).ModInverse(s2, N)
    98  	r2s2 := new(big.Int).Mul(r2, sm2)
    99  	// r2s2.Mod(r2s2, N)
   100  
   101  	m1 := hashToInt(M1, curve)
   102  	m1s1 := new(big.Int).Mul(m1, sm1)
   103  	// m1s1.Mod(m1s1, N)
   104  
   105  	m2 := hashToInt(M2, curve)
   106  	m2s2 := new(big.Int).Mul(m2, sm2)
   107  	// m2s2.Mod(m2s2, N)
   108  
   109  	zero := l3.I64(0)
   110  	basis := [][]l3.T{
   111  		{l3.I(N), zero, zero, zero},
   112  		{zero, l3.I(N), zero, zero},
   113  		{l3.I(r1s1), l3.I(r2s2), l3.F(B, N), zero},
   114  		{l3.I(m1s1), l3.I(m2s2), zero, l3.I(B)},
   115  	}
   116  	fmt.Println(basis)
   117  	mx := l3.Reduction(l3.F64(3, 4), basis)
   118  	fmt.Println(mx)
   119  	for _, row := range mx {
   120  		var k big.Int
   121  		l3.SetInt(&k, row[0])
   122  		fmt.Println("k: ", &k)
   123  		D := reveal1(r1, s1, &k, N, m1)
   124  		fmt.Println("D :", priv.D)
   125  		fmt.Println("D':", D)
   126  		if D.Cmp(priv.D) == 0 {
   127  			return D
   128  		}
   129  	}
   130  	return new(big.Int)
   131  }
   132  
   133  // leakK recovers a private key
   134  func leakK(priv *ecdsa.PrivateKey, stdlib bool) *big.Int {
   135  	M := []byte("hello, world!")
   136  	hash := H(M)
   137  
   138  	var buf bytes.Buffer
   139  	rng := antiMaybeReader{io.TeeReader(rand.Reader, &buf)}
   140  
   141  	var r, s *big.Int
   142  	var err error
   143  	if stdlib {
   144  		r, s, err = ecdsa.Sign(rng, priv, hash)
   145  	} else {
   146  		r, s, err = Sign(rng, priv, hash)
   147  	}
   148  	if err != nil {
   149  		panic(err)
   150  	}
   151  
   152  	curve := priv.Curve
   153  	K := buildK(&buf, curve, priv.D, hash, stdlib)
   154  	N := curve.Params().N
   155  	return reveal1(r, s, K, N, hashToInt(hash, curve))
   156  }
   157  
   158  func reuseK(priv *ecdsa.PrivateKey) *big.Int {
   159  	M1 := []byte("hello, world!")
   160  	M2 := []byte("!dlrow ,olleh")
   161  
   162  	rng := func() io.Reader {
   163  		key := make([]byte, 32)
   164  		nonce := make([]byte, chacha20.NonceSizeX)
   165  		s, err := chacha20.NewUnauthenticatedCipher(key, nonce)
   166  		if err != nil {
   167  			panic(err)
   168  		}
   169  		r := &cipher.StreamReader{
   170  			S: s,
   171  			R: zeroReader{},
   172  		}
   173  		return antiMaybeReader{r}
   174  	}
   175  
   176  	hash1 := H(M1)
   177  	r1, s1, err := Sign(rng(), priv, hash1)
   178  	if err != nil {
   179  		panic(err)
   180  	}
   181  
   182  	hash2 := H(M2)
   183  	r1, s2, err := Sign(rng(), priv, hash2)
   184  	if err != nil {
   185  		panic(err)
   186  	}
   187  
   188  	curve := priv.Curve
   189  	N := curve.Params().N
   190  
   191  	e1 := hashToInt(hash1, curve)
   192  	e2 := hashToInt(hash2, curve)
   193  	return reveal2(r1, s1, s2, N, e1, e2)
   194  }
   195  
   196  // reveal1 reconstructs the private key from a signature (r, s), message e,
   197  // leaked nonce k, and curve order N.
   198  func reveal1(r, s, k, N, e *big.Int) *big.Int {
   199  	// r = k*G
   200  	// s = k^-1(H(M) + r*priv)
   201  	// x = r^-1*((k*s) - H(M))
   202  	ks := new(big.Int)
   203  	ks = ks.Mul(k, s)
   204  	ks = ks.Mod(ks, N)
   205  	ks = ks.Sub(ks, e)
   206  
   207  	x := new(big.Int).ModInverse(r, N)
   208  	x = x.Mul(x, ks)
   209  	x = x.Mod(x, N)
   210  	return x
   211  }
   212  
   213  // reveal2 reconstructs the private key from two signtures (r1, s1) and (r1, s2),
   214  // the signatures' respective messages e1 and e2, and the curve order N.
   215  func reveal2(r, s1, s2, N, e1, e2 *big.Int) *big.Int {
   216  	// r1 = k*G
   217  	// s1 = k^-1(H(M1) + r1*priv)
   218  	// r2 = k*G
   219  	// s2 = k^-1(H(M2) + r2*priv)
   220  	// s1 - s2 = k^-1(H(M1) - H(M2))
   221  	// k(s1-s2) = H(M1) - H(M2)
   222  	// k = (s1-s2)^-1(H(M1) - H(M2))
   223  	k := new(big.Int)
   224  	k = k.Sub(s1, s2)
   225  	k = k.ModInverse(k, N)
   226  	k = k.Mul(k, new(big.Int).Sub(e1, e2))
   227  	k = k.Mod(k, N)
   228  	return reveal1(r, s1, k, N, e1)
   229  }
   230  
   231  // H returns SHA-256(M).
   232  func H(M []byte) []byte {
   233  	h := sha256.New()
   234  	h.Write(M)
   235  	return h.Sum(nil)
   236  }
   237  
   238  // antiMaybeReader ignores one-byte reads.
   239  //
   240  // The stdlib performs one-byte reads with 50% probability so that applications
   241  // do not use deterministic RNGs.
   242  type antiMaybeReader struct {
   243  	r io.Reader
   244  }
   245  
   246  var _ io.Reader = antiMaybeReader{}
   247  
   248  func (r antiMaybeReader) Read(p []byte) (int, error) {
   249  	if len(p) == 1 {
   250  		return 1, nil
   251  	}
   252  	return r.r.Read(p)
   253  }
   254  
   255  func buildK(rand io.Reader, curve elliptic.Curve, D *big.Int, hash []byte, stdlib bool) *big.Int {
   256  	rng := rand
   257  	if stdlib {
   258  		// Get min(log2(q) / 2, 256) bits of entropy from rand.
   259  		entropylen := (curve.Params().BitSize + 7) / 16
   260  		if entropylen > 32 {
   261  			entropylen = 32
   262  		}
   263  		entropy := make([]byte, entropylen)
   264  		_, err := io.ReadFull(rand, entropy)
   265  		if err != nil {
   266  			panic(err)
   267  		}
   268  
   269  		// Initialize an SHA-512 hash context; digest ...
   270  		md := sha512.New()
   271  		md.Write(D.Bytes())     // the private key,
   272  		md.Write(entropy)       // the entropy,
   273  		md.Write(hash)          // and the input hash;
   274  		key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512),
   275  		// which is an indifferentiable MAC.
   276  
   277  		// Create an AES-CTR instance to use as a CSPRNG.
   278  		block, err := aes.NewCipher(key)
   279  		if err != nil {
   280  			panic(err)
   281  		}
   282  
   283  		// Create a CSPRNG that xors a stream of zeros with
   284  		// the output of the AES-CTR instance.
   285  		rng = &cipher.StreamReader{
   286  			R: zeroReader{},
   287  			S: cipher.NewCTR(block, []byte("IV for ECDSA CTR")),
   288  		}
   289  	}
   290  	for {
   291  		k, err := randFieldElement(curve, rng)
   292  		if err != nil {
   293  			panic(err)
   294  		}
   295  		r, _ := curve.ScalarBaseMult(k.Bytes())
   296  		r.Mod(r, curve.Params().N)
   297  		if r.Sign() != 0 {
   298  			return k
   299  		}
   300  	}
   301  }
   302  
   303  // Sign is ecdsa.Sign but without using a deterministic CSPRNG for generating k.
   304  func Sign(rand io.Reader, priv *ecdsa.PrivateKey, hash []byte) (r, s *big.Int, err error) {
   305  	c := priv.Curve
   306  	N := c.Params().N
   307  	if N.Sign() == 0 {
   308  		return nil, nil, errors.New("zero parameter")
   309  	}
   310  	var k, kInv *big.Int
   311  	for {
   312  		for {
   313  			k, err = randFieldElement(c, rand)
   314  			if err != nil {
   315  				r = nil
   316  				return
   317  			}
   318  
   319  			kInv = new(big.Int).ModInverse(k, N) // N != 0
   320  
   321  			r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
   322  			r.Mod(r, N)
   323  			if r.Sign() != 0 {
   324  				break
   325  			}
   326  		}
   327  
   328  		e := hashToInt(hash, c)
   329  		s = new(big.Int).Mul(priv.D, r)
   330  		s.Add(s, e)
   331  		s.Mul(s, kInv)
   332  		s.Mod(s, N) // N != 0
   333  		if s.Sign() != 0 {
   334  			break
   335  		}
   336  	}
   337  	return
   338  }
   339  
   340  func SignWithNonce(priv *ecdsa.PrivateKey, hash []byte, k *big.Int) (r, s *big.Int, err error) {
   341  	c := priv.Curve
   342  	N := c.Params().N
   343  	if N.Sign() == 0 {
   344  		return nil, nil, errors.New("zero parameter")
   345  	}
   346  	kInv := new(big.Int).ModInverse(k, N) // N != 0
   347  	e := hashToInt(hash, c)
   348  	r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
   349  	r.Mod(r, N)
   350  	s = new(big.Int).Mul(priv.D, r)
   351  	s.Add(s, e)
   352  	s.Mul(s, kInv)
   353  	s.Mod(s, N) // N != 0
   354  	return
   355  }
   356  
   357  func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
   358  	orderBits := c.Params().N.BitLen()
   359  	orderBytes := (orderBits + 7) / 8
   360  	if len(hash) > orderBytes {
   361  		hash = hash[:orderBytes]
   362  	}
   363  
   364  	ret := new(big.Int).SetBytes(hash)
   365  	excess := len(hash)*8 - orderBits
   366  	if excess > 0 {
   367  		ret.Rsh(ret, uint(excess))
   368  	}
   369  	return ret
   370  }
   371  
   372  func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) {
   373  	params := c.Params()
   374  	b := make([]byte, params.BitSize/8+8)
   375  	_, err = io.ReadFull(rand, b)
   376  	if err != nil {
   377  		return
   378  	}
   379  
   380  	k = new(big.Int).SetBytes(b)
   381  	n := new(big.Int).Sub(params.N, one)
   382  	k.Mod(k, n)
   383  	k.Add(k, one)
   384  	return
   385  }
   386  
   387  var one = big.NewInt(1)
   388  
   389  type zeroReader struct{}
   390  
   391  var _ io.Reader = zeroReader{}
   392  
   393  func (zeroReader) Read(p []byte) (int, error) {
   394  	for i := range p {
   395  		p[i] = 0
   396  	}
   397  	return len(p), nil
   398  }