mirror of
https://github.com/burrowers/garble.git
synced 2025-12-24 12:58:05 +08:00
22
hash.go
22
hash.go
@@ -204,10 +204,10 @@ func toUpper(b byte) byte { return b - ('a' - 'A') }
|
||||
func runtimeHashWithCustomSalt(salt []byte) uint32 {
|
||||
hasher.Reset()
|
||||
if !flagSeed.present() {
|
||||
hasher.Write(sharedCache.ListedPackages["runtime"].GarbleActionID[:])
|
||||
} else {
|
||||
hasher.Write(flagSeed.bytes)
|
||||
panic("runtimeHashWithCustomSalt: no seed")
|
||||
}
|
||||
|
||||
hasher.Write(flagSeed.bytes)
|
||||
hasher.Write(salt)
|
||||
sum := hasher.Sum(sumBuffer[:0])
|
||||
return binary.LittleEndian.Uint32(sum)
|
||||
@@ -226,12 +226,6 @@ func entryOffKey() uint32 {
|
||||
}
|
||||
|
||||
func hashWithPackage(pkg *listedPackage, name string) string {
|
||||
// If the user provided us with an obfuscation seed,
|
||||
// we use that with the package import path directly..
|
||||
// Otherwise, we use GarbleActionID as a fallback salt.
|
||||
if !flagSeed.present() {
|
||||
return hashWithCustomSalt(pkg.GarbleActionID[:], name)
|
||||
}
|
||||
// Use a separator at the end of ImportPath as a salt,
|
||||
// to ensure that "pkgfoo.bar" and "pkg.foobar" don't both hash
|
||||
// as the same string "pkgfoobar".
|
||||
@@ -256,13 +250,6 @@ func hashWithStruct(strct *types.Struct, field *types.Var) string {
|
||||
// TODO: rethink once the proposed go/types.Hash API in https://go.dev/issue/69420 is merged.
|
||||
salt := strconv.AppendUint(nil, uint64(typeutil_hash(strct)), 32)
|
||||
|
||||
// If the user provided us with an obfuscation seed,
|
||||
// we only use the identity struct type as a salt.
|
||||
// Otherwise, we add garble's own inputs to the salt as a fallback.
|
||||
if !flagSeed.present() {
|
||||
withGarbleHash := addGarbleToHash(salt)
|
||||
salt = withGarbleHash[:]
|
||||
}
|
||||
return hashWithCustomSalt(salt, field.Name())
|
||||
}
|
||||
|
||||
@@ -333,6 +320,9 @@ func hashWithCustomSalt(salt []byte, name string) string {
|
||||
if name == "" {
|
||||
panic("hashWithCustomSalt: empty name")
|
||||
}
|
||||
if !flagSeed.present() {
|
||||
panic("hashWithCustomSalt:no seed")
|
||||
}
|
||||
|
||||
hasher.Reset()
|
||||
hasher.Write(salt)
|
||||
|
||||
73
main.go
73
main.go
@@ -9,6 +9,7 @@ import (
|
||||
"bytes"
|
||||
"cmp"
|
||||
cryptorand "crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/gob"
|
||||
@@ -35,6 +36,7 @@ import (
|
||||
"runtime/debug"
|
||||
"runtime/pprof"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -562,6 +564,11 @@ This command wraps "go %s". Below is its help:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Compute a deterministic default seed if the user did not provide one.
|
||||
if err := computeDefaultSeed(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sharedTempDir, err = saveSharedCache()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -969,10 +976,10 @@ func (tf *transformer) transformCompile(args []string) ([]string, error) {
|
||||
}
|
||||
|
||||
// Literal and control flow obfuscation uses math/rand, so seed it deterministically.
|
||||
randSeed := tf.curPkg.GarbleActionID[:]
|
||||
if flagSeed.present() {
|
||||
randSeed = flagSeed.bytes
|
||||
if !flagSeed.present() {
|
||||
panic("transformCompile: no seed")
|
||||
}
|
||||
randSeed := flagSeed.bytes
|
||||
// log.Printf("seeding math/rand with %x\n", randSeed)
|
||||
tf.obfRand = mathrand.New(mathrand.NewSource(int64(binary.BigEndian.Uint64(randSeed))))
|
||||
|
||||
@@ -2336,3 +2343,63 @@ To install Go, see: https://go.dev/doc/install
|
||||
sharedCache.GOGARBLE = cmp.Or(os.Getenv("GOGARBLE"), "*") // we default to obfuscating everything
|
||||
return nil
|
||||
}
|
||||
|
||||
func computeDefaultSeed() error {
|
||||
// If the user has provided a seed explicitly (or random), keep it.
|
||||
if flagSeed.present() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Step 1: hash module information from `go list -m`.
|
||||
args := []string{"list", "-m", "-json=Path,Version,GoVersion,Sum,GoModSum,Indirect,Time,Main", "all"}
|
||||
|
||||
cmd := exec.Command(sharedCache.GoCmd, args...)
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("go list modules failed: %v\n%s", err, stderr.String())
|
||||
}
|
||||
|
||||
hasher := sha256.New()
|
||||
hasher.Write(stdout.Bytes())
|
||||
|
||||
// Parse the module list to determine the main module path.
|
||||
dec := json.NewDecoder(bytes.NewReader(stdout.Bytes()))
|
||||
mainModulePath := ""
|
||||
for dec.More() {
|
||||
var mod struct {
|
||||
Path string
|
||||
Main bool
|
||||
}
|
||||
if err := dec.Decode(&mod); err != nil {
|
||||
return fmt.Errorf("decode module json: %w", err)
|
||||
}
|
||||
if mod.Main {
|
||||
mainModulePath = mod.Path
|
||||
}
|
||||
}
|
||||
if mainModulePath == "" {
|
||||
return errors.New("could not determine main module path for seed derivation")
|
||||
}
|
||||
|
||||
// Step 2: include BuildIDs of all packages inside the main module.
|
||||
var pkgs []string
|
||||
for path := range sharedCache.ListedPackages {
|
||||
if strings.HasPrefix(path, mainModulePath) {
|
||||
pkgs = append(pkgs, path)
|
||||
}
|
||||
}
|
||||
// Sort for deterministic order.
|
||||
sort.Strings(pkgs)
|
||||
for _, path := range pkgs {
|
||||
if buildID := sharedCache.ListedPackages[path].BuildID; buildID != "" {
|
||||
hasher.Write([]byte(buildID))
|
||||
}
|
||||
}
|
||||
|
||||
seed := hasher.Sum(nil)
|
||||
flagSeed.bytes = seed
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user