github.com/iDigitalFlame/xmt@v0.5.4/c2/wrapper/crypto.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 wrapper 18 19 import ( 20 "crypto/cipher" 21 "io" 22 23 "github.com/iDigitalFlame/xmt/data/crypto" 24 "github.com/iDigitalFlame/xmt/util/xerr" 25 ) 26 27 // CBK is the crypto.CBK implementation of a Wrapper. This instance will create 28 // a new CBK instance with these supplied values and size. 29 type CBK [5]byte 30 31 // XOR is the crypto.XOR implementation of a Wrapper. This instance will create 32 // a XOR key stream with IV based on the supplied values. 33 type XOR struct { 34 _ [0]func() 35 k crypto.XOR 36 iv []byte 37 } 38 39 // Block is the cipher.Block implementation of a Wrapper. This instance will create 40 // a Block based Wrapper with ciphers such as AES. 41 type Block struct { 42 _ [0]func() 43 b cipher.Block 44 v []byte 45 } 46 type nopCloser struct { 47 io.Reader 48 } 49 50 // NewXOR is a function that is an alias for 'Stream(crypto.XOR(k), crypto.XOR(k))' 51 // 52 // This wil return a Stream-backed XOR Wrapper. 53 func NewXOR(k []byte) XOR { 54 x := XOR{k: k, iv: make([]byte, len(k))} 55 for i := range k { 56 x.iv[i] = (k[i] + byte(i)) ^ 2 57 } 58 return x 59 } 60 func (nopCloser) Close() error { 61 return nil 62 } 63 64 // NewCBK creates a special type of Wrapper for CBK-based encryptors. 65 // 66 // NOTE: This function will prevent CBK from using its index based block 67 // functions, not sure if there's a way to work around this. 68 func NewCBK(a, b, c, d, size byte) CBK { 69 var e CBK 70 e[0], e[1], e[2], e[3], e[4] = a, b, c, d, size 71 return e 72 } 73 74 // Unwrap fulfils the Wrapper interface. 75 func (c CBK) Unwrap(r io.Reader) (io.Reader, error) { 76 e, err := crypto.NewCBKSource(c[0], c[1], c[2], c[3], c[4]) 77 if err != nil { 78 return nil, err 79 } 80 return crypto.NewCBKReader(e, r), nil 81 } 82 83 // Unwrap fulfils the Wrapper interface. 84 func (x XOR) Unwrap(r io.Reader) (io.Reader, error) { 85 return nopCloser{&cipher.StreamReader{R: r, S: cipher.NewCFBDecrypter(x.k, x.iv)}}, nil 86 } 87 88 // Unwrap fulfils the Wrapper interface. 89 func (b Block) Unwrap(r io.Reader) (io.Reader, error) { 90 return &cipher.StreamReader{R: r, S: cipher.NewCFBDecrypter(b.b, b.v)}, nil 91 } 92 93 // NewBlock returns a Wrapper based on a Block Cipher, such as AES. 94 func NewBlock(b cipher.Block, v []byte) (Block, error) { 95 if b == nil || len(v) == 0 { 96 return Block{}, xerr.Sub("arguments cannot be nil or empty", 0x6E) 97 } 98 if len(v) != b.BlockSize() { 99 return Block{}, xerr.Sub("block size must equal IV size", 0x29) 100 } 101 return Block{v: v, b: b}, nil 102 } 103 104 // Wrap fulfils the Wrapper interface. 105 func (c CBK) Wrap(w io.WriteCloser) (io.WriteCloser, error) { 106 e, err := crypto.NewCBKSource(c[0], c[1], c[2], c[3], c[4]) 107 if err != nil { 108 return nil, err 109 } 110 return crypto.NewCBKWriter(e, w), nil 111 } 112 113 // Wrap fulfils the Wrapper interface. 114 func (x XOR) Wrap(w io.WriteCloser) (io.WriteCloser, error) { 115 return &cipher.StreamWriter{W: w, S: cipher.NewCFBEncrypter(x.k, x.iv)}, nil 116 } 117 118 // Wrap fulfils the Wrapper interface. 119 func (b Block) Wrap(w io.WriteCloser) (io.WriteCloser, error) { 120 return &cipher.StreamWriter{W: w, S: cipher.NewCFBEncrypter(b.b, b.v)}, nil 121 }