Severity: Info
File: src/Servy.Core/Security/ProtectedKeyProvider.cs:118-137
Code:
```csharp
private static byte[] GetMachineEntropy()
{
using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Cryptography"))
{
var guid = key?.GetValue("MachineGuid") as string;
if (!string.IsNullOrWhiteSpace(guid))
{
return Encoding.UTF8.GetBytes(guid);
}
Logger.Error(\"CRITICAL SECURITY DEGRADATION: 'MachineGuid' registry key is missing or inaccessible. \" +
\"Falling back to predictable Environment.MachineName for DPAPI entropy. \" +
\"This reduces protection against offline attacks.\");
return Encoding.UTF8.GetBytes(Environment.MachineName);
}
}
```
Explanation:
The path `SOFTWARE\Microsoft\Cryptography` exists in the 64-bit view of the registry only — `MachineGuid` is not present in the WoW6432Node mirror. `Registry.LocalMachine.OpenSubKey(...)` follows the WoW64 redirection rules of the current process, so:
- 64-bit Servy process → reads the real `HKLM\SOFTWARE\Microsoft\Cryptography\MachineGuid` (works, today's case for x64 builds)
- 32-bit process loading the same assembly (e.g. a future x86 build, or a third-party tool importing `Servy.Core`) → reads `HKLM\SOFTWARE\WoW6432Node\Microsoft\Cryptography\MachineGuid`, which is empty → silently falls back to `Environment.MachineName`.
The fallback is logged loudly, but the encryption key is still derived from a low-entropy, easily guessable source (`MachineName` is often `DESKTOP-XXXXXXX` or a fleet-wide naming scheme). Anyone who can see the source code and the file knows the entropy.
The code is correct in practice today because the published artifacts target `win-x64` (per AppConfig.cs:84), but the registry call is bitness-dependent and there is no guard preventing a 32-bit caller from silently downgrading the entropy. Worse, a 32-bit caller is the exact case where the loud error message would fire — so anyone reading their logs for the first time after a bitness migration gets a vague "key inaccessible" message rather than "the lookup is bitness-redirected."
Suggested fix:
Force the 64-bit registry view explicitly so the call is bitness-independent:
```csharp
private static byte[] GetMachineEntropy()
{
using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
using (var key = hklm.OpenSubKey(@"SOFTWARE\Microsoft\Cryptography"))
{
var guid = key?.GetValue("MachineGuid") as string;
if (!string.IsNullOrWhiteSpace(guid))
return Encoding.UTF8.GetBytes(guid);
Logger.Error(\"CRITICAL SECURITY DEGRADATION: 'MachineGuid' registry key is missing or inaccessible. \" +
\"Falling back to predictable Environment.MachineName for DPAPI entropy.\");
return Encoding.UTF8.GetBytes(Environment.MachineName);
}
}
```
`RegistryView.Registry64` works from both 32-bit and 64-bit processes on 64-bit Windows, and degrades gracefully on 32-bit-only OSes (which Servy doesn't target anyway).
Severity: Info
File: src/Servy.Core/Security/ProtectedKeyProvider.cs:118-137
Code:
```csharp
private static byte[] GetMachineEntropy()
{
using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Cryptography"))
{
var guid = key?.GetValue("MachineGuid") as string;
}
```
Explanation:
The path `SOFTWARE\Microsoft\Cryptography` exists in the 64-bit view of the registry only — `MachineGuid` is not present in the WoW6432Node mirror. `Registry.LocalMachine.OpenSubKey(...)` follows the WoW64 redirection rules of the current process, so:
The fallback is logged loudly, but the encryption key is still derived from a low-entropy, easily guessable source (`MachineName` is often `DESKTOP-XXXXXXX` or a fleet-wide naming scheme). Anyone who can see the source code and the file knows the entropy.
The code is correct in practice today because the published artifacts target `win-x64` (per AppConfig.cs:84), but the registry call is bitness-dependent and there is no guard preventing a 32-bit caller from silently downgrading the entropy. Worse, a 32-bit caller is the exact case where the loud error message would fire — so anyone reading their logs for the first time after a bitness migration gets a vague "key inaccessible" message rather than "the lookup is bitness-redirected."
Suggested fix:
Force the 64-bit registry view explicitly so the call is bitness-independent:
```csharp
private static byte[] GetMachineEntropy()
{
using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
using (var key = hklm.OpenSubKey(@"SOFTWARE\Microsoft\Cryptography"))
{
var guid = key?.GetValue("MachineGuid") as string;
}
```
`RegistryView.Registry64` works from both 32-bit and 64-bit processes on 64-bit Windows, and degrades gracefully on 32-bit-only OSes (which Servy doesn't target anyway).