main.go 4.9 KB

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