//go:build windows package windows import ( "errors" "path/filepath" "golang.org/x/sys/windows" "golang.org/x/sys/windows/registry" ) const machineGUIDRegistryPath = `SOFTWARE\Microsoft\Cryptography` // MachineHash reads the two required Windows identifiers only for the duration // of this call and returns their derived licensing hash. func MachineHash() (string, error) { return machineHashFrom(readMachineGUID, readSystemVolumeSerial) } func readMachineGUID() (string, error) { key, err := registry.OpenKey(registry.LOCAL_MACHINE, machineGUIDRegistryPath, registry.QUERY_VALUE) if err != nil { return "", err } defer key.Close() value, _, err := key.GetStringValue("MachineGuid") if err != nil { return "", err } return value, nil } func readSystemVolumeSerial() (uint32, error) { windowsDirectory, err := windows.GetWindowsDirectory() if err != nil { return 0, err } volumeName := filepath.VolumeName(windowsDirectory) if len(volumeName) != 2 || volumeName[1] != ':' || !isASCIIAlpha(volumeName[0]) { return 0, errors.New("windows directory is not on a drive volume") } root, err := windows.UTF16PtrFromString(volumeName + `\`) if err != nil { return 0, err } var serial uint32 if err := windows.GetVolumeInformation(root, nil, 0, &serial, nil, nil, nil, 0); err != nil { return 0, err } return serial, nil } func isASCIIAlpha(character byte) bool { return character >= 'a' && character <= 'z' || character >= 'A' && character <= 'Z' }