开发者

Decrypting with Cipher and AES yields 208 decrypted bytes followed by trash

[Edit: don't try to understand the whole thing and don't waste your time to read all of my question - just keep in mind decryption worked up to a certain position... and read my answer that explains why!]

I got an annoying problem here I have no clue about how to solve...

A system writes encrypted data to files, some are serialized objects, others text (XML) files. The base class that does the decryption when needed initializes a Cipher with AES encryption, prepares a key (read from a file) and has to ways to access data:

A way to get an InputStream:

public InputStream getInputStream(File pFile) throws IOException {
  return
    new CipherInputStream(
      new BufferedInputStream(new FileInputStream(pFile)),
      getCipher(Cipher.DECRYPT_MODE)
    );
}

and a method to read an object that just wraps an ObjectInputStream around the InputStream derived from this method and reads the object using ObjectInputStream.readObject().

Now. Within the software system, everything works this way. What I wanted to write is a command line tool to help decrypt files for the support. So, I used exactly the same methods to get my Cipher, I even used the identical class and the InputStream built there.

But: no matter what I do: only the first 208 (!) bytes get decrypted, the rest stays encrypted!

I tried to simply "copy" the data from this InputStream to a new OutputStream using a byte buffer, but I also tried just getting a String from the data to see what's happening in a Debugger. => effect is always the same. Up to this "border" of 208 bytes, I see clear text - followed by trash.

I have no idea what could go wrong here! Any clues??

The Cipher is created like this:

public Cipher getCipher(int opMode) throws IOException {
    Cipher cipher = null;

    try {
        cipher = Cipher.getInstance("AES");
    } catch (NoSuchAlgorithmException e) {
        throw new MdmFatalInternalErrorException("Getting instance of cipher failed. Should never happen. BUG ", e);
    } catch (NoSuchPaddingException e) {
        throw new MdmFatalInternalErrorException("Getting instance of cipher failed. Should never happen. BUG ", e);
    }
    try {
        cipher.init(opMode, readKey());
    } catch (InvalidKeyException e) {
        throw new MdmInvalidKeyException();
    } catch (ClassNotFoundException e) {
        throw new MdmInvalidKeyException();
    } catch (NumberFormatException e) {
        throw new MdmInvalidKeyException();
    }
    return cipher;
}

So, here's the code that actually uses the InputStream IN the software system:

String s = readStream(reader.getInputStream(file));

where readStream is implemented like this:

public String readStream(InputStream is) throws IOException {
    Buf开发者_开发技巧feredReader reader = new BufferedReader(new InputStreamReader(is));

    StringBuffer sb = new StringBuffer();
    String line = null;
    try {
        while ((line = reader.readLine()) != null) {
            sb.append(line).append('\n');
        }
    } finally {
        reader.close();
    }

    return sb.toString();
}

All this works (within the software)! But my attempt to read it the same way fails: the String s contains exactly 208 decrypted characters followed by garbage!!

The writing of the XML files is done exactly the other way around, but that really does not matter here because the shown code works within the system, but not in my simple copy program! I use exactly the same class there!! Why on earth all only 208 characters decrypted??

Thanks!

Edit: It is now clear that the effect of getting only a certain number of bytes decrypted is dependent on the OS and machine! On my Windows OS with 32bit Java 1.6 Update 20 it fails to decrypt - on a Linux machine with 64bit Java 1.6 Update 18 it works!!

So - here's the challenge: does anybody know how that interferes with the output???


AES is a block cipher, so it must encrypt blocks of an exact size (16 bytes). When you encrypt data, you have to make sure it can be split in blocks of 16 bytes; if the last block is shorter than that you can get an Exception or you can get garbage (because of the way Buffered Streams work). If you don't want to be bothered with manually padding your data then you can set up the Cipher to use PKCS5Padding. Instead of just calling Cipher.getInstance("AES") you have to use Cipher.getInstance("AES/ECB/PKCS5Padding"), and you have to do that on BOTH sides.

Also, I recommend using CBC or CFB, you need an initialization vector (salt) for those modes but it's better than using ECB which is the same as using no mode, that means that you're just encrypting each block independently so any block can be cracked separately. If you use CBC or CFB then to crack a block of data you need to crack the previous block (CBC stands for Cipher Block Chaining).

And last but not least... if you want to encrypt data over a stream, you might be better off using a stream cipher like RC4 instead of a block cipher.


It is a little bit embarrassing - but I leave this (answered!) question in here in case anybody ever stumbles upon a similar problem!

The reason I got xx bytes correctly decrypted followed by trash is easily explained - shame on me!

We had XML files encrypted on a Linux system. The decryption within the system itself worked fine; but whenever I tried to decrypt them on my Windows machine it failed like described.

WHY? Because the files' extensions are XML - and my WinScp FTP tool treats file with XML extension as text files - AND replaces each LF (#10) with CR LF (#13#10)!

Thus, the decryption worked correctly until the first stupid CR character was hit! :-(

So, we learn: never give a binary file the extension of a text file unless you want trouble! *sigh*

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜