【问题标题】:Why does ECIES encryption gives a different value each time is called?为什么 ECIES 加密每次调用都会给出不同的值?
【发布时间】:2020-10-14 21:03:42
【问题描述】:

我写了一个函数来加密一个字符串,因为它是一个敏感信息。我正在运行一些睾丸,我发现每次运行生成的输出都不同。

我不确定它是否与盐或类似的东西有关。

每次调用输出都不同是正常行为吗?这是一个好的做法还是坏的做法?

import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.jce.interfaces.ECPublicKey;
import javax.crypto.Cipher;
import java.io.BufferedReader;
import java.io.FileReader;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;


public class App {

    private static String PUBLIC_PEM = "/opt/public.pem";

    static String TO_ENCODE = "not going well";

    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        App app = new App();

        PublicKey publicKey = app.getECPublicKeyFromPEM(PUBLIC_PEM);

        byte[] message = TO_ENCODE.getBytes();

        byte[] out1;

        Cipher c1 = Cipher.getInstance("ECIES");

        c1.init(Cipher.ENCRYPT_MODE, publicKey, new SecureRandom());

        out1 = c1.doFinal(message, 0, message.length);

        System.out.println(Base64.toBase64String(out1));
    }

    public ECPublicKey getECPublicKeyFromPEM(String publicPem) throws  Exception {
        PEMParser pemParser = getPemFile(publicPem);
        SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(pemParser.readObject());

        return (ECPublicKey) new JcaPEMKeyConverter().getPublicKey(subjectPublicKeyInfo);
    }

    private PEMParser getPemFile(String path) throws Exception {
        BufferedReader reader = new BufferedReader(new FileReader(path));
        return new PEMParser(reader);
    }
}

【问题讨论】:

    标签: java encryption bouncycastle


    【解决方案1】:

    如果每次调用函数时加密的数据都相同,则加密不安全。

    考虑:

    1. 您想发送一条消息,“攻击”或“不攻击”。
    2. 攻击者截获了消息。
    3. 攻击者后来发现接收者没有攻击。
    4. 攻击者截获下一条消息。
    5. 攻击者将消息与之前的消息进行比较。如果它们相同,则攻击者知道消息说“不要攻击”。如果它们不相同,则攻击者知道消息是“攻击”。

    无论如何,当您使用 ECIES 加密某些东西时,您要做的第一件事就是创建一个随机的临时密钥。所以那个键每次都会不同。

        c1.init(Cipher.ENCRYPT_MODE, publicKey, new SecureRandom());
    

    理论上,您可以通过使用哈希函数从消息和接收方公钥以及一些秘密信息(例如私钥)确定性地生成“随机”密钥来使结果每次都相同。

    更新

    攻击者无法预测或确定加密过程中使用的临时私钥至关重要。执行此操作的常用方法是使用安全的随机数生成器,就像您在代码中所做的那样。

    如果您希望相同的输入产生相同的输出,您需要生成临时私钥,以确保相同输入的相同结果,同时确保攻击者无法预测或猜测临时私钥.

    满足这两个要求的一种方法是使用收件人的公钥、发件人的私钥和消息的哈希值作为临时私钥。攻击者无法猜测或预测这一点,因为他们不知道发送者的私钥。只要密钥和消息相同,它将是相同的,因此它将确保同一发送者发送给同一接收者的同一消息产生相同的临时私钥,从而产生相同的结果。

    请注意,ECIES 不要求发件人拥有私钥。您可以只使用一些保密的发件人标识符(它必须足够长以确保安全,因此将其视为私钥!)。只要发件人标识符保持不变,发送给同一收件人的同一消息将产生相同的加密输出。

    【讨论】:

    • 很好的解释。你的意思是“你可以通过使用散列函数从消息和收件人公钥以及一些秘密信息(如私钥)确定性地生成“随机”密钥来导致结果每次都相同”?
    • 最后一个问题:使用new SecureRandom() 是一种不好的做法吗?
    猜你喜欢
    • 1970-01-01
    • 2018-05-02
    • 1970-01-01
    • 2019-10-27
    • 2019-06-15
    • 2020-08-24
    • 2017-11-23
    • 2022-11-19
    • 1970-01-01
    相关资源
    最近更新 更多