main.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // Copyright (C) 2016 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package main
  7. import (
  8. "crypto/ecdsa"
  9. "crypto/elliptic"
  10. "crypto/rand"
  11. "crypto/rsa"
  12. "crypto/x509"
  13. "crypto/x509/pkix"
  14. "encoding/pem"
  15. "errors"
  16. "flag"
  17. "fmt"
  18. "math/big"
  19. mr "math/rand"
  20. "os"
  21. "runtime"
  22. "strings"
  23. "sync"
  24. "sync/atomic"
  25. "time"
  26. "github.com/syncthing/syncthing/lib/protocol"
  27. )
  28. type result struct {
  29. id protocol.DeviceID
  30. priv *ecdsa.PrivateKey
  31. derBytes []byte
  32. }
  33. func main() {
  34. flag.Parse()
  35. prefix := strings.ToUpper(strings.ReplaceAll(flag.Arg(0), "-", ""))
  36. if len(prefix) > 7 {
  37. prefix = prefix[:7] + "-" + prefix[7:]
  38. }
  39. found := make(chan result)
  40. stop := make(chan struct{})
  41. var count atomic.Int64
  42. // Print periodic progress reports.
  43. go printProgress(prefix, &count)
  44. // Run one certificate generator per CPU core.
  45. var wg sync.WaitGroup
  46. for i := 0; i < runtime.GOMAXPROCS(-1); i++ {
  47. wg.Go(func() {
  48. generatePrefixed(prefix, &count, found, stop)
  49. })
  50. }
  51. // Save the result, when one has been found.
  52. res := <-found
  53. close(stop)
  54. wg.Wait()
  55. fmt.Println("Found", res.id)
  56. saveCert(res.priv, res.derBytes)
  57. fmt.Println("Saved to cert.pem, key.pem")
  58. }
  59. // Try certificates until one is found that has the prefix at the start of
  60. // the resulting device ID. Increments count atomically, sends the result to
  61. // found, returns when stop is closed.
  62. func generatePrefixed(prefix string, count *atomic.Int64, found chan<- result, stop <-chan struct{}) {
  63. notBefore := time.Now()
  64. notAfter := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC)
  65. template := x509.Certificate{
  66. SerialNumber: new(big.Int).SetInt64(mr.Int63()),
  67. Subject: pkix.Name{
  68. CommonName: "syncthing",
  69. },
  70. NotBefore: notBefore,
  71. NotAfter: notAfter,
  72. KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
  73. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
  74. BasicConstraintsValid: true,
  75. }
  76. priv, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
  77. if err != nil {
  78. fmt.Println(err)
  79. os.Exit(1)
  80. }
  81. for {
  82. select {
  83. case <-stop:
  84. return
  85. default:
  86. }
  87. derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
  88. if err != nil {
  89. fmt.Println(err)
  90. os.Exit(1)
  91. }
  92. id := protocol.NewDeviceID(derBytes)
  93. count.Add(1)
  94. if strings.HasPrefix(id.String(), prefix) {
  95. select {
  96. case found <- result{id, priv, derBytes}:
  97. case <-stop:
  98. }
  99. return
  100. }
  101. }
  102. }
  103. func printProgress(prefix string, count *atomic.Int64) {
  104. started := time.Now()
  105. wantBits := 5 * len(prefix)
  106. if wantBits > 63 {
  107. fmt.Printf("Want %d bits for prefix %q, refusing to boil the ocean.\n", wantBits, prefix)
  108. os.Exit(1)
  109. }
  110. expectedIterations := float64(int(1) << uint(wantBits))
  111. fmt.Printf("Want %d bits for prefix %q, about %.2g certs to test (statistically speaking)\n", wantBits, prefix, expectedIterations)
  112. for range time.NewTicker(15 * time.Second).C {
  113. tried := count.Load()
  114. elapsed := time.Since(started)
  115. rate := float64(tried) / elapsed.Seconds()
  116. expected := timeStr(expectedIterations / rate)
  117. fmt.Printf("Trying %.0f certs/s, tested %d so far in %v, expect ~%s total time to complete\n", rate, tried, elapsed/time.Second*time.Second, expected)
  118. }
  119. }
  120. func saveCert(priv interface{}, derBytes []byte) {
  121. certOut, err := os.Create("cert.pem")
  122. if err != nil {
  123. fmt.Println(err)
  124. os.Exit(1)
  125. }
  126. err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
  127. if err != nil {
  128. fmt.Println(err)
  129. os.Exit(1)
  130. }
  131. err = certOut.Close()
  132. if err != nil {
  133. fmt.Println(err)
  134. os.Exit(1)
  135. }
  136. keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
  137. if err != nil {
  138. fmt.Println(err)
  139. os.Exit(1)
  140. }
  141. block, err := pemBlockForKey(priv)
  142. if err != nil {
  143. fmt.Println(err)
  144. os.Exit(1)
  145. }
  146. err = pem.Encode(keyOut, block)
  147. if err != nil {
  148. fmt.Println(err)
  149. os.Exit(1)
  150. }
  151. err = keyOut.Close()
  152. if err != nil {
  153. fmt.Println(err)
  154. os.Exit(1)
  155. }
  156. }
  157. func pemBlockForKey(priv interface{}) (*pem.Block, error) {
  158. switch k := priv.(type) {
  159. case *rsa.PrivateKey:
  160. return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}, nil
  161. case *ecdsa.PrivateKey:
  162. b, err := x509.MarshalECPrivateKey(k)
  163. if err != nil {
  164. return nil, err
  165. }
  166. return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}, nil
  167. default:
  168. return nil, errors.New("unknown key type")
  169. }
  170. }
  171. func timeStr(seconds float64) string {
  172. if seconds < 60 {
  173. return fmt.Sprintf("%.0fs", seconds)
  174. }
  175. if seconds < 3600 {
  176. return fmt.Sprintf("%.0fm", seconds/60)
  177. }
  178. if seconds < 86400 {
  179. return fmt.Sprintf("%.0fh", seconds/3600)
  180. }
  181. if seconds < 86400*365 {
  182. return fmt.Sprintf("%.0f days", seconds/3600)
  183. }
  184. return fmt.Sprintf("%.0f years", seconds/86400/365)
  185. }