There is padding and there is chaining. You should first get the chaining right.
AES encrypts blocks of 16 bytes, no more and no less. When you want to encrypt a message which is potentially longer than 16 bytes, then you have to decide how data is split into blocks and reassembled afterwards. The basic splitting algorithm is called ECB: this is "just a split" into blocks encrypted individually. ECB is known to be weak with real-world data because it leaks information about which plaintext blocks are equal to each other (they will be encrypted identically) and such redundancy often happens in "normal" data.
Thus it is needed to "randomize" the data blocks in some way, so that data redundancy is hidden. The CBC mode performs that through "chaining": the processing of a block depends on the result of the encryption of the previous block. Namely, the to-encrypt plaintext block is combined (with bitwise XOR) with the output of the previous block encryption.
The important point here is that the first block to encrypt (the first 16 bytes of data) has no "previous block" so there is nothing to XOR with. This is solved by choosing a "random IV", i.e. a sequence of 16 random bytes, which will be used as "block -1" for the XORing step. The IV must be known to the decrypting party (otherwise it will not know what to XOR the decrypted block with, and the first 16 bytes of data will not be intelligible). The bright side is that the IV needs not be secret; it MUST be selected uniformly (it cannot be a counter incremented for each message), but it can be transmitted "in the clear", usually along the encrypted message itself.
So you have to worry a bit about the IV, and I see nothing about it in either the Java or Ruby code. Usually, Java defaults to ECB (hence no IV at all). If Ruby defaults to an "all-zero IV" in CBC (which is, conceptually, insecure), then it is normal that you can decrypt the first block (write it down, it "just works"), but it is equally normal that it does not work for subsequent blocks.
So I suggest that you explicitly use CBC (in Java, use "AES/CBC/PKCS5Padding"
as algorithm name, not "AES"
) and manage the IV (which must then be transmitted; you could take the convention to concatenate the IV right before the encrypted message).
A few other notes:
Padding is about adding some data to the plaintext so that you have an appropriate input length. CBC requires that the input length has a length multiple of the block size (16 bytes). The PKCS#5 padding is a popular method, by which you add at least 1 byte, at most 16 bytes, such that all of them have value n where n is the number of added bytes. The receiver can then know (unambiguously) how many bytes were added, and remove them. Java can add the padding for you, and I suppose Ruby can also process the padding automatically if nicely asked.
In the Java code, you use key.getBytes()
. I suppose that key
is a String
. Know that getBytes()
encodes the string according to the platform default character set, which is not always the same worldwide. You will save some worry by specifying an explicit charset. Also, since you want to use a 128-bit key but you get something on the Ruby side only with "AES-256", then I assume that you are actually using a 256-bit key on the Java side. My guess is that your key
string is the hexadecimal representation of your key, as 32 characters. key.getBytes()
does not interpret hexadecimal digits; it encodes the characters themselves, yielding a 32-byte array -- and 32 bytes, that's 256 bits, not 128.