main.go 4.9 KB

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