博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
GO语言的进阶之路-网络安全之proxy
阅读量:7119 次
发布时间:2019-06-28

本文共 12769 字,大约阅读时间需要 42 分钟。

                  GO语言的进阶之路-网络安全之proxy

                                          作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

 

  在党的带领下,我们大陆的孩子身心健康还是杠杠的,尤其是像我这种农村孩纸,从来不会像《人命的名义》的法院陈清泉哪样学英语,也不知道什么你们城里人总是挂嘴边的“亚麻得”是啥意思哈~就是偶尔会问一些我二师兄(谷歌)一些我不太懂的知识,相信我大师兄大家也都认识,顶顶大名的百度是也。当然,偶尔也要下载一些github的一些插件用于学习研究。就是因为这么一点点的需求感,导致我不得不学习一下代理,即proxy。

  我之前发表过一篇文章,是有关代理的2个协议,即,。通过socks5协议实现了一个proxy基本框架,但是为了考虑它的安全性,我们就需要在传输的过程中进行数据加密,这个时候我们了解一些加密的方法就是很有必要了,本篇博客主要讲用Golang实现数据加密的两种常用方式。

 

一.对称加密和非对称加密。

  下面是对对称加密和非对称加密的一个简单总结,以及rc4加密解密的玩法。

1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7  8 package main 9 10 import (11     "crypto/rc4"12     "log"13     "crypto/md5"14 15 )16 17 /*18 对称加密和非对称加密:19     我们生活中常见的就是秘钥,说道秘钥就得说私钥和公钥。20     对称加密  :表现为:公钥可以解开私钥,而私钥也可以解开公钥。加密速度更快!21     非对称加密:表现为:公钥和公钥之间是无法互相解开,私钥和私钥之间也是无法相互解开的。22     一般而言,对称加密速度更快,但是生产环节中都是对称秘钥和非对称秘钥相结合使用的。生产环境中会先用非对称加密协商出来23 一个秘钥,然后再用这个秘钥进行对称加密,这也是SSL传输数据的方式哟!24     现代的文本加密主要还是对称加密。非对称加密太慢,而且也不适合对全文本加密,所以一般只是用在小数据加密上,比如加密文本25 对称加密密钥再传给对方。然后文本本身还是用对称加密。非对称加密还有一个用处就是核实发件人身份。26     现代主要有两种对称加密,数据流加密和数据块加密。数据流加密就是用算法和密钥一起产生一个随机码流,再和数据流XOR一起产生27 加密后的数据流。解密方只要产生同样的随机码流就可以了。数据块加密把原数据分成固定大小的数据块(比如64位),加密器使用密钥28 对数据块进行处理。一般来说数据流加密更快,但块加密更安全一些。常见的加密法里,des和3des是使用最多的数据块加密,aes是更新29 一些的块加密法,rc4是数据流加密,等等。30     二战以后,大家一般都放弃了保护加密算法的做法,因为太难了。而且数学上很强的算法就这么几种。所以现在都是公开算法。这些31 算法特性都不错,如果一个密钥长度不够强了,只要加长密钥长度就可以了。当然这种改变涉及改变加密硬软件,在使用中有些不便,不32 过一般认为算法本身还是够强不必改变。33     关于rc4流式加密官方文档:https://godoc.org/crypto/rc434 */35 36 37 38 func main() {39     key := "123456" //定义一个秘钥40     md5sum := md5.Sum([]byte(key))   //我们可以将秘钥生成MD5值就会得到一个16字节的,即128位,相对来说安全一些!41     cipher,err := rc4.NewCipher([]byte(md5sum[:])) //定义一个加密器“cipher”,把我们的秘钥穿进去就OK拉!42     if err != nil {43         log.Fatal(err)44     }45     buf := []byte("yinzhengjie") //我们定义一串字节。46 47     cipher.XORKeyStream(buf,buf) //第一个参数表示加密后的数据存放在那个变量中,第二个参数表示我们需要对谁进行加密。我们这里写同名就是进行原地加密,这是Golang比较牛逼的地方。48     log.Printf("加密后的样子:%s",string(buf)) //我们可以看下加密后的样子49     { //上面是进行加密,现在我们进行解密:首先创建一个作用域,这样我们就可以和上面定义相同的变量名,哈哈~50         cipher,err := rc4.NewCipher([]byte(md5sum[:])) //注意,我们传入的秘钥要和加密的秘钥要一致哟!51         if err != nil {52             log.Fatal(err)53         }54         cipher.XORKeyStream(buf,buf) //进行原地解密!55         log.Printf("解密后的样子:%s",string(buf))56     }57 }58 59 60 61 #以上代码输出结果如下:62 2017/08/15 23:05:20 加密后的样子:�gňu�:Job�63 2017/08/15 23:05:20 解密后的样子:yinzhengjie

 

 

二.手写加密工具。

1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7  8  9 package main10 11 import (12     "crypto/rc4"13     "log"14     "crypto/md5"15     "io"16     "os"17     "flag"18 )19 20 var (21     yinzhengjie_key = flag.String("yinzhengjie","","yinzhengjie + string")22 )23 24 func Crypto(w io.Writer,f io.Reader,key string)  {25     md5sum := md5.Sum([]byte(key)) //首先对秘钥进行MD5运算,使得秘钥的长度更长!26     cipher,err :=rc4.NewCipher([]byte(md5sum[:])) //定义一个加密器27     if err != nil {28         log.Fatal(err)29     }30     buf := make([]byte,4096) //定义一个指定大小的容器。31     for  {32         n,err := f.Read(buf) //将“f”的内容读取到“buf”中去,但是读取的大小是固定的哟!33         if err == io.EOF { //当读取到结 尾的时候就中止循环,我们这里不考虑其他异常!34             break35         }36         src := buf[:n] //将读取到的内容取出来,即都是字节。而非一个长度数字。37         cipher.XORKeyStream(src,src) //进行原地加密38         w.Write(src) //将加密后的数据写入到“w”中。39     }40 }41 42 func main() {43     flag.Parse()44     Crypto(os.Stdout,os.Stdin,*yinzhengjie_key)45 }46 47 /*48 用法展示:49 加密:[root@yinzhengjie ~]# go run rc4.go -yinzhengjie 123 
111150 解密:[root@yinzhengjie ~]# go run rc4.go -yinzhengjie 123 <1111 >222251 52 53 我们用加密tar包:54 加密:[root@yinzhengjie ~]# tar czf - * | ./rc4 -yinzhengjie 666666 > yinzhengjie.tar.gz55 解密:[root@yinzhengjie ~]# ./rc4 -yinzhengjie 666666

 

三.其他加密方式扩展。

  通过上面的学习,我们知道了rc4是一种流式加密,也基本上回使用rc4进行数据加密了,但是还有一种方式是基于块加密的,比如des,和aes等等。还有一些大牛实现了和其他语言混搭的加密解密套路,我已经对Golang的知识库目不暇接了。觉得Golang这个语言越来越有意思了。(如果想要了解des和aes的区别,)

1.des加密解密。

 

DES(Data Encryption Standard)是对称加密算法,也就是加密和解密用相同的密钥。其入口参数有三个:key、data、mode。

 

    1>.key为加密解密使用的密钥;

 

    2>.data为加密解密的数据;

 

    3>.mode为其工作模式。当模式为加密模式时,明文按照64位(即8bytes,字节)进行分组,形成明文组,key用于对数据加密,当模式为解密模式时,key用于对数据解密。

 

  想要了解更多Golang在实现使用des的使用方法,可以参考官网说明:https://godoc.org/crypto/des,以下是关于des加密方法的一个实例:

1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7  8 package main 9 10 import (11     "bytes"12     "crypto/cipher"13     "crypto/des"14     "encoding/base64"15     "fmt"16 )17 18 func main() {19     key := []byte("zhengjie") //这里你可以自定义秘钥长度,但是由于des的加密模式的特点,只会有8个字节生效。20     data := []byte("尹正杰")21     Mydes(data,key) // 调用DES加解密函数。22 }23 24 func Mydes(data ,key []byte) {25     key = key[:8] //用户输入的key可能长度可能会多余或少于8个字节,因此,我们可用对key进行切片操作,让代码的容错性增强。26     result, err := DesEncrypt(data, key) //我们进行加密操作,如要输入的字符串都是"[]byte"类型。最终我们会拿到切片数组。27     if err != nil {28         panic(err)29     }30     fmt.Println("加密后的样子:",base64.StdEncoding.EncodeToString(result))31     buf, err := DesDecrypt(result, key)  //这是进行解密操作,将加密的数据和key传入进去进行解密操作。32     if err != nil {33         panic(err)34     }35     fmt.Println("解密后的样子:",string(buf))36 }37 38 func DesEncrypt(data, key []byte) ([]byte, error) {39     block, err := des.NewCipher(key) //定义一个加密器“block”,把我们的秘钥传进去就OK拉!40     if err != nil {41         return nil, err42     }43     padding:= block.BlockSize() - len(data)%block.BlockSize()44     padtext := bytes.Repeat([]byte{byte(padding)},padding)45     data = append(data,padtext...)46     blockMode := cipher.NewCBCEncrypter(block, key) //对块数据进行加密操作。47     crypted := make([]byte, len(data))  // 根据CryptBlocks方法的说明,如下方式初始化crypted也可以crypted := date48     blockMode.CryptBlocks(crypted, data) //将date进行加密生成crypted,其实我们也可以原地进行加密,就是直接对源数据进行修改吗。可以节省内存,根据的需求来。49     return crypted, nil //将加密后的数据crypte返回给用户。50 }51 52 func DesDecrypt(crypted, key []byte) ([]byte, error) {53     block, err := des.NewCipher(key) //定义一个加密器“block”,把我们的秘钥传进去就OK拉!54     if err != nil {55         return nil, err56     }57     blockMode := cipher.NewCBCDecrypter(block, key) //对块数据进行解密操作。58     data := crypted  当然,我们也可以这样写“date := make([]byte, len(crypted))”59     blockMode.CryptBlocks(data, crypted) //对块数据进行解密操作,将数据存放在data里面60     return data, nil //将data内容返回给用户。61 }62 63 64 65 66 #以上代码执行结果如下:67 加密后的样子: MAS7R6K+tVPPLUx3/P+hxA==68 解密后的样子: 尹正杰

 

 

2.3DES加解密 

  3DES是DES加密算法的一种模式,它使用3条64位的密钥对数据进行三次加密。数据加密标准(DES)是美国的一种由来已久的加密标准,它使用对称密钥加密法。3DES(即Triple DES)是DESAES过渡的加密算法(1999年,NIST将3-DES指定为过渡的加密标准),是DES的一个更安全的变形。它以DES为基本模块,通过组合分组方法设计出分组加密算法。可以参考官网说明:https://godoc.org/crypto/des,下面是关于3DES的一个实例:

1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7  8 package main 9 10 import (11     "crypto/des"12     "bytes"13     "crypto/cipher"14     "log"15     "fmt"16 )17 18 func My3DesEncrypt(data, key []byte) ([]byte,error) {19     block,err := des.NewTripleDESCipher(key)20     if err != nil {21         return nil,err22     }23     padding := block.BlockSize() - len(data)%block.BlockSize()24     padtext := bytes.Repeat([]byte{byte(padding)},padding)25     data = append(data,padtext...)26     BlockMode := cipher.NewCBCEncrypter(block,key[:8])27     BlockMode.CryptBlocks(data,data) //原地加密28     return data,nil29 }30 31 func My3DesDecrypt(data, key []byte) ([]byte,error) {32     block,err := des.NewTripleDESCipher(key)33     if err != nil {34         return nil,err35     }36     BlockMode := cipher.NewCBCDecrypter(block,key[:8])37     BlockMode.CryptBlocks(data,data) //原地解密38     data = data[:len(data)-1]39     return data,nil40 }41 42 43 func main() {44     data := []byte("尹正杰")45     key := []byte("zhengjiezhengjiezhengjie") //根据des3的原理,key的长度必须是24个字节,即192bit。46     buf,err := My3DesEncrypt(data,key)47     if err != nil {48         log.Print(err)49     }50     fmt.Println("加密后的样子:",string(buf))51     buf1,err := My3DesDecrypt(buf,key)52     if err != nil {53         log.Print(err)54     }55     fmt.Println("解密后的样子:",string(buf1))56 }57 58 59 60 61 #以上代码执行结果如下:62 加密后的样子: 0�G���S�-Lw����63 解密后的样子: 尹正杰

   

3.aes加密解密

  AES(Advanced Encryption Standard):高级加密标准,是下一代的加密算法标准,速度快,安全级别高。AES使用几种不同的方法来执行排列和置换运算。AES是一个迭代的对称密钥分组的密码,它可以使用128192256位密钥,并且用128位(16字节)分组加密和解密数据。想要了解更多aes,

 

1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7  8 package main 9 10 import (11     "crypto/md5"12     "crypto/aes"13     "io"14     "crypto/rand"15     "crypto/cipher"16     "log"17     "fmt"18 )19 20 func main() {21     data := []byte("大河之剑天上来")22     key := []byte("yinzhengjie")23     encrypt_buf ,err := MyAesEncrypt(data,key)24     if err != nil {25         log.Print(err)26     }27     fmt.Println("加密后的样子:",string(encrypt_buf))28 29     //decipher_buf,err := MyAesDecrypt(encrypt_buf,key)30     //if err != nil {31     //    log.Print(err)32     //}33     //fmt.Println("解密后的样子:",string(decipher_buf))34 35 }36 37 func MyAesEncrypt(data,key []byte)([]byte,error)  {38     md5sum := md5.Sum([]byte(key)) //我们队密钥进行md4运算,得到的数字是一个16字节的数字。这样我们就不用考虑key的自身长度了,因为不管你多长都会被格式化成一个128的密钥。39     block,err := aes.NewCipher(md5sum[:])40     if err != nil {41         panic(err)42     }43     iv := make([]byte,block.BlockSize())44     io.ReadFull(rand.Reader,iv)45 46     stream := cipher.NewCFBEncrypter(block,iv)47     stream.XORKeyStream(data,data) //进行原地加密。48     return data,nil49 }50 51 //func MyAesDecrypt(data, key []byte) ([]byte, error) {52 //    md5sum := md5.Sum([]byte(key))53 //    block,err := aes.NewCipher(md5sum[:])54 //    if err != nil {55 //        panic(err)56 //    }57 //    BlockSize := block.BlockSize()58 //    BlockMode := cipher.NewCBCDecrypter(block,md5sum[:BlockSize])59 //    BlockMode.CryptBlocks(data,data)60 //    data = data[:len(data)-1]61 //    return data,nil62 //}

  如果你想要了解Golang如何使和其他语言进行加解密的可以查看这位大神的博客:

 

四.手写TCP代理。

/*#!/usr/bin/env gorun@author :yinzhengjieBlog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/EMAIL:y1053419035@qq.com*/package mainimport (    "net"    "io"    "flag"    "log"    "sync"    "crypto/md5"    "crypto/rc4")/*1>安装switchyomega软件;2.Golang编写代理服务3>以下代码是一个TCP代理程序,它是一个通用的四层代理。4.了解什么是透明代理。*/var    (    target = flag.String("yinzhengjie","www.qq.com:80","yinzhengjie == host:port") //第一个参数是定义关键字,第二个参数是告诉让用户输入相应的主机+端口。第三个参数是告诉用户使用方法)func Crypto(w io.Writer,f io.Reader,key string)  {    md5sum := md5.Sum([]byte(key)) //首先对秘钥进行MD5运算,使得秘钥的长度更长!    cipher,err :=rc4.NewCipher([]byte(md5sum[:])) //定义一个加密器    if err != nil {        log.Fatal(err)    }    buf := make([]byte,4096) //定义一个指定大小的容器。    for  {        n,err := f.Read(buf) //将“f”的内容读取到“buf”中去,但是读取的大小是固定的哟!        if err == io.EOF { //当读取到结尾的时候就中止循环,我们这里不考虑其他异常!            break        }        src := buf[:n] //将读取到的内容取出来,即都是字节。而非一个长度数字。        cipher.XORKeyStream(src,src) //进行原地加密        w.Write(src) //将加密后的数据写入到“w”中。    }}func handle_conn(conn net.Conn)  {    var   (        remote net.Conn  //定义远端的服务器连接。        err error    )    remote,err = net.Dial("tcp",*target) //建立到目标服务器的连接。    if err != nil {        log.Print(err)        conn.Close()        return    }    wg := new(sync.WaitGroup)    wg.Add(2)    go func() {        defer wg.Done()        io.Copy(remote,conn) //读取原地址请求(conn),然后将读取到的数据发送给目标主机。        remote.Close()    }()    go func() {        defer conn.Close()        io.Copy(conn,remote) //与上面相反,就是讲目标主机的数据返回给客户端。        conn.Close()    }()    wg.Wait()}func main() {    flag.Parse()    listener,err := net.Listen("tcp",":8888")    if err != nil {        log.Fatal(err)    }    for  {        conn,err := listener.Accept()        if err != nil {            log.Fatal(err)        }        go handle_conn(conn)    }}/*用法一:    不指定参数,会用代码默认的参数。    服务端:[root@yinzhengjie yinzhengjie]# go run tcp_proxy.go    客户端:[root@yinzhengjie ~]# curl -v 127.0.0.1:8888用法二:    指定参数时需要知名IP和端口号。    服务端:[root@yinzhengjie yinzhengjie]# go run tcp_proxy.go --yinzhengjie=127.0.0.1:22    客户端:[root@yinzhengjie ~]# ssh -p 8888 127.0.0.1用法三:    星球大战代理:    服务端:[root@yinzhengjie yinzhengjie]# go run tcp_proxy.go --yinzhengjie=towel.blinkenlights.nl:23    客户端:[root@yinzhengjie ~]# telnet 127.0.0.1 8888*/

 

 五.优化SOCKS5代理脚本

  在现在的互联网时代,每个老板都会考虑到数据的安全性,我们上次分享的代码只是将明文的数据进行转发作用,但是数据时透明的,其结构图如下:

 

  我们可以在上面的拓扑图中对数据进行加密 操作。

 

 

  未完待续。。。。。

 

转载于:https://www.cnblogs.com/yinzhengjie/p/7368030.html

你可能感兴趣的文章
面试题解:输入一个数A,找到大于A的一个最小数B,且B中不存在连续相等的两个数字...
查看>>
助力春运 重庆机场今晨新增一架飞机入列
查看>>
刘海I关于iPhone X 的适配
查看>>
百度Apollo发布智能驾驶商业化解决方案
查看>>
关闭tomcat报错Cannot allocate memory
查看>>
从源码角度看ContentProvider
查看>>
iOS--React Native浏览器插件
查看>>
一个JSON字符串和文件处理的命令行神器jq,windows和linux都可用
查看>>
Flask源码解析:从第一个版本开始阅读Flask源码
查看>>
JavaScript 工作原理之二-如何在 V8 引擎中书写最优代码的 5 条小技巧(译)
查看>>
SpringBoot Cache 深入
查看>>
Three.js Scene Graph
查看>>
PAT A1045 动态规划
查看>>
保持ssh的连接不断开
查看>>
897-递增顺序查找树
查看>>
wiki迁移方法操作步骤
查看>>
php_screw
查看>>
Go语言之读写锁
查看>>
openstack mitaka 完整安装详细文档(亲测,花了3天时间)
查看>>
for 循环嵌套for循环
查看>>