mirror of
https://github.com/hairyhenderson/go-onerng.git
synced 2025-04-04 09:40:12 -05:00
Some incomplete initial code
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
This commit is contained in:
parent
d45c09fb92
commit
926b9f6304
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
onerng
|
20
cmd/flush.go
Normal file
20
cmd/flush.go
Normal file
@ -0,0 +1,20 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hairyhenderson/go-onerng"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// flushCmd represents the flush command
|
||||
func flushCmd(ctx context.Context) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "flush",
|
||||
Short: "Flush the OneRNG's entropy pool",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
o := onerng.OneRNG{Path: opts.Device}
|
||||
return o.Flush(ctx)
|
||||
},
|
||||
}
|
||||
}
|
26
cmd/id.go
Normal file
26
cmd/id.go
Normal file
@ -0,0 +1,26 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hairyhenderson/go-onerng"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// idCmd represents the id command
|
||||
func idCmd(ctx context.Context) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "id",
|
||||
Short: "Display the OneRNG's hardware id",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
o := onerng.OneRNG{Path: opts.Device}
|
||||
id, err := o.Identify(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("OneRNG Hardware ID: %s\n", id)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
26
cmd/image.go
Normal file
26
cmd/image.go
Normal file
@ -0,0 +1,26 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hairyhenderson/go-onerng"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// imageCmd represents the image command
|
||||
func imageCmd(ctx context.Context) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "image",
|
||||
Short: "Dump the OneRNG's firmware image",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
o := onerng.OneRNG{Path: opts.Device}
|
||||
image, err := o.Image(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%q\n", image)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
31
cmd/onerng/main.go
Normal file
31
cmd/onerng/main.go
Normal file
@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/hairyhenderson/go-onerng/cmd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
|
||||
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(3*time.Second))
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
defer func() {
|
||||
signal.Stop(c)
|
||||
cancel()
|
||||
}()
|
||||
go func() {
|
||||
select {
|
||||
case <-c:
|
||||
cancel()
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}()
|
||||
|
||||
cmd.Execute(ctx)
|
||||
}
|
73
cmd/root.go
Normal file
73
cmd/root.go
Normal file
@ -0,0 +1,73 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var (
|
||||
cfgFile string
|
||||
opts Config
|
||||
)
|
||||
|
||||
func rootCmd(ctx context.Context) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "onerng [opts] COMMAND",
|
||||
Short: "Tool for the OneRNG open source hardware entropy generator",
|
||||
Long: `OneRNG is an open source hardware entropy generator in a USB dongle.
|
||||
|
||||
This tool can be used to verify that the OneRNG device operates
|
||||
correctly, and that the firmware has not been tampered with.`,
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
cmd.SilenceErrors = true
|
||||
cmd.SilenceUsage = true
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Execute -
|
||||
func Execute(ctx context.Context) {
|
||||
cmd := rootCmd(ctx)
|
||||
initConfig(ctx, cmd)
|
||||
if err := cmd.Execute(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func initConfig(ctx context.Context, cmd *cobra.Command) {
|
||||
cmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.go-onerng.yaml)")
|
||||
opts = Config{}
|
||||
cmd.PersistentFlags().StringVarP(&opts.Device, "device", "d", "/dev/ttyACM0", "the OneRNG device")
|
||||
|
||||
cmd.AddCommand(
|
||||
verifyCmd(ctx),
|
||||
versionCmd(ctx),
|
||||
idCmd(ctx),
|
||||
flushCmd(ctx),
|
||||
imageCmd(ctx),
|
||||
)
|
||||
|
||||
if cfgFile != "" { // enable ability to specify config file via flag
|
||||
viper.SetConfigFile(cfgFile)
|
||||
}
|
||||
|
||||
viper.SetConfigName(".go-onerng") // name of config file (without extension)
|
||||
viper.AddConfigPath(os.Getenv("HOME")) // adding home directory as first search path
|
||||
viper.AutomaticEnv() // read in environment variables that match
|
||||
|
||||
// If a config file is found, read it in.
|
||||
if err := viper.ReadInConfig(); err == nil {
|
||||
fmt.Println("Using config file:", viper.ConfigFileUsed())
|
||||
}
|
||||
}
|
||||
|
||||
// Config -
|
||||
type Config struct {
|
||||
Device string
|
||||
}
|
84
cmd/verify.go
Normal file
84
cmd/verify.go
Normal file
@ -0,0 +1,84 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
publicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v1
|
||||
|
||||
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
|
||||
=IjnI
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
`
|
||||
)
|
||||
|
||||
func verifyCmd(ctx context.Context) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "verify",
|
||||
Short: "Verify that OneRNG's firmware has not been tampered with.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
26
cmd/version.go
Normal file
26
cmd/version.go
Normal file
@ -0,0 +1,26 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hairyhenderson/go-onerng"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// versionCmd represents the version command
|
||||
func versionCmd(ctx context.Context) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Display the OneRNG's hardware version",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
o := onerng.OneRNG{Path: opts.Device}
|
||||
version, err := o.Version(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("OneRNG Hardware Version: %d\n", version)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
33
commands.go
Normal file
33
commands.go
Normal file
@ -0,0 +1,33 @@
|
||||
package onerng
|
||||
|
||||
const (
|
||||
// CmdVersion - print firmware version (as "Version n")
|
||||
CmdVersion = "cmdv\n"
|
||||
// CmdFlush - flush entropy pool
|
||||
CmdFlush = "cmdw\n"
|
||||
// CmdImage - extract the signed firmware image for verification
|
||||
CmdImage = "cmdX\n"
|
||||
// CmdID - print hardware ID
|
||||
CmdID = "cmdI\n"
|
||||
// CmdRun - start the task
|
||||
CmdRun = "cmdO\n"
|
||||
// CmdPause - stop/pause the task
|
||||
CmdPause = "cmdo\n"
|
||||
|
||||
// CmdAvalancheWhitener - Avalanche noise with whitener (default)
|
||||
CmdAvalancheWhitener = "cmd0\n"
|
||||
// CmdAvalanche - Raw avalanche noise
|
||||
CmdAvalanche = "cmd1\n"
|
||||
// CmdAvalancheRFWhitener - Avalanche noise and RF noise with whitener
|
||||
CmdAvalancheRFWhitener = "cmd2\n"
|
||||
// CmdAvalancheRF - Raw avalanche noise and RF noise
|
||||
CmdAvalancheRF = "cmd3\n"
|
||||
// CmdSilent - No noise (necessary for image extraction)
|
||||
CmdSilent = "cmd4\n"
|
||||
// CmdSilent2 - No noise
|
||||
CmdSilent2 = "cmd5\n"
|
||||
// CmdRFWhitener - RF noise with whitener
|
||||
CmdRFWhitener = "cmd6\n"
|
||||
// CmdRF - Raw RF noise
|
||||
CmdRF = "cmd7\n"
|
||||
)
|
222
onerng.go
Normal file
222
onerng.go
Normal file
@ -0,0 +1,222 @@
|
||||
package onerng
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// OneRNG - a OneRNG device
|
||||
type OneRNG struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
func (o *OneRNG) cmd(ctx context.Context, d *os.File, c ...string) (err error) {
|
||||
for _, v := range c {
|
||||
_, err = d.WriteString(v)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Errored on command %s", v)
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Version -
|
||||
func (o *OneRNG) Version(ctx context.Context) (int, error) {
|
||||
d, err := os.OpenFile(o.Path, os.O_RDWR, 0600)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
_, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
buf := make(chan string)
|
||||
errc := make(chan error, 1)
|
||||
go func() {
|
||||
defer close(buf)
|
||||
defer close(errc)
|
||||
scanner := bufio.NewScanner(d)
|
||||
for scanner.Scan() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case buf <- scanner.Text():
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
err = o.cmd(ctx, d, CmdSilent, CmdVersion, CmdRun)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
verString := ""
|
||||
loop:
|
||||
for {
|
||||
var b string
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return 0, ctx.Err()
|
||||
case b = <-buf:
|
||||
if strings.HasPrefix(b, "Version ") {
|
||||
verString = b
|
||||
cancel()
|
||||
break loop
|
||||
}
|
||||
case err := <-errc:
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
err = o.cmd(ctx, d, CmdPause)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
n := strings.Replace(verString, "Version ", "", 1)
|
||||
version, err := strconv.Atoi(n)
|
||||
return version, err
|
||||
}
|
||||
|
||||
// Identify -
|
||||
func (o *OneRNG) Identify(ctx context.Context) (string, error) {
|
||||
d, err := os.OpenFile(o.Path, os.O_RDWR, 0600)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
_, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
buf := make(chan string)
|
||||
errc := make(chan error, 1)
|
||||
go func() {
|
||||
defer close(buf)
|
||||
defer close(errc)
|
||||
scanner := bufio.NewScanner(d)
|
||||
for scanner.Scan() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case buf <- scanner.Text():
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
err = o.cmd(ctx, d, CmdSilent, CmdID, CmdRun)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
idString := ""
|
||||
loop:
|
||||
for {
|
||||
var b string
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return "", ctx.Err()
|
||||
case b = <-buf:
|
||||
if strings.HasPrefix(b, "___") {
|
||||
idString = b
|
||||
cancel()
|
||||
break loop
|
||||
}
|
||||
case err := <-errc:
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
err = o.cmd(ctx, d, CmdPause)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return idString, err
|
||||
}
|
||||
|
||||
// Flush -
|
||||
func (o *OneRNG) Flush(ctx context.Context) error {
|
||||
d, err := os.OpenFile(o.Path, os.O_RDWR, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
_, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
err = o.cmd(ctx, d, CmdFlush)
|
||||
return err
|
||||
}
|
||||
|
||||
// Image -
|
||||
func (o *OneRNG) Image(ctx context.Context) ([]byte, error) {
|
||||
d, err := os.OpenFile(o.Path, os.O_RDWR, 0600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
_, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
buf := make(chan []byte)
|
||||
errc := make(chan error, 1)
|
||||
go func() {
|
||||
defer close(buf)
|
||||
defer close(errc)
|
||||
b := make([]byte, 128)
|
||||
for {
|
||||
n, err := d.Read(b)
|
||||
if err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case buf <- b:
|
||||
}
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
err = o.cmd(ctx, d, CmdSilent, CmdImage, CmdRun)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
image := []byte{}
|
||||
loop:
|
||||
for {
|
||||
var b []byte
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case b = <-buf:
|
||||
copy(image, b)
|
||||
if len(b) == 0 {
|
||||
break loop
|
||||
}
|
||||
case err := <-errc:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = o.cmd(ctx, d, CmdPause)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return image, err
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user