2017-04-07 73 views
2

我需要在C#中对一个值进行加密,然后在经典ASP中对其进行解密。我最接近的是Blowfish。但问题是这两个实现产生稍微不同的结果,我不知道为什么。Blowfish在C#和经典ASP之间的结果不同

实现使用:

C#:https://defuse.ca/blowfish.htm

的VBScript:http://www.di-mgt.com.au/cryptoBlowfishASP.html

C#代码:

var input = "Hello World"; 
var key = "04B915BA43FEB5B6"; 
BlowFish b = new BlowFish(key); 

string enc, dec; 

enc = b.Encrypt_ECB(input); 
dec = b.Decrypt_ECB(enc); 

的VBScript:

Dim aKey() 
Dim nKeyLen, szTxtKey, szTxtPlain, szTxtKeyAsString, szTxtCipher, szTxtCipherHex, szTxtCipher64, szTxtDecrypt 

szTxtKey = "04B915BA43FEB5B6" 
szTxtPlain = "Hello World" 

ReDim aKey((Len(szTxtKey) \ 2) - 1) 
nKeyLen = bu_HexStr2Bytes(szTxtKey, aKey) 
Call blf_Key(aKey, nKeyLen) 
szTxtKeyAsString = bu_Bytes2HexStr(aKey, nKeyLen) 

szTxtCipher = blf_StringEnc(szTxtPlain) 
szTxtCipherHex = bu_Str2Hex(szTxtCipher) 

C#输出:

819dd50a925a5eb83ed723bea6d84984 

VBScript的输出:

819DD50A925A5EB8CABE974A654A18A8 

输出的前半部分是相同的: “819DD50A925A5EB8”

一个有趣的事情是,如果我解密的VBScript输出与C#库我得到这个: Hello World♣♣♣♣♣

所以...它几乎可以工作,但有某种填充或发生的事情。我不知道如何解决这个问题。

+2

不同的填充:https://en.wikipedia.org/wiki/Padding_(cryptography) –

+0

@ArtjomB。这就是我在想什么,所以这意味着这两个实现是不兼容的,没有办法让他们一起工作而不重写/改变其中的一个? – FirstDivision

+0

在最糟糕的情况下,可以在代码中解决填充问题。但是,不要使用Blowfish,它已经过时了,即使它的作者现在使用AES。 AES不仅比Blowfish更难使用,而且更安全。 – zaph

回答

2

由于@artjom-balready mentioned in the comments,罪魁祸首是不同的填充。

对不同的填充方法here有很好的解释。

分析blowfish.cs文件显示它使用NULL填充(请注意此文件中的片段);

/// <summary> 
/// Decrypts a string (ECB) 
/// </summary> 
/// <param name="ct">hHex string of the ciphertext</param> 
/// <returns>Plaintext ascii string</returns> 
public string Decrypt_ECB(string ct) 
{ 
    return Encoding.ASCII.GetString(Decrypt_ECB(HexToByte(ct))).Replace("\0", ""); 
} 

与此相反,传统的ASP实现使用PKCS5填充(从basBlowfishFns.asp片断显示PKCS5方法)

Using Padding in Encryption
垫与字节所有相同的值的数量的填充字节(PKCS5填充)

' Get # of padding bytes from last char 
nPad = Asc(Right(strData, 1)) 
If nPad > 8 Then nPad = 0 ' In case invalid 
strData = Left(strData, nLen - nPad) 

此修复措施是为c#库使用的NULL填充应用变通方法。

这里是修改的basBlowfishFns.asp(只是显示修改后的功能);

Public Function blf_StringEnc(strData, padMethod) 
' Encrypts plaintext strData after adding RFC 2630 padding 
' Returns encrypted string. 
' Requires key and boxes to be already set up. 
' Version 5. Completely revised. 
' The speed improvement here is due to Robert Garofalo. 
    Dim strIn 
    Dim strOut 
    Dim nLen 
    Dim sPad 
    Dim nPad 
    Dim nBlocks 
    Dim i 
    Dim j 
    Dim aBytes(7) 
    Dim sBlock 
    Dim iIndex 

    ' Pad data string to multiple of 8 bytes 
    strIn = PadString(strData, padMethod) 
    ' Calc number of 8-byte blocks 
    nLen = Len(strIn) 
    nBlocks = nLen \ 8 
    ' Allocate output string here so we can use Mid($ below 
    ' strOut = String(nLen, " ") 
    strOut = ""  ' Fix for VBScript 

    ' Work through string in blocks of 8 bytes 
    iIndex = 0 
    For i = 1 To nBlocks 
     sBlock = Mid(strIn, iIndex + 1, 8) 
     ' Convert to bytes 
     ' aBytes() = StrConv(sBlock, vbFromUnicode) 
     Call bu_String2Bytes(sBlock, aBytes) 
     ' Encrypt the block 
     Call blf_EncryptBytes(aBytes) 
     ' Convert back to a string 
     ' sBlock = StrConv(aBytes(), vbUnicode) 
     sBlock = bu_Bytes2String(aBytes, 8) 
     ' Copy to output string 
     ' Mid(strOut, iIndex + 1, 8) = sBlock 
     strOut = strOut & sBlock 
     iIndex = iIndex + 8 
    Next 

    blf_StringEnc = strOut 

End Function 

Public Function blf_StringDec(strData, padMethod) 
' Decrypts ciphertext strData and removes RFC 2630 padding 
' Returns decrypted string. 
' Requires key and boxes to be already set up. 
' Version 5. Completely revised. 
' The speed improvement here is due to Robert Garofalo. 
    Dim strIn 
    Dim strOut 
    Dim nLen 
    Dim sPad 
    Dim nPad 
    Dim nBlocks 
    Dim i 
    Dim j 
    Dim aBytes(7) 
    Dim sBlock 
    Dim iIndex 

    strIn = strData 
    ' Calc number of 8-byte blocks 
    nLen = Len(strIn) 
    nBlocks = nLen \ 8 
    ' Allocate output string here so we can use Mid($ below 
    'strOut = String(nLen, " ") 
    strOut = "" 

    ' Work through string in blocks of 8 bytes 
    iIndex = 0 
    For i = 1 To nBlocks 
     sBlock = Mid(strIn, iIndex + 1, 8) 
     ' Convert to bytes 
     ' aBytes() = StrConv(sBlock, vbFromUnicode) 
     Call bu_String2Bytes(sBlock, aBytes) 
     ' Encrypt the block 
     Call blf_DecryptBytes(aBytes) 
     ' Convert back to a string 
     'sBlock = StrConv(aBytes(), vbUnicode) 
     sBlock = bu_Bytes2String(aBytes, 8) 
     ' Copy to output string 
     ' Mid(strOut, iIndex + 1, 8) = sBlock 
     strOut = strOut & sBlock 
     iIndex = iIndex + 8 
    Next 

    ' Strip padding, if valid 
    strOut = UnpadString(strOut, padMethod) 

    blf_StringDec = strOut 

End Function 

Public Function PadString(strData, method) 
' Pad data string to next multiple of 8 bytes as per RFC 2630 
    Dim nLen 
    Dim sPad 
    Dim nPad 
    nLen = Len(strData) 
    nPad = ((nLen \ 8) + 1) * 8 - nLen 
    Select Case method 
    Case "PKCS5" 
     sPad = String(nPad, Chr(nPad)) ' Pad with # of pads (1-8) 
    Case "NULL" 
     sPad = String(nPad, Chr(0)) ' Pad with # of NULL characters 
    End Select 
    PadString = strData & sPad 

End Function 

Public Function UnpadString(strData, method) 
' Strip RFC 2630-style padding 
    Dim nLen 
    Dim nPad 
    nLen = Len(strData) 
    If nLen = 0 Then Exit Function 
    Select Case method 
    Case "PKCS5" 
     ' Get # of padding bytes from last char 
     nPad = Asc(Right(strData, 1)) 
     If nPad > 8 Then nPad = 0 ' In case invalid 
     strData = Left(strData, nLen - nPad) 
    Case "NULL" 
     'Remove any NULL characters, obviously, this method isn't ideal if 
     'the data contains valid NULLs. This shouldn't be an issue with 
     'ASCII text. 
     strData = Replace(strData, Chr(0), "") 
    End Select 
    UnpadString = strData 
End Function 

重要的修改是对PadString()UnpadString()功能。我添加了一个参数method,允许您传递标识符NULLPKCS5以确定我们如何填充/取消填充数据。这些功能已经存在,但由于某种原因,blf_StringEnc()blf_StringDec()功能没有使用,所以为了DRY principle的利益,我修改了它们以便它们被使用。

使用以下代码修改(这只是快速刺激代码更灵活);

Dim aKey() 
Dim nKeyLen, szTxtKey, szTxtPlain, szTxtKeyAsString, szTxtCipher, szTxtCipherHex, szTxtCipher64, szTxtDecrypt 

szTxtKey = "04B915BA43FEB5B6" 
szTxtPlain = "Hello World" 

ReDim aKey((Len(szTxtKey) \ 2) - 1) 
nKeyLen = bu_HexStr2Bytes(szTxtKey, aKey) 
Call blf_Key(aKey, nKeyLen) 
szTxtKeyAsString = bu_Bytes2HexStr(aKey, nKeyLen) 

'Encrypt using NULL padding method. 
szTxtCipher = blf_StringEnc(szTxtPlain, "NULL") 
szTxtCipherHex = bu_Str2Hex(szTxtCipher) 

Call Response.Write(szTxtCipherHex) 

会导致;

819DD50A925A5EB83ED723BEA6D84984 

如原先预期。

+0

感谢您的优秀回应,解释和解决方案! – FirstDivision

2

如果您可以从VBScript转出命令行,则可以使用加密字符串的相同C#库创建控制台应用程序。有点解决方法,但你会使用相同的库。