7

製品のdllの1つを削除し、それを純粋なC#のものに置き換えるという割り当てが与えられました。古いDLLは、Win32ネイティブCryptoAPIへの呼び出しをラップする.NET2.0マネージC++(C ++ \ CLI)です。新しいDLLは、同じ名前とメソッドを持つ新しいオブジェクトを公開する必要がありますが、C#(.NET 4.0)で作成する必要があります。もちろん、新しいDLLは古いDLLと同じ方法で暗号化(および復号化)する必要があります。そうしないと、DBやファイルなどの永続ストレージに保存されているすべての暗号化パスワードが解決されません。

これは、ネイティブ(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;

今、私は.NET APIによって公開された新しい暗号オブジェクトでC#(System.Security.Cryptography名前空間)を使用して同じプロシージャを作成しようとしています。

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文字)は両方の方法を使用して同じように暗号化されますが、長い文字列は異なる暗号化データになります。

2つの方法を強制的に同等にするにはどうすればよいですか?つまり、出力が同じになるように同じ方法で暗号化および復号化するには?ここで何が欠けていますか?.NET APIとネイティブ(Win32)APIの間でデフォルト値\動作に変更はありますか?(Win32 Crypto APIのデフォルトの3DES暗号モードはEBCであると思いますが、C#を使用するデフォルトはCBCです。間違っている場合は修正してください)。

ありがとう!

オムリ

4

2 に答える 2

6

CryptDeriveKeyのMSDNページによると、3DESのデフォルトの暗号モードはEBCではなくCBCであるようです-「対称ブロック暗号用にキーが生成される場合、キーはデフォルトで暗号ブロック連鎖(CBC)モードで設定されます。ゼロの初期化ベクトル。この暗号モードは、データを一括暗号化するための優れたデフォルトの方法を提供します。これらのパラメーターを変更するには、CryptSetKeyParam関数を使用します。」.NetTripleDESプロバイダーのデフォルトモードもCBCです。EBCに設定している行を削除してみて、それが役立つかどうかを確認してください。

ここで重要な注意点として、正常に復号化できるようにするには、初期化ベクトルを知っている必要があります。CryptDeriveKey関数はデフォルトでゼロIVを使用します。つまり、純粋なC#コードで一致させるには、ゼロIVも使用していることを確認する必要があります。

于 2011-06-06T17:30:24.763 に答える
0

後で参照できるように正しいC#コードを投稿するだけで、IVおよびCBCモードの設定の変更に注意してください。

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.CBC;
            prov3des.Padding = PaddingMode.PKCS7;
            prov3des.IV = new byte[]{0,0,0,0,0,0,0,0}; //8 bytes, zero-ed

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

            ICryptoTransform cTransform = prov3des.CreateEncryptor();

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

        }

        return resultArray;
    }

}

どうもありがとう'pstrjds'!!!! 暗号化/復号化の結果は同じになりました=>メソッドは同等です:-)

オムリ

于 2011-06-07T01:34:45.283 に答える