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 }