Skip to content

Commit

Permalink
React gracefully if credentials cannot be decrypted
Browse files Browse the repository at this point in the history
If credentials were stored in the registry with a different/
old DPAPI key, a CryptographicException was thrown.

Handle situation gracefully by ignoring undecypherable
credentials.

Change-Id: I312b2d813fd44141cc6e51f20aa45c436eb49045
  • Loading branch information
Johannes Passing authored and jpassing committed Nov 28, 2019
1 parent 39da9dc commit 56dc8fa
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 8 deletions.
34 changes: 34 additions & 0 deletions Google.Solutions.Compute.Test/Auth/TestRegistryStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,40 @@ public async Task GetNonexistingKeyReturnsNull()
}
}

[Test]
public async Task GetUndecypherableValueReturnsNull()
{
// Store a value as if it had been encrypted with a different user's
// DPAPI key.
var valueFromOtherUser =
"AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAmr8hZDsnM0KybdI4HPGUBgAAAAACAAAAAAAQZgAAAAEAACA" +
"AAACl7vLBymJHa5kqvN5PBSTf2TXOvEL6rqYwF5AlRrgU8gAAAAAOgAAAAAIAACAAAACHJPnnyoGjDQ" +
"UkKzbfmj5N7QQOE7izdhTIkuC6JDAYHNABAAAUdpXRCzMR2JVCQWe4FfQ/eeXYPhAndmTYSXHGFgr3N" +
"r8ezULrsoc7Gic09DVEDV+t8MaTylYEizioq02gw0tX+23cPr8XlVlevxsfZw/CP35Ghi4C9maFOic8" +
"AB7jZbaRXIbH4FWWksHmkBwNQ8uBWkgkmU8+X6NvBmJfIwcJ8nfPeJKQTzYbc8frapzqYfI3ynaa0t4" +
"9YfMd1cLKGHM5Tldv0W+BS/lu3/vG3l1PXfzIYEuCg26jvCOmsBHS3f6ga3WCk8wd26f6GYKcbcXdju" +
"euigofnzC56uoayxp5Ii5sBNS8JBXmi5g9AJUB3gK/falkf52xgizONB1dQFMVFHIaj6AKFxZwDD8wH" +
"chzUthGPJDqvHlPWOGfPILc5poSfUBsh9oRcMTxlMhh+r8tpV+ZsOsbc3uIaLw8pXTwE5Z3UcoXxek0" +
"99AA7I8CxBVYsRePwE9KSKX20mjATBUmCd0HOwmjh+F1zJK3DKMpjf1iGRHSjXxhay+Hxe8OvuJljxE" +
"PzxQnCqTASbyUsnQQVDXtGLk6VJ0t/YT+B6wEOj3st+ZYmzBrOsPnsJLMSoOTQZ6+Lujpn4TGUeBtU1" +
"GgqeTKoJG12J2SJyCvC9JK1UAAAABCgq/Mh/8A0GwpSpd44z/ydevpy8CUqmhZjsMNjT9eSRKCgErFh" +
"PQmR4JrkL/eZfSr39sq72OrwLKZaOOM893a";

using (var key = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default)
.CreateSubKey(RegistryPath, true))
{
key.SetValue("otheruser", Convert.FromBase64String(valueFromOtherUser));
//var val= (byte[])key.GetValue("oauth");
//var b64 = Convert.ToBase64String(val);
//b64.ToString();
}

using (var store = new RegistryStore(RegistryHive.CurrentUser, RegistryPath))
{
Assert.IsNull(await store.GetAsync<TokenResponse>("otheruser"));
}
}

[Test]
public async Task DeleteExistingKeySucceeds()
{
Expand Down
27 changes: 19 additions & 8 deletions Google.Solutions.Compute/Auth/RegistryStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,25 @@ public Task<T> GetAsync<T>(string entryKey)

if (encryptedValue is byte[] encryptedValueBytes)
{
var plaintextString = Encoding.UTF8.GetString(
ProtectedData.Unprotect(
(byte[])encryptedValue,
Encoding.UTF8.GetBytes(entryKey),
this.ProtectionScope));

return Task.FromResult(
NewtonsoftJsonSerializer.Instance.Deserialize<T>(plaintextString));
try
{
var plaintextString = Encoding.UTF8.GetString(
ProtectedData.Unprotect(
(byte[])encryptedValue,
Encoding.UTF8.GetBytes(entryKey),
this.ProtectionScope));

return Task.FromResult(
NewtonsoftJsonSerializer.Instance.Deserialize<T>(plaintextString));
}
catch (CryptographicException)
{
// Value cannot be decrypted. This can happen if it was
// written by a different user or if the current user's
// key has changed (for example, because its credentials
// been reset on GCE).
return Task.FromResult(default(T));
}
}
else
{
Expand Down

0 comments on commit 56dc8fa

Please sign in to comment.