//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))...) }