Base64解码值中的字符串已损坏(Java),

Base64解码值中的字符串已损坏(Java),,java,jsp,asp-classic,character-encoding,base64,Java,Jsp,Asp Classic,Character Encoding,Base64,我正在从Classic ASP页面向JSP页面发送base64编码字符串。该字符串在编码之前已RC4加密 现在,我注意到,在ASP页面中,使用base64对字符串进行编码和解码工作正常。但是,JSP页面上的base64解码字符串不正确。我还尝试在Eclipse中解码字符串,得到了相同的结果。这似乎与字符编码类型有关,但我正在努力确定到底是什么问题 base64编码字符串:yOBIc4FY base64解码字符串(来自ASP页面):a HsX(正确) base64解码字符串(来自JSP页面和Ec

我正在从
Classic ASP
页面向
JSP
页面发送
base64编码字符串。该字符串在编码之前已
RC4
加密

现在,我注意到,在
ASP
页面中,使用
base64
对字符串进行编码和解码工作正常。但是,
JSP
页面上的
base64解码字符串
不正确。我还尝试在Eclipse中解码字符串,得到了相同的结果。这似乎与字符编码类型有关,但我正在努力确定到底是什么问题

  • base64编码字符串:yOBIc4FY
  • base64解码字符串(来自ASP页面):a HsX(正确)
  • base64解码字符串(来自JSP页面和Eclipse):ÈHs?X(不正确)
Java/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 crytographic算法广泛可用,所以我不会浪费时间在这里发布它。但是,我将在下面展示我用于“经典ASP”的
base64编码器/解码器

对于RC4,我使用的纯文本值是foobar。我使用的关键是测试。从表面上看,解码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: mark@shamedesigns.com
' Visit our website at: http://www.shamedesigns.com/
'

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


    ' 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如下所示:

纯文本:foobar(来自ASP)

密文:ÈáHsX(来自ASP)

base64字符串:yOBIc4FY

解码的base64字符串:Èá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字符串解码为type
byte[]
,然后将其转换为type
string
,然后再次转换为type
byte[]
,以decrypyt,这将返回
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

String base64String = "yOBIc4FY";

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

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

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

那么,为什么ASP和JSP/Java报告的密码值略有不同,这仍然没有道理?ASP在将base64字符串或密码解码回其明文值时没有问题。我不知道是ASP、JSP还是两者都有问题。

yOBIc4FY的正确解码是6个字节,特别是:

c8 e0 48 73 81 58
a 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[]
,但不要从中创建
字符串,因为编码会把它弄乱:

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
不代表从字节数组创建
字符串时使用的字符集中的有效字符。

您使用的是哪台web服务器?Tomcat?是的,Tomcat代表JSP。我还在Eclipse(JDK/JRE 1.6-1.8)中对其进行了本地测试,发现了同样的问题。你有没有参考资料,说明你是如何推断出它是6个字节以及那些特定的6个字节的?我不能完全肯定这是正确的。我将进一步阐述这个问题。非常感谢。@user3621633我已经使用过了-您必须下载解码后的值作为文件,并在十六进制编辑器中查看它。base64中每个字符8个字符*6位=编码的48位,即6字节(编码字符串中没有填充)。它还与
java.util.Base64
解码它的方式一致。