下面是一个简单的 golang 编写的 http AES 加密代理示例代码:
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
"io"
"log"
"net/http"
"net/url"
)
const key = "1234567890123456" // 16字节的AES加密密钥
func encrypt(text string) string {
block, err := aes.NewCipher([]byte(key))
if err != nil {
panic(err)
}
plaintext := []byte(text)
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
return base64.URLEncoding.EncodeToString(ciphertext)
}
func decrypt(text string) (string, error) {
ciphertext, err := base64.URLEncoding.DecodeString(text)
if err != nil {
return "", err
}
block, err := aes.NewCipher([]byte(key))
if err != nil {
return "", err
}
if len(ciphertext) < aes.BlockSize {
return "", fmt.Errorf("ciphertext too short")
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(ciphertext, ciphertext)
return string(ciphertext), nil
}
func handleProxy(w http.ResponseWriter, r *http.Request) {
targetUrl := r.URL.Query().Get("url")
u, err := url.Parse(targetUrl)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
req, err := http.NewRequest(r.Method, u.String(), r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer resp.Body.Close()
w.Header().Set("Content-Type", "application/json")
io.Copy(w, resp.Body)
}
func handleEncryptProxy(w http.ResponseWriter, r *http.Request) {
targetUrl := r.URL.Query().Get("url")
u, err := url.Parse(targetUrl)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
req, err := http.NewRequest(r.Method, u.String(), r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer resp.Body.Close()
w.Header().Set("Content-Type", "application/json")
var encryptedBody string
io.Copy(&encryptedBody, resp.Body)
fmt.Fprintf(w, `{"data": "%s"}`, encrypt(encryptedBody))
}
func main() {
http.HandleFunc("/proxy/", handleProxy)
http.HandleFunc("/encrypt-proxy/", handleEncryptProxy)
log.Fatal(http.ListenAndServe(":8080", nil))
}
这段代码实现了两个路由:
/proxy/
:直接代理访问目标地址,并返回原始响应内容。/encrypt-proxy/
:代理访问目标地址,加密响应内容后返回。
其中,AES 加密使用的是 CTR 模式。在 encrypt
函数中,先生成一个随机的 16 字节的初始向量(IV),再用 AES 加密算法对原始数据进行加密,并将 IV 和密文拼接成一个字节数组,并使用 base64 编码转换成字符串返回。在 decrypt
函数中,先将密文字符串解码为字节数组,然后从中提取出 IV 和密文部分,再用 AES 解密算法对密文进行解密,最后返回解密出来的明文字符串。
需要注意的是,由于原始的响应内容可能包含二进制数据,在将响应内容加密后,需要将加密后的字节数组转换成字符串类型返回给客户端。在 handleEncryptProxy
中,我使用了 fmt.Fprintf
来格式化输出 JSON 响应结果,但实际情况下,这种方式可能不太适合复杂的 JSON 结构,需要根据实际情况选择更适合的方式。