74 lines
1.6 KiB
Go
74 lines
1.6 KiB
Go
//go:build windows
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
type dataBlob struct {
|
|
cbData uint32
|
|
pbData *byte
|
|
}
|
|
|
|
var (
|
|
crypt32DLL = syscall.NewLazyDLL("crypt32.dll")
|
|
kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
|
|
cryptProtectData = crypt32DLL.NewProc("CryptProtectData")
|
|
unprotect = crypt32DLL.NewProc("CryptUnprotectData")
|
|
localFree = kernel32DLL.NewProc("LocalFree")
|
|
)
|
|
|
|
func protectData(data []byte) ([]byte, error) {
|
|
if len(data) == 0 {
|
|
return nil, fmt.Errorf("empty data")
|
|
}
|
|
input := dataBlob{cbData: uint32(len(data)), pbData: &data[0]}
|
|
var output dataBlob
|
|
result, _, err := cryptProtectData.Call(
|
|
uintptr(unsafe.Pointer(&input)),
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
uintptr(unsafe.Pointer(&output)),
|
|
)
|
|
if result == 0 {
|
|
return nil, fmt.Errorf("CryptProtectData failed: %w", err)
|
|
}
|
|
defer localFree.Call(uintptr(unsafe.Pointer(output.pbData)))
|
|
return cloneBlob(output), nil
|
|
}
|
|
|
|
func unprotectData(data []byte) ([]byte, error) {
|
|
if len(data) == 0 {
|
|
return nil, fmt.Errorf("empty data")
|
|
}
|
|
input := dataBlob{cbData: uint32(len(data)), pbData: &data[0]}
|
|
var output dataBlob
|
|
result, _, err := unprotect.Call(
|
|
uintptr(unsafe.Pointer(&input)),
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
uintptr(unsafe.Pointer(&output)),
|
|
)
|
|
if result == 0 {
|
|
return nil, fmt.Errorf("CryptUnprotectData failed: %w", err)
|
|
}
|
|
defer localFree.Call(uintptr(unsafe.Pointer(output.pbData)))
|
|
return cloneBlob(output), nil
|
|
}
|
|
|
|
func cloneBlob(blob dataBlob) []byte {
|
|
if blob.pbData == nil || blob.cbData == 0 {
|
|
return nil
|
|
}
|
|
return append([]byte(nil), unsafe.Slice(blob.pbData, int(blob.cbData))...)
|
|
}
|