Implemented a slightly more secure handling of GMSA passwords.

This commit is contained in:
Michael Grafnetter 2019-01-08 16:40:40 +01:00
parent 8e2a188632
commit ca52581151
2 changed files with 43 additions and 13 deletions

View File

@ -1,9 +1,9 @@
using System;
using System.IO;
using System.Text;
namespace DSInternals.Common.Data
namespace DSInternals.Common.Data
{
using System;
using System.IO;
using System.Security;
/// <summary>
/// Represents a group-managed service account's password information.
/// </summary>
@ -25,6 +25,17 @@ namespace DSInternals.Common.Data
/// Gets the current password.
/// </summary>
public string CurrentPassword
{
get
{
return this.SecureCurrentPassword.ToUnicodeString();
}
}
/// <summary>
/// Gets the current password.
/// </summary>
public SecureString SecureCurrentPassword
{
get;
private set;
@ -34,6 +45,17 @@ namespace DSInternals.Common.Data
/// Gets the previous password.
/// </summary>
public string PreviousPassword
{
get
{
return this.SecurePreviousPassword.ToUnicodeString();
}
}
/// <summary>
/// Gets the previous password.
/// </summary>
public SecureString SecurePreviousPassword
{
get;
private set;
@ -86,13 +108,13 @@ namespace DSInternals.Common.Data
// A 16-bit offset, in bytes, from the beginning of this structure to the CurrentPassword field. The CurrentPasswordOffset field MUST NOT be set to 0x0000.
short currentPasswordOffset = reader.ReadInt16();
this.CurrentPassword = blob.ReadWString(currentPasswordOffset);
this.SecureCurrentPassword = blob.ReadSecureWString(currentPasswordOffset);
// A 16-bit offset, in bytes, from the beginning of this structure to the PreviousPassword field. If this field is set to 0x0000, then the account has no previous password.
short previousPasswordOffset = reader.ReadInt16();
if(previousPasswordOffset > 0)
{
this.PreviousPassword = blob.ReadWString(previousPasswordOffset);
this.SecurePreviousPassword = blob.ReadSecureWString(previousPasswordOffset);
}
// A 16-bit offset, in bytes, from the beginning of this structure to the QueryPasswordInterval field.

View File

@ -2,6 +2,7 @@
{
using System;
using System.IO;
using System.Security;
using System.Security.Principal;
using System.Text;
@ -62,22 +63,29 @@
}
}
public static string ReadWString(this byte[] buffer, int startIndex)
public static SecureString ReadSecureWString(this byte[] buffer, int startIndex)
{
Validator.AssertNotNull(buffer, "buffer");
Validator.AssertNotNull(buffer, nameof(buffer));
// TODO: Assert startIndex > 0
int maxLength = buffer.Length - startIndex;
var sb = new StringBuilder(maxLength);
// Prepare an empty SecureString that will eventually be returned
var result = new SecureString();
for (int i = startIndex; i < buffer.Length; i += UnicodeEncoding.CharSize)
{
// Convert the next 2 bytes from the byte array into a unicode character
char c = BitConverter.ToChar(buffer, i);
if (c == Char.MinValue)
{
// End of string reached
return sb.ToString();
// End of string has been reached
return result;
}
sb.Append(c);
result.AppendChar(c);
}
// If we reached this point, the \0 char has not been found, so throw an exception.
// TODO: Add a reasonable exception message
throw new ArgumentException();