Почему я получаю разные результаты при шифровании с использованием DPAPI? - PullRequest
6 голосов
/ 19 сентября 2009

Я использую DPAPI в C ++ для шифрования некоторых данных, которые мне нужно сохранить в файле. Дело в том, что мне нужно прочитать этот файл из C #, поэтому мне нужно:

C ++ шифрование, C ++ расшифровка (работает хорошо)

C # шифрование, C # расшифровка (работает хорошо)

C ++ шифрование, C # дешифрование и наоборот (не работает)

В C # я использую DllImport для pInvoke методов CryptProtectData и CryptUnprotectData, и я реализую их, как объяснено здесь . Я знаю, что в C # я могу использовать методы, содержащиеся в классе ProtectedData, но я делаю это таким образом (используя DllImport), чтобы убедиться, что оба кода (c ++ и c #) выглядят и работают примерно одинаково.

Теперь странная вещь заключается в том, что даже если оба кода выглядят одинаково, я получаю разные выходные данные, например для этого текста:

"обычный текст"

в C ++ я получаю:

01 00 00 00 D0 8C 9D DF 01 15 D1 11 8C 7A 00 C0 4F C2 97 EB 01 00 00 00 2E 6F 88 86 E6 16 9B 4F 9B BF 35 DA 9F C6 EC 12 00 00 00 00 02 00 00 00 00 00 03 66 00 00 A8 00 00 00 10 00 00 00 93 06 68 39 DB 58 FE E9 C4 1F B0 3D 7B 0A B7 48 00 00 00 00 04 80 00 00 A0 00 00 00 10 00 00 00 36 4E 84 05 0D 4A 34 15 97 DC 5B 1F 6C A4 19 D9 10 00 00 00 F5 33 9F 55 49 94 26 54 2B C8 CB 70 7B FE EC 96 14 00 00 00 C5 23 DA BA C8 23 6C 0B B3 88 69 06 00 95 29 AE 76 A7 63 E4

и в C # я получаю:

01 00 00 00 D0 8C 9D DF 01 15 D1 11 8C 7A 00 C0 4F C2 97 EB 01 00 00 00 2E 6F 88 86 E6 16 9B 4F 9B BF 35 DA 9F C6 EC 12 00 00 00 00 02 00 00 00 00 00 03 66 00 00 A8 00 00 00 10 00 00 00 34 C4 40 CD 91 EC 94 66 E5 E9 23 F7 9E 04 9C 83 00 00 00 00 04 80 00 00 A0 00 00 00 10 00 00 00 12 54 1E 26 72 26 0A D1 11 1D 4D EF 13 1D B2 6F 10 00 00 00 81 9D 46 37 D1 68 5D 17 B8 23 78 48 18 ED 06 ED 14 00 00 00 E4 45 07 1C 08 55 99 80 A4 59 D9 33 BC 0B 71 35 39 05 C4 BB

Как видите, первые символы одинаковы, а остальные - нет, поэтому, если у кого-то есть представление о том, почему это происходит, я буду признателен за помощь.

Спасибо.

Код в C ++:


value = "plain text";
DATA_BLOB DataIn;
DATA_BLOB DataOut;

BYTE *pbDataInput =(BYTE *)(char*)value.c_str();
DWORD cbDataInput = strlen((char *)pbDataInput)+1;
DataIn.pbData = pbDataInput; 
DataIn.cbData = cbDataInput;

CryptProtectData(&DataIn, NULL, NULL, NULL, NULL, 0, &DataOut))

Код в C #:

(вы можете увидеть, как мой код C # выглядит здесь , поскольку он идентичен тому, что показан в этом примере Microsoft)

1 Ответ

5 голосов
/ 19 сентября 2009

Было бы полезно, если бы вы могли опубликовать свой C ++ и код C #. Возможно, есть некоторые тонкие различия параметров или что-то вроде этого. Например, вы должны убедиться, что параметр pOptionalEntropy одинаков (или установить его в NULL, чтобы проверить, является ли это источником ошибки). Также обязательно попытайтесь зашифровать и расшифровать на одном компьютере:

[...] дешифрование обычно может быть сделано только на компьютер, на котором были данные зашифрованы

(Источник: MSDN )

РЕДАКТИРОВАТЬ: Некоторые комментарии по поводу кода, который вы опубликовали, и версии C # из MSDN (ее части следующие):

public byte[] Encrypt(byte[] plainText, byte[] optionalEntropy) {
  [...]
  int bytesSize = plainText.Length;
  plainTextBlob.pbData = Marshal.AllocHGlobal(bytesSize);
  plainTextBlob.cbData = bytesSize;
  Marshal.Copy(plainText, 0, plainTextBlob.pbData, bytesSize);
  [...]
  dwFlags = CRYPTPROTECT_LOCAL_MACHINE|CRYPTPROTECT_UI_FORBIDDEN;
  [...]
  if(null == optionalEntropy)
  {//Allocate something
  optionalEntropy = new byte[0]; // Is copied to entropyBlob later
  }
  [...]
  retVal = CryptProtectData(ref plainTextBlob, "", ref entropyBlob,    
    IntPtr.Zero, ref prompt, dwFlags, 
    ref cipherTextBlob);
  [...]
}

И снова ваш код C ++, чтобы иметь в виду оба:

[...]
BYTE *pbDataInput =(BYTE *)(char*)value.c_str();
DWORD cbDataInput = strlen((char *)pbDataInput)+1;
[...]
CryptProtectData(&DataIn, NULL, NULL, NULL, NULL, 0, &DataOut))

Параметры не совпадают, и я думаю, что это источник различий.

Первое - это флаги. Код C # использует dwFlags! = 0, ваш код C ++ использует dwFlags = 0, так что это явно различие.

Я не уверен насчет энтропии. Если вы не передали optionEntropy = null, это различие, но если оно пустое, есть назначение «new byte [0]», и я не уверен, что это создаст, но я думаю, что вы должны хотя бы попробовать передать IntPtr.Zero вместо entropyBlob в CryptProtectData для соответствия с кодом C ++.

Наконец, но не в последнюю очередь, ваш код C ++ включает в себя завершающий NUL, который разделяет строку C, я не знаю, как работает шифрование, используемое здесь, но есть шифрование, которое даст вам очень разные выходные данные, если один байт отличается ( или у вас есть еще один байт, как в этом случае), поэтому вы должны либо включить завершающий NUL в код C #, либо удалить его в код C ++.

...