main.go 4.9 KB

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