1

I am using Java to make a toy program that encrypts a message using DES encryption. The message I want to encrypt is:

String msg="This is a secret message";

Which I convert to bytes as:

byte [] msgBytes=msg.getBytes();

And send it to encrypt function that works as follows:

//encryption function
public static String encryptMsg(byte [] msgBytes, SecretKey myDesKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
    Cipher desCipher;
    // Create the cipher 
    desCipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
    desCipher.init(Cipher.ENCRYPT_MODE, myDesKey);
    byte[] textEncrypted = desCipher.doFinal(msgBytes);

// converts to base64 for easier display.
byte[] base64Cipher = Base64.encode(textEncrypted);
return new String(base64Cipher);
} //end encryptMsg

Then, I display the cipher, the cipher and plaintext lengths and I get:

Encrypted Message: FDCU+kgWz25urbQB5HbFtqm0HqWHGlGBHlwwEatFTiI=
Original msg length: 24
Encrypted msg length: 44

Can you please clarify to me why the cipher length is 44 while the original message length is 24?

EDIT: Kindly, I need the answer with clarification. The cipher always ends with =. Could this be because of the padding? Can you explain to me why/how the cipher is resulted with this length? And always ends with =? Is my code correct or there is a mistake? I have doubts in the encoding part.

4

2 回答 2

2

There are several things going on:

  1. msg.getBytes() returns the bytes representing an encoding of the string using the "platform's default charset" (e.g. could be UTF-8 or UTF-16 or ..): specify the encoding manually to avoid confusion! In any case, see msgBytes.length to get the true plain text length.

  2. DES, being a block cypher, will have output padded along a block size boundary - but this will always be larger than the plain text (refer to msgBytes.length) length when using PKCS#5 because the plain text is always padded with [1,8] bytes. To see what the true encrypted size is, see textEncrypted.length.

  3. The encrypted bytes are encoded using base-64 and this process - which is independent of the encryption - inflates the number of bytes required by about 33% (as only 6 bits per character/byte are used). The Java base-64 implementation also adds padding which is where the trailing "=" character is introduced.

As long as you (or someone else with the correct algorithm and cipher key) can retrieve the initial string - by performing the inverse of each step in reverse order, then it works. If a particular step does not have an inverse/reverse operation or cannot be "undone", then something is wrong; but this also means that every step can be individually tested.


To the numbers!

  1. msg.getBytes() returns an ASCII/UTF-8 encoded sequence (if it used UTF-16 or another another "wide" encoding then the numbers below would be too large)
  2. Therefore, msgBytes.length is 24
  3. And since msgBytes.length mod 8 is 0, the plain text is padded with 8 bytes that have the value of 0x08 (per CKCS#5)
  4. Thus, textEncrypted.length is 32 (24 data + 8 padding)
  5. Due to base-64 encoding, 32 bytes * 1.33 ~ 43 characters
  6. And with base-64 padding (=), the final result is 44 characters!
于 2013-10-19T05:49:51.910 回答
2

The result of a DES encryption will always be a multiple of 8 bytes. The input is also padded to a multiple of 8 bytes according to the padding algorithm specified.

The base 64 encoding encodes each 3 bytes into 4 characters (3x8 = 4x6 = 24), and ensures the output length is a multiple of 4 by padding with = characters.

So, the 44 characters output corresponds to 33 bytes, but the = at the end indicates that in fact there were only 32 bytes. Which is fine, since 24 bytes clear data with PKCS5 padding becomes 32 bytes.

于 2013-10-19T17:25:00.417 回答