Files

50 lines
1.1 KiB
Go

//go:build windows
package winapi
import (
"fmt"
"unsafe"
)
var (
procCryptUnprotectData = Crypt32.NewProc("CryptUnprotectData")
procLocalFree = Kernel32.NewProc("LocalFree")
)
// dataBlob mirrors the DPAPI DATA_BLOB struct.
type dataBlob struct {
cbData uint32
pbData *byte
}
func newBlob(d []byte) *dataBlob {
if len(d) == 0 {
return &dataBlob{}
}
return &dataBlob{pbData: &d[0], cbData: uint32(len(d))}
}
func (b *dataBlob) bytes() []byte {
d := make([]byte, b.cbData)
copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
return d
}
// DecryptDPAPI decrypts a DPAPI-protected blob using the current user's
// master key. It is the Windows counterpart to macOS/Linux os_crypt
// fallbacks and is called by crypto.DecryptDPAPI.
func DecryptDPAPI(ciphertext []byte) ([]byte, error) {
var out dataBlob
r, _, err := procCryptUnprotectData.Call(
uintptr(unsafe.Pointer(newBlob(ciphertext))),
0, 0, 0, 0, 0,
uintptr(unsafe.Pointer(&out)),
)
if r == 0 {
return nil, fmt.Errorf("CryptUnprotectData: %w", err)
}
defer procLocalFree.Call(uintptr(unsafe.Pointer(out.pbData)))
return out.bytes(), nil
}