2015-10-28 134 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