You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
48 lines
1.6 KiB
48 lines
1.6 KiB
package controlplane
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
// protectSecret binds encrypted data to the current Windows user through DPAPI.
|
|
// The database stores only this encrypted blob, never a plaintext Provider key.
|
|
func protectSecret(value string) ([]byte, error) {
|
|
input := []byte(value)
|
|
if len(input) == 0 {
|
|
return nil, fmt.Errorf("API Key 不能为空")
|
|
}
|
|
inputBlob := windows.DataBlob{Size: uint32(len(input)), Data: &input[0]}
|
|
var outputBlob windows.DataBlob
|
|
if err := windows.CryptProtectData(
|
|
&inputBlob, nil, nil, 0, nil, windows.CRYPTPROTECT_UI_FORBIDDEN, &outputBlob,
|
|
); err != nil {
|
|
return nil, fmt.Errorf("无法使用 Windows 数据保护保存 API Key: %w", err)
|
|
}
|
|
defer windows.LocalFree(windows.Handle(uintptr(unsafe.Pointer(outputBlob.Data))))
|
|
protected := unsafe.Slice(outputBlob.Data, int(outputBlob.Size))
|
|
result := append([]byte(nil), protected...)
|
|
runtime.KeepAlive(input)
|
|
return result, nil
|
|
}
|
|
|
|
func unprotectSecret(protected []byte) (string, error) {
|
|
if len(protected) == 0 {
|
|
return "", fmt.Errorf("未找到 API Key")
|
|
}
|
|
inputBlob := windows.DataBlob{Size: uint32(len(protected)), Data: &protected[0]}
|
|
var outputBlob windows.DataBlob
|
|
if err := windows.CryptUnprotectData(
|
|
&inputBlob, nil, nil, 0, nil, windows.CRYPTPROTECT_UI_FORBIDDEN, &outputBlob,
|
|
); err != nil {
|
|
return "", fmt.Errorf("无法读取受保护的 API Key: %w", err)
|
|
}
|
|
defer windows.LocalFree(windows.Handle(uintptr(unsafe.Pointer(outputBlob.Data))))
|
|
plain := unsafe.Slice(outputBlob.Data, int(outputBlob.Size))
|
|
result := string(plain)
|
|
runtime.KeepAlive(protected)
|
|
return result, nil
|
|
}
|
|
|