Я разрабатываю инструмент для импорта профилей Outlook с использованием файла PRF, но он не импортирует пароль, поэтому мне нужно вручную добавить его в реестр.
Я потратил много часов на чтение, тестирование и отладку этой процедуры и сумел выяснить, как все работает, за исключением того, что Outlook отказывается от пароля, сгенерированного CryptProtectData(). Я пробовал использовать как С#.NET-оболочку ProtectedData.Protect(), так и DLL-библиотеку C++, вызывающую CryptProtectData(), но безрезультатно.
Всякий раз, когда я меняю пароль в реестре и открываю Outlook, он показывает диалог учетных данных. Если я наберу пароль, он успешно войдет в мой адрес электронной почты.
Вот код С#, использующий оболочку.NET:
RegistryKey RegKey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows Messaging Subsystem\\Profiles\\MyProfile\\9375CFF0413111d3B88A00104B2A6676\\0000000b", true);
Byte[] Password = Encoding.UTF8.GetBytes("MyPassword");
Byte[] EncPassword = ProtectedData.Protect(Password, null, DataProtectionScope.CurrentUser);
RegKey.SetValue("IMAP Password", EncPassword);
Этот код генерирует двоичные данные с 234 байтами, что на 39 байт меньше пароля, сгенерированного Outlook (273 байта).
Вот код C++:
extern "C" DLLEXPORT DATA_BLOB crypt(BYTE *input) {
DATA_BLOB DataIn;
DATA_BLOB DataOut;
BYTE *pbDataInput = input;
DWORD cbDataInput = strlen((char *)pbDataInput)+1;
DataIn.pbData = pbDataInput;
DataIn.cbData = cbDataInput;
if( !CryptProtectData(&DataIn, L"IMAP Password", NULL, NULL, NULL, 0, &DataOut) )
{
printf("Encryption error");
}
return DataOut;
}
Код С#, вызывающий DLL:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DATA_BLOB
{
public int cbData;
public IntPtr pbData;
}
[DllImport("MyLib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern DATA_BLOB crypt(Byte[] input);
(...)
RegistryKey RegKey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows Messaging Subsystem\\Profiles\\MyProfile\\9375CFF0413111d3B88A00104B2A6676\\0000000b", true);
Byte[] Password = Encoding.UTF8.GetBytes("MyPassword");
DATA_BLOB BlobData = crypt(Encoding.UTF8.GetBytes("MyPassword"));
Byte[] EncPassword = new Byte[BlobData.cbData];
Marshal.Copy(BlobData.pbData, EncPassword, 0, BlobData.cbData);
RegKey.SetValue("IMAP Password", EncPassword);
Этот код генерирует пароль с 256 байтами, но не 273 байта, которые я получаю из Outlook.
Я предполагаю, что эти недостающие байты относятся к определенной энтропии, которую я не использую, или даже к некоторым деталям, которые мне не хватает.
Любой наконечник в правильном направлении поможет много.
Спасибо!