Skip to content

Commit

Permalink
xorgen and multilocker bug fixes
Browse files Browse the repository at this point in the history
 - Adding modmake build for ease of distribution.
  • Loading branch information
Doug Saylor committed Nov 5, 2023
1 parent 74b262c commit 14aefcd
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 61 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/.idea
/*.tar.gz
/*.zip
/build
/dist
19 changes: 0 additions & 19 deletions build.sh

This file was deleted.

6 changes: 0 additions & 6 deletions clean.sh

This file was deleted.

21 changes: 21 additions & 0 deletions cmd/internal/exit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package internal

import (
"fmt"
"os"
"strings"
)

// Fatal will Echo the message and os.Exit with code 1.
func Fatal(msg string, args ...any) {
Echo(msg, args...)
os.Exit(1)
}

// Echo will emit the given message without any logging formatting.
func Echo(msg string, args ...any) {
if !strings.HasSuffix(msg, "\n") {
msg += "\n"
}
_, _ = fmt.Fprintf(os.Stderr, msg, args...)
}
2 changes: 1 addition & 1 deletion cmd/xorgen/internal/tmpl/screen_embed.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,6 @@ func {{if .Exposed}}S{{else}}s{{end}}tream{{.FileMethodName}}() (io.Reader, erro
}
return gzip.NewReader(r)
{{- else }}
return xor.NewReader(bytes.NewReader(data), key, offset)
return xor.NewReader(bytes.NewReader(data{{.FileMethodName}}), key{{.FileMethodName}}, offset{{.FileMethodName}})
{{- end }}
}
49 changes: 27 additions & 22 deletions cmd/xorgen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,27 @@ package main
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
. "github.com/saylorsolutions/gocryptx/cmd/internal"
"github.com/saylorsolutions/gocryptx/cmd/xorgen/internal/tmpl"
flag "github.com/spf13/pflag"
"io"
"os"
"strings"
)

var (
version = "unknown"
versionFlag bool
helpFlag bool
exposedFlag bool
compressFlag bool
)

func main() {
var (
helpFlag bool
exposedFlag bool
compressFlag bool
)
flags := flag.NewFlagSet("xorgen", flag.ContinueOnError)
flags.BoolVar(&versionFlag, "version", false, "Prints the version of this executable")
flags.BoolVarP(&helpFlag, "help", "h", false, "Prints this usage information.")
flags.BoolVarP(&exposedFlag, "exposed", "E", false, "Make the unscreen function exposed from the file. It's recommended to only expose from within an internal package.")
flags.BoolVarP(&compressFlag, "compressed", "c", false, "Payload should be gzip compressed when embedded, which includes a checksum to help prevent tampering.")
Expand Down Expand Up @@ -51,16 +57,26 @@ This isn't really important to the threat model of this obfuscation method, sinc
}
if err := flags.Parse(os.Args[1:]); err != nil {
flags.Usage()
fatal("Error parsing flags: %v", err)
Fatal("Error parsing flags: %v", err)
}
if helpFlag {
flags.Usage()
return
}
if versionFlag {
Echo("xorgen version: %s", version)
return
}
if err := run(flags); err != nil {
Fatal("Error running xorgen: %v", err)
}
Echo("xorgen ran successfully")
}

func run(flags *flag.FlagSet) error {
switch flags.NArg() {
case 0:
fatal("Missing required FILE argument")
return errors.New("missing required FILE argument")
case 1:
err := tmpl.GenerateFile(
flags.Arg(0),
Expand All @@ -69,13 +85,13 @@ This isn't really important to the threat model of this obfuscation method, sinc
tmpl.ExposeFunctions(exposedFlag),
)
if err != nil {
fatal("Failed to generate file: %v", err)
return fmt.Errorf("failed to generate file: %w", err)
}
default:
var key bytes.Buffer
_, err := io.Copy(&key, hex.NewDecoder(strings.NewReader(flags.Arg(1))))
if err != nil {
fatal("Failed to decode KEY, must be a hex string with only the characters a-f, A-F, or 0-9")
return errors.New("failed to decode KEY, must be a hex string with only the characters a-f, A-F, or 0-9")
}
err = tmpl.GenerateFile(
flags.Arg(0),
Expand All @@ -84,19 +100,8 @@ This isn't really important to the threat model of this obfuscation method, sinc
tmpl.ExposeFunctions(exposedFlag),
)
if err != nil {
fatal("Failed to generate file: %v", err)
return fmt.Errorf("failed to generate file: %w", err)
}
}
}

func fatal(msg string, args ...any) {
echo(msg, args...)
os.Exit(1)
}

func echo(msg string, args ...any) {
if !strings.HasSuffix(msg, "\n") {
msg += "\n"
}
fmt.Printf(msg, args...)
return nil
}
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ go 1.19

require (
github.com/saylorsolutions/binmap v0.4.0
github.com/saylorsolutions/modmake v0.1.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.4
golang.org/x/crypto v0.11.0
golang.org/x/crypto v0.13.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/saylorsolutions/cache v1.1.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
16 changes: 10 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
github.com/bitfield/script v0.22.0 h1:LA7QHuEsXMPD52YLtxWrlqCCy+9FOpzNYfsRHC5Gsrc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU=
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/saylorsolutions/binmap v0.2.0 h1:HADBNp5OROKwpy/cdQxrLnAkoIFl4eD6g8ixzoi5vkc=
github.com/saylorsolutions/binmap v0.2.0/go.mod h1:nNL5x213T4kD+n7Oe8j0cSDXym11HX9++T3immOI1hg=
github.com/saylorsolutions/binmap v0.3.0 h1:JtCzLOeZNjwBiK/ON9CIidkNDi8uvJAh+QSc11Uq6eg=
github.com/saylorsolutions/binmap v0.3.0/go.mod h1:nNL5x213T4kD+n7Oe8j0cSDXym11HX9++T3immOI1hg=
github.com/saylorsolutions/binmap v0.4.0 h1:khmenzTziUUPi7ZZaaBbEJnJXTFnKNBODjLW+L9gz98=
github.com/saylorsolutions/binmap v0.4.0/go.mod h1:nNL5x213T4kD+n7Oe8j0cSDXym11HX9++T3immOI1hg=
github.com/saylorsolutions/cache v1.1.0 h1:DNOBHCWZK0aUxviRnVLNyuF8HneiLCjpbLC3BCv9RN4=
github.com/saylorsolutions/cache v1.1.0/go.mod h1:NXWMylDOfhrn9Jju2GnYXPlWCMDntw2rA9PBT3F0We8=
github.com/saylorsolutions/modmake v0.1.1 h1:ktMgCtjqS0urWA4gDQYNnP0Q0B7Bl4EZL+iZ9k2jn6s=
github.com/saylorsolutions/modmake v0.1.1/go.mod h1:zKHy6MpE5nHK4OnKfvbJSb478Gakc0WslzoHWHpNI8U=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg=
76 changes: 76 additions & 0 deletions modmake/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package main

import (
. "github.com/saylorsolutions/modmake"
)

const (
xorgenVersion = "1.0.1"
)

var (
xorgenBuildPath = Path("build/xorgen")
xorgenPackagePath = Path("dist/xorgen")
)

func main() {
b := NewBuild()
b.Generate().DependsOnRunner("tidy", "", Go().ModTidy())
b.Test().Does(
Script(
Go().Clean().TestCache(), // Some of these tests can be a bit flaky, not sure why.
Go().TestAll(),
),
)
b.Build().DependsOnRunner("clean-build", "", RemoveDir(Path("build/xorgen")))
b.Package().DependsOnRunner("clean-dist", "", RemoveDir(Path("dist/xorgen")))

xorgenVariants := map[string][]string{
"windows": {"amd64"},
"linux": {"amd64", "arm64"},
"darwin": {"amd64", "arm64"},
}
for os, archs := range xorgenVariants {
for _, arch := range archs {
variant := "xorgen-" + os + "-" + arch
imported := xorgenBuild(os, arch)
b.Import(variant, imported)
b.Build().DependsOn(imported.Build())
b.Package().DependsOn(imported.Package())
}
}
b.Package().AfterRun(RemoveDir(Path("build/xorgen")))

b.Execute()
}

func xorgenBuild(os, arch string) *Build {
outputFile := "xorgen"
qualifier := os + "_" + arch
if os == "windows" {
outputFile += ".exe"
}
outputPath := xorgenBuildPath.Join(qualifier, outputFile)
b := NewBuild()
build := Go().Build(Go().ToModulePath("cmd/xorgen")).
OS(os).Arch(arch).
OutputFilename(outputPath).
StripDebugSymbols().
SetVariable("main", "version", xorgenVersion)
b.Build().Does(build)
b.Build().DependsOnRunner("create-build-dir", "", MkdirAll(outputPath.Dir(), 0600))

var pkg Runner
if os == "windows" {
pkg = Zip(xorgenPackagePath.Join("xorgen-"+qualifier+"-"+xorgenVersion+".zip")).
AddFileWithPath(outputPath, "xorgen.exe").
Create()
} else {
pkg = Tar(xorgenPackagePath.Join("xorgen-"+qualifier+"-"+xorgenVersion+".tar.gz")).
AddFileWithPath(outputPath, "xorgen").
Create()
}
b.Package().Does(pkg)
b.Package().DependsOnRunner("create-pkg-dir", "", MkdirAll(xorgenPackagePath, 0600))
return b
}
28 changes: 24 additions & 4 deletions pkg/passlock/multilocker.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,19 @@ func NewMultiLocker(gen *KeyGenerator) *MultiLocker {
}
}

func (l *MultiLocker) validateHasGenerator() error {
if l.keyGen == nil {
return errors.New("no generator set")
}
return nil
}

func (l *MultiLocker) validateInitialized() error {
if len(l.payload) == 0 {
return errors.New("no payload set")
}
if l.keyGen == nil {
return errors.New("no generator set")
if err := l.validateHasGenerator(); err != nil {
return err
}
return nil
}
Expand Down Expand Up @@ -204,10 +211,23 @@ func (l *MultiLocker) UpdateSurrogatePass(id string, newPass Passphrase) error {

// Lock will lock a new payload with the base key.
// If surrogate keys are present, then the same salt will be used to ensure that surrogate keys are not invalidated.
func (l *MultiLocker) Lock(pass []byte, unencrypted []byte) error {
if err := l.validateInitialized(); err != nil {
func (l *MultiLocker) Lock(pass []byte, unencrypted Plaintext) error {
if err := l.validateHasGenerator(); err != nil {
return err
}
if len(l.payload) == 0 {
key, salt, err := l.keyGen.GenerateKey(pass)
if err != nil {
return err
}
encrypted, err := Lock(key, salt, unencrypted)
if err != nil {
return err
}
l.payload = encrypted
l.baseKey = key
return nil
}
if len(l.surKeys) > 0 {
// Must maintain the same salt to avoid invalidating surrogate keys
key, salt, err := l.keyGen.DeriveKeySalt(pass, l.payload)
Expand Down

0 comments on commit 14aefcd

Please sign in to comment.