尝试将旧的加密算法移植到C#

时间:2014-05-22 14:34:40

标签: c# vb6-migration encryption-symmetric 3des

我首先要说以下链接对我有很大帮助:

Translating Win32 Crypto API calls to C# with System.Security.Cryptography

我遇到了同样的问题,除了他的修复程序没有修复我的代码。

这是我的旧(vb6)代码:

Private Const ALG_CLASS_DATA_ENCRYPT = 24576&
Private Const ALG_CLASS_HASH = 32768
Private Const ALG_SID_3DES = 3&
Private Const ALG_SID_SHA1 = 4&
Private Const ALG_TYPE_ANY = 0&
Private Const ALG_TYPE_BLOCK = 1536&
Private Const CALG_3DES = (ALG_CLASS_DATA_ENCRYPT Or ALG_TYPE_BLOCK Or ALG_SID_3DES)
Private Const CALG_SHA1 = (ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_SHA1)
Private Const CRYPT_SILENT = &H40&
Private Const CRYPT_VERIFYCONTEXT = &HF0000000
Private Const MS_ENHANCED_PROV = "Microsoft Enhanced Cryptographic Provider v1.0"
Private Const PROV_RSA_FULL = 1&

Private Declare Function CryptAcquireContextApi Lib "advapi32.dll" Alias "CryptAcquireContextA" (ByRef phProv As Long, ByVal pszContainer As String, ByVal pszProvider As String, ByVal dwProvType As Long, ByVal dwFlags As Long) As Long
Private Declare Function CryptCreateHashApi Lib "advapi32.dll" Alias "CryptCreateHash" (ByVal hProv As Long, ByVal Algid As Long, ByVal hKey As Long, ByVal dwFlags As Long, ByRef phHash As Long) As Long
Private Declare Function CryptDecryptApi Lib "advapi32.dll" Alias "CryptDecrypt" (ByVal hKey As Long, ByVal hHash As Long, ByVal Final As Long, ByVal dwFlags As Long, ByRef pbData As Byte, ByRef pdwDataLen As Long) As Long
Private Declare Function CryptDeriveKeyApi Lib "advapi32.dll" Alias "CryptDeriveKey" (ByVal hProv As Long, ByVal Algid As Long, ByVal hBaseData As Long, ByVal dwFlags As Long, ByRef phKey As Long) As Long
Private Declare Function CryptDestroyHashApi Lib "advapi32.dll" Alias "CryptDestroyHash" (ByVal hHash As Long) As Long
Private Declare Function CryptDestroyKeyApi Lib "advapi32.dll" Alias "CryptDestroyKey" (ByVal hKey As Long) As Long
Private Declare Function CryptEncryptApi Lib "advapi32.dll" Alias "CryptEncrypt" (ByVal hKey As Long, ByVal hHash As Long, ByVal Final As Long, ByVal dwFlags As Long, ByRef pbData As Byte, ByRef pdwDataLen As Long, ByVal dwBufLen As Long) As Long
Private Declare Function CryptGetHashParamApi Lib "advapi32.dll" Alias "CryptGetHashParam" (ByVal hHash As Long, ByVal dwParam As Long, pbData As Any, pdwDataLen As Long, ByVal dwFlags As Long) As Long
Private Declare Function CryptHashDataApi Lib "advapi32.dll" Alias "CryptHashData" (ByVal hHash As Long, ByRef pbData As Byte, ByVal dwDataLen As Long, ByVal dwFlags As Long) As Long
Private Declare Function CryptReleaseContextApi Lib "advapi32.dll" Alias "CryptReleaseContext" (ByVal hProv As Long, ByVal dwFlags As Long) As Long
Private Declare Function CryptGetKeyParamApi Lib "advapi32.dll" Alias "CryptGetKeyParam" (ByVal hKey As Long, ByVal dwParam As Long, ByRef pbData As Byte, ByRef pdwDataLen As Long, dwFlags As Long) As Long

Private Declare Sub CopyMemoryApi Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)

Function Encrypt(message As String, Password As String) As String

   If CryptAcquireContextApi(provider, vbNullString, ProviderName, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) = 0 Then
      Goto Encrypt_Failure
   End-If
   If CryptCreateHashApi(provider, CALG_SHA1, 0&, 0&, hash) = 0 Then
      Goto Encrypt_Failure
   End-If

   buffer = StrConv(Password, vbFromUnicode)
   If CryptHashDataApi(hash, buffer(0), CLng(UBound(buffer) + 1), 0&) = 0 Then
      GoTo Encrypt_Failure
   End If

   If CryptDeriveKeyApi(provider, CALG_3DES, hash, 1&, key) = 0 Then
      key = 0
      GoTo Encrypt_Failure
   End If

   length = Len(message)
   bfrlen = length
   If CryptEncryptApi(key, 0&, 1&, 0&, ByVal 0&, bfrlen, bfrlen) = 0 Then
      GoTo Encrypt_Failure
   End If

   ReDim buffer(bfrlen - 1)

   For i = 0 To length - 1
      buffer(i) = Asc(Mid(message, i + 1, 1))
   Next i

   If CryptEncryptApi(key, 0&, 1&, 0&, buffer(0), length, bfrlen) = 0 Then
      GoTo Encrypt_Failure
   End If

   Call CryptDestroyKeyApi(key)
   Call CryptReleaseContextApi(provider, 0)

   Encrypt = left(StrConv(buffer, vbUnicode), length)

Encrypt_Failure:
   If key Then
      Call CryptDestroyKeyApi(key)
   End If
   If hash Then
      Call CryptDestroyHashApi(hash)
   End If
   If provider Then
      Call CryptReleaseContextApi(provider, 0)
   End If

Exit Function

这是新的C#版本:

   public byte[] Encrypt(string source, string pass)
    {
        byte[] password = Encoding.UTF8.GetBytes(pass);
        byte[] resultArray = null;
        byte[] streamToEncrypt = Encoding.UTF8.GetBytes(source);

        if(streamToEncrypt.Length % 8 != 0)
        {
            byte[] inputArray = new byte[streamToEncrypt.Length + (8 - (streamToEncrypt.Length % 8))]; //add padding to the end to make the message groups of 8 bytes
            int i = 0;
            foreach (byte element in streamToEncrypt)
            {
                inputArray[i] = element;
                i++;
            }
            streamToEncrypt = inputArray;
        }


        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 salt needed here
            {
                prov3des.Key = pdb.CryptDeriveKey("TripleDES", "SHA1", 168, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 });
            }

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

        }

        return resultArray;

    }

并且,与上面链接的海报一样,密码的散列是相同的,加密字节数组的前8个字节是相同的。我已经将初始化向量设置为8个字节的零,但我想如果加密数据的前8个字节是相同的,那么初始化向量必须匹配。我无法弄清楚为什么接下来的8个字节会有所不同。我在这里做错了什么想法?

谢谢!

2 个答案:

答案 0 :(得分:1)

如果前8个字节相同而其余部分不相同,则听起来您使用的反馈形式与原始算法不同。尝试使用不同的CipherMode值,看看其中一个是否匹配。

答案 1 :(得分:1)

实际上这是一个非常简单的解决方案,尽管它并不明显。你有一段代码表示"如果这个数据不是8的倍数,那就填上它。"但是,这是更改您正在加密的值,因此您会得到不同的结果。

只需删除整个if(streamToEncrypt.Length.Dump("Length") % 8 != 0) {}块,即可获得预期结果。