【问题标题】:CFB mode output is the same as CTR output; am I doing something wrong?CFB模式输出与CTR输出相同;难道我做错了什么?
【发布时间】:2018-06-30 06:07:49
【问题描述】:

我一直在尝试使用 AES 比较加密模式,并注意到我的 CFB 输出与我的 CTR 输出相同。我做错了什么还是应该发生这种情况?我的 CTR 加密函数与下面的 CFB 函数相同,只是将“AES/CTR/NoPadding”字符串作为 Cipher.getInstance() 的参数。谢谢!

try {
        // Dernier exemple CTR mode
        // Clé 16 bits
        byte[] keyBytes = new byte[]{(byte) 0x36, (byte) 0xf1, (byte) 0x83,
                (byte) 0x57, (byte) 0xbe, (byte) 0x4d, (byte) 0xbd,
                (byte) 0x77, (byte) 0xf0, (byte) 0x50, (byte) 0x51,
                (byte) 0x5c, 0x73, (byte) 0xfc, (byte) 0xf9, (byte) 0xf2};
        // IV 16 bits (préfixe du cipherText)
        byte[] ivBytes = new byte[]{(byte) 0x69, (byte) 0xdd, (byte) 0xa8,
                (byte) 0x45, (byte) 0x5c, (byte) 0x7d, (byte) 0xd4,
                (byte) 0x25, (byte) 0x4b, (byte) 0xf3, (byte) 0x53,
                (byte) 0xb7, (byte) 0x73, (byte) 0x30, (byte) 0x4e, (byte) 0xec};

        // Initialisation
        SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);

        // Mode
        Cipher cipher = Cipher.getInstance("AES/CFB/PKCS5Padding");

        String originalText = "hello i am original";
        // ///////////////////////////////ENCRYPTING
        cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
        ciphered = cipher.doFinal(originalText.getBytes());
        String cipherText = new String(ciphered, "UTF-8");
        System.out.println("ciphered: " + cipherText);
        // ///////////////////////////////DECRYPTING
        cipher = Cipher.getInstance("AES/CFB/PKCS5Padding");

        cipher.init(Cipher.DECRYPT_MODE , key, ivSpec);
        byte[] plain = cipher.doFinal(ciphered);
        originalText = new String(plain, "UTF-8");
        System.out.println("plaintext: " + originalText);
    }
    catch (Exception e){

    }

【问题讨论】:

  • 尝试加密多个块,看看它们是否仍然相同。如果您只加密单个块,它们基本上是相同的。您确实有 CFB 模式的填充,这是一个区别。不要理会new String(ciphered, "UTF-8");,这没有任何意义。如果你想可视化它,你可能应该对输出进行十六进制编码。 Base64 也是一种选择。
  • @JamesKPolk 成功了!谢谢大佬

标签: java encryption cryptography


【解决方案1】:

CFB (Cipher Feedback) 模式和CTR (Counter) 模式都是modes of operation,它们指定如何使用基本分组密码原语(在本例中为 AES)来加密和解密字节序列。

但是,第一个块(在本例中为 16 个字节)最终以相同的方式加密。这是Wikipedia的CTR模式图:

这是CFB模式的示意图,同样来自Wikipedia

如果 CFB 模式下的 IV 与 CTR 模式下的 Nonce/Counter 相同,则关注最左边的块,您可以看到它们在两种情况下都会产生相同的输出。

这里对您的代码稍作修改,显示了在两种模式下加密hello i am original 的区别。

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

class Main {

    public static void main(String[] args) throws Exception {
        // Dernier exemple CTR mode
        // Clé 16 bits
        byte[] keyBytes = new byte[]{(byte) 0x36, (byte) 0xf1, (byte) 0x83,
                (byte) 0x57, (byte) 0xbe, (byte) 0x4d, (byte) 0xbd,
                (byte) 0x77, (byte) 0xf0, (byte) 0x50, (byte) 0x51,
                (byte) 0x5c, 0x73, (byte) 0xfc, (byte) 0xf9, (byte) 0xf2};
        // IV 16 bits (préfixe du cipherText)
        byte[] ivBytes = new byte[]{(byte) 0x69, (byte) 0xdd, (byte) 0xa8,
                (byte) 0x45, (byte) 0x5c, (byte) 0x7d, (byte) 0xd4,
                (byte) 0x25, (byte) 0x4b, (byte) 0xf3, (byte) 0x53,
                (byte) 0xb7, (byte) 0x73, (byte) 0x30, (byte) 0x4e, (byte) 0xec};

        // Initialisation
        SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);

        // Mode
        Cipher cipher = Cipher.getInstance("AES/CFB/PKCS5Padding");

        String originalText = "hello i am original";
        // ///////////////////////////////ENCRYPTING
        cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
        byte[] ciphered = cipher.doFinal(originalText.getBytes());
//            String cipherText = new String(ciphered, "UTF-8");
        System.out.println("CFB: " + DatatypeConverter.printHexBinary(ciphered));

        // CTR mode
        cipher = Cipher.getInstance("AES/CTR/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
        ciphered = cipher.doFinal(originalText.getBytes());
        System.out.println("CTR: " + DatatypeConverter.printHexBinary(ciphered));

    }
}

输出是:

CFB: 25F64E6F324681A2B6534807BAFB11C52C0F9BBD28BE2032915EB423B1E0B415
CTR: 25F64E6F324681A2B6534807BAFB11C59390BE

CTR 模式基本上是将块密码转换为面向字节的流密码,因此密文的长度与明文的长度相同。这也意味着攻击者相对容易修改密文以在解密的明文中引起可预测的变化。因此,您必须使用 MAC 来检测对密码的任何修改,例如 HMAC。现代的选择是 AES-GCM,这是一种类似计数器的模式,还包括一个内置的 MAC。

【讨论】:

  • 为什么CTR输出比CFB输出短?
  • @justan0therlurker:我会在答案中添加一些信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-28
  • 1970-01-01
  • 2014-03-28
  • 1970-01-01
  • 2019-08-16
  • 1970-01-01
相关资源
最近更新 更多