Documentation
¶
Overview ¶
Package tunnel 提供基于 AES-256-GCM 的加密隧道转发功能。
核心能力
- 密钥管理:生成随机密钥(GenerateKey)、解析十六进制密钥(ParseKey)
- 加解密:AES-256-GCM 加密(Encrypt)和解密(Decrypt),nonce 随机生成并前置
- 编解码:Base64 编码(EncodeBody)和解码(DecodeBody),用于传输二进制数据
- 服务端:NewHandler / NewLocalHandler 返回标准 http.Handler,可嵌入任意 HTTP 服务
- 本地路由:NewLocalHandler 支持将相对路径请求直接路由到本地 handler,无需外部 HTTP 调用
- 客户端:Client 结构体提供 Do 方法,发送加密请求并解密响应
- 密钥轮换:Handler.UpdateKey 支持在运行时热替换密钥,旧密钥保留短时窗口供存量连接使用
- 多路复用隧道:NewTunnel 基于 mux 层创建持久双向隧道,支持流复用和双向 HTTP 请求交换
协议格式
所有请求/响应统一使用帧协议(application/x-tunnel-frame):
[4B big-endian metaLen][encrypted metadata][stream chunks...]
其中 encrypted metadata = Encrypt(key, metaJSON, AADMeta),stream chunks 由 EncryptStream(key, body, writer, AADStream) 生成, 格式为 [2B chunkLen][nonce|ciphertext|tag],每块独立加密。 body 为空时 stream chunks 部分为零字节。
安全特性
- 每次加密使用随机 nonce(12 字节),相同明文产生不同密文
- GCM 模式提供认证加密,可检测篡改
- 密钥为 32 字节(AES-256),需通过安全通道分发
- UpdateKey 热替换密钥时,旧密钥仍可解密存量连接(短时窗口)
使用示例
服务端嵌入:
key, _ := tunnel.ParseKey("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
mux := http.NewServeMux()
mux.Handle("POST /tunnel", tunnel.NewHandler(key))
http.ListenAndServe(":8080", mux)
客户端调用(标准库风格):
client, _ := tunnel.NewClient("0123456789abcdef...", "http://proxy:8080/tunnel", 30*time.Second)
req, _ := http.NewRequest("GET", "https://api.example.com/data", nil)
resp, _ := client.Do(req)
defer resp.Body.Close()
io.Copy(os.Stdout, resp.Body)
Example ¶
package main
import (
"fmt"
"os"
"github.com/cocomhub/sproxy/pkg/tunnel"
)
func main() {
os.Setenv("TUNNEL_KEY", "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
defer os.Unsetenv("TUNNEL_KEY")
hexKey := os.Getenv("TUNNEL_KEY")
key, err := tunnel.ParseKey(hexKey)
if err != nil {
fmt.Println("parse key error:", err)
return
}
plaintext, err := tunnel.Encrypt(key, []byte("hello"), []byte(tunnel.AADMeta))
if err != nil {
return
}
decrypted, err := tunnel.Decrypt(key, plaintext, []byte(tunnel.AADMeta))
if err != nil {
return
}
fmt.Println(string(decrypted))
}
Output: hello
Example (EncryptDecrypt) ¶
package main
import (
"fmt"
"github.com/cocomhub/sproxy/pkg/tunnel"
)
func main() {
key, _ := tunnel.ParseKey("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
plaintext := []byte("hello secure tunnel")
encrypted, err := tunnel.Encrypt(key, plaintext, []byte(tunnel.AADMeta))
if err != nil {
fmt.Println("encrypt error:", err)
return
}
decrypted, err := tunnel.Decrypt(key, encrypted, []byte(tunnel.AADMeta))
if err != nil {
fmt.Println("decrypt error:", err)
return
}
fmt.Println(string(decrypted))
}
Output: hello secure tunnel
Example (EncryptStreamDecryptStream) ¶
package main
import (
"bytes"
"fmt"
"github.com/cocomhub/sproxy/pkg/tunnel"
)
func main() {
key, _ := tunnel.ParseKey("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
original := []byte("hello streaming world with chunked AES-256-GCM encryption")
var encrypted bytes.Buffer
n, err := tunnel.EncryptStream(key, bytes.NewReader(original), &encrypted, []byte(tunnel.AADStream))
if err != nil {
fmt.Println("encrypt error:", err)
return
}
_ = n
var decrypted bytes.Buffer
n2, err := tunnel.DecryptStream(key, bytes.NewReader(encrypted.Bytes()), &decrypted, []byte(tunnel.AADStream))
if err != nil {
fmt.Println("decrypt error:", err)
return
}
_ = n2
fmt.Println(decrypted.String())
}
Output: hello streaming world with chunked AES-256-GCM encryption
Example (NewHandlerEmptyKey) ¶
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"github.com/cocomhub/sproxy/pkg/tunnel"
)
func main() {
mux := http.NewServeMux()
mux.Handle("POST /tunnel", tunnel.NewHandler(nil, nil))
server := httptest.NewServer(mux)
defer server.Close()
resp, err := http.Post(server.URL+"/tunnel", "application/octet-stream", nil)
if err != nil {
fmt.Println("error:", err)
return
}
defer resp.Body.Close()
fmt.Println(resp.StatusCode)
}
Output: 403
Example (RandomNonce) ¶
package main
import (
"fmt"
"github.com/cocomhub/sproxy/pkg/tunnel"
)
func main() {
key, _ := tunnel.ParseKey("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
plaintext := []byte("same plaintext")
c1, _ := tunnel.Encrypt(key, plaintext, []byte(tunnel.AADMeta))
c2, _ := tunnel.Encrypt(key, plaintext, []byte(tunnel.AADMeta))
fmt.Println(string(c1) != string(c2))
}
Output: true
Example (TamperDetection) ¶
package main
import (
"bytes"
"fmt"
"net/http"
"net/http/httptest"
"github.com/cocomhub/sproxy/pkg/tunnel"
)
func main() {
key, _ := tunnel.ParseKey("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
mux := http.NewServeMux()
mux.Handle("POST /tunnel", tunnel.NewHandler(key, nil))
server := httptest.NewServer(mux)
defer server.Close()
// 发送损坏的帧(非法 metadata),服务端应返回 400
resp, err := http.Post(server.URL+"/tunnel", "application/x-tunnel-frame", bytes.NewReader([]byte("corrupted frame data")))
if err != nil {
fmt.Println("error:", err)
return
}
defer resp.Body.Close()
fmt.Println(resp.StatusCode)
}
Output: 400
Index ¶
- Constants
- Variables
- func Decrypt(key, data, aad []byte) ([]byte, error)
- func DecryptStream(key []byte, r io.Reader, w io.Writer, aad []byte) (int64, error)
- func DecryptStreamWithChunkSize(key []byte, r io.Reader, w io.Writer, maxChunkSize int, aad []byte) (int64, error)
- func Encrypt(key, plaintext, aad []byte) ([]byte, error)
- func EncryptStream(key []byte, r io.Reader, w io.Writer, aad []byte) (int64, error)
- func EncryptStreamWithChunkSize(key []byte, r io.Reader, w io.Writer, chunkSize int, aad []byte) (int64, error)
- func GenerateKey() (string, error)
- func NewHandler(key []byte, logger *slog.Logger) http.Handler
- func NewLocalHandler(key []byte, local http.Handler, logger *slog.Logger) http.Handler
- func ParseKey(hexKey string) ([]byte, error)
- type Client
- type Handler
- type ReplayProtector
- type Request
- type Response
- type StreamDecryptor
- type StreamEncryptor
- type Tunnel
Examples ¶
Constants ¶
const ( // MaxMetadataBytes 限制 metadata 帧的最大长度(1 MiB),防止远程攻击者通过伪造的 metaLen 触发 OOM。 // 合法 metadata 通常仅几百字节到几 KiB,1 MiB 已留足上限。 MaxMetadataBytes = 1 << 20 // AADMeta 是 metadata 加密使用的 AAD(Additional Authenticated Data)上下文标签。 // 将密文绑定到"隧道 metadata 帧"这一特定上下文,防止密文被重放到其他上下文(如 stream body)。 AADMeta = "tunnel:meta:v1" // AADStream 是流式 body 加密使用的 AAD 上下文标签。 // 将密文绑定到"隧道流式 body"这一特定上下文,防止密文被重放到其他上下文(如 metadata 帧)。 AADStream = "tunnel:stream:v1" )
Variables ¶
var DefaultChunkSize = 64 * 1024
DefaultChunkSize 是 EncryptStream 默认的块大小(64 KB)。 每个块使用随机 nonce 独立加密。可在调用 EncryptStream 前修改此变量以调整块大小。
var ErrMetadataTooLarge = fmt.Errorf("metadata frame too large (> %d bytes)", MaxMetadataBytes)
ErrMetadataTooLarge 表示 metadata 帧长度超过 MaxMetadataBytes。
Functions ¶
func Decrypt ¶
Decrypt 使用 AES-256-GCM 解密由 Encrypt 生成的密文。
自动从密文中提取 nonce(前 12 字节),然后进行 GCM 解密和认证。 如果密文被篡改或密钥不匹配,返回错误。 aad 必须与加密时使用的 aad 一致,否则解密失败。
func DecryptStream ¶
DecryptStream 从 r 中读取 EncryptStream 生成的帧格式密文, 使用 AES-256-GCM 解密每个块,并将明文写入 w。
读取格式:先读 4 字节大端序长度获取块密文长度,再读取对应字节数的密文块。 每个密文块格式为 [nonce(12字节) | ciphertext | tag(16字节)], nonce 为块的前 12 字节,用于 GCM 解密。
aad 必须与加密时使用的 aad 一致,否则解密失败。 返回写入 w 的总字节数。当 r 返回 io.EOF(无更多块)时正常结束。 如果任一块解密失败,返回错误。
DecryptStream 等价于 DecryptStreamWithChunkSize(key, r, w, maxChunkLen, aad)。
func DecryptStreamWithChunkSize ¶
func DecryptStreamWithChunkSize(key []byte, r io.Reader, w io.Writer, maxChunkSize int, aad []byte) (int64, error)
DecryptStreamWithChunkSize 与 DecryptStream 行为一致,但允许指定最大块大小 maxChunkSize。
maxChunkSize 为单帧密文最大允许字节数,超出时返回错误,防止恶意超大帧触发 OOM。
func Encrypt ¶
Encrypt 使用 AES-256-GCM 加密明文,并通过 aad 将密文绑定到特定上下文。
返回的密文格式为:nonce(12 字节) + ciphertext + auth_tag(16 字节)。 每次调用生成随机 nonce,相同明文产生不同密文。 aad 是额外认证数据(Additional Authenticated Data),不需要保密,但任何修改都会导致解密失败。 用于防止密文混淆攻击:将密文绑定到特定上下文(如协议版本、流方向)。
func EncryptStream ¶
EncryptStream 从 r 中分块读取数据,使用 AES-256-GCM 独立加密每个块, 并将帧格式的密文写入 w。
帧格式:每个块先写入 4 字节大端序的密文长度,再写入 [nonce(12字节) | ciphertext | tag(16字节)]。 每个块使用随机 nonce 独立加密,块大小为 DefaultChunkSize(64KB), 最后一个块可能小于该值。
aad 是额外认证数据,将每个块密文绑定到特定上下文(如 AADStream)。 返回写入 w 的总字节数。当 r 返回 io.EOF 时正常结束。
EncryptStream 等价于 EncryptStreamWithChunkSize(key, r, w, DefaultChunkSize, aad)。
func EncryptStreamWithChunkSize ¶
func EncryptStreamWithChunkSize(key []byte, r io.Reader, w io.Writer, chunkSize int, aad []byte) (int64, error)
EncryptStreamWithChunkSize 与 EncryptStream 行为一致,但允许指定块大小 chunkSize。
chunkSize 每块的明文大小。较大的块可降低帧头(4 字节长度 + nonce)开销, 但会增大单次分配和加密延迟。
func GenerateKey ¶
GenerateKey 使用 crypto/rand 生成一个随机的 AES-256 密钥,返回 64 字符的十六进制字符串。
生成的密钥可用于配置 sproxy 的 tunnel_key 和 sclient 的 tunnel_key。
Example ¶
package main
import (
"fmt"
"github.com/cocomhub/sproxy/pkg/tunnel"
)
func main() {
key, err := tunnel.GenerateKey()
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("len=%d\n", len(key))
}
Output: len=64
func NewHandler ¶
NewHandler 创建一个仅支持外部转发的加密隧道处理器。
行为同旧版闭包实现。如果 key 为空,处理器直接返回 403 Forbidden。 logger 为 nil 时使用 slog.Default()。 使用方式:mux.Handle("POST /tunnel", tunnel.NewHandler(key))
Example ¶
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"time"
"github.com/cocomhub/sproxy/pkg/tunnel"
)
func main() {
key, _ := tunnel.ParseKey("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
targetServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
w.Write([]byte("target response"))
}))
defer targetServer.Close()
mux := http.NewServeMux()
mux.Handle("POST /tunnel", tunnel.NewHandler(key, nil))
proxyServer := httptest.NewServer(mux)
defer proxyServer.Close()
client, _ := tunnel.NewClient(
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
proxyServer.URL+"/tunnel",
5*time.Second,
nil,
)
req, _ := http.NewRequest("GET", targetServer.URL, nil)
resp, err := client.Do(req)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(resp.Status)
}
Output: 200 OK
func NewLocalHandler ¶
NewLocalHandler 创建一个支持本地路由和外部转发的加密隧道处理器。
当请求 URL 为绝对路径(如 /upload)且在 local 中注册时,直接在当前进程中转发到 local handler; 当请求 URL 为绝对 URL(如 https://example.com/api)时,与原 NewHandler 行为一致。 logger 为 nil 时使用 slog.Default()。
func ParseKey ¶
ParseKey 将十六进制字符串解析为 32 字节的 AES-256 密钥。
hexKey 必须是 64 个十六进制字符(编码 32 字节)。 返回的密钥可直接用于 Encrypt、Decrypt、NewHandler、NewClient。
Example ¶
package main
import (
"fmt"
"github.com/cocomhub/sproxy/pkg/tunnel"
)
func main() {
key, err := tunnel.ParseKey("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("len=%d\n", len(key))
}
Output: len=32
Example (InvalidLength) ¶
package main
import (
"fmt"
"github.com/cocomhub/sproxy/pkg/tunnel"
)
func main() {
_, err := tunnel.ParseKey("00ff")
fmt.Println(err)
}
Output: key must be 32 bytes (64 hex chars)
Types ¶
type Client ¶
type Client struct {
Key []byte
TunnelURL string
HTTPClient *http.Client
// contains filtered or unexported fields
}
Client 是加密隧道客户端,用于向隧道服务端发送加密请求并接收解密响应。
零值不可用,必须通过 NewClient 创建。
func NewClient ¶
func NewClient(hexKey, tunnelURL string, timeout time.Duration, logger *slog.Logger) (*Client, error)
NewClient 创建一个加密隧道客户端。
参数:
- hexKey: 64 位十六进制密钥字符串,与 sproxy 服务端 tunnel_key 一致
- tunnelURL: 隧道服务端地址,如 "http://proxy:8080/tunnel"
- timeout: HTTP 客户端超时时间
- logger: 日志记录器,为 nil 时使用 slog.Default()
如果 hexKey 格式无效(非 64 位十六进制),返回错误。
func (*Client) Do ¶
Do 接受标准 *http.Request,通过加密隧道转发并返回标准 *http.Response。
使用标准库类型,调用方零学习成本。 所有请求/响应统一使用流式帧协议,内存占用恒定(不超过单个加密块大小)。 返回的 *http.Response.Body 为流式 Reader,调用方可边读边消费,关闭时自动释放底层连接。 目标返回非 2xx 状态码时,仍返回 *http.Response(非 error),StatusCode 正确反映目标状态。
Example ¶
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"time"
"github.com/cocomhub/sproxy/pkg/tunnel"
)
func main() {
key, _ := tunnel.ParseKey("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
targetServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Response-Header", "test-value")
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, `{"method":"%s","path":"%s"}`, r.Method, r.URL.Path)
}))
defer targetServer.Close()
mux := http.NewServeMux()
mux.Handle("POST /tunnel", tunnel.NewHandler(key, nil))
proxyServer := httptest.NewServer(mux)
defer proxyServer.Close()
client, _ := tunnel.NewClient(
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
proxyServer.URL+"/tunnel",
5*time.Second,
nil,
)
req, _ := http.NewRequest("GET", targetServer.URL+"/api/hello", nil)
req.Header.Set("X-Custom", "test")
resp, err := client.Do(req)
if err != nil {
fmt.Println("error:", err)
return
}
defer resp.Body.Close()
fmt.Println(resp.StatusCode)
fmt.Println(resp.Header.Get("X-Response-Header"))
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
Output: 200 test-value {"method":"GET","path":"/api/hello"}
Example (LargeBody) ¶
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"net/http/httptest"
"time"
"github.com/cocomhub/sproxy/pkg/tunnel"
)
func main() {
key, _ := tunnel.ParseKey("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
targetServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
fmt.Fprintf(w, `{"size":%d}`, len(body))
}))
defer targetServer.Close()
mux := http.NewServeMux()
mux.Handle("POST /tunnel", tunnel.NewHandler(key, nil))
proxyServer := httptest.NewServer(mux)
defer proxyServer.Close()
client, _ := tunnel.NewClient(
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
proxyServer.URL+"/tunnel",
10*time.Second,
nil,
)
// 使用 ≥ 64KB 的数据验证流式传输(2 个完整 chunk)
largeBody := make([]byte, 128*1024)
for i := range largeBody {
largeBody[i] = byte('A' + (i % 26))
}
req, _ := http.NewRequest("POST", targetServer.URL, bytes.NewReader(largeBody))
req.Header.Set("Content-Type", "application/octet-stream")
resp, err := client.Do(req)
if err != nil {
fmt.Println("error:", err)
return
}
defer resp.Body.Close()
fmt.Println(resp.StatusCode)
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
Output: 200 {"size":131072}
Example (StreamResponse) ¶
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"net/http/httptest"
"time"
"github.com/cocomhub/sproxy/pkg/tunnel"
)
func main() {
key, _ := tunnel.ParseKey("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
const responseSize = 128 * 1024 // 128KB
targetServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
data := make([]byte, responseSize)
for i := range data {
data[i] = byte('Z' - (i % 26))
}
w.WriteHeader(http.StatusOK)
w.Write(data)
}))
defer targetServer.Close()
mux := http.NewServeMux()
mux.Handle("POST /tunnel", tunnel.NewHandler(key, nil))
proxyServer := httptest.NewServer(mux)
defer proxyServer.Close()
client, _ := tunnel.NewClient(
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
proxyServer.URL+"/tunnel",
10*time.Second,
nil,
)
req, _ := http.NewRequest("GET", targetServer.URL, nil)
resp, err := client.Do(req)
if err != nil {
fmt.Println("error:", err)
return
}
defer resp.Body.Close()
// 流式消费:io.Copy 边解密边读,内存占用恒定
var buf bytes.Buffer
n, err := io.Copy(&buf, resp.Body)
if err != nil {
fmt.Println("copy error:", err)
return
}
fmt.Println(resp.StatusCode)
fmt.Println(n == responseSize)
}
Output: 200 true
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler 处理加密隧道请求,支持外部转发和本地路由两种模式。
外部转发(默认):将加密请求解密后转发到外部目标 URL。 本地路由:当配置了 localHandler 且请求 URL 为相对路径时,将请求直接路由到本地 handler。
两种模式统一使用流式帧协议,响应体通过 Pipe 流式加密,不缓冲在内存中。
密钥轮换:通过 UpdateKey 可运行时热替换密钥,旧密钥保留短时窗口供存量连接完成。 所有新加密使用新密钥;解密时先尝试新密钥,不匹配则尝试旧密钥。 重放保护:ServiceHTTP 中解析 metadata 后调用 replayProtector.Validate 检测重放攻击。
type ReplayProtector ¶
type ReplayProtector struct {
// contains filtered or unexported fields
}
ReplayProtector 用于检测和拒绝重放的隧道帧。
type Request ¶
type Request struct {
Method string `json:"method"`
URL string `json:"url"`
Headers map[string]string `json:"headers"`
IAT int64 `json:"iat,omitempty"` // 签发时间(Unix 秒),用于重放保护
JTI string `json:"jti,omitempty"` // 请求唯一 ID(hex 16 字节),用于重放保护
}
Request 表示一个加密隧道请求,包含要转发到目标服务器的 HTTP 请求信息。
Example ¶
package main
import (
"fmt"
"github.com/cocomhub/sproxy/pkg/tunnel"
)
func main() {
req := &tunnel.Request{
Method: "POST",
URL: "https://api.example.com/echo",
Headers: map[string]string{"Content-Type": "application/json"},
}
fmt.Println(req.Method)
fmt.Println(req.URL)
fmt.Println(req.Headers["Content-Type"])
}
Output: POST https://api.example.com/echo application/json
type Response ¶
type Response struct {
Proto string `json:"proto"`
Status int `json:"status"`
Headers http.Header `json:"headers"`
ContentLength int64 `json:"content_length"`
}
Response 表示加密隧道响应,包含目标服务器返回的 HTTP 响应信息。
Example ¶
package main
import (
"fmt"
"net/http"
"github.com/cocomhub/sproxy/pkg/tunnel"
)
func main() {
resp := tunnel.Response{
Status: 200,
Headers: http.Header{
"Content-Type": {"application/json"},
},
}
fmt.Println(resp.Status)
fmt.Println(resp.Headers.Get("Content-Type"))
}
Output: 200 application/json
type StreamDecryptor ¶
type StreamDecryptor struct {
// contains filtered or unexported fields
}
StreamDecryptor 封装 AES-256-GCM 流式解密。
func NewStreamDecryptor ¶
func NewStreamDecryptor(key []byte, maxChunkLen int) (*StreamDecryptor, error)
NewStreamDecryptor 创建流解密器。
func (*StreamDecryptor) DecryptChunk ¶
DecryptChunk 从 r 中读取一个加密块并使用 aad 解密,将明文写入 w。 aad 必须与加密时使用的 aad 一致,否则解密失败。
func (*StreamDecryptor) DecryptStream ¶
DecryptStream 从 r 中读取并解密流,将明文写入 w。 每个块使用 aad 作为 GCM 的额外认证数据。
type StreamEncryptor ¶
type StreamEncryptor struct {
// contains filtered or unexported fields
}
StreamEncryptor 封装 AES-256-GCM 流式加密。
func NewStreamEncryptor ¶
func NewStreamEncryptor(key []byte, chunkSize int) (*StreamEncryptor, error)
NewStreamEncryptor 创建流加密器。
func (*StreamEncryptor) EncryptChunk ¶
EncryptChunk 加密 single plaintext 块并写入 w。 使用 aad 作为 GCM 的额外认证数据,将密文绑定到特定上下文。 返回写入的字节数(4B 长度前缀 + nonce + ciphertext + tag)。
func (*StreamEncryptor) EncryptStream ¶
EncryptStream 使用流加密器从 r 中分块读取数据并加密写入 w。 每个块使用 aad 作为 GCM 的额外认证数据。 返回写入 w 的总字节数。
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package hub 提供中继网络的核心类型与接口。
|
Package hub 提供中继网络的核心类型与接口。 |
|
Package p2p provides a peer-to-peer transport layer that combines DHT discovery with WebRTC transport and stream multiplexing into a complete P2P link.
|
Package p2p provides a peer-to-peer transport layer that combines DHT discovery with WebRTC transport and stream multiplexing into a complete P2P link. |
|
Package tracing provides a lightweight OpenTelemetry-like tracing skeleton built on standard log/slog, with no external dependencies.
|
Package tracing provides a lightweight OpenTelemetry-like tracing skeleton built on standard log/slog, with no external dependencies. |
|
Package xfer 定义传输层抽象接口和注册表。
|
Package xfer 定义传输层抽象接口和注册表。 |
|
internal/tcp
Package tcp 提供基于 TCP 的 xfer.Conn 传输层实现。
|
Package tcp 提供基于 TCP 的 xfer.Conn 传输层实现。 |
|
xfertest
Package xfertest 提供 xfer.Conn 的测试工具。
|
Package xfertest 提供 xfer.Conn 的测试工具。 |
|
ext/webrtc
module
|