【问题标题】:ECB and CBC AES output is equal in JavaJava 中的 ECB 和 CBC AES 输出相等
【发布时间】:2017-06-10 09:33:59
【问题描述】:

我玩过 Java AES En/Decryption 并为此使用了不同的密码模式。即我使用CBC和ECB。由于欧洲央行被认为很弱,我想选择加拿大央行。

我假设加密文本 ob cbc 和 ecb 的输出不同,但它们是相等的。这怎么可能?

import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Hex;

import com.instana.backend.common.exception.InstanaException;

public class AESTest {

  private static String pwd = "etjrgp9user9fu3984h1&(/&%$§";

  public static void main(String[] args) throws Exception {
    System.out.println("UNSECURE WITH ECB:");
    String ecbEncrypt = encrypt("YOLO", cypher(Cipher.ENCRYPT_MODE, "AES"));
    System.out.println("Encrypted: " + ecbEncrypt);

    String ebcDecrypt = decrypt(ecbEncrypt, cypher(Cipher.DECRYPT_MODE, "AES"));
    System.out.println("Decrypted: " + ebcDecrypt);

    System.out.println("=====================================");
    System.out.println("SECURE WITH CBC");

    String cbcEncrypt = encrypt("YOLO", cypher(Cipher.ENCRYPT_MODE, "AES/CBC/PKCS5Padding"));
    System.out.println("Encrypted: " + cbcEncrypt);

    String cbcDecrypt = decrypt(cbcEncrypt, cypher(Cipher.DECRYPT_MODE, "AES/CBC/PKCS5Padding"));
    System.out.println("Decrypted: " + cbcDecrypt);

    System.out.println("=====================================");
    System.out.println("Decrypting CBC with ECB");


  }

  public static String encrypt(String superDuperSecret, Cipher cipher) throws IOException {
    try {
      byte[] encrypted = cipher.doFinal(superDuperSecret.getBytes("UTF-8"));

      return new String(new Hex().encode(encrypted));

    } catch (Exception e) {
      throw new InstanaException("Encryption of token failed.", e);
    }
  }

  public static String decrypt(String superDuperSecret, Cipher cipher) {
    try {
      byte[] encrypted1 = new Hex().decode(superDuperSecret.getBytes("UTF-8"));

      return new String(cipher.doFinal(encrypted1));

    } catch (Exception e) {
      throw new InstanaException("Encrypted text could not be decrypted.", e);
    }
  }

  private static Cipher cypher(int mode, String method)
      throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException,
      InvalidAlgorithmParameterException {
    SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    KeySpec spec = new PBEKeySpec(pwd.toCharArray(), pwd.getBytes(), 128, 128);
    SecretKey tmp = skf.generateSecret(spec);
    SecretKey key = new SecretKeySpec(tmp.getEncoded(), "AES");
    Cipher cipher = Cipher.getInstance(method);

    if(method.contains("CBC")) {
      byte[] ivByte = new byte[cipher.getBlockSize()];
      IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte);

      cipher.init(mode, key, ivParamsSpec);
    }else{
      cipher.init(mode, key);
    }

    return cipher;
  }
}

【问题讨论】:

    标签: java encryption aes cbc-mode ecb


    【解决方案1】:

    由于您传递的是一个空的 IV(您从未在您的 ivByte 中放入任何内容),因此无论使用何种模式,对第一个块执行的操作都是相同的。在CBC 的情况下,加密更长的有效负载会导致第二个块链接到第一个块,并且ECB/CBC 之间的后续块将有所不同。

    在使用 CBC 模式时,您应该传递一个非空 IV,因此第一个块将与 IV 异或,从而导致从第一个块开始的不同加密值。

    【讨论】:

    • 你能给我举个例子吗?只是一个简单的小。谢谢
    • 加密更长的字符串。一个比块大小长的。
    • 这不正确。正确生成的 IV 应用于第一个块,然后开始链接。 OP 之所以得到这个结果,是因为他没有正确生成 IV。
    • 我需要在代码中更改哪些内容才能正确实现?
    • @Christian 使用随机 IV。只需在加密数据前加前缀用于解密即可,不需要不保密。
    猜你喜欢
    • 2011-10-04
    • 2011-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-07
    • 1970-01-01
    相关资源
    最近更新 更多