为什么在加密的base64编码字符串中添加字符不会破坏解密?

时间:2013-12-10 19:26:17

标签: java encryption

我有使用aes算法的java代码。它可以正确地加密和解密字符串。然而,我们发现,如果我在加密字符串的末尾添加一个(只有一个)字符,我仍然可以解密它以纠正纯文本值。如果我追加2或更多,则无法解密。

我尝试了des和其他alogorithm,但仍然是相同的行为。我也试过填充等,没有运气

这是正常行为吗?我怎么能绕过它?

由于

中号

public class testCipher 
{
    public static final String PROVIDER = "SunJCE";
    private static final String ALGORITHM = "AES";
    private static final String aesKey = "some long key";
    static Cipher ecipher;
    static Cipher dcipher;

    public static void main(String[] args)  
    {

    try {

    byte[] buf1 = aesKey.getBytes("UTF-8");
    MessageDigest sha = MessageDigest.getInstance("SHA-256");
    buf1 = sha.digest(buf1);
    buf1 = Arrays.copyOf(buf1, 16);
    SecretKeySpec keySpec = null;
    keySpec = new SecretKeySpec(buf1, "AES");

    ecipher = Cipher.getInstance(ALGORITHM, PROVIDER);
    dcipher = Cipher.getInstance(ALGORITHM, PROVIDER);

    ecipher.init(1, keySpec);
    dcipher.init(2, keySpec, ecipher.getParameters());

    if (args[0].equals("encrypt"))
    System.out.println(encrypt(args[1]));
    else if (args[0].equals("decrypt"))
    System.out.println(decrypt(args[1]));
    else {
    System.out.println("USAGE: encrypt/decrypt '<string>'");
    System.exit(15);
   }

} catch (Exception e) {
    System.exit(5);
} 

}

public static String encrypt(String str) 
{
    try {

        byte[] utf8 = str.getBytes("UTF8");
        byte[] enc = ecipher.doFinal(utf8);
        return new sun.misc.BASE64Encoder().encode(enc);

    } catch (Exception e) {
        System.exit(7);
    }

    return null;
}

public static String decrypt(String str) 
{
    try {
        // Decode base64 to get bytes
        byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);

        // Decrypt
        byte[] utf8 = dcipher.doFinal(dec);

        // Decode using utf-8
        return new String(utf8, "UTF8");
    } catch (Exception e) {
        System.exit(7);
    } 
    return null;
}
}

1 个答案:

答案 0 :(得分:4)

如果没有某种源代码来指示你究竟在做什么,就不可能正确回答,但是有很多可能性,主要与编码大小有关。

编码和加密通常会阻止大小。例如,一组字节的十六进制编码对于每一个输入字节需要两个输出字节。 Base 64编码每4个输入字节使用5个输出字节。大多数加密算法工作在64或128位块,即8或16字节。

如果你正在摆弄一个编码的字符串并且只添加一个字符,那么你可能会在没有源代码的情况下确定你要为其他字符添加不足的信息。在任何正在处理的处理中的块,所以听起来它被默默地忽略了。添加两个角色崩溃,这可能会推动你超过一些限制。

正如blorgbeard在评论中指出的那样,a)你为什么关心b)为什么你首先要摆弄加密的字符串?

编辑:

根据您的代码,这正是我所说的。它与加密无关,而与您正在使用的Base64编码有关。

    String str = "foo";
    String enc = new sun.misc.BASE64Encoder().encode(str.getBytes(Charsets.UTF_8));
    // enc = enc + "x";
    // enc = enc + "x";
    byte [] decBytes = new sun.misc.BASE64Decoder().decodeBuffer(enc);
    String dec = new String(decBytes, Charsets.UTF_8);
    System.out.println(dec);

如果你注释掉其中一条enc = enc + "X";行,程序仍会打印'foo',但是如果你注释掉其中两行,那么之后会打印foo +一些乱码。这是因为Base64编码数据的单个字符没有意义。它需要至少两个字符来编码Base64中的单个字节,这就是为什么忽略第一个字符而第二个字符会导致问题。

但是,回到问题的根源,您的评论表明用户可能能够编辑这些值?那是......好吧,那太疯狂了。除了将加密数据从一个位置移动到另一个位置,或加密或解密数据外,您不会提供任何修改加密数据的功能。

另外,你不应该真正使用sun.misc包中的任何类。 sun.misc被认为是Java的内部,使用它意味着不能保证它将以给定的方式工作,或者它将从一个JVM存在到另一个JVM。有一些开源库可以进行Base64转码(Apache Commons-Codec很受欢迎),你应该使用其中一种。在JVM中使用未记录的功能很容易被认为是您的主要问题。我没有检查Commons-Codec上的文档,但如果遇到意外数量的输入字节进行解码,它可能会抛出异常。