Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions cmd/garden/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package main

import (
"crypto/ed25519"
"encoding/base64"
"encoding/hex"
"flag"
"fmt"
"os"
"os/signal"
"regexp"
"runtime"
"strings"
"syscall"
"time"

"github.com/craumix/onionmsg/pkg/generator"
"github.com/craumix/onionmsg/pkg/openssh"
"github.com/craumix/onionmsg/internal/types"
)

const (
ups = 2
warning = "The Content of this file is VERY sensitive!\nAll the keys here are UNENCRYPTED!\nIf you are using any of these keys, don't share them with ANYONE!\n"
)

var (
match = ""
count = 10
threads = runtime.NumCPU()
anywhere = false
format = "base64"
nowarn = false
file = ""

err error
)

func main() {
flag.StringVar(&match, "m", match, "Specify a filter to match")
flag.BoolVar(&anywhere, "a", anywhere, "Matches anywhere (not just at the start)")
flag.IntVar(&count, "c", count, "Specify an amount of Identities to generate")
flag.IntVar(&threads, "t", threads, "Number of threads")
flag.StringVar(&format, "form", format, "The output format for the keys ( base64 / openssh / hex )")
flag.BoolVar(&nowarn, "nw", nowarn, "No warning above output")
flag.StringVar(&file, "f", file, "Output file")
flag.Parse()

//Save cursor position & hide it
fmt.Print("\033[s\033[?25l")
//Show cursor position on exit
defer fmt.Print("\033[?25h")
func(){
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
fmt.Print("\033[?25h")
os.Exit(0)
}()
}()

if !anywhere && !strings.HasPrefix(match, "^") {
match = "^" + match
}

keys := generator.GenerateIdentities(generator.GeneratorOptions{
Threads: threads,
Count: count,
Regex: regexp.MustCompile(match),
TickTimeout: time.Second / ups,
DidTick: func(t time.Time, pk ed25519.PrivateKey, i int, j uint64) {
lastFP := ""
if pk != nil {
lastFP = types.FingerprintKeyFormatting(pk.Public().(ed25519.PublicKey))
}

var keysPerSecondPerThread time.Duration = 0
if j > 0 {
keysPerThread := float64(j) / float64(threads)
keysPerSecondPerThread = time.Duration(keysPerThread / float64(time.Since(t)/time.Second))
}
if keysPerSecondPerThread < 0 {
keysPerSecondPerThread = 0
}

//Load cursor position
fmt.Print("\033[u")
fmt.Printf("Progress: [%d/%d] %d\033[K\n", i, count, j)
fmt.Printf("Time elapsed: %s\033[K\n", time.Since(t))
fmt.Printf("Speed: avg. %d keys / second / thread\033[K\n", keysPerSecondPerThread)
fmt.Printf("Last: %s\033[K\n", lastFP)

},
})

fmt.Println()

keyout := os.Stdout
if file != "" {
keyout, err = os.OpenFile(file, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
if err != nil {
fmt.Println(err)
keyout = os.Stdout
}

if keyout != os.Stdout {
defer keyout.Close()
}
}

outputKeys(keys, keyout, format, !nowarn)
}

func outputKeys(keys []ed25519.PrivateKey, out *os.File, format string, warn bool) {
if warn {
out.WriteString(warning + "\n")
}

for _, k := range keys {
out.WriteString("Fingerprint: " + types.FingerprintKeyFormatting(k.Public().(ed25519.PublicKey)) + "\n")
out.WriteString("Key:\n" + formatKey(k, format) + "\n\n")
}
}

func formatKey(key ed25519.PrivateKey, format string) string {
switch(format) {
case "openssh":
return string(openssh.EncodeToPemBytes(key))
case "hex":
return hex.EncodeToString(key)
default:
return base64.StdEncoding.EncodeToString(key)
}
}
2 changes: 0 additions & 2 deletions internal/daemon/room_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ func initRooms() (err error) {
}
}

log.Infof("Loaded %d Rooms\n", len(data.Rooms))

for _, room := range data.Rooms {
room.RunMessageQueueForAllPeers()
}
Expand Down
11 changes: 10 additions & 1 deletion internal/types/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"crypto/ed25519"
"encoding/base64"
"fmt"

"github.com/wybiral/torgo"
)

Expand Down Expand Up @@ -105,7 +106,15 @@ func (i Identity) Fingerprint() string {
return ""
}

return base64.RawURLEncoding.EncodeToString(*i.Pub)
return FingerprintKeyFormatting(*i.Pub)
}

func FingerprintKeyFormatting(pub ed25519.PublicKey) string {
if pub == nil {
return ""
}

return base64.RawURLEncoding.EncodeToString(pub)
}

func (i Identity) String() string {
Expand Down
77 changes: 77 additions & 0 deletions pkg/generator/generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package generator

import (
"context"
"crypto/ed25519"
"regexp"
"time"
)

type GeneratorOptions struct {
Threads int
Count int
Regex *regexp.Regexp
TickTimeout time.Duration
DidTick func(time.Time, ed25519.PrivateKey, int, uint64)
Ctx context.Context
}

func DefaultGeneratorOpts() GeneratorOptions {
return GeneratorOptions{
Threads: 1,
Count: 1,
Regex: &regexp.Regexp{},
TickTimeout: time.Hour * 24 * 365,
Ctx: context.Background(),
}
}

func GenerateIdentities(opts GeneratorOptions) []ed25519.PrivateKey {
if opts.Ctx == nil {
opts.Ctx = context.Background()
}

nextKeyChan := make(chan ed25519.PrivateKey)
keys := make([]ed25519.PrivateKey, 0)
ctx, cancel := context.WithCancel(opts.Ctx)
threads := setupThreads(opts.Threads, ctx, nextKeyChan, opts.Regex)

startTime := time.Now()
var lastKey ed25519.PrivateKey
for ctx.Err() == nil {
var count uint64
for _, thread := range threads {
if lastKey != nil && (len(keys) == 0 || !lastKey.Equal(keys[len(keys)-1])) {
keys = append(keys, lastKey)
}
count += thread.Counter

if opts.DidTick != nil {
opts.DidTick(startTime, lastKey, len(keys), count)
}

if len(keys) >= opts.Count {
cancel()
}
}

select {
case lastKey = <-nextKeyChan:
case <-ctx.Done():
case <-time.After(opts.TickTimeout):
}
}

return keys
}

func setupThreads(count int, threadCtx context.Context, nextKeyChan chan ed25519.PrivateKey, regex *regexp.Regexp) []GeneratorThread {
threads := make([]GeneratorThread, count)

for i := 0; i < count; i++ {
threads[i] = CreateGeneratorThread(threadCtx, nextKeyChan, regex)
threads[i].Start()
}

return threads
}
47 changes: 47 additions & 0 deletions pkg/generator/generator_thread.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package generator

import (
"context"
"crypto/ed25519"
"fmt"
"os"
"regexp"

"github.com/craumix/onionmsg/internal/types"
)

type GeneratorThread struct {
Counter uint64

ctx context.Context
nextKeyChan chan ed25519.PrivateKey
regex *regexp.Regexp
}

func CreateGeneratorThread(ctx context.Context, nextKey chan ed25519.PrivateKey, regex *regexp.Regexp) GeneratorThread {
return GeneratorThread{
ctx: ctx,
nextKeyChan: nextKey,
regex: regex,
}
}

func (t *GeneratorThread) Start() {
go func() {
for t.ctx.Err() == nil {

pub, priv, err := ed25519.GenerateKey(nil)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

fingerprint := types.FingerprintKeyFormatting(pub)
if t.regex.MatchString(fingerprint) {
t.nextKeyChan <- priv
}

t.Counter++
}
}()
}
Loading