2009-09-18 10 views
6

Estoy usando DPAPI en C++ para cifrar algunos datos que necesito almacenar en un archivo. El caso es que tengo que leer ese archivo desde C#, así que tiene que ser capaz de:¿Por qué obtengo salidas diferentes al encriptar usando DPAPI?

cifrar C++, C++ descifrar (funciona bien)

C# cifrar, C# descifrar (funciona bien)

C++ cifrar, descifrar C# y viceversa (no funciona)

En C# que estoy usando DllImport a PInvoke los métodos CryptProtectData y CryptUnprotectData y ponerlas en práctica como se explica here. Sé que en C# puedo usar los métodos contenidos en la clase ProtectedData pero lo estoy haciendo de esta manera (usando DllImport) para asegurarme de que ambos códigos (C++ y C#) se vean y funcionen de manera muy similar.

Ahora lo raro es que incluso si los dos códigos se ve igual llego diferentes salidas, por ejemplo, para este texto:

"texto plano"

en C++ consigo:

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 CE 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

y en C# consigo:

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

Como puede ver, los primeros caracteres son los mismos pero el resto ar e no, así que si alguien tiene una idea de por qué esto puede estar pasando, agradeceré la ayuda.

Gracias.

Código en 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ódigo en C#:

(se puede ver cómo mi código C# parece here, ya que es idéntica a la que en este ejemplo Microsoft)

+2

Algún editor hexadecimal con formato como ejemplo de datos en lugar de esas capturas de pantalla sería bueno. – schnaader

+0

No se pueden distinguir las capturas de pantalla. –

+0

@Newton: Puede abrir el enlace al gráfico en una pestaña separada para verlo mejor (en Firefox "Mostrar gráficos" también funciona) – schnaader

Respuesta

5

Se ayudaría si pudieras publicar tu C++ y tu código C#. Tal vez haya algunas diferencias de parámetros sutiles o algo así. Por ejemplo, debe asegurarse de que el parámetro pOptionalEntropy sea el mismo (o establézcalo en NULL para comprobar si este es el origen del error). Además, asegúrese de intentar cifrar y descifrar en la misma PC:

[...] Descifrado por lo general sólo se puede realizar en el equipo en el que los datos se cifran

(Fuente: MSDN)

EDIT: Algunas observaciones sobre el código que envió y la versión C# de MSDN (partes de lo siguiente):

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); 
    [...] 
} 

Y aquí está el código C++ de nuevo para tener ambas cosas a la vista:

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

Los parámetros no coinciden y creo que esa es la fuente de las diferencias.

Lo primero son las banderas. El código C# usa dwFlags! = 0, tu código C++ usa dwFlags = 0, por lo que esta es claramente una diferencia.

No estoy seguro acerca de la entropía. Si no pasó opcionalEntropy = null es una diferencia, pero si es nulo, hay una asignación de "nuevo byte [0]" y no estoy seguro de lo que esto creará, pero creo que al menos debería intentarlo pasar IntPtr.Zero en lugar de entropyBlob a CryptProtectData para que coincida con el código de C++.

Por último, pero no menos importante, su código C++ incluye el NUL posterior que delimita la cadena C, no sé cómo funciona el cifrado aquí pero hay encriptaciones que le darán salidas muy diferentes si un byte es diferente (o tiene un byte más como en este caso), por lo que debe incluir un NUL de terminación en el código de C# o eliminarlo en el código de C++.

+0

Agregué un código que espero que ayude. – Vic

Cuestiones relacionadas