package encoder import ( "bytes" "compress/gzip" "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/base64" "io" "io/ioutil" "local/encoder/pipe" "local/encryptor" "log" "strconv" "github.com/golang/snappy" "github.com/klauspost/reedsolomon" "github.com/pierrec/lz4" ) var pipeBuffSize = int64(aes.BlockSize + 2) func SetPipeBuffSize(n int) { if n < 50 { n = 50 } pipeBuffSize = int64(n) } type BOP3 interface { Wrap3(chan []byte) chan []byte Unwrap3(chan []byte) chan []byte BOP } type BOP2 interface { Wrap2(io.Reader) io.Reader Unwrap2(io.Reader) io.Reader BOP } type BOP interface { Wrap([]byte) []byte Unwrap([]byte) []byte } type Base64 struct{} type Zipper struct{} type snapper struct{} type symCryptor struct{ encryptor.Encryptor } type asymCryptor struct{ encryptor.Encryptor } type Salter struct{ n int } type LZ4 struct{} type AES struct { Key []byte keylen int block cipher.Block } type PAR2 struct { chunks int pars int enc reedsolomon.Encoder } func (p *PAR2) fix() error { if p.chunks == 0 { p.chunks = 50 } if p.pars == 0 { p.pars = 5 } if p.enc == nil { e, err := reedsolomon.New(p.chunks, p.pars) p.enc = e return err } return nil } func (p *PAR2) Unwrap2(r io.Reader) io.Reader { b, _ := ioutil.ReadAll(r) b = p.Unwrap(b) return bytes.NewReader(b) } func (p *PAR2) Wrap2(r io.Reader) io.Reader { b, _ := ioutil.ReadAll(r) b = p.Wrap(b) return bytes.NewReader(b) } func (p *PAR2) Wrap(b []byte) []byte { if p.fix() != nil { return b } split, err := p.enc.Split(b) if err != nil { return b } if err := p.enc.Encode(split); err != nil { return b } if ok, err := p.enc.Verify(split); err != nil || !ok { return b } l := strconv.Itoa(len(b)) l = string(byte(len(l))) + l b = []byte(l) for i := range split { b = append(b, split[i]...) } return b } func (p *PAR2) Unwrap(b []byte) []byte { if p.fix() != nil { return b } l := int(b[0]) o := b[1 : l+1] c := b[l+1:] m, err := strconv.Atoi(string(o)) if err != nil { return b } split := make([][]byte, p.chunks+p.pars) chunklen := len(c) / (p.chunks + p.pars) for i := range split { split[i] = c[i*chunklen : (i+1)*chunklen] } if err := p.enc.Reconstruct(split); err != nil { return b } d := []byte{} for i := 0; i < p.chunks; i++ { d = append(d, split[i]...) } return d[:m] } func (z *Zipper) Wrap3(b chan []byte) chan []byte { out := make(chan []byte) go func() { defer close(out) pipeR, pipeW := io.Pipe() go func() { zw := gzip.NewWriter(pipeW) defer pipeW.Close() defer zw.Close() for input := range b { if _, err := zw.Write(input); err != nil { panic(err) } } }() subbuff := make([]byte, pipeBuffSize) for { n, err := pipeR.Read(subbuff) if err != nil && err != io.EOF { panic(err) } else if n > 0 { out <- copyBSlice(subbuff[:n]) } if err == io.EOF { break } } }() return out } func (z *Zipper) Unwrap3(b chan []byte) chan []byte { out := make(chan []byte) go func() { pipeR, pipeW := io.Pipe() defer close(out) go func() { defer pipeW.Close() for input := range b { if _, err := pipeW.Write(input); err != nil { panic(err) } } }() zr, err := gzip.NewReader(pipeR) if err != nil { panic(err) } buff := make([]byte, pipeBuffSize) for { n, err := zr.Read(buff) if err != nil && err != io.EOF { panic(err) } if n > 0 { out <- copyBSlice(buff[:n]) } if err == io.EOF { break } } }() return out } func (z *Zipper) Wrap2(b io.Reader) io.Reader { pipe := pipe.New() pipe.SetCap(pipeBuffSize) zw := gzip.NewWriter(pipe) go func() { defer pipe.Close() defer zw.Close() for { m, err := io.CopyN(zw, b, pipeBuffSize) if err != nil && err != io.EOF { panic(err) } if m > 0 { zw.Flush() } if err == io.EOF { return } } /* internalBuffer := make([]byte, pipeBuffSize/2+bytes.MinRead) if _, err := io.CopyBuffer(zw, b, internalBuffer); err != nil { panic(err) } */ }() return pipe } func (z *Zipper) Unwrap2(b io.Reader) io.Reader { pipe := pipe.New() pipe.SetCap(pipeBuffSize) go func() { defer pipe.Close() zr, err := gzip.NewReader(b) if err != nil && err != io.EOF { panic(err) } else if err == nil { if _, err := io.Copy(pipe, zr); err != nil { panic(err) } defer zr.Close() } }() return pipe } func (z *Zipper) Wrap(b []byte) []byte { var buf bytes.Buffer zw := gzip.NewWriter(&buf) if _, err := zw.Write(b); err != nil { return b } zw.Close() return buf.Bytes() } func (z *Zipper) Unwrap(b []byte) []byte { buf := bytes.NewBuffer(b) zw, err := gzip.NewReader(buf) if err != nil { return b } decompressed, err := ioutil.ReadAll(zw) if err != nil { return b } return decompressed } func (s *Salter) Unwrap3(b chan []byte) chan []byte { out := make(chan []byte) go func() { defer close(out) first := <-b saltLen := int(first[0]) for len(first) < saltLen+1 { first = append(first, <-b...) } first = first[saltLen+1:] out <- copyBSlice(first) for input := range b { out <- copyBSlice(input) } }() return out } func (s *Salter) Wrap3(b chan []byte) chan []byte { out := make(chan []byte) salt := s.makeSalt() go func() { defer close(out) out <- copyBSlice(salt) for input := range b { out <- copyBSlice(input) } }() return out } func (s *Salter) makeSalt() []byte { n := 21 if s.n > 0 { n = s.n } salt := make([]byte, n) _, err := rand.Read(salt) if err != nil { return nil } return append([]byte{byte(len(salt))}, salt...) } func (s *Salter) Wrap2(b io.Reader) io.Reader { salt := s.makeSalt() pipe := pipe.New() pipe.SetCap(pipeBuffSize) go func() { defer pipe.Close() if _, err := pipe.Write(salt); err != nil { panic(err) } tmpbuff := make([]byte, pipeBuffSize) if _, err := io.CopyBuffer(pipe, b, tmpbuff); err != nil { panic(err) } }() return pipe } func (s *Salter) Unwrap2(b io.Reader) io.Reader { buffer := bytes.NewBuffer(nil) if _, err := io.CopyN(buffer, b, 1); err != nil { panic(err) } l := int(buffer.Bytes()[0]) if _, err := io.CopyN(buffer, b, int64(l)); err != nil { panic(err) } pipe := pipe.New() pipe.SetCap(pipeBuffSize) go func() { defer pipe.Close() if _, err := io.Copy(pipe, b); err != nil && err != io.EOF { panic(err) } }() return pipe } func (s *Salter) Wrap(b []byte) []byte { salt := s.makeSalt() return append(salt, b...) } func (s *Salter) Unwrap(b []byte) []byte { if len(b) < 1 { return b } l := int(b[0]) if l > len(b)+1 { return b } return b[1+l:] } func (sc *symCryptor) Wrap(b []byte) []byte { return []byte(sc.Encrypt(string(b))) } func (sc *symCryptor) Unwrap(b []byte) []byte { return []byte(sc.Decrypt(string(b))) } func (sc *asymCryptor) Wrap(b []byte) []byte { return []byte(sc.Encrypt(string(b))) } func (sc *asymCryptor) Unwrap(b []byte) []byte { return []byte(sc.Decrypt(string(b))) } func (s *snapper) Wrap(b []byte) []byte { return snappy.Encode(nil, b) } func (s *snapper) Unwrap(b []byte) []byte { d, err := snappy.Decode(nil, b) if err != nil { return b } return d } func (s *AES) Wrap3(b chan []byte) chan []byte { s.fix() out := make(chan []byte) go func() { defer close(out) // IV iv := make([]byte, aes.BlockSize) if n, err := io.ReadFull(rand.Reader, iv); err != nil || n != len(iv) { panic(err) } out <- copyBSlice(iv) // cipher ttl := int64(0) stream := cipher.NewCFBEncrypter(s.block, iv) for input := range b { ttl += int64(len(input)) stream.XORKeyStream(input, input) if len(input) > 0 { out <- copyBSlice(input) } } // padding out <- copyBSlice(s.getPadding(ttl)) }() return out } func (s *AES) Wrap2(b io.Reader) io.Reader { s.fix() pipe := pipe.New() pipe.SetCap(pipeBuffSize) go func() { defer pipe.Close() // IV iv := make([]byte, aes.BlockSize) if n, err := io.ReadFull(rand.Reader, iv); err != nil || n != len(iv) { panic(err) } pipe.Write(iv) // cipher ttl := int64(0) stream := cipher.NewCFBEncrypter(s.block, iv) buff := make([]byte, pipeBuffSize) for n, err := b.Read(buff); err == nil || err == io.EOF; n, err = b.Read(buff) { ttl += int64(n) stream.XORKeyStream(buff[:n], buff[:n]) if m, err := pipe.Write(buff[:n]); err != nil || m != n { panic(err) } if err == io.EOF { break } } // padding pipe.Write(s.getPadding(ttl)) }() return pipe } func (s *AES) Unwrap2(b io.Reader) io.Reader { s.fix() pipe := pipe.New() pipe.SetCap(pipeBuffSize) go func() { defer pipe.Close() // IV var iv []byte add := make([]byte, pipeBuffSize) for len(iv) < aes.BlockSize { n, err := b.Read(add) if err != nil && err != io.EOF { panic(err) } iv = append(iv, add[:n]...) } last := iv[aes.BlockSize:] iv = iv[:aes.BlockSize] // cipher var n int var err error stream := cipher.NewCFBDecrypter(s.block, iv) for n, err = b.Read(add); err == nil || err == io.EOF; n, err = b.Read(add) { last = append(last, add[:n]...) stream.XORKeyStream(last[:len(last)-s.needModZero()], last[:len(last)-s.needModZero()]) pipe.Write(last[:len(last)-s.needModZero()]) last = last[len(last)-s.needModZero():] if err == io.EOF { break } } if err != nil && err != io.EOF { panic(err) } // padding trim := int(last[len(last)-1]) last = last[:len(last)-trim] stream.XORKeyStream(last, last) pipe.Write(last) }() return pipe } func (s *AES) Unwrap3(b chan []byte) chan []byte { s.fix() out := make(chan []byte) go func() { defer close(out) // IV var lastTwo [2][]byte var iv []byte for len(iv) < aes.BlockSize { add := <-b if len(add) >= aes.BlockSize-len(iv) { isIV := aes.BlockSize - len(iv) lastTwo[0] = add[isIV:] add = add[:isIV] } iv = append(iv, add...) } // cipher stream := cipher.NewCFBDecrypter(s.block, iv) for input := range b { stream.XORKeyStream(lastTwo[1], lastTwo[1]) if len(lastTwo[1]) > 0 { out <- copyBSlice(lastTwo[1]) } lastTwo[1] = lastTwo[0] lastTwo[0] = input } last := append(lastTwo[1], lastTwo[0]...) // padding trim := int(last[len(last)-1]) last = last[:len(last)-trim] stream.XORKeyStream(last, last) if len(last) > 0 { out <- copyBSlice(last) } }() return out } func (s *AES) Wrap(b []byte) []byte { s.fix() c := s.pad(b) d := make([]byte, aes.BlockSize+len(c)) iv := d[:aes.BlockSize] if _, err := io.ReadFull(rand.Reader, iv); err != nil { return nil } stream := cipher.NewCFBEncrypter(s.block, iv) stream.XORKeyStream(d[aes.BlockSize:], c) return d } func (s *AES) Unwrap(b []byte) []byte { s.fix() iv := b[:aes.BlockSize] b = b[aes.BlockSize:] stream := cipher.NewCFBDecrypter(s.block, iv) stream.XORKeyStream(b, b) return s.unpad(b) } func (s *AES) fix() { if s.keylen < 1 { s.keylen = 32 } if len(s.Key) != s.keylen { s.Key = bytes.Repeat(append(s.Key, 0), s.keylen)[:s.keylen] } if s.block == nil { s.block, _ = aes.NewCipher(s.Key) } } func (s *AES) unpad(b []byte) []byte { s.fix() if len(b) < 1 || len(b) < int(b[len(b)-1]) { return b } return b[:len(b)-int(b[len(b)-1])] } func (s *AES) pad(b []byte) []byte { s.fix() return append(b, s.getPadding(int64(len(b)))...) } func (s *AES) getPadding(l int64) []byte { padding := int(int64(s.needModZero()) - l%int64(s.needModZero())) return bytes.Repeat([]byte{byte(padding)}, padding) } func (s *AES) needModZero() int { return aes.BlockSize } func (l *LZ4) Wrap(b []byte) []byte { var buf bytes.Buffer w := lz4.NewWriter(&buf) if _, err := io.Copy(w, bytes.NewBuffer(b)); err != nil { panic(err) } if err := w.Close(); err != nil { panic(err) } return buf.Bytes() } func (l *LZ4) Unwrap(b []byte) []byte { zr := lz4.NewReader(bytes.NewBuffer(b)) b, err := ioutil.ReadAll(zr) if err != nil { panic(err) } return b } func copyBSlice(b []byte) []byte { return append([]byte{}, b...) } func screenReader(b io.Reader) io.Reader { return b c, err := ioutil.ReadAll(b) if err != nil { panic(err) } log.Printf("screened %v", len(c)) if len(c) > 20 { log.Printf("%s...%s", c[:5], c[len(c)-5:]) } else if len(c) > 0 { log.Printf("%s", c) } return bytes.NewReader(c) } func (b64 *Base64) Wrap(b []byte) []byte { return []byte(base64.StdEncoding.EncodeToString(b)) } func (b64 *Base64) Unwrap(b []byte) []byte { b, err := base64.StdEncoding.DecodeString(string(b)) if err != nil { return nil } return b }