每个消息需要Cipher.init()? [英] Cipher.init() required for each message?

查看:162
本文介绍了每个消息需要Cipher.init()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设两个客户端来回交换安全消息。



每个消息必须每次运行此块,或者只需要执行任何步骤一开始:

  cipher = Cipher.getInstance(AES / CBC / PKCS5Padding); 
cipher.init(Cipher.ENCRYPT_MODE,keySpec);
output = cipher.doFinal(content);

我想借出一些上下文 - 虽然我还没有完全了解内部,我的理解是,为了安全起见,更改每条消息的IV很重要。所以我认为这个问题的答案将取决于这个步骤是在doFinal()阶段或者init()....的引擎盖下发生的。

解决方案

你是正确的:为了安全起见,你需要为每个消息使用一个新的,随机的IV。这意味着您需要重新创建密码,或者为每个后续消息随机设置IV。前者可能更安全,因为如果您更改密码或模式,还可能需要随机设置一些其他状态,并重新初始化密码应该处理所有这些。



如果您不这样做,您最终会遇到与SSL相同的错误错误。重用



Cipher.doFinal不会将密码重置为随机IV。事实上,它比这更糟糕,似乎将内部状态重置为与您开始的IV相同的IV。如本代码所示。

  Cipher f = Cipher.getInstance(AES / CBC / PKCS5Padding); 
byte [] keyBytes = new byte [] {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0 $ 0x0c,0x0d,0x0e,0x0f} ;

SecretKeySpec key = new SecretKeySpec(keyBytes,AES);
f.init(Cipher.ENCRYPT_MODE,key);
byte [] iv = f.getIV();
System.out.println(Arrays.toString(f.doFinal(hello.getBytes())));
System.out.println(Arrays.toString(f.getIV()));
System.out.println(Arrays.toString(f.doFinal(hello.getBytes())));
System.out.println(Arrays.toString(f.getIV()));
System.out.println(Arrays.equals(f.getIV(),iv)); // true


Assume two clients are exchanging secure messages back and forth.

Must this block be run every time for each message, or can any step(s) be done just once at start:

cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
output = cipher.doFinal(content);

I guess to lend some context- although I don't (yet) understand the internals completely, it is my understanding that for security purposes it's important to change the IV for each message. So I think the answer to this question will depend on whether that step happens under the hood at the doFinal() stage or init()....?

解决方案

You are correct: to be safe you need to use a new,random, IV for each message. This means you either need to recreate the cipher or randomly set the IV yourself for each subsequent message. The former is probably safer since if you change ciphers or modes, there maybe some other state you need to randomly set as well and reinitializing the cipher should handle all of it.

If you don't do this, you end up with the same rather bad bug SSL had with IV reuse.

Cipher.doFinal does not reset the cipher to a random IV. In fact, its far worse than that, it appears to reset the internal state to the same IV you started with. As shown by this code.

    Cipher f = Cipher.getInstance("AES/CBC/PKCS5Padding");
     byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
                0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };

            SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
    f.init(Cipher.ENCRYPT_MODE, key);
    byte[] iv = f.getIV();
    System.out.println(Arrays.toString(f.doFinal("hello".getBytes())));
    System.out.println(Arrays.toString(f.getIV()));
    System.out.println(Arrays.toString(f.doFinal("hello".getBytes())));
    System.out.println(Arrays.toString(f.getIV()));
    System.out.println( Arrays.equals(f.getIV(), iv)); // true

这篇关于每个消息需要Cipher.init()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆