使用AES加密16个字节时,为什么密文长32个字节?

我使用加密AES算法,当我加密16字节(一个块)时,结果是32字节。 这个可以吗?

我使用的源代码是:

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: * 
 * String crypto = SimpleCrypto.encrypt(masterpassword, cleartext) * ... * String cleartext = SimpleCrypto.decrypt(masterpassword, crypto) * 

* @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 >4)&0x0f)).append(HEX.charAt(b&0x0f)); } }

如果查看规范部分5,那么您可以看到输入, 输出和状态都是128位。 唯一不同的是密钥的大小:128,196或256位。 因此,加密16字节输入状态将产生16字节输出状态。

你确定你没有用hex表示法或类似的长度混合它吗? 如果它是hex表示法则那么它是正确的,因为对于每个字节,需要两个字符来表示它: 00-FF (范围0-255 )。

另一种测试加密是否正确的方法是进行等效解密,看它是否与明文输入字符串匹配。

无论如何,它做的是正确的。 这是一个测试:

 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(); } } 

产量:

加密’Hello world’得率:(32)5B68978D821FCA6022D4B90081F76B4F

解密它产生:Hello world

AES默认使用PKCS#7兼容填充模式进行ECB模式加密(对于目前为止观察到的所有提供商 )。 如果输入不是块大小的倍数,则ECB和CBC模式加密需要填充,其中16是AES的块大小(以字节为单位)。

不幸的是,unpadding机制可能无法区分填充和数据; 数据本身可以表示有效的填充。 因此,对于16个字节的输入,您将获得另外16个字节的填充。 诸如PKCS#7之类的确定性填充模式总是用1到[块大小]字节填充

如果你看一下int output = cipher.getOutputSize(16); 你会得到32个字节。 在解密期间使用"AES/ECB/NoPadding"来查看填充字节(例如, 4D61617274656E20426F64657765732110101010101010101010101010101010 )。

当您完全指定算法时(通常使用"AES/CBC/PKCS5Padding" ),您会"AES/CBC/PKCS5Padding" 。 否则你将继续猜测实际使用的是哪种模式。

请注意,使用ECB模式并不安全,因为攻击者可以从密文中检索信息。 相同的纯文本块编码为相同的密文块。

 package com.cipher; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; public class Encrypt { public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { // TODO Auto-generated method stub String s="You are doing encryption at deep level"; SecureRandom sr=SecureRandom.getInstance("SHA1PRNG"); sr.setSeed(s.getBytes()); byte[] k=new byte[128/8]; sr.nextBytes(k); SecretKeySpec spec=new SecretKeySpec(k,"AES"); byte[] iv={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; IvParameterSpec ivs=new IvParameterSpec(iv); Cipher cps=Cipher.getInstance("AES/CBC/PKCS5Padding"); cps.init(Cipher.ENCRYPT_MODE,spec,ivs); byte[] iv2=cps.doFinal(s.getBytes()); System.out.println("En"+iv2); Cipher cpr=Cipher.getInstance("AES/CBC/PKCS5Padding"); cpr.init(Cipher.DECRYPT_MODE, spec,ivs); byte[] iv3=cpr.doFinal(iv2); String ds=new String(iv3); System.out.println(ds); } }