diff --git a/raylib/rres.go b/raylib/rres.go index 6e9f403..aecbc68 100644 --- a/raylib/rres.go +++ b/raylib/rres.go @@ -1,26 +1,14 @@ package raylib import ( - "bytes" - "crypto/aes" - "crypto/cipher" - "crypto/des" "encoding/binary" "fmt" "io" - "io/ioutil" "os" "unsafe" - "github.com/dsnet/compress/bzip2" - "github.com/klauspost/compress/flate" - "github.com/pierrec/lz4" - "github.com/rootlch/encrypt" - "github.com/ulikunitz/xz" - "golang.org/x/crypto/blowfish" - "golang.org/x/crypto/xtea" - "github.com/gen2brain/raylib-go/rres" + "github.com/gen2brain/raylib-go/rres/rlib" ) // LoadResource - Load resource from file by id @@ -68,14 +56,14 @@ func LoadResource(reader io.ReadSeeker, rresID int, key []byte) (data rres.Data) b := make([]byte, infoHeader.DataSize) reader.Read(b) - // Uncompress data - data.Data, err = uncompress(b, int(infoHeader.CompType)) + // Decompress data + data.Data, err = rlib.Decompress(b, int(infoHeader.CompType)) if err != nil { TraceLog(LogWarning, "[ID %d] %v", infoHeader.ID, err) } // Decrypt data - data.Data, err = decrypt(key, data.Data, int(infoHeader.CryptoType)) + data.Data, err = rlib.Decrypt(key, data.Data, int(infoHeader.CryptoType)) if err != nil { TraceLog(LogWarning, "[ID %d] %v", infoHeader.ID, err) } @@ -95,209 +83,3 @@ func LoadResource(reader io.ReadSeeker, rresID int, key []byte) (data rres.Data) return } - -// decrypt data -func decrypt(key, data []byte, cryptoType int) ([]byte, error) { - switch cryptoType { - case rres.CryptoXOR: - c, err := encrypt.NewXor(string(key)) - if err != nil { - return nil, err - } - - b := c.Encode(data) - return b, nil - case rres.CryptoAES: - b, err := decryptAES(key, data) - if err != nil { - return nil, err - } - return b, nil - case rres.Crypto3DES: - b, err := decrypt3DES(key, data) - if err != nil { - return nil, err - } - return b, nil - case rres.CryptoBlowfish: - b, err := decryptBlowfish(key, data) - if err != nil { - return nil, err - } - return b, nil - case rres.CryptoXTEA: - b, err := decryptXTEA(key, data) - if err != nil { - return nil, err - } - return b, nil - default: - return data, nil - } -} - -// uncompress data -func uncompress(data []byte, compType int) ([]byte, error) { - switch compType { - case rres.CompNone: - return data, nil - case rres.CompDeflate: - r := flate.NewReader(bytes.NewReader(data)) - - u, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - r.Close() - - return u, nil - case rres.CompLZ4: - r := lz4.NewReader(bytes.NewReader(data)) - - u, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - return u, nil - case rres.CompLZMA2: - r, err := xz.NewReader(bytes.NewReader(data)) - if err != nil { - return nil, err - } - - u, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - return u, nil - case rres.CompBZIP2: - r, err := bzip2.NewReader(bytes.NewReader(data), &bzip2.ReaderConfig{}) - if err != nil { - return nil, err - } - - u, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - return u, nil - default: - return data, nil - } -} - -// unpad -func unpad(src []byte) ([]byte, error) { - length := len(src) - unpadding := int(src[length-1]) - - if unpadding > length { - return nil, fmt.Errorf("unpad error. This can happen when incorrect encryption key is used.") - } - - return src[:(length - unpadding)], nil -} - -// decryptAES -func decryptAES(key, text []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - - if (len(text) % aes.BlockSize) != 0 { - return nil, fmt.Errorf("blocksize must be multiple of decoded message length") - } - - iv := text[:aes.BlockSize] - msg := text[aes.BlockSize:] - - cfb := cipher.NewCFBDecrypter(block, iv) - cfb.XORKeyStream(msg, msg) - - unpadMsg, err := unpad(msg) - if err != nil { - return nil, err - } - - return unpadMsg, nil -} - -// decrypt3DES -func decrypt3DES(key, text []byte) ([]byte, error) { - block, err := des.NewCipher(key) - if err != nil { - return nil, err - } - - if (len(text) % des.BlockSize) != 0 { - return nil, fmt.Errorf("blocksize must be multiple of decoded message length") - } - - iv := text[:des.BlockSize] - msg := text[des.BlockSize:] - - cbc := cipher.NewCBCDecrypter(block, iv) - cbc.CryptBlocks(msg, msg) - - unpadMsg, err := unpad(msg) - if err != nil { - return nil, err - } - - return unpadMsg, nil -} - -// decryptBlowfish -func decryptBlowfish(key, text []byte) ([]byte, error) { - block, err := blowfish.NewCipher(key) - if err != nil { - return nil, err - } - - if (len(text) % blowfish.BlockSize) != 0 { - return nil, fmt.Errorf("blocksize must be multiple of decoded message length") - } - - iv := text[:blowfish.BlockSize] - msg := text[blowfish.BlockSize:] - - cbc := cipher.NewCBCDecrypter(block, iv) - cbc.CryptBlocks(msg, msg) - - unpadMsg, err := unpad(msg) - if err != nil { - return nil, err - } - - return unpadMsg, nil -} - -// decryptXTEA -func decryptXTEA(key, text []byte) ([]byte, error) { - block, err := xtea.NewCipher(key) - if err != nil { - return nil, err - } - - if (len(text) % xtea.BlockSize) != 0 { - return nil, fmt.Errorf("blocksize must be multiple of decoded message length") - } - - iv := text[:xtea.BlockSize] - msg := text[xtea.BlockSize:] - - cbc := cipher.NewCBCDecrypter(block, iv) - cbc.CryptBlocks(msg, msg) - - unpadMsg, err := unpad(msg) - if err != nil { - return nil, err - } - - return unpadMsg, nil -} diff --git a/rres/cmd/rrem/main.go b/rres/cmd/rrem/main.go index d64aeff..3e356e8 100644 --- a/rres/cmd/rrem/main.go +++ b/rres/cmd/rrem/main.go @@ -3,10 +3,6 @@ package main import ( "bytes" - "crypto/aes" - "crypto/cipher" - "crypto/des" - "crypto/rand" "encoding/binary" "flag" "fmt" @@ -29,18 +25,12 @@ import ( _ "github.com/jbuchbinder/gopnm" _ "golang.org/x/image/bmp" - "github.com/dsnet/compress/bzip2" "github.com/jfreymuth/oggvorbis" "github.com/jteeuwen/go-bindata" - "github.com/klauspost/compress/flate" "github.com/moutend/go-wav" - "github.com/pierrec/lz4" - xor "github.com/rootlch/encrypt" - "github.com/ulikunitz/xz" - "golang.org/x/crypto/blowfish" - "golang.org/x/crypto/xtea" "github.com/gen2brain/raylib-go/rres" + "github.com/gen2brain/raylib-go/rres/rlib" ) func init() { @@ -166,7 +156,7 @@ func main() { } // Encryption - data, err = encrypt([]byte(*key), data, int(infoHeader.CryptoType)) + data, err = rlib.Encrypt([]byte(*key), data, int(infoHeader.CryptoType)) if err != nil { fmt.Printf("%v\n", err) } @@ -174,7 +164,7 @@ func main() { infoHeader.UncompSize = uint32(len(data)) // Compression - data, err = compress(data, int(infoHeader.CompType)) + data, err = rlib.Compress(data, int(infoHeader.CompType)) if err != nil { fmt.Printf("%v\n", err) } @@ -391,120 +381,6 @@ func params(data []byte, dataType int) (d []byte, p1, p2, p3, p4 uint32, err err return } -// encrypt data -func encrypt(key, data []byte, cryptoType int) ([]byte, error) { - switch cryptoType { - case rres.CryptoXOR: - c, err := xor.NewXor(string(key)) - if err != nil { - return nil, err - } - - return c.Encode(data), nil - case rres.CryptoAES: - b, err := encryptAES(key, data) - if err != nil { - return nil, err - } - - return b, nil - case rres.Crypto3DES: - b, err := encrypt3DES(key, data) - if err != nil { - return nil, err - } - - return b, nil - case rres.CryptoBlowfish: - b, err := encryptBlowfish(key, data) - if err != nil { - return nil, err - } - - return b, nil - case rres.CryptoXTEA: - b, err := encryptXTEA(key, data) - if err != nil { - fmt.Printf("%v\n", err) - } - - return b, nil - default: - return data, nil - } -} - -// compress data -func compress(data []byte, compType int) ([]byte, error) { - switch compType { - case rres.CompNone: - return data, nil - case rres.CompDeflate: - buf := new(bytes.Buffer) - - w, err := flate.NewWriter(buf, flate.DefaultCompression) - if err != nil { - return nil, err - } - - _, err = w.Write(data) - if err != nil { - return nil, err - } - - w.Close() - - return buf.Bytes(), nil - case rres.CompLZ4: - buf := new(bytes.Buffer) - - w := lz4.NewWriter(buf) - - _, err := w.Write(data) - if err != nil { - return nil, err - } - - w.Close() - - return buf.Bytes(), nil - case rres.CompLZMA2: - buf := new(bytes.Buffer) - - w, err := xz.NewWriter(buf) - if err != nil { - return nil, err - } - - _, err = w.Write(data) - if err != nil { - return nil, err - } - - w.Close() - - return buf.Bytes(), nil - case rres.CompBZIP2: - buf := new(bytes.Buffer) - - w, err := bzip2.NewWriter(buf, &bzip2.WriterConfig{Level: bzip2.BestCompression}) - if err != nil { - return nil, err - } - - _, err = w.Write(data) - if err != nil { - return nil, err - } - - w.Close() - - return buf.Bytes(), nil - default: - return data, nil - } -} - // genSource generates C source file func genSource(w io.Writer, data []byte) error { length := len(data) @@ -557,90 +433,3 @@ func genBin(base string) error { return bindata.Translate(cfg) } - -// pad to block size -func pad(src []byte, blockSize int) []byte { - padding := blockSize - len(src)%blockSize - padtext := bytes.Repeat([]byte{byte(padding)}, padding) - return append(src, padtext...) -} - -// encryptAES -func encryptAES(key, text []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - - msg := pad(text, aes.BlockSize) - ciphertext := make([]byte, aes.BlockSize+len(msg)) - iv := ciphertext[:aes.BlockSize] - if _, err := io.ReadFull(rand.Reader, iv); err != nil { - return nil, err - } - - cfb := cipher.NewCFBEncrypter(block, iv) - cfb.XORKeyStream(ciphertext[aes.BlockSize:], msg) - - return ciphertext, nil -} - -// encrypt3DES -func encrypt3DES(key, text []byte) ([]byte, error) { - block, err := des.NewTripleDESCipher(key) - if err != nil { - return nil, err - } - - msg := pad(text, des.BlockSize) - ciphertext := make([]byte, des.BlockSize+len(msg)) - iv := ciphertext[:des.BlockSize] - if _, err := io.ReadFull(rand.Reader, iv); err != nil { - return nil, err - } - - cbc := cipher.NewCBCEncrypter(block, iv) - cbc.CryptBlocks(ciphertext[des.BlockSize:], msg) - - return ciphertext, nil -} - -// encryptBlowfish -func encryptBlowfish(key, text []byte) ([]byte, error) { - block, err := blowfish.NewCipher(key) - if err != nil { - return nil, err - } - - msg := pad(text, blowfish.BlockSize) - ciphertext := make([]byte, blowfish.BlockSize+len(msg)) - iv := ciphertext[:blowfish.BlockSize] - if _, err := io.ReadFull(rand.Reader, iv); err != nil { - return nil, err - } - - cbc := cipher.NewCBCEncrypter(block, iv) - cbc.CryptBlocks(ciphertext[blowfish.BlockSize:], msg) - - return ciphertext, nil -} - -// encryptXTEA -func encryptXTEA(key, text []byte) ([]byte, error) { - block, err := xtea.NewCipher(key) - if err != nil { - return nil, err - } - - msg := pad(text, xtea.BlockSize) - ciphertext := make([]byte, xtea.BlockSize+len(msg)) - iv := ciphertext[:xtea.BlockSize] - if _, err := io.ReadFull(rand.Reader, iv); err != nil { - return nil, err - } - - cbc := cipher.NewCBCEncrypter(block, iv) - cbc.CryptBlocks(ciphertext[xtea.BlockSize:], msg) - - return ciphertext, nil -} diff --git a/rres/rlib/cgo/Makefile b/rres/rlib/cgo/Makefile new file mode 100644 index 0000000..d7e1300 --- /dev/null +++ b/rres/rlib/cgo/Makefile @@ -0,0 +1,4 @@ +all: build + +build: + go build -buildmode=c-archive -o rlib.a diff --git a/rres/rlib/cgo/make.bash b/rres/rlib/cgo/make.bash new file mode 100755 index 0000000..84ba576 --- /dev/null +++ b/rres/rlib/cgo/make.bash @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +CHROOT="/usr/x86_64-pc-linux-gnu-static" +MINGW="/usr/i686-w64-mingw32" +RPI="/usr/armv6j-hardfloat-linux-gnueabi" +ANDROID="/opt/android-toolchain-arm7" + +CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -buildmode=c-archive -o release/linux/rlib.a -ldflags "-s -w" + +CC="i686-w64-mingw32-gcc" CXX="i686-w64-mingw32-g++" \ +CGO_ENABLED=1 GOOS=windows GOARCH=386 go build -buildmode=c-archive -o release/win32/rlib.a -ldflags "-s -w" + +CC="armv6j-hardfloat-linux-gnueabi-gcc" CXX="armv6j-hardfloat-linux-gnueabi-g++" \ +CGO_ENABLED=1 GOOS=linux GOARCH=arm go build -buildmode=c-archive -o release/rpi/rlib.a -ldflags "-s -w" + +PATH="$PATH:$ANDROID/bin" \ +CC="arm-linux-androideabi-gcc" CXX="arm-linux-androideabi-g++" \ +CGO_ENABLED=1 GOOS=android GOARCH=arm go build -buildmode=c-shared -o release/android/armeabi-v7a/rlib.so -ldflags "-s -w" diff --git a/rres/rlib/cgo/rlib.go b/rres/rlib/cgo/rlib.go new file mode 100644 index 0000000..b7a876c --- /dev/null +++ b/rres/rlib/cgo/rlib.go @@ -0,0 +1,69 @@ +package main + +import "C" + +import ( + "unsafe" + + "github.com/gen2brain/raylib-go/rres/rlib" +) + +//export Compress +func Compress(compType C.int, data *C.uchar, uncompSize C.ulong, outCompSize *C.ulong) *C.uchar { + d := C.GoBytes(unsafe.Pointer(data), C.int(uncompSize)) + + c, err := rlib.Compress(d, int(compType)) + if err != nil { + return nil + } + + *outCompSize = C.ulong(len(c)) + return (*C.uchar)(unsafe.Pointer(&c[0])) +} + +//export Decompress +func Decompress(compType C.int, data *C.uchar, uncompSize C.ulong, compSize C.ulong) *C.uchar { + d := C.GoBytes(unsafe.Pointer(data), C.int(compSize)) + + c, err := rlib.Decompress(d, int(compType)) + if err != nil { + return nil + } + + if len(c) != int(uncompSize) { + return nil + } + + return (*C.uchar)(unsafe.Pointer(&c[0])) +} + +//export Encrypt +func Encrypt(cryptoType C.int, key *C.char, data *C.uchar, dataSize C.ulong, outDataSize *C.ulong) *C.uchar { + k := []byte(C.GoString(key)) + d := C.GoBytes(unsafe.Pointer(data), C.int(dataSize)) + + c, err := rlib.Encrypt(k, d, int(cryptoType)) + if err != nil { + return nil + } + + *outDataSize = C.ulong(len(c)) + return (*C.uchar)(unsafe.Pointer(&c[0])) +} + +//export Decrypt +func Decrypt(cryptoType C.int, key *C.char, data *C.uchar, dataSize C.ulong) *C.uchar { + k := []byte(C.GoString(key)) + d := C.GoBytes(unsafe.Pointer(data), C.int(dataSize)) + + c, err := rlib.Decrypt(k, d, int(cryptoType)) + if err != nil { + return nil + } + + return (*C.uchar)(unsafe.Pointer(&c[0])) +} + +// We need the main() so we can compile as C library +func main() { +} diff --git a/rres/rlib/rlib.go b/rres/rlib/rlib.go new file mode 100644 index 0000000..5b2a3b6 --- /dev/null +++ b/rres/rlib/rlib.go @@ -0,0 +1,431 @@ +// Package rlib provides Encrypt/Decrypt and Compress/Uncompress functions +package rlib + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/des" + "crypto/rand" + "fmt" + "io" + "io/ioutil" + + "golang.org/x/crypto/blowfish" + "golang.org/x/crypto/xtea" + + "github.com/dsnet/compress/bzip2" + "github.com/klauspost/compress/flate" + "github.com/pierrec/lz4" + xor "github.com/rootlch/encrypt" + "github.com/ulikunitz/xz" + + "github.com/gen2brain/raylib-go/rres" +) + +// Encrypt data +func Encrypt(key, data []byte, cryptoType int) ([]byte, error) { + switch cryptoType { + case rres.CryptoXOR: + c, err := xor.NewXor(string(key)) + if err != nil { + return nil, err + } + + return c.Encode(data), nil + case rres.CryptoAES: + b, err := encryptAES(key, data) + if err != nil { + return nil, err + } + + return b, nil + case rres.Crypto3DES: + b, err := encrypt3DES(key, data) + if err != nil { + return nil, err + } + + return b, nil + case rres.CryptoBlowfish: + b, err := encryptBlowfish(key, data) + if err != nil { + return nil, err + } + + return b, nil + case rres.CryptoXTEA: + b, err := encryptXTEA(key, data) + if err != nil { + fmt.Printf("%v\n", err) + } + + return b, nil + default: + return data, nil + } +} + +// Decrypt data +func Decrypt(key, data []byte, cryptoType int) ([]byte, error) { + switch cryptoType { + case rres.CryptoXOR: + c, err := xor.NewXor(string(key)) + if err != nil { + return nil, err + } + + b := c.Encode(data) + return b, nil + case rres.CryptoAES: + b, err := decryptAES(key, data) + if err != nil { + return nil, err + } + return b, nil + case rres.Crypto3DES: + b, err := decrypt3DES(key, data) + if err != nil { + return nil, err + } + return b, nil + case rres.CryptoBlowfish: + b, err := decryptBlowfish(key, data) + if err != nil { + return nil, err + } + return b, nil + case rres.CryptoXTEA: + b, err := decryptXTEA(key, data) + if err != nil { + return nil, err + } + return b, nil + default: + return data, nil + } +} + +// Compress data +func Compress(data []byte, compType int) ([]byte, error) { + switch compType { + case rres.CompNone: + return data, nil + case rres.CompDeflate: + buf := new(bytes.Buffer) + + w, err := flate.NewWriter(buf, flate.DefaultCompression) + if err != nil { + return nil, err + } + + _, err = w.Write(data) + if err != nil { + return nil, err + } + + w.Close() + + return buf.Bytes(), nil + case rres.CompLZ4: + buf := new(bytes.Buffer) + + w := lz4.NewWriter(buf) + + _, err := w.Write(data) + if err != nil { + return nil, err + } + + w.Close() + + return buf.Bytes(), nil + case rres.CompLZMA2: + buf := new(bytes.Buffer) + + w, err := xz.NewWriter(buf) + if err != nil { + return nil, err + } + + _, err = w.Write(data) + if err != nil { + return nil, err + } + + w.Close() + + return buf.Bytes(), nil + case rres.CompBZIP2: + buf := new(bytes.Buffer) + + w, err := bzip2.NewWriter(buf, &bzip2.WriterConfig{Level: bzip2.BestCompression}) + if err != nil { + return nil, err + } + + _, err = w.Write(data) + if err != nil { + return nil, err + } + + w.Close() + + return buf.Bytes(), nil + default: + return data, nil + } +} + +// Decompress data +func Decompress(data []byte, compType int) ([]byte, error) { + switch compType { + case rres.CompNone: + return data, nil + case rres.CompDeflate: + r := flate.NewReader(bytes.NewReader(data)) + + u, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + r.Close() + + return u, nil + case rres.CompLZ4: + r := lz4.NewReader(bytes.NewReader(data)) + + u, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + return u, nil + case rres.CompLZMA2: + r, err := xz.NewReader(bytes.NewReader(data)) + if err != nil { + return nil, err + } + + u, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + return u, nil + case rres.CompBZIP2: + r, err := bzip2.NewReader(bytes.NewReader(data), &bzip2.ReaderConfig{}) + if err != nil { + return nil, err + } + + u, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + return u, nil + default: + return data, nil + } +} + +// pad to block size +func pad(src []byte, blockSize int) []byte { + padding := blockSize - len(src)%blockSize + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + return append(src, padtext...) +} + +// unpad +func unpad(src []byte) ([]byte, error) { + length := len(src) + unpadding := int(src[length-1]) + + if unpadding > length { + return nil, fmt.Errorf("unpad error. This can happen when incorrect encryption key is used.") + } + + return src[:(length - unpadding)], nil +} + +// encryptAES +func encryptAES(key, text []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + msg := pad(text, aes.BlockSize) + ciphertext := make([]byte, aes.BlockSize+len(msg)) + iv := ciphertext[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + + cfb := cipher.NewCFBEncrypter(block, iv) + cfb.XORKeyStream(ciphertext[aes.BlockSize:], msg) + + return ciphertext, nil +} + +// decryptAES +func decryptAES(key, text []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + if (len(text) % aes.BlockSize) != 0 { + return nil, fmt.Errorf("blocksize must be multiple of decoded message length") + } + + iv := text[:aes.BlockSize] + msg := text[aes.BlockSize:] + + cfb := cipher.NewCFBDecrypter(block, iv) + cfb.XORKeyStream(msg, msg) + + unpadMsg, err := unpad(msg) + if err != nil { + return nil, err + } + + return unpadMsg, nil +} + +// encrypt3DES +func encrypt3DES(key, text []byte) ([]byte, error) { + block, err := des.NewTripleDESCipher(key) + if err != nil { + return nil, err + } + + msg := pad(text, des.BlockSize) + ciphertext := make([]byte, des.BlockSize+len(msg)) + iv := ciphertext[:des.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + + cbc := cipher.NewCBCEncrypter(block, iv) + cbc.CryptBlocks(ciphertext[des.BlockSize:], msg) + + return ciphertext, nil +} + +// decrypt3DES +func decrypt3DES(key, text []byte) ([]byte, error) { + block, err := des.NewCipher(key) + if err != nil { + return nil, err + } + + if (len(text) % des.BlockSize) != 0 { + return nil, fmt.Errorf("blocksize must be multiple of decoded message length") + } + + iv := text[:des.BlockSize] + msg := text[des.BlockSize:] + + cbc := cipher.NewCBCDecrypter(block, iv) + cbc.CryptBlocks(msg, msg) + + unpadMsg, err := unpad(msg) + if err != nil { + return nil, err + } + + return unpadMsg, nil +} + +// encryptBlowfish +func encryptBlowfish(key, text []byte) ([]byte, error) { + block, err := blowfish.NewCipher(key) + if err != nil { + return nil, err + } + + msg := pad(text, blowfish.BlockSize) + ciphertext := make([]byte, blowfish.BlockSize+len(msg)) + iv := ciphertext[:blowfish.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + + cbc := cipher.NewCBCEncrypter(block, iv) + cbc.CryptBlocks(ciphertext[blowfish.BlockSize:], msg) + + return ciphertext, nil +} + +// decryptBlowfish +func decryptBlowfish(key, text []byte) ([]byte, error) { + block, err := blowfish.NewCipher(key) + if err != nil { + return nil, err + } + + if (len(text) % blowfish.BlockSize) != 0 { + return nil, fmt.Errorf("blocksize must be multiple of decoded message length") + } + + iv := text[:blowfish.BlockSize] + msg := text[blowfish.BlockSize:] + + cbc := cipher.NewCBCDecrypter(block, iv) + cbc.CryptBlocks(msg, msg) + + unpadMsg, err := unpad(msg) + if err != nil { + return nil, err + } + + return unpadMsg, nil +} + +// encryptXTEA +func encryptXTEA(key, text []byte) ([]byte, error) { + block, err := xtea.NewCipher(key) + if err != nil { + return nil, err + } + + msg := pad(text, xtea.BlockSize) + ciphertext := make([]byte, xtea.BlockSize+len(msg)) + iv := ciphertext[:xtea.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + + cbc := cipher.NewCBCEncrypter(block, iv) + cbc.CryptBlocks(ciphertext[xtea.BlockSize:], msg) + + return ciphertext, nil +} + +// decryptXTEA +func decryptXTEA(key, text []byte) ([]byte, error) { + block, err := xtea.NewCipher(key) + if err != nil { + return nil, err + } + + if (len(text) % xtea.BlockSize) != 0 { + return nil, fmt.Errorf("blocksize must be multiple of decoded message length") + } + + iv := text[:xtea.BlockSize] + msg := text[xtea.BlockSize:] + + cbc := cipher.NewCBCDecrypter(block, iv) + cbc.CryptBlocks(msg, msg) + + unpadMsg, err := unpad(msg) + if err != nil { + return nil, err + } + + return unpadMsg, nil +}