669 lines
12 KiB
Go
669 lines
12 KiB
Go
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
|
|
}
|