添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
俊逸的铅笔  ·  java - SFTP ...·  1 年前    · 
小眼睛的葡萄酒  ·  基于PostgreSql ...·  1 年前    · 
私奔的数据线  ·  Python 3.x 使用 opencv ...·  1 年前    · 
大力的西瓜  ·  SOME | ANY ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm trying to learn encoding in Java and stuck with Cipher.update() method. Does it have some maximum length of data it can update? Here is an example of what I'm speaking (I put "String s" value just to speed up process, this value goes through encryption and decryption process):

public class AES {
    public static String s = "long string";
    public byte [] encryptAES(byte[] data, byte[] keyPass) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
        Cipher ciph = Cipher.getInstance("AES");
        SecretKeySpec AESkeySpec = new SecretKeySpec(keyPass, "AES");
        ciph.init(ENCRYPT_MODE,AESkeySpec);
        ciph.update(s.getBytes());
        byte[] encryptedData = ciph.doFinal();
        return encryptedData;

Output after decryption: long string

If I change value

public static String s = "long long long long long long long long long long long string";

output after decoding will be: g long string

And if after I take out .update() method and perform encryption like

Cipher ciph = Cipher.getInstance("AES");
SecretKeySpec AESkeySpec = new SecretKeySpec(keyPass, "AES");
ciph.init(ENCRYPT_MODE,AESkeySpec);
//ciph.update(s.getBytes());
byte[] encryptedData = ciph.doFinal(s.getBytes());
return encryptedData;

I will get expected output like: long long long long long long long long long long long string

Why does it happen like that?

"AES" for Cipher will use the provider's default. For the SUN provider, that would be "AES/ECB/PKCS5Padding". You should use at least "AES/CBC/PKCS5Padding" (requires a random IV) or "AES/CTR/NoPadding" (requires a unique IV). Always specify the mode of operation and padding explicitly. And never use getBytes() without specifying a character encoding. – Maarten Bodewes - on strike Aug 1, 2014 at 21:54 I know that, ty. This example above was just for learning of methods, not the part of some project. – Mikekekeke Aug 3, 2014 at 14:39

The update method returns encrypted block. But as I see you take the ciphertext only from doFinal. You supposed to use all blocks from update and from the doFinal for completed encrypted stream of blocks.

Note: you are using ECB mode, it means each block encrypted independently, it is less secure and should be used only if you know what are you doing. That's why you are able to decrypt the last block (16 bytes for AES) and see truncated plaintext. More info: http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation

For ECB and CBC modes of operation, each block (128 bits or 16 bytes for AES) of plaintext or will be encrypted once it is available. Furthermore, your example uses PKCS#7 padding (or, in Java, "PKCS5Padding") to make sure that the last plaintext is padded to a full block. Otherwise you would not be able to encrypt it.

When you encrypt it is obviously not a good idea to buffer all the resulting ciphertext. So update will simply return all blocks it can encrypt. Therefore you will always get a multiple of the blocksize back. That means that it may keep part of a block in an internal buffer. Of course, once you add enough bytes for a full block it will encrypt and return the data. All this means that the update may return up to blocksize - 1 bytes more or less than the input. For smaller input it may not return anything at all - everything is buffered until the block is full.

Now PKCS#7 padding is always applied, adding 1 to blocksize bytes. Obviously the cipher must know if more bytes are to be expected, or if the end of the plaintext is reached, before it applies the padding. So doFinal will return at least one block, even if no data is presented to it. If the previous updates did not return any data, then the doFinal() method will return the entire ciphertext.

More or less the same reasoning can be performed for decryption. Also note the getOutputSize(int inputLength) and the getBlockSize() methods of Cipher. If you want to receive all the data back at once, you can use a stream cipher mode of operation, such as "AES/CTR/NoPadding", which has a block size of 1 byte.

Although this should explain the actual issue, the question you asked was "Does it have some maximum length of data it can update?". The answer is that the update is only limited by the amount of memory available in the JVM and the size of byte arrays in Java.

Didn't quite understand, how am I ignoring it? I'm just changing the value of String s, and getting different output depending on length of string. – Mikekekeke Aug 1, 2014 at 19:20 But why I'm not loosing this bytes if String s = "long string"? (Sry if my questions are too stupid :) ) – Mikekekeke Aug 1, 2014 at 19:52 It doesn't precisely produce the ciphertext for that plaintext, so this answer is plain wrong (for ECB and CBC mode of operation anyway). – Maarten Bodewes - on strike Aug 1, 2014 at 21:50

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.