Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the ciphertext 32 bytes long when encrypting 16 bytes with AES?

I use encryption AES algorithm, when i encrypt 16 byte(one block) the result is 32 byte. Is this ok?

My source code that i used is:

package net.sf.andhsli.hotspotlogin;

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * Usage:
 * <pre>
 * String crypto = SimpleCrypto.encrypt(masterpassword, cleartext)
 * ...
 * String cleartext = SimpleCrypto.decrypt(masterpassword, crypto)
 * </pre>
 * @author ferenc.hechler
 */
public class SimpleCrypto {

    public static String encrypt(String seed, String cleartext) throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] result = encrypt(rawKey, cleartext.getBytes());
        return toHex(result);
    }

    public static String decrypt(String seed, String encrypted) throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] enc = toByte(encrypted);
        byte[] result = decrypt(rawKey, enc);
        return new String(result);
    }

    private static byte[] getRawKey(byte[] seed) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
        sr.setSeed(seed);
        kgen.init(128, sr); // 192 and 256 bits may not be available
        SecretKey skey = kgen.generateKey();
        byte[] raw = skey.getEncoded();
        return raw;
    }


    private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(clear);
        return encrypted;
    }

    private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] decrypted = cipher.doFinal(encrypted);
        return decrypted;
    }

    public static String toHex(String txt) {
        return toHex(txt.getBytes());
    }
    public static String fromHex(String hex) {
        return new String(toByte(hex));
    }

    public static byte[] toByte(String hexString) {
        int len = hexString.length()/2;
        byte[] result = new byte[len];
        for (int i = 0; i < len; i++)
            result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
        return result;
    }

    public static String toHex(byte[] buf) {
        if (buf == null)
            return "";
        StringBuffer result = new StringBuffer(2*buf.length);
        for (int i = 0; i < buf.length; i++) {
            appendHex(result, buf[i]);
        }
        return result.toString();
    }
    private final static String HEX = "0123456789ABCDEF";
    private static void appendHex(StringBuffer sb, byte b) {
        sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
    }

}
like image 923
ebra Avatar asked Jun 26 '11 19:06

ebra


People also ask

How many bytes can AES encrypt?

AES has always 128-bit block size with 128,192 and 256-bit keyspaces. Therefore, you can encrypt 16-byte at a time if you are using ECB and CBC modes. By using CTR mode you can encrypt 1-bit to 128-bit.

How long is AES encrypted string?

AES uses a 128-bit block size, in which data is divided into a four-by-four array containing 16 bytes. Since there are eight bits per byte, the total in each block is 128 bits. The size of the encrypted data remains the same: 128 bits of plaintext yields 128 bits of ciphertext.

What affects the length of ciphertext?

The relation depends on the padding and the chaining modes you are using, and the algorithm block size (if it is a block cipher). Some encryption algorithms are stream ciphers which encrypt data "bit by bit" (or "byte by byte").

Does AES encryption change file size?

AES does not expand the data, except for a few bytes of padding at the end of the last block. The resulting data are not compressible, at any rate, because they are basically random - no dictionary-based algorithm is able to effectively compress them. A best practice is to compress the data first, then encrypt them.


2 Answers

If you look at the specification section 5 then you can see that the input, output and state are all 128 bit. The only thing that varies is the size of the key: 128, 196 or 256 bits. So encrypting a 16 byte input state will yield a 16 byte output state.

Are you sure you aren't mixing it up with the length in hexadecimal notation or similar? If it is in hexadecimal notation then it's correct because for each byte two characters are needed to represent it: 00-FF (for the range 0-255). So, for example, 16 bytes would be encoded as 32 characters in hexadecimal notation.

Another way you can test if the encryption is correct is by doing the equivalent decryption, see if it matches the plaintext input string.

Anyway, it does the correct thing. Here's a test:

public static void main(String[] args) {
  try {
    String plaintext = "Hello world", key = "test";
    String ciphertext = encrypt(key, plaintext);
    String plaintext2 = decrypt(key, ciphertext);
    System.out.println("Encrypting '" + plaintext +
                       "' yields: (" + ciphertext.length() + ") " + ciphertext);
    System.out.println("Decrypting it yields: " + plaintext2);
  }
  catch (Exception ex) {
      ex.printStackTrace();
  }
}

Which yields:

Encrypting 'Hello world' yields: (32) 5B68978D821FCA6022D4B90081F76B4F

Decrypting it yields: Hello world

like image 54
Morten Kristensen Avatar answered Nov 02 '22 23:11

Morten Kristensen


AES defaults to ECB mode encryption with PKCS#7 compatible padding mode (for all providers observed so far). ECB and CBC mode encryption require padding if the input is not precisely a multiple of the blocksize in size, with 16 being the block size of AES in bytes.

Unfortunately there might be no way for the unpadding mechanism to distinguish between padding and data; the data itself may represent valid padding. So for 16 bytes of input you will get another 16 bytes of padding. Padding modes that are deterministic such as PKCS#7 always pad with 1 up to [blocksize] bytes.

If you look at int output = cipher.getOutputSize(16); you will get back 32 bytes. Use "AES/ECB/NoPadding" during decipher to see the padding bytes (e.g. 4D61617274656E20426F64657765732110101010101010101010101010101010).

You are better off when you fully specify the algorithm. Previously most developers would go for "AES/CBC/PKCS5Padding" but nowadays "AES/GCM/NoPadding" should probably be used because it offers message authentication and integrity. Otherwise you will keep guessing which mode is actually used.

Note that using ECB mode is not safe as an attacker can retrieve information from the cipher text; identical blocks of plain text encode to identical blocks of cipher text.

like image 21
Maarten Bodewes Avatar answered Nov 03 '22 01:11

Maarten Bodewes