2015-10-28 129 views
1

我正在從Classic ASP頁面發送base64 encoded string頁面到JSP頁面。在編碼之前,該字符串是RC4加密的。來自Base64的字符串解碼值損壞(Java),

現在,我觀察到,在ASP頁面內,編碼和解碼字符串base64的工作正常。但是,JSP頁面上的base64 decoded string不正確。我也嘗試在Eclipse中解碼字符串並得到相同的結果。它似乎與字符編碼類型有關,但我正在努力確定究竟是什麼問題。

  • base64編碼字符串:yOBIc4FY
  • 的base64解碼(從ASP頁)字符串:ÈàHsX(正確)
  • 的base64解碼的字符串(從JSP頁面和Eclipse):ÈàHsX? (不正確的)

爪哇/ JSP代碼:

import org.apache.commons.codec.binary.Base64; 

String base64String = "yOBIc4FY"; 

byte[] decodedBase64Byte = Base64.decodeBase64(base64String); 

// ÈàHs?X 
decodedBase64String = new String(decodedBase64Byte, "ISO-8859-1"); 

// ÈàHs?X 
decodedBase64String = new String(decodedBase64Byte, "windows-1252"); 

// ??Hs?X 
decodedBase64String = new String(decodedBase64Byte, "utf-8"); 

重申,正確的值應該是ÈàHsX。我不明白是什麼問題。任何幫助,將不勝感激。

謝謝。

更新

讓我在此進一步闡述。

經典ASP中的RC4加密算法廣泛普及,所以我不會浪費房地產在這裏發佈它。不過,我會在下面顯示我使用'經典ASP'的base64 encoder/decoder

對於RC4,我使用的明文值是foobar。我正在使用的密鑰是test。表面上,解碼base64字符串應該返回密碼。解密密碼應該返回明文值。

' Functions to provide encoding/decoding of strings with Base64. 
' 
' Encoding: myEncodedString = base64_encode(inputString) 
' Decoding: myDecodedString = base64_decode(encodedInputString) 
' 
' Programmed by Markus Hartsmar for ShameDesigns in 2002. 
' Email me at: [email protected] 
' Visit our website at: http://www.shamedesigns.com/ 
' 

    Dim Base64Chars 
    Base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" & _ 
      "abcdefghijklmnopqrstuvwxyz" & _ 
      "" & _ 
      "+/" 


    ' Functions for encoding string to Base64 
    Public Function base64_encode(byVal strIn) 
     Dim c1, c2, c3, w1, w2, w3, w4, n, strOut 
     For n = 1 To Len(strIn) Step 3 
      c1 = Asc(Mid(strIn, n, 1)) 
      c2 = Asc(Mid(strIn, n + 1, 1) + Chr(0)) 
      c3 = Asc(Mid(strIn, n + 2, 1) + Chr(0)) 
      w1 = Int(c1/4) : w2 = (c1 And 3) * 16 + Int(c2/16) 
      If Len(strIn) >= n + 1 Then 
       w3 = (c2 And 15) * 4 + Int(c3/64) 
      Else 
       w3 = -1 
      End If 
      If Len(strIn) >= n + 2 Then 
       w4 = c3 And 63 
      Else 
       w4 = -1 
      End If 
      strOut = strOut + mimeencode(w1) + mimeencode(w2) + _ 
         mimeencode(w3) + mimeencode(w4) 
     Next 
     base64_encode = strOut 
    End Function 

    Private Function mimeencode(byVal intIn) 
     If intIn >= 0 Then 
      mimeencode = Mid(Base64Chars, intIn + 1, 1) 
     Else 
      mimeencode = "" 
     End If 
    End Function  


    ' Function to decode string from Base64 
    Public Function base64_decode(byVal strIn) 
     Dim w1, w2, w3, w4, n, strOut 
     For n = 1 To Len(strIn) Step 4 
      w1 = mimedecode(Mid(strIn, n, 1)) 
      w2 = mimedecode(Mid(strIn, n + 1, 1)) 
      w3 = mimedecode(Mid(strIn, n + 2, 1)) 
      w4 = mimedecode(Mid(strIn, n + 3, 1)) 
      If w2 >= 0 Then _ 
       strOut = strOut + _ 
        Chr(((w1 * 4 + Int(w2/16)) And 255)) 
      If w3 >= 0 Then _ 
       strOut = strOut + _ 
        Chr(((w2 * 16 + Int(w3/4)) And 255)) 
      If w4 >= 0 Then _ 
       strOut = strOut + _ 
        Chr(((w3 * 64 + w4) And 255)) 
     Next 
     base64_decode = strOut 
    End Function 

    Private Function mimedecode(byVal strIn) 
     If Len(strIn) = 0 Then 
      mimedecode = -1 : Exit Function 
     Else 
      mimedecode = InStr(Base64Chars, strIn) - 1 
     End If 
    End Function 

從內ASP,明文值被正確地從密碼實現的:

明文:foobar的

密文:ÈàHsX

BASE64字符串:yOBIc4FY

解碼base64字符串:ÈàHsX

解密正文:foobar的

然而,通過密碼爲Base64字符串JSP/Java中,JSP/Java的是這樣的:

明文:(從ASP)

foobar的

密文:ÈàHsX(從ASP)

BASE64字符串:yOBIc4FY

解碼的base64字符串:EA HS X

解密文本:foobßr

所以,自己是不是加起來就在這裏。實際上,對於Java,在解密解密過程中進行一次更改將返回正確的解密文本foobar。 Java代碼中的RC4解密採用類型爲int[]的密碼。

public int[] decrypt(int[] ciphertext, byte[] key) throws Exception { 
    return encrypt(ciphertext, key); 
} 

換句話說,我必須將密碼從String類型轉換爲鍵入int[]。我使用下面的功能來做到這一點:

public static int[] convertToIntArray(byte[] input) 
{ 
    int[] ret = new int[input.length]; 
    for (int i = 0; i < input.length; i++) 
    { 
     ret[i] = input[i] & 0xff; // Range 0 to 255 
    } 
    return ret; 
} 

我有兩種選擇。我可以將base64字符串解碼爲類型byte[]並解密,這將返回foobar

String base64String = "yOBIc4FY"; 

byte[] decodedBase64Byte = Base64.decodeBase64(base64String); 

int[] cipheredText = convertToIntArray(decodedBase64Byte); 

或者,我可以解碼的base64字符串作爲byte[]類型,然後將其轉換爲鍵入String,然後再返回到輸入byte[]到decrpyt,這將返回foobßr

String base64String = "yOBIc4FY"; 

byte[] decodedBase64Byte = Base64.decodeBase64(base64String); 

// ÈàHs?X 
String decodedBase64String = new String(decodedBase64Byte, "ISO-8859-1"); 

int[] cipheredText = convertToIntArray(decodedBase64String.getBytes()); 

我的猜測是那麼原始字節序列是正確的,因爲RC4解密函數成功返回foobar。但是,當我將字節序列轉換爲某個字符編碼集的字符串時,它將更改該值,最終以解密值foobßr

它仍然沒有道理,那麼爲什麼ASP和JSP/Java報告稍微不同的密碼值? ASP將base64字符串或密碼解碼回明文值沒有問題。我不知道這個問題是與ASP,JSP還是兩者兼而有之。

+1

您正在使用哪個Web服務器? Tomcat的? – rickz

+0

是的,Tomcat for JSP。我也在Eclipse(JDK/JRE 1.6-1.8)中進行了本地測試,同樣的問題。 – user3621633

回答

2

yOBIc4FY正確解碼是6個字節,具體有:

c8 e0 48 73 81 58 

ÈàHsX值可能只是忽略字符0x81爲不可打印。

證明:

y  O  B  I  c  4  F  Y 
110010 001110 000001 001000 011100 111000 000101 011000 

11001000 11100000 01001000 01110011 10000001 01011000 
c8  e0  48  73  81  58 

爲了解決您的後續問題 - 你應該使用的字節數組,你從以base64解碼器獲得。它轉換爲int[]如果你需要,但不創建一個String出來,因爲編碼會搞砸了:

static void printByteArray(byte[] bytes) { 
    for (byte b : bytes) { 
     System.out.print(Integer.toHexString(b & 0xff) + ", "); 
    } 
    System.out.println(); 
} 

public static void main(String[] args) { 

    byte[] cipherBytes = Base64.getDecoder().decode("yOBIc4FY"); 
    printByteArray(cipherBytes); // c8, e0, 48, 73, 81, 58 - correct 

    cipherBytes = new String(cipherBytes).getBytes(); 
    printByteArray(cipherBytes); // c8, e0, 48, 73, 3f, 58 - wrong 
    // your results may vary depending on your default charset, 
    // these are for windows-1250 
} 

在這裏你可以看到,原來的正確字節0x81改爲問號?(字節0x3f),因爲0x81在從字節數組創建String時使用的字符集中不表示有效字符。

+0

有趣。你有沒有參考你如何推斷​​它是6個字節和那些特定的6個字節?我不完全確定這是正確的。我將進一步詳細闡述這個問題。非常感謝。 – user3621633

+1

@ user3621633我已經使用http://www.freeformatter.com/base64-encoder.html - 您將不得不將解碼後的值作爲文件下載並在十六進制編輯器中查看。還有8個字符* base64 = 48位編碼的每個字符6位,這是6個字節(編碼字符串中沒有填充)。它也同意'java.util.Base64'如何解碼它。 – Cinnam

+1

@ user3621633我已經添加了「手動」證明。 – Cinnam