github.com/iDigitalFlame/xmt@v0.5.4/c2/transform/base64.go (about)

     1  // Copyright (C) 2020 - 2023 iDigitalFlame
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU General Public License as published by
     5  // the Free Software Foundation, either version 3 of the License, or
     6  // any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU General Public License
    14  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    15  //
    16  
    17  package transform
    18  
    19  import (
    20  	"encoding/base64"
    21  	"io"
    22  	"sync"
    23  
    24  	"github.com/iDigitalFlame/xmt/util/bugtrack"
    25  )
    26  
    27  // Base64 is a transform that auto converts the data to and from Base64
    28  // encoding. This instance does not include any shifting.
    29  const Base64 = B64(0)
    30  
    31  const bufMax = 2 << 14
    32  
    33  var bufs = sync.Pool{
    34  	New: func() interface{} {
    35  		b := make([]byte, 512, bufMax)
    36  		_ = b[511] // BCE
    37  		return &b
    38  	},
    39  }
    40  
    41  // B64 is the underlying type for the Base64 Transform. This Transform encodes
    42  // data into a Base64 string before the final write to the output.
    43  type B64 byte
    44  
    45  // B64Shift returns a Base64 Transform that also shifts the bytes by the
    46  // specified amount before writes and after reads. This is useful for evading
    47  // detection by avoiding commonly flagged Base64 values.
    48  func B64Shift(n int) B64 {
    49  	return B64(n)
    50  }
    51  
    52  // Read satisfies the Transform interface requirements.
    53  func (b B64) Read(p []byte, w io.Writer) error {
    54  	n := base64.StdEncoding.DecodedLen(len(p))
    55  	if n > bufMax {
    56  		if bugtrack.Enabled {
    57  			bugtrack.Track("transform.(B64).Read(): Creating non-heap buffer, n=%d, bufMax=%d", n, bufMax)
    58  		}
    59  		var (
    60  			o   = make([]byte, n)
    61  			err = decodeShift(w, byte(b), p, &o)
    62  		)
    63  		o = nil
    64  		return err
    65  	}
    66  	o := bufs.Get().(*[]byte)
    67  	if len(*o) < n {
    68  		if bugtrack.Enabled {
    69  			bugtrack.Track("transform.(B64).Read(): Increasing heap buffer size len(*o)=%d, n=%d", len(*o), n)
    70  		}
    71  		*o = append(*o, make([]byte, n-len(*o))...)
    72  	}
    73  	err := decodeShift(w, byte(b), p, o)
    74  	bufs.Put(o)
    75  	return err
    76  }
    77  
    78  // Write satisfies the Transform interface requirements.
    79  func (b B64) Write(p []byte, w io.Writer) error {
    80  	if b != 0 {
    81  		for i := range p {
    82  			p[i] += byte(b)
    83  		}
    84  	}
    85  	var (
    86  		e      = base64.NewEncoder(base64.StdEncoding, w)
    87  		c, err = e.Write(p)
    88  	)
    89  	if e.Close(); c != len(p) {
    90  		return io.ErrShortWrite
    91  	}
    92  	e = nil
    93  	return err
    94  }
    95  func decodeShift(w io.Writer, b byte, p []byte, o *[]byte) error {
    96  	n, err := base64.StdEncoding.Decode(*o, p)
    97  	if err != nil {
    98  		return err
    99  	}
   100  	if b != 0 {
   101  		for x := 0; x < n; x++ {
   102  			(*o)[x] -= b
   103  		}
   104  	}
   105  	c, err := w.Write((*o)[:n])
   106  	if err != nil {
   107  		return err
   108  	}
   109  	if c != n {
   110  		return io.ErrShortWrite
   111  	}
   112  	return nil
   113  }