Перевод вызовов Win32 Crypto API на C # с помощью System.Security.Cryptography

Мне было поручено удалить одну из dll нашего продукта и заменить ее чистой на C #. Старая библиотека DLL представляет собой управляемый C ++ .NET 2.0 (C ++ \ CLI), который обертывает вызовы собственного Crypto API Win32. Новая DLL должна предоставлять новый объект с тем же именем и методами, но должна быть написана на C # (.NET 4.0). Конечно, новая DLL должна шифровать (и расшифровывать) таким же образом, что и старая, иначе все сохраненные зашифрованные пароли в постоянном хранилище, например в БД или в файле, не будут разрешены!

(псевдо) код вызовов собственного (Win32) API (обратите внимание, что ввод всегда закодирован в Unicode):

//buffer_to_encrypt - Is the input to the following procedure and is the buffer
// to be encrypted using 3DES and the below password to generate a valid 3DES key
// The buffer is Unicode encoded!!!


HCRYPTPROV m_provider = NULL;
HCRYPTHASH m_hash = NULL;
HCRYPTKEY m_key = NULL;

static const unsigned char password[] = { 
                                                0xF1, 0x49, 0x4C, 0xD0, 0xC1, 
                                                0xE2, 0x1A, 0xEA, 0xFB, 0x34, 
                                                0x25, 0x5A, 0x63, 0xA5, 0x29, 
                                                0x09, 0x8E, 0xB6, 0x7B, 0x75 
                                            }; //20 BYTES password


CryptAcquireContextW( &m_provider, NULL, NULL, PROV_DH_SCHANNEL, CRYPT_MACHINE_KEYSET | CRYPT_VERIFYCONTEXT);

CryptCreateHash( m_provider, CALG_SHA1, NULL, 0, &m_hash );

CryptHashData( m_hash, password, (DWORD)20, 0 ); //password is a 20Bytes buffer 

CryptDeriveKey(m_provider, CALG_3DES, m_hash, CRYPT_EXPORTABLE, &m_key);

CryptEncrypt( m_key.handle(), NULL, TRUE, 0, buffer_to_encrypt, &dwFilled, (DWORD)total );

return buffer_to_encrypt;

Теперь я пытаюсь написать ту же процедуру, используя C # (пространство имен System.Security.Cryptography) с новые объекты Crypto, предоставляемые .NET API:

class Encryptor
{

         private static byte[] password = { 
                                            0xF1, 0x49, 0x4C, 0xD0, 0xC1, 
                                            0xE2, 0x1A, 0xEA, 0xFB, 0x34, 
                                            0x25, 0x5A, 0x63, 0xA5, 0x29, 
                                            0x09, 0x8E, 0xB6, 0x7B, 0x75 
                                        }; //20 BYTES password, same as the above native code




        private static byte[] EncryptInternal(string source)
        {
            byte[] resultArray = null;
            byte[] streamToEncrypt = Encoding.Unicode.GetBytes(source);

            using (TripleDESCryptoServiceProvider prov3des = new TripleDESCryptoServiceProvider())
            {

                prov3des.Mode = CipherMode.ECB;
                prov3des.Padding = PaddingMode.PKCS7;

                using (PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, null)) //No slat needed here
                {
                    prov3des.Key = pdb.CryptDeriveKey("TripleDES", "SHA1", prov3des.KeySize, ZeroIV);
                }

                ICryptoTransform cTransform = prov3des.CreateEncryptor();

                resultArray = cTransform.TransformFinalBlock(streamToEncrypt, 0, streamToEncrypt.Length);

            }

            return resultArray;
        }
}

Здесь я столкнулся с досадной проблемой - зашифрованный массив (зашифрованный буфер результата) не является одинаковым при использовании обоих методов! Первые 8 байтов (64 бита) каждого массива идентичны, а следующие байты - нет. Это приводит к тому, что короткие строки (максимум 3 символа) шифруются одинаково с использованием обоих методов, но более длинные строки приводят к разным зашифрованным данным.

Как я могу заставить эти два метода быть эквивалентными? То есть - зашифровать и расшифровать таким же образом, чтобы результат был таким же? Что мне здесь не хватает? Есть ли изменение значений \ поведения по умолчанию между API .NET и Native (Win32)? (Я думаю, что режим шифрования 3DES по умолчанию в Win32 Crypto API - EBC, а C # по умолчанию - CBC - поправьте меня, если я ошибаюсь).

Спасибо!

Омри

7
задан OmriSela 6 June 2011 в 14:15
поделиться