diff --git a/.gitignore b/.gitignore index 0ffbc64..0d7fe17 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ +!*/onerng onerng diff --git a/cmd/onerng/doc.go b/cmd/onerng/doc.go new file mode 100644 index 0000000..cd499b7 --- /dev/null +++ b/cmd/onerng/doc.go @@ -0,0 +1,10 @@ +/* + +onerng is a OneRNG hardware random number generation utility. + +Usage + +TODO... + +*/ +package main diff --git a/cmd/flush.go b/cmd/onerng/flush.go similarity index 96% rename from cmd/flush.go rename to cmd/onerng/flush.go index 83a671f..38ff207 100644 --- a/cmd/flush.go +++ b/cmd/onerng/flush.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "context" diff --git a/cmd/id.go b/cmd/onerng/id.go similarity index 97% rename from cmd/id.go rename to cmd/onerng/id.go index 95db05b..61a46e6 100644 --- a/cmd/id.go +++ b/cmd/onerng/id.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "context" diff --git a/cmd/image.go b/cmd/onerng/image.go similarity index 98% rename from cmd/image.go rename to cmd/onerng/image.go index 8c0d51d..edbc730 100644 --- a/cmd/image.go +++ b/cmd/onerng/image.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "context" diff --git a/cmd/init.go b/cmd/onerng/init.go similarity index 96% rename from cmd/init.go rename to cmd/onerng/init.go index 19883ef..1604bf2 100644 --- a/cmd/init.go +++ b/cmd/onerng/init.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "context" diff --git a/cmd/onerng/main.go b/cmd/onerng/main.go index d68a8fe..5042c66 100644 --- a/cmd/onerng/main.go +++ b/cmd/onerng/main.go @@ -1,11 +1,12 @@ +// onerng: OneRNG hardware random number generation utility + package main import ( "context" + "fmt" "os" "os/signal" - - "github.com/hairyhenderson/go-onerng/cmd" ) func main() { @@ -26,5 +27,10 @@ func main() { } }() - cmd.Execute(ctx) + cmd := rootCmd(ctx) + initConfig(ctx, cmd) + if err := cmd.Execute(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } } diff --git a/cmd/read.go b/cmd/onerng/read.go similarity index 97% rename from cmd/read.go rename to cmd/onerng/read.go index 861a378..6b02049 100644 --- a/cmd/read.go +++ b/cmd/onerng/read.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "context" @@ -26,7 +26,7 @@ func readCmd(ctx context.Context) *cobra.Command { Use: "read", Short: "read some random data from the OneRNG", RunE: func(cmd *cobra.Command, args []string) error { - o := onerng.OneRNG{Path: opts.Device} + o := &onerng.OneRNG{Path: opts.Device} err := o.Init(ctx) if err != nil { return errors.Wrapf(err, "init failed") diff --git a/cmd/root.go b/cmd/onerng/root.go similarity index 86% rename from cmd/root.go rename to cmd/onerng/root.go index f38f376..ba9f424 100644 --- a/cmd/root.go +++ b/cmd/onerng/root.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "context" @@ -11,7 +11,7 @@ import ( var ( cfgFile string - opts Config + opts config ) func rootCmd(ctx context.Context) *cobra.Command { @@ -30,19 +30,9 @@ correctly, and that the firmware has not been tampered with.`, } } -// 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{} + opts = config{} cmd.PersistentFlags().StringVarP(&opts.Device, "device", "d", "/dev/ttyACM0", "the OneRNG device") cmd.AddCommand( @@ -69,7 +59,6 @@ func initConfig(ctx context.Context, cmd *cobra.Command) { } } -// Config - -type Config struct { +type config struct { Device string } diff --git a/cmd/verify.go b/cmd/onerng/verify.go similarity index 99% rename from cmd/verify.go rename to cmd/onerng/verify.go index d060324..95a1219 100644 --- a/cmd/verify.go +++ b/cmd/onerng/verify.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "bytes" diff --git a/cmd/version.go b/cmd/onerng/version.go similarity index 90% rename from cmd/version.go rename to cmd/onerng/version.go index 48a06eb..5b3b0cc 100644 --- a/cmd/version.go +++ b/cmd/onerng/version.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "context" @@ -14,7 +14,7 @@ func versionCmd(ctx context.Context) *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} + o := &onerng.OneRNG{Path: opts.Device} version, err := o.Version(ctx) if err != nil { return err diff --git a/commands.go b/commands.go deleted file mode 100644 index c42d56b..0000000 --- a/commands.go +++ /dev/null @@ -1,47 +0,0 @@ -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" -) - -const ( - // DisableWhitener - Disable the on-board CRC16 generator - no effect if both noise generators are disabled - DisableWhitener ReadMode = 1 << iota - // EnableRF - Enable noise generation from RF - EnableRF - // DisableAvalanche - Disable noise generation from the Avalanche Diode - DisableAvalanche - - // Default - Avalanche enabled, RF disabled, Whitener enabled. - Default ReadMode = 0 - // Silent - a convenience - everything disabled - Silent ReadMode = 4 -) diff --git a/copy.go b/copy.go deleted file mode 100644 index db2107e..0000000 --- a/copy.go +++ /dev/null @@ -1,46 +0,0 @@ -package onerng - -import ( - "context" - "io" - "os" - "strings" - "time" -) - -type readerFunc func(p []byte) (n int, err error) - -func (rf readerFunc) Read(p []byte) (n int, err error) { return rf(p) } - -// io.CopyN/io.Copy with context support -func copyWithContext(ctx context.Context, dst io.Writer, src *os.File, n int64) (int64, error) { - // allow 10 500ms timeouts, for a total of 5s. After this, it's probably worth just giving up - allowedTimeouts := 10 - - rf := func(p []byte) (int, error) { - // I don't want reads to block forever, but I also don't want to time out immediately - err := src.SetReadDeadline(time.Now().Add(500 * time.Millisecond)) - if err != nil { - return 0, err - } - - select { - case <-ctx.Done(): - return 0, ctx.Err() - default: - n, err := src.Read(p) - if allowedTimeouts > 0 { - if err != nil && strings.HasSuffix(err.Error(), "i/o timeout") { - allowedTimeouts-- - return n, nil - } - } - return n, err - } - } - - if n < 0 { - return io.Copy(dst, readerFunc(rf)) - } - return io.CopyN(dst, readerFunc(rf), n) -} diff --git a/onerng.go b/onerng.go index d0589d5..9c48961 100644 --- a/onerng.go +++ b/onerng.go @@ -1,3 +1,32 @@ +/* +Package onerng provides functions to help interface with the OneRNG hardware RNG. + +See http://onerng.info for information about the device, and see especially +http://www.moonbaseotago.com/onerng/theory.html for the theory of operation. + +To use this package, you must first plug the OneRNG into an available USB port, +and your OS should auto-detect the device as a USB serial modem. On Linux, you +may need to load the cdc_acm module. + +Once you know which device file points to the OneRNG, you can instantiate a +*OneRNG struct instance. All communication with the OneRNG is done through +this instance. + + o := &OneRNG{Path: "/dev/ttyACM0"} + version, err := o.Version(context.TODO()) + if err != nil { + return err + } + fmt.Printf("version is %d\n", version) + +Reading data from the OneRNG can be done with the Read function: + + o := &OneRNG{Path: "/dev/ttyACM0"} + _, err = o.Read(context.TODO(), os.Stdout, -1, EnableRF | DisableWhitener) + if err != nil { + return err + } +*/ package onerng import ( @@ -6,7 +35,6 @@ import ( "context" "crypto/aes" "crypto/cipher" - "fmt" "io" mrand "math/rand" "os" @@ -20,21 +48,20 @@ import ( // OneRNG - a OneRNG device type OneRNG struct { Path string - device *os.File + device io.ReadWriteCloser } -// ReadMode - -type ReadMode uint32 - +// cmd sends one or more commands to the OneRNG. The device is not closed on +// completion, as it's usually being read from simultaneously. func (o *OneRNG) cmd(ctx context.Context, c ...string) error { err := o.open() if err != nil { return err } for _, v := range c { - _, err = o.device.WriteString(v) + _, err = o.device.Write([]byte(v)) if err != nil { - return errors.Wrapf(err, "Errored on command %s", v) + return errors.Wrapf(err, "Errored on command %q", v) } select { case <-ctx.Done(): @@ -45,6 +72,8 @@ func (o *OneRNG) cmd(ctx context.Context, c ...string) error { return nil } +// open the OneRNG device for read/write, if it hasn't already been opened. +// Access it as o.device. func (o *OneRNG) open() (err error) { if o.device != nil { return nil @@ -53,6 +82,7 @@ func (o *OneRNG) open() (err error) { return err } +// close the OneRNG device if it hasn't already been closed func (o *OneRNG) close() error { if o.device == nil { return nil @@ -62,7 +92,7 @@ func (o *OneRNG) close() error { return err } -// Version - +// Version - query the OneRNG for its hardware version func (o *OneRNG) Version(ctx context.Context) (int, error) { err := o.open() if err != nil { @@ -70,7 +100,7 @@ func (o *OneRNG) Version(ctx context.Context) (int, error) { } defer o.close() - err = o.cmd(ctx, CmdPause) + err = o.cmd(ctx, cmdPause) if err != nil { return 0, err } @@ -81,7 +111,7 @@ func (o *OneRNG) Version(ctx context.Context) (int, error) { errc := make(chan error, 1) go o.scan(ctx, buf, errc) - err = o.cmd(ctx, CmdSilent, CmdVersion, CmdRun) + err = o.cmd(ctx, noiseCommand(Silent), cmdVersion, cmdRun) if err != nil { return 0, err } @@ -104,7 +134,7 @@ loop: } } - err = o.cmd(ctx, CmdPause) + err = o.cmd(ctx, cmdPause) if err != nil { return 0, err } @@ -114,7 +144,7 @@ loop: return version, err } -// Identify - +// Identify - query the OneRNG for its ID func (o *OneRNG) Identify(ctx context.Context) (string, error) { err := o.open() if err != nil { @@ -128,7 +158,7 @@ func (o *OneRNG) Identify(ctx context.Context) (string, error) { errc := make(chan error, 1) go o.scan(ctx, buf, errc) - err = o.cmd(ctx, CmdSilent, CmdID, CmdRun) + err = o.cmd(ctx, noiseCommand(Silent), cmdID, cmdRun) if err != nil { return "", err } @@ -151,7 +181,7 @@ loop: } } - err = o.cmd(ctx, CmdPause) + err = o.cmd(ctx, cmdPause) if err != nil { return "", err } @@ -159,7 +189,7 @@ loop: return idString, err } -// Flush - +// Flush the OneRNG's entropy pool func (o *OneRNG) Flush(ctx context.Context) error { err := o.open() if err != nil { @@ -169,11 +199,14 @@ func (o *OneRNG) Flush(ctx context.Context) error { _, cancel := context.WithCancel(ctx) defer cancel() - err = o.cmd(ctx, CmdFlush) + err = o.cmd(ctx, cmdFlush) return err } -// Image - +// Image extracts the firmware image. This image is padded with random data to +// either 128Kb or 256Kb (depending on hardware), and signed. +// +// See also the Verify function. func (o *OneRNG) Image(ctx context.Context) ([]byte, error) { err := o.open() if err != nil { @@ -181,7 +214,7 @@ func (o *OneRNG) Image(ctx context.Context) ([]byte, error) { } defer o.close() - err = o.cmd(ctx, CmdPause, CmdSilent) + err = o.cmd(ctx, cmdPause, noiseCommand(Silent)) if err != nil { return nil, err } @@ -194,7 +227,7 @@ func (o *OneRNG) Image(ctx context.Context) ([]byte, error) { errc := make(chan error, 1) go o.stream(ctx, 4, buf, errc) - err = o.cmd(ctx, CmdSilent, CmdImage, CmdRun) + err = o.cmd(ctx, noiseCommand(Silent), cmdImage, cmdRun) if err != nil { return nil, err } @@ -224,7 +257,7 @@ loop: } } - err = o.cmd(ctx, CmdPause) + err = o.cmd(ctx, cmdPause) if err != nil { return nil, err } @@ -244,24 +277,28 @@ func (o *OneRNG) Init(ctx context.Context) error { break } } - fmt.Fprintf(os.Stderr, "Initialized after %d loops\n", i) + // fmt.Fprintf(os.Stderr, "Initialized after %d loops\n", i) return nil } -// Read - -func (o *OneRNG) Read(ctx context.Context, out io.WriteCloser, n int64, flags ReadMode) (written int64, err error) { +// Read n bytes of data from the OneRNG into the given Writer. Set flags to +// configure the OneRNG's. Set n to -1 to continuously read until an error is +// encountered, or the context is cancelled. +// +// The OneRNG device will be closed when the operation completes. +func (o *OneRNG) Read(ctx context.Context, out io.Writer, n int64, flags NoiseMode) (written int64, err error) { err = o.open() if err != nil { return 0, err } defer o.close() - err = o.cmd(ctx, NoiseCommand(flags), CmdRun) + err = o.cmd(ctx, noiseCommand(flags), cmdRun) if err != nil { return 0, err } - defer o.cmd(ctx, CmdPause) + defer o.cmd(ctx, cmdPause) written, err = copyWithContext(ctx, out, o.device, n) return written, err @@ -282,13 +319,13 @@ func (o *OneRNG) readData(ctx context.Context) (int, error) { errc := make(chan error, 1) go o.stream(ctx, 1, buf, errc) - err = o.cmd(ctx, CmdAvalanche, CmdRun) + err = o.cmd(ctx, noiseCommand(Default), cmdRun) if err != nil { return 0, err } // make sure we always end with a pause/silence/flush - defer o.cmd(ctx, CmdPause, CmdSilent, CmdFlush) + defer o.cmd(ctx, cmdPause, noiseCommand(Silent), cmdFlush) // blocking read from the channel, with a timeout (from context) select { @@ -350,15 +387,20 @@ func (o *OneRNG) scan(ctx context.Context, buf chan string, errc chan error) { } } -// NoiseCommand - returns the appropriate noise-generation command for the given flags -func NoiseCommand(flags ReadMode) string { - num := strconv.Itoa(int(flags)) - return "cmd" + num + "\n" -} - -type aesWhitener struct { - out io.WriteCloser -} +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" +) // AESWhitener creates a "whitener" that wraps the provided writer. The random // data that the OneRNG generates is sometimes a little "too" random for some @@ -396,14 +438,76 @@ func (o *OneRNG) key(ctx context.Context) ([]byte, error) { buf := &bytes.Buffer{} - err = o.cmd(ctx, CmdAvalanche, CmdRun) + err = o.cmd(ctx, noiseCommand(Default), cmdRun) if err != nil { return []byte{}, err } - defer o.cmd(ctx, CmdPause) + defer o.cmd(ctx, cmdPause) // 16 bytes == AES-128 _, err = copyWithContext(ctx, buf, o.device, 16) k := buf.Bytes() return k, err } + +// NoiseMode represents the different noise-generation modes available to the OneRNG +type NoiseMode uint32 + +const ( + // DisableWhitener - Disable the on-board CRC16 generator - no effect if both noise generators are disabled + DisableWhitener NoiseMode = 1 << iota + // EnableRF - Enable noise generation from RF + EnableRF + // DisableAvalanche - Disable noise generation from the Avalanche Diode + DisableAvalanche + + // Default mode - Avalanche enabled, RF disabled, Whitener enabled. + Default NoiseMode = 0 + // Silent - a convenience - everything disabled + Silent NoiseMode = 4 +) + +// noiseCommand converts the given mode to the appropriate command to send to the OneRNG +func noiseCommand(flags NoiseMode) string { + num := strconv.Itoa(int(flags)) + return "cmd" + num + "\n" +} + +type readerFunc func(p []byte) (n int, err error) + +func (rf readerFunc) Read(p []byte) (n int, err error) { return rf(p) } + +// io.CopyN/io.Copy with cancellation support +func copyWithContext(ctx context.Context, dst io.Writer, src io.Reader, n int64) (int64, error) { + // allow 10 500ms timeouts, for a total of 5s. After this, it's probably worth just giving up + allowedTimeouts := 10 + + rf := func(p []byte) (int, error) { + if f, ok := src.(*os.File); ok { + // I don't want reads to block forever, but I also don't want to time out immediately + err := f.SetReadDeadline(time.Now().Add(500 * time.Millisecond)) + if err != nil { + return 0, err + } + } + + select { + case <-ctx.Done(): + return 0, ctx.Err() + default: + n, err := src.Read(p) + if allowedTimeouts > 0 { + if err != nil && os.IsTimeout(err) { + allowedTimeouts-- + return n, nil + } + } + return n, err + } + } + + if n < 0 { + return io.Copy(dst, readerFunc(rf)) + } + return io.CopyN(dst, readerFunc(rf), n) +} diff --git a/onerng_test.go b/onerng_test.go index 17d31a5..cf36a16 100644 --- a/onerng_test.go +++ b/onerng_test.go @@ -1,34 +1,103 @@ package onerng import ( - "fmt" + "bytes" + "context" "testing" "github.com/stretchr/testify/assert" ) -func TestNoiseCommand(t *testing.T) { - fmt.Println(DisableWhitener) - fmt.Println(EnableRF) - fmt.Println(DisableAvalanche) +// func TestNoiseCommand(t *testing.T) { +// fmt.Println(DisableWhitener) +// fmt.Println(EnableRF) +// fmt.Println(DisableAvalanche) - fmt.Println(Default) - fmt.Println(Silent) +// fmt.Println(Default) +// fmt.Println(Silent) - testdata := []struct { - flags ReadMode - cmd string - }{ - {Default, "cmd0\n"}, - {DisableWhitener, "cmd1\n"}, - {EnableRF, "cmd2\n"}, - {EnableRF | DisableWhitener, "cmd3\n"}, - {DisableAvalanche, "cmd4\n"}, - {DisableAvalanche | DisableWhitener, "cmd5\n"}, - {DisableAvalanche | EnableRF, "cmd6\n"}, - {DisableAvalanche | EnableRF | DisableWhitener, "cmd7\n"}, - } - for _, d := range testdata { - assert.Equal(t, d.cmd, NoiseCommand(d.flags), d.cmd, d.flags) - } +// testdata := []struct { +// flags NoiseMode +// cmd string +// }{ +// {Default, "cmd0\n"}, +// {DisableWhitener, "cmd1\n"}, +// {EnableRF, "cmd2\n"}, +// {EnableRF | DisableWhitener, "cmd3\n"}, +// {DisableAvalanche, "cmd4\n"}, +// {DisableAvalanche | DisableWhitener, "cmd5\n"}, +// {DisableAvalanche | EnableRF, "cmd6\n"}, +// {DisableAvalanche | EnableRF | DisableWhitener, "cmd7\n"}, +// } +// for _, d := range testdata { +// assert.Equal(t, d.cmd, noiseCommand(d.flags), d.cmd, d.flags) +// } +// } + +type fakeDev struct { + closed bool + rbuf *bytes.Buffer + wbuf *bytes.Buffer +} + +func (d *fakeDev) reset() { + d.closed = false + d.rbuf.Reset() + d.wbuf.Reset() +} + +func (d *fakeDev) Close() error { + d.closed = true + return nil +} + +func (d *fakeDev) Read(b []byte) (int, error) { + return d.rbuf.Read(b) +} + +func (d *fakeDev) Write(b []byte) (int, error) { + return d.wbuf.Write(b) +} + +func TestCmd(t *testing.T) { + d := &fakeDev{rbuf: &bytes.Buffer{}, wbuf: &bytes.Buffer{}} + o := &OneRNG{Path: "/dev/null", device: d} + ctx, cancel := context.WithCancel(context.Background()) + err := o.cmd(ctx, "foo", "bar") + assert.NoError(t, err) + assert.Equal(t, "foobar", d.wbuf.String()) + + d.reset() + cancel() + err = o.cmd(ctx, "foo", "bar") + assert.NoError(t, err) + assert.Equal(t, "foo", d.wbuf.String()) +} + +func TestClose(t *testing.T) { + d := &fakeDev{} + o := &OneRNG{Path: "/dev/null", device: d} + err := o.close() + assert.NoError(t, err) + assert.True(t, d.closed) + + o = &OneRNG{Path: "/dev/null", device: nil} + err = o.close() + assert.NoError(t, err) + assert.Nil(t, o.device) +} + +func TestVersion(t *testing.T) { + d := &fakeDev{ + wbuf: &bytes.Buffer{}, + rbuf: bytes.NewBufferString("dfoawiuhf98h9inf2oifoi2jr\n" + + "dfkjawflihjwfoiuh2rliu13he487631487645t98y23rtoqu3rbno9q34htgfv\n" + + "\r\nVersion 3\r\nas;dlfjaw;oihf2ih2o3iuf2ofnlo2jnlfuhf2iou\n\n"), + } + o := &OneRNG{Path: "/dev/null", device: d} + ctx := context.Background() + v, err := o.Version(ctx) + assert.NoError(t, err) + assert.Equal(t, "cmdo\ncmd4\ncmdv\ncmdO\ncmdo\n", d.wbuf.String()) + assert.Equal(t, 3, v) } diff --git a/verify.go b/verify.go index a2ec490..40be3a0 100644 --- a/verify.go +++ b/verify.go @@ -11,25 +11,13 @@ import ( "golang.org/x/crypto/openpgp" ) -// looks like: -// fe ed be ef 20 14 - magic number -// 00 00 04 - len (little endian) -// 00 00 - version (little endian) -// image - len bytes of image -type fwImage struct { - magic [6]byte // must be 0xfeedbeef2014 - length [3]byte // LE - version [2]byte // LE - _ [1]byte // - fullimg [262144]byte // full image - // image [261536]byte // 256kb minus end offset - // slen [2]byte // signature length - // sig [543]byte // signature - // endOff [608]byte -} - -// Verify - this is a more-or-less straight port from the onerng_verify.py script -// distributed with the OneRNG package +// Verify reads a signed firmware image, extracts the signature, and verifies +// it against the given public key. +// +// Details are printed to Stderr on success, otherwise an error is returned. +// +// This is a more-or-less straight port from the official onerng_verify.py +// script distributed alongside the OneRNG package. func Verify(ctx context.Context, image io.Reader, pubkey string) error { var x byte length := 0 @@ -108,9 +96,6 @@ func Verify(ctx context.Context, image io.Reader, pubkey string) error { signature := bytes.NewBuffer(c[length-endOff+2 : length-endOff+2+klen]) signed := bytes.NewBuffer(c[0 : length-endOff]) - // leftovers := c[length-endOff+2+klen : length] - // fmt.Fprintf(os.Stderr, "leftovers (%d):\n%#x\n", len(leftovers), leftovers) - // read public key keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(pubkey)) if err != nil {