diff --git a/crypto.go b/crypto.go index 197c8d4..eacd724 100644 --- a/crypto.go +++ b/crypto.go @@ -9,26 +9,29 @@ import ( // If math/rand.Seed() is not called, the generator behaves as if seeded by rand.Seed(1), // so the generator is deterministic. -// genAesKey generates a 128bit AES Key +// genAesKey generates a 128-bit AES Key. func genAesKey() []byte { return genRandBytes(16) } -// genAesKey generates a 128bit nonce +// genAesKey generates a 128-bit nonce. func genNonce() []byte { return genRandBytes(12) } -// genRandBytes return a random []byte with the length of size +// genRandBytes return a random []byte with the length of size. func genRandBytes(size int) []byte { buffer := make([]byte, size) rand.Read(buffer) // error is always nil so save to ignore return buffer } -// encAes encrypt data with AesKey in AES gcm mode -func encAes(data []byte, AesKey []byte) ([]byte, error) { - block, _ := aes.NewCipher(AesKey) +// encAES encrypt data with key in AES GCM mode. +func encAES(data, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } nonce := genNonce() aesgcm, err := cipher.NewGCM(block) diff --git a/main.go b/main.go index 486b19e..b7eaea5 100644 --- a/main.go +++ b/main.go @@ -192,14 +192,14 @@ func mainErr(args []string) error { } if info, err := os.Stat(flagDebugDir); os.IsNotExist(err) { - err := os.MkdirAll(flagDebugDir, 0755) + err := os.MkdirAll(flagDebugDir, 0o755) if err != nil { return err } } else if err != nil { - return fmt.Errorf("Debugdir error: %v", err) + return fmt.Errorf("debugdir error: %v", err) } else if !info.IsDir() { - return fmt.Errorf("Debugdir exists, but is a file not a directory") + return fmt.Errorf("debugdir exists, but is a file not a directory") } } @@ -371,7 +371,7 @@ func transformCompile(args []string) ([]string, error) { if envGarbleDebugDir != "" { osPkgPath := filepath.FromSlash(pkgPath) pkgDebugDir = filepath.Join(envGarbleDebugDir, osPkgPath) - err = os.MkdirAll(pkgDebugDir, 0755) + err = os.MkdirAll(pkgDebugDir, 0o755) if err != nil { return nil, err } diff --git a/main_test.go b/main_test.go index 986b08f..ae520d7 100644 --- a/main_test.go +++ b/main_test.go @@ -54,7 +54,7 @@ func TestScripts(t *testing.T) { "GONOSUMDB=*", ) bindir := filepath.Join(env.WorkDir, ".bin") - if err := os.Mkdir(bindir, 0777); err != nil { + if err := os.Mkdir(bindir, 0o777); err != nil { return err } binfile := filepath.Join(bindir, "garble") diff --git a/strings.go b/strings.go index 9ebded6..3799b37 100644 --- a/strings.go +++ b/strings.go @@ -2,9 +2,9 @@ package main import ( "encoding/hex" + "fmt" "go/ast" "go/token" - "log" "strconv" "strings" @@ -12,7 +12,6 @@ import ( ) func obfuscateLiterals(files []*ast.File) []*ast.File { - pre := func(cursor *astutil.Cursor) bool { t, ok := cursor.Node().(*ast.GenDecl) if !ok { @@ -24,7 +23,6 @@ func obfuscateLiterals(files []*ast.File) []*ast.File { if t.Tok == token.CONST { t.Tok = token.VAR } - return true } @@ -33,9 +31,7 @@ func obfuscateLiterals(files []*ast.File) []*ast.File { fset = token.NewFileSet() addedToPkg bool // we only want to inject the code and imports once ) - post := func(cursor *astutil.Cursor) bool { - switch x := cursor.Node().(type) { case *ast.File: if !addedToPkg { @@ -43,14 +39,8 @@ func obfuscateLiterals(files []*ast.File) []*ast.File { x.Decls = append(x.Decls, keyStmt(key)) if x.Imports == nil { - var newDecls = []ast.Decl{ - cryptoAesImportSpec, - } - - for _, decl := range x.Decls { - newDecls = append(newDecls, decl) - } - + newDecls := []ast.Decl{cryptoAesImportSpec} + newDecls = append(newDecls, x.Decls...) x.Decls = newDecls } else { astutil.AddImport(fset, x, "crypto/aes") @@ -58,7 +48,6 @@ func obfuscateLiterals(files []*ast.File) []*ast.File { } addedToPkg = true - return true } case *ast.BasicLit: @@ -71,15 +60,12 @@ func obfuscateLiterals(files []*ast.File) []*ast.File { value, err := strconv.Unquote(x.Value) if err != nil { - log.Fatalln("[Fatal]: Could not unqote string", err) - return false + panic(fmt.Sprintf("cannot unquote string: %v", err)) } - ciphertext, err := encAes([]byte(value), key) + ciphertext, err := encAES([]byte(value), key) if err != nil { - - log.Fatalln("[Fatal]: Could not encrypt string:", err) - return false + panic(fmt.Sprintf("cannot encrypt string: %v", err)) } cursor.Replace(ciphertextStmt(ciphertext)) @@ -88,14 +74,14 @@ func obfuscateLiterals(files []*ast.File) []*ast.File { return true } - for _, file := range files { - file = astutil.Apply(file, pre, post).(*ast.File) + for i := range files { + files[i] = astutil.Apply(files[i], pre, post).(*ast.File) } return files } -// ast definitions for injection +// AST definitions for injection var ( aesCipherStmt = &ast.AssignStmt{ Lhs: []ast.Expr{ @@ -103,17 +89,13 @@ var ( &ast.Ident{Name: "err"}, }, Tok: token.DEFINE, - Rhs: []ast.Expr{ - &ast.CallExpr{ - Fun: &ast.SelectorExpr{ - X: &ast.Ident{Name: "aes"}, - Sel: &ast.Ident{Name: "NewCipher"}, - }, - Args: []ast.Expr{ - &ast.Ident{Name: "garbleKey"}, - }, + Rhs: []ast.Expr{&ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{Name: "aes"}, + Sel: &ast.Ident{Name: "NewCipher"}, }, - }, + Args: []ast.Expr{&ast.Ident{Name: "garbleKey"}}, + }}, } aesGcmCipherStmt = &ast.AssignStmt{ @@ -122,17 +104,13 @@ var ( &ast.Ident{Name: "err"}, }, Tok: token.DEFINE, - Rhs: []ast.Expr{ - &ast.CallExpr{ - Fun: &ast.SelectorExpr{ - X: &ast.Ident{Name: "cipher"}, - Sel: &ast.Ident{Name: "NewGCM"}, - }, - Args: []ast.Expr{ - &ast.Ident{Name: "block"}, - }, + Rhs: []ast.Expr{&ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{Name: "cipher"}, + Sel: &ast.Ident{Name: "NewGCM"}, }, - }, + Args: []ast.Expr{&ast.Ident{Name: "block"}}, + }}, } plaintextStmt = &ast.AssignStmt{ @@ -141,44 +119,38 @@ var ( &ast.Ident{Name: "err"}, }, Tok: token.DEFINE, - Rhs: []ast.Expr{ - &ast.CallExpr{ - Fun: &ast.SelectorExpr{ - X: &ast.Ident{Name: "aesgcm"}, - Sel: &ast.Ident{Name: "Open"}, - }, - Args: []ast.Expr{ - &ast.Ident{Name: "nil"}, - &ast.SliceExpr{ - X: &ast.Ident{Name: "ciphertext"}, - High: &ast.BasicLit{ - Kind: token.INT, - Value: "12", - }, + Rhs: []ast.Expr{&ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{Name: "aesgcm"}, + Sel: &ast.Ident{Name: "Open"}, + }, + Args: []ast.Expr{ + &ast.Ident{Name: "nil"}, + &ast.SliceExpr{ + X: &ast.Ident{Name: "ciphertext"}, + High: &ast.BasicLit{ + Kind: token.INT, + Value: "12", }, - &ast.SliceExpr{ - X: &ast.Ident{Name: "ciphertext"}, - Low: &ast.BasicLit{ - Kind: token.INT, - Value: "12", - }, + }, + &ast.SliceExpr{ + X: &ast.Ident{Name: "ciphertext"}, + Low: &ast.BasicLit{ + Kind: token.INT, + Value: "12", }, - &ast.Ident{Name: "nil"}, }, + &ast.Ident{Name: "nil"}, }, - }, + }}, } - returnStmt = &ast.ReturnStmt{ - Results: []ast.Expr{ - &ast.CallExpr{ - Fun: &ast.Ident{Name: "string"}, - Args: []ast.Expr{ - &ast.Ident{Name: "plaintext"}, - }, - }, + returnStmt = &ast.ReturnStmt{Results: []ast.Expr{ + &ast.CallExpr{ + Fun: &ast.Ident{Name: "string"}, + Args: []ast.Expr{&ast.Ident{Name: "plaintext"}}, }, - } + }} ) func decErrStmt() *ast.IfStmt { @@ -188,137 +160,102 @@ func decErrStmt() *ast.IfStmt { Op: token.NEQ, Y: &ast.Ident{Name: "nil"}, }, - Body: &ast.BlockStmt{ - List: []ast.Stmt{ - &ast.ExprStmt{ - X: &ast.CallExpr{ - Fun: &ast.Ident{Name: "panic"}, - Args: []ast.Expr{ - &ast.BinaryExpr{ - X: &ast.BasicLit{ - Kind: token.STRING, - Value: `"[garble] Literal couldn't be decrypted: "`, - }, - Op: token.ADD, - Y: &ast.CallExpr{ - Fun: &ast.SelectorExpr{ - X: &ast.Ident{Name: "err"}, - Sel: &ast.Ident{Name: "Error"}, - }, - }, - }, - }, + Body: &ast.BlockStmt{List: []ast.Stmt{ + &ast.ExprStmt{X: &ast.CallExpr{ + Fun: &ast.Ident{Name: "panic"}, + Args: []ast.Expr{&ast.BinaryExpr{ + X: &ast.BasicLit{ + Kind: token.STRING, + Value: `"garble: literal couldn't be decrypted: "`, }, - }, - }, - }, + Op: token.ADD, + Y: &ast.CallExpr{Fun: &ast.SelectorExpr{ + X: &ast.Ident{Name: "err"}, + Sel: &ast.Ident{Name: "Error"}, + }}, + }}, + }}, + }}, } } var funcStmt = &ast.FuncDecl{ Name: &ast.Ident{Name: "garbleDecrypt"}, Type: &ast.FuncType{ - Params: &ast.FieldList{ - List: []*ast.Field{ - { - Names: []*ast.Ident{{Name: "ciphertext"}}, - Type: &ast.ArrayType{ - Elt: &ast.Ident{Name: "byte"}, - }, - }, - }, - }, - Results: &ast.FieldList{ - List: []*ast.Field{ - { - Type: &ast.Ident{Name: "string"}, - }, + Params: &ast.FieldList{List: []*ast.Field{{ + Names: []*ast.Ident{{Name: "ciphertext"}}, + Type: &ast.ArrayType{ + Elt: &ast.Ident{Name: "byte"}, }, - }, - }, - Body: &ast.BlockStmt{ - List: []ast.Stmt{ - aesCipherStmt, - decErrStmt(), - aesGcmCipherStmt, - decErrStmt(), - plaintextStmt, - decErrStmt(), - returnStmt, - }, + }}}, + Results: &ast.FieldList{List: []*ast.Field{{ + Type: &ast.Ident{Name: "string"}, + }}}, }, + Body: &ast.BlockStmt{List: []ast.Stmt{ + aesCipherStmt, + decErrStmt(), + aesGcmCipherStmt, + decErrStmt(), + plaintextStmt, + decErrStmt(), + returnStmt, + }}, } func ciphertextStmt(ciphertext []byte) *ast.CallExpr { - ciphertextLit := byteToByteLit(ciphertext) + ciphertextLit := dataAsByteSlice(ciphertext) return &ast.CallExpr{ - Fun: &ast.Ident{Name: "garbleDecrypt"}, - Args: []ast.Expr{ - ciphertextLit, - }, + Fun: &ast.Ident{Name: "garbleDecrypt"}, + Args: []ast.Expr{ciphertextLit}, } } -func byteToByteLit(buffer []byte) *ast.CallExpr { - hexstr := hex.EncodeToString(buffer) - +// dataAsByteSlice turns a byte slice like []byte{1, 2, 3} into an AST +// expression which encodes it, such as []byte("\x01\x02\x03"). +func dataAsByteSlice(data []byte) *ast.CallExpr { var b strings.Builder - b.WriteString(`"`) + b.WriteByte('"') + hexstr := hex.EncodeToString(data) for i := 0; i < len(hexstr); i += 2 { b.WriteString("\\x" + hexstr[i:i+2]) } - - b.WriteString(`"`) + b.WriteByte('"') return &ast.CallExpr{ Fun: &ast.ArrayType{ Elt: &ast.Ident{Name: "byte"}, }, - Args: []ast.Expr{ - &ast.BasicLit{ - Kind: token.STRING, - Value: b.String(), - }, - }, + Args: []ast.Expr{&ast.BasicLit{ + Kind: token.STRING, + Value: b.String(), + }}, } } -func keyStmt(key []byte) (decl *ast.GenDecl) { - keyLit := byteToByteLit(key) - - decl = &ast.GenDecl{ +func keyStmt(key []byte) *ast.GenDecl { + keyLit := dataAsByteSlice(key) + return &ast.GenDecl{ Tok: token.VAR, - Specs: []ast.Spec{ - &ast.ValueSpec{ - Names: []*ast.Ident{ - {Name: "garbleKey"}, - }, - Values: []ast.Expr{ - keyLit, - }, - }, - }, + Specs: []ast.Spec{&ast.ValueSpec{ + Names: []*ast.Ident{{Name: "garbleKey"}}, + Values: []ast.Expr{keyLit}, + }}, } - - return } var cryptoAesImportSpec = &ast.GenDecl{ Tok: token.IMPORT, Specs: []ast.Spec{ - &ast.ImportSpec{ - Path: &ast.BasicLit{ - Kind: token.STRING, - Value: `"crypto/aes"`, - }, - }, - &ast.ImportSpec{ - Path: &ast.BasicLit{ - Kind: token.STRING, - Value: `"crypto/cipher"`, - }, - }, + &ast.ImportSpec{Path: &ast.BasicLit{ + Kind: token.STRING, + Value: `"crypto/aes"`, + }}, + &ast.ImportSpec{Path: &ast.BasicLit{ + Kind: token.STRING, + Value: `"crypto/cipher"`, + }}, }, }