C#密码未正确加密

时间:2011-07-11 17:13:20

标签: c#

我尝试使用crypt32.dll加密.rdp文件中的密码,如下所示:

internal static class CryptPassword
{
#region KeyType enum

public enum KeyType
{
UserKey = 1,
MachineKey
} ;

#endregion

private const int CRYPTPROTECT_LOCAL_MACHINE = 0x4;
private const int CRYPTPROTECT_UI_FORBIDDEN = 0x1;
private static readonly IntPtr NullPtr = ((IntPtr)((0)));
private static KeyType defaultKeyType = KeyType.UserKey;

public static byte[] DoRawEncryption(string strToEncrypt)
{
byte[] cryptBytes = Encrypt(KeyType.UserKey, Encoding.UTF8.GetBytes(strToEncrypt), null, null);

return cryptBytes;
}

// Wrapper for DPAPI CryptProtectData function.
[DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool CryptProtectData(ref DATA_BLOB pPlainText, string szDescription, ref DATA_BLOB pEntropy, IntPtr pReserved, ref CRYPTPROTECT_PROMPTSTRUCT pPrompt, int dwFlags, ref DATA_BLOB pCipherText);

// Wrapper for DPAPI CryptUnprotectData function.
[DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool CryptUnprotectData(ref DATA_BLOB pCipherText, ref string pszDescription, ref DATA_BLOB pEntropy, IntPtr pReserved, ref CRYPTPROTECT_PROMPTSTRUCT pPrompt, int dwFlags, ref DATA_BLOB pPlainText);

// BLOB structure used to pass data to DPAPI functions.

private static void InitPrompt(ref CRYPTPROTECT_PROMPTSTRUCT ps)
{
ps.cbSize = Marshal.SizeOf(typeof(CRYPTPROTECT_PROMPTSTRUCT));
ps.dwPromptFlags = 0;
ps.hwndApp = NullPtr;
ps.szPrompt = null;
}

private static void InitBLOB(byte[] data, ref DATA_BLOB blob)
{
// Use empty array for null parameter.
if (data == null)
data = new byte[0];

// Allocate memory for the BLOB data.
blob.pbData = Marshal.AllocHGlobal(data.Length);

// Make sure that memory allocation was successful.
if (blob.pbData == IntPtr.Zero)
throw new Exception("Unable to allocate data buffer for BLOB structure.");

// Specify number of bytes in the BLOB.
blob.cbData = data.Length;

// Copy data from original source to the BLOB structure.
Marshal.Copy(data, 0, blob.pbData, data.Length);
}

public static string Encrypt(string plainText)
{
return Encrypt(defaultKeyType, plainText, String.Empty, String.Empty);
}

public static string Encrypt(KeyType keyType, string plainText)
{
return Encrypt(keyType, plainText, String.Empty, String.Empty);
}

public static string Encrypt(KeyType keyType, string plainText, string entropy)
{
return Encrypt(keyType, plainText, entropy, String.Empty);
}

public static string Encrypt(KeyType keyType, string plainText, string entropy, string description)
{
// Make sure that parameters are valid.
if (plainText == null) plainText = String.Empty;
if (entropy == null) entropy = String.Empty;

// Call encryption routine and convert returned bytes into a base64-encoded value.
return Convert.ToBase64String(Encrypt(keyType, Encoding.UTF8.GetBytes(plainText), Encoding.UTF8.GetBytes(entropy), description));
}

public static byte[] Encrypt(KeyType keyType, byte[] plainTextBytes, byte[] entropyBytes, string description)
{
// Make sure that parameters are valid.
if (plainTextBytes == null) plainTextBytes = new byte[0];
if (entropyBytes == null) entropyBytes = new byte[0];
if (description == null) description = String.Empty;

// Create BLOBs to hold data.
DATA_BLOB plainTextBlob = new DATA_BLOB();
DATA_BLOB cipherTextBlob = new DATA_BLOB();
DATA_BLOB entropyBlob = new DATA_BLOB();

// We only need prompt structure because it is a required
// parameter.
CRYPTPROTECT_PROMPTSTRUCT prompt = new CRYPTPROTECT_PROMPTSTRUCT();
InitPrompt(ref prompt);

try
{
// Convert plaintext bytes into a BLOB structure.
try
{
InitBLOB(plainTextBytes, ref plainTextBlob);
}
catch (Exception ex)
{
throw new Exception("Cannot initialize plaintext BLOB.", ex);
}

// Convert entropy bytes into a BLOB structure.
try
{
InitBLOB(entropyBytes, ref entropyBlob);
}
catch (Exception ex)
{
throw new Exception("Cannot initialize entropy BLOB.", ex);
}

// Disable any types of UI.
int flags = CRYPTPROTECT_UI_FORBIDDEN;

// When using machine-specific key, set up machine flag.
if (keyType == KeyType.MachineKey)
flags |= CRYPTPROTECT_LOCAL_MACHINE;

// Call DPAPI to encrypt data.
bool success = CryptProtectData(ref plainTextBlob, description, ref entropyBlob, IntPtr.Zero, ref prompt, flags, ref cipherTextBlob);
// Check the result.
if (!success)
{
// If operation failed, retrieve last Win32 error.
int errCode = Marshal.GetLastWin32Error();

// Win32Exception will contain error message corresponding to the Windows error code.
throw new Exception("CryptProtectData failed.");
}

// Allocate memory to hold ciphertext.
byte[] cipherTextBytes = new byte[cipherTextBlob.cbData];

// Copy ciphertext from the BLOB to a byte array.
Marshal.Copy(cipherTextBlob.pbData, cipherTextBytes, 0, cipherTextBlob.cbData);

// Return the result.
return cipherTextBytes;
}
catch (Exception ex)
{
throw new Exception("DPAPI was unable to encrypt data.", ex);
}
// Free all memory allocated for BLOBs.
finally
{
if (plainTextBlob.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(plainTextBlob.pbData);

if (cipherTextBlob.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(cipherTextBlob.pbData);

if (entropyBlob.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(entropyBlob.pbData);
}
}

#region Nested type: CRYPTPROTECT_PROMPTSTRUCT

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct CRYPTPROTECT_PROMPTSTRUCT
{
public int cbSize;
public int dwPromptFlags;
public IntPtr hwndApp;
public string szPrompt;
}
#endregion

#region Nested type: DATA_BLOB

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct DATA_BLOB
{
public int cbData;
public IntPtr pbData;
}
#endregion
}

并将其命名如下:

class Program
{
    public static String EncryptedPassword;
    static void Main(string[] args)
    {
        byte[] cryptBytes = CryptPassword.DoRawEncryption("t");
        EncryptedPassword = Encoding.UTF8.GetString(cryptBytes);
        EncryptedPassword = BitConverter.ToString(cryptBytes).Replace("-", "");

    }
}

问题是结果与.rdp加密不匹配:

代码加密结果:

01000000D08C9DDF0115D1118C7A00C04FC297EB01000000085A862EC951114CAEDC00A80522CC48000000000
2000000000003660000A800000010000000D20EDDD67EC1BB9F0B1E996CA4A1930A0000000004800000A00000
00100000003B458BC56D4D6C81CFD7CE797D31353C08000000A523707EC1C6963A14000000F1918840B926CF4
887085B0FCFA5A1AD8E929D30

使用http://www.remkoweijnen.nl/blog/2007/10/18/how-rdp-passwords-are-encrypted/加密

演示转换器应用程序是:

01000000D08C9DDF0115D1118C7A00C04FC297EB010000002D0779E40801FB4984E12A8A519D599904000
00008000000700073007700000003660000A800000010000000A9ABEDB349D432ECB0CC8CCF337ECB0F00
00000004800000A00000001000000015F29360976A00EA2E85E9A1BBD9E123080000006C8B090A9CD09B7
5140000003C77984DAD4134987D16113AF4FF0DF8BBBD392C

请帮忙!

1 个答案:

答案 0 :(得分:4)

我不得不这样做一段时间,我做的有点不同,但一个关键的事情是:你需要在你的GetBytes调用中使用Unicode,而不是UTF8。