github.com/AntonOrnatskyi/goproxy@v0.0.0-20190205095733-4526a9fa18b4/core/lib/transport/encrypt/encrypt.go (about) 1 package encrypt 2 3 import ( 4 "crypto/aes" 5 "crypto/cipher" 6 "crypto/des" 7 "crypto/md5" 8 "crypto/rc4" 9 "crypto/sha256" 10 "errors" 11 12 lbuf "github.com/AntonOrnatskyi/goproxy/core/lib/buf" 13 "github.com/Yawning/chacha20" 14 "golang.org/x/crypto/blowfish" 15 "golang.org/x/crypto/cast5" 16 ) 17 18 const leakyBufSize = 2048 19 const maxNBuf = 2048 20 21 var leakyBuf = lbuf.NewLeakyBuf(maxNBuf, leakyBufSize) 22 var errEmptyPassword = errors.New("proxy key") 23 24 func md5sum(d []byte) []byte { 25 h := md5.New() 26 h.Write(d) 27 return h.Sum(nil) 28 } 29 30 func evpBytesToKey(password string, keyLen int) (key []byte) { 31 const md5Len = 16 32 cnt := (keyLen-1)/md5Len + 1 33 m := make([]byte, cnt*md5Len) 34 copy(m, md5sum([]byte(password))) 35 36 // Repeatedly call md5 until bytes generated is enough. 37 // Each call to md5 uses data: prev md5 sum + password. 38 d := make([]byte, md5Len+len(password)) 39 start := 0 40 for i := 1; i < cnt; i++ { 41 start += md5Len 42 copy(d, m[start-md5Len:start]) 43 copy(d[md5Len:], password) 44 copy(m[start:], md5sum(d)) 45 } 46 return m[:keyLen] 47 } 48 49 type DecOrEnc int 50 51 const ( 52 Decrypt DecOrEnc = iota 53 Encrypt 54 ) 55 56 func newStream(block cipher.Block, err error, key, iv []byte, 57 doe DecOrEnc) (cipher.Stream, error) { 58 if err != nil { 59 return nil, err 60 } 61 if doe == Encrypt { 62 return cipher.NewCFBEncrypter(block, iv), nil 63 } else { 64 return cipher.NewCFBDecrypter(block, iv), nil 65 } 66 } 67 68 func newAESCFBStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) { 69 block, err := aes.NewCipher(key) 70 return newStream(block, err, key, iv, doe) 71 } 72 73 func newAESCTRStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) { 74 block, err := aes.NewCipher(key) 75 if err != nil { 76 return nil, err 77 } 78 return cipher.NewCTR(block, iv), nil 79 } 80 81 func newDESStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) { 82 block, err := des.NewCipher(key) 83 return newStream(block, err, key, iv, doe) 84 } 85 86 func newBlowFishStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) { 87 block, err := blowfish.NewCipher(key) 88 return newStream(block, err, key, iv, doe) 89 } 90 91 func newCast5Stream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) { 92 block, err := cast5.NewCipher(key) 93 return newStream(block, err, key, iv, doe) 94 } 95 96 func newRC4MD5Stream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) { 97 h := md5.New() 98 h.Write(key) 99 h.Write(iv) 100 rc4key := h.Sum(nil) 101 102 return rc4.NewCipher(rc4key) 103 } 104 105 func newChaCha20Stream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) { 106 return chacha20.NewCipher(key, iv) 107 } 108 109 func newChaCha20IETFStream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) { 110 return chacha20.NewCipher(key, iv) 111 } 112 113 type cipherInfo struct { 114 keyLen int 115 ivLen int 116 newStream func(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) 117 } 118 119 var cipherMethod = map[string]*cipherInfo{ 120 "aes-128-cfb": {16, 16, newAESCFBStream}, 121 "aes-192-cfb": {24, 16, newAESCFBStream}, 122 "aes-256-cfb": {32, 16, newAESCFBStream}, 123 "aes-128-ctr": {16, 16, newAESCTRStream}, 124 "aes-192-ctr": {24, 16, newAESCTRStream}, 125 "aes-256-ctr": {32, 16, newAESCTRStream}, 126 "des-cfb": {8, 8, newDESStream}, 127 "bf-cfb": {16, 8, newBlowFishStream}, 128 "cast5-cfb": {16, 8, newCast5Stream}, 129 "rc4-md5": {16, 16, newRC4MD5Stream}, 130 "rc4-md5-6": {16, 6, newRC4MD5Stream}, 131 "chacha20": {32, 8, newChaCha20Stream}, 132 "chacha20-ietf": {32, 12, newChaCha20IETFStream}, 133 } 134 135 func GetCipherMethods() (keys []string) { 136 keys = []string{} 137 for k := range cipherMethod { 138 keys = append(keys, k) 139 } 140 return 141 } 142 func CheckCipherMethod(method string) error { 143 if method == "" { 144 method = "aes-256-cfb" 145 } 146 _, ok := cipherMethod[method] 147 if !ok { 148 return errors.New("Unsupported encryption method: " + method) 149 } 150 return nil 151 } 152 153 type Cipher struct { 154 WriteStream cipher.Stream 155 ReadStream cipher.Stream 156 key []byte 157 info *cipherInfo 158 } 159 160 func NewCipher(method, password string) (c *Cipher, err error) { 161 if password == "" { 162 return nil, errEmptyPassword 163 } 164 mi, ok := cipherMethod[method] 165 if !ok { 166 return nil, errors.New("Unsupported encryption method: " + method) 167 } 168 key := evpBytesToKey(password, mi.keyLen) 169 c = &Cipher{key: key, info: mi} 170 if err != nil { 171 return nil, err 172 } 173 //hash(key) -> read IV 174 riv := sha256.New().Sum(c.key)[:c.info.ivLen] 175 c.ReadStream, err = c.info.newStream(c.key, riv, Decrypt) 176 if err != nil { 177 return nil, err 178 } //hash(read IV) -> write IV 179 wiv := sha256.New().Sum(riv)[:c.info.ivLen] 180 c.WriteStream, err = c.info.newStream(c.key, wiv, Encrypt) 181 if err != nil { 182 return nil, err 183 } 184 return c, nil 185 }