【问题标题】:Why does this AES encryption program gives a different value on each call?为什么这个 AES 加密程序在每次调用时给出不同的值?
【发布时间】:2011-09-05 00:30:17
【问题描述】:

基本上,我发现了这段代码,由某人发布,它允许您在 AES 中加密消息并对其进行解密。我对这个加密的东西有点新,我想知道,它使用的种子值在哪里,种子每次随机化吗?因为从外观上看,相同的字符串会给出不同的加密结果。

谢谢。

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.*;

public class AESGUI extends JPanel {

    public static void main(String[] args) {
        JFrame frame = new JFrame("AES Encryption");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setPreferredSize(new Dimension(600,300));

        frame.setLocationRelativeTo(null);
        frame.setResizable(false);

        AESGUI p = new AESGUI();

        frame.getContentPane().add(p);
        frame.pack();
        frame.setVisible(true);
    }

    private JTextField in;
    private JTextArea out;

    public AESGUI() {
        JLabel info = new JLabel("Type any String");
        in = new JTextField(20);
        JButton encrypt = new JButton("Encrypt");
        out = new JTextArea(10,40);

        out.setEditable(false);

        encrypt.addActionListener(new encryptListener());
        in.addActionListener(new encryptListener());

        add(info);
        add(in);
        add(encrypt);
        add(out);
        add(new JScrollPane(out));
    }

    private class encryptListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            String data = in.getText();
            if (data.length() == 0) { }
            else
                try {
                    String en = encrypt(data);
                    out.append("Encrypted string: " + en + "\n");
                    out.append("Original String: " + decrypt(en) + "\n\n");
                } catch(Exception ex) { }
        }
    }

    public String asHex(byte[] buf) {
        StringBuffer strbuf = new StringBuffer(buf.length * 2);
        int i;
        for (i = 0; i < buf.length; i++) {
            if (((int) buf[i] & 0xff) < 0x10)
                strbuf.append("0");
            strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
        }
        return strbuf.toString();
    }

    private SecretKeySpec skeySpec;
    private Cipher cipher;
    private byte[] encrypted;

    public String encrypt(String str) throws Exception {
        // Get the KeyGenerator
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128); // 192 and 256 bits may not be available

        // Generate the secret key specs.
        SecretKey skey = kgen.generateKey();
        byte[] raw = skey.getEncoded();
        skeySpec = new SecretKeySpec(raw, "AES");

        // Instantiate the cipher
        cipher = Cipher.getInstance("AES");

        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

        encrypted = cipher.doFinal(str.getBytes());
        return asHex(encrypted);
    }

    public String decrypt(String str) throws Exception {
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] original = cipher.doFinal(encrypted);
        String originalString = new String(original);
        return originalString;
    }

}

没有 gui(我希望这就是我删除的全部内容)

public String asHex(byte[] buf) {
    StringBuffer strbuf = new StringBuffer(buf.length * 2);
    int i;
    for (i = 0; i < buf.length; i++) {
        if (((int) buf[i] & 0xff) < 0x10)
            strbuf.append("0");
        strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
    }
    return strbuf.toString();
}

private SecretKeySpec skeySpec;
private Cipher cipher;
private byte[] encrypted;

public String encrypt(String str) throws Exception {
    // Get the KeyGenerator
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    kgen.init(128); // 192 and 256 bits may not be available

    // Generate the secret key specs.
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    skeySpec = new SecretKeySpec(raw, "AES");

    // Instantiate the cipher
    cipher = Cipher.getInstance("AES");

    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

    encrypted = cipher.doFinal(str.getBytes());
    return asHex(encrypted);
}

public String decrypt(String str) throws Exception {
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    byte[] original = cipher.doFinal(encrypted);
    String originalString = new String(original);
    return originalString;
}

【问题讨论】:

  • 与其粘贴 GUI 和所有内容的所有代码,不如只隔离相关代码,即对加密例程的调用等?
  • 我刚刚发布了我获得的代码。我猜如果没有 gui,它会像(见上文,已编辑)

标签: java encryption aes


【解决方案1】:

是的,它对相同的文本给出不同的结果,原因是每次加密消息时都会生成密钥。

// Get the KeyGenerator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available

// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
skeySpec = new SecretKeySpec(raw, "AES");

你可以做的是,把它从 encrypt() 方法中取出来,让它变得通用。

【讨论】:

    【解决方案2】:

    它使用的种子值在哪里,种子每次都随机化吗?

    Javadocs 是你的朋友,年轻的 padawan ;) 从你的代码示例中,我们看到你正在调用 keyGenerator.init(int keysize)

        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128); // 192 and 256 bits may not be available
    

    检查the javadoc 对该类的该方法调用,我们得到以下信息:

    为特定的密钥大小初始化此密钥生成器。如果这个键 生成器需要任何随机字节,它将使用 SecureRandom 最高优先级已安装提供程序的实现 作为随机性的来源。 (如果没有安装的提供程序 提供 SecureRandom 的实现,系统提供的源 将使用随机性。)

    换句话说,正如您最初猜测的那样,对init(int keysize) 的调用意味着每次都使用随机种子。如果你有一个特定的种子 1) 对你的需要有好处,并且 2) 你需要使用,那么你需要使用 init(int keysize,SecureRandom random),或者在你对 init(int keysize) 的其他调用的同时调用 [init(SecureRandom random)][4]

    希望对你有帮助。

    顺便说一句,如果您想更深入地介绍密码学,我建议您获得 Alfred Menezes、Paul van Oorschot 和 Scott Vanstone 的 Handbook of Applied Cryptography (Discrete Mathematics and Its Applications)。尽管出版于 1996 年,但我一直都在提到这本书而不是其他所有书。

    一本关于密码学理论基础的书是Understanding Cryptography: A Textbook for Students and Practitioners。它是高度数学化的,如果您最终想成为密码学家/密码​​分析家,您需要这样做。对于密码学工具和算法的整体使用和理解,上面提到的 Menezes 等书将是一个好的开始。

    为了全面了解计算机安全主题,我建议由 Edward G. Amoroso 撰写 Fundamentals of Computer Security Technology。对于它的价值,我总是在工作中随身携带这本书作为参考。

    【讨论】:

      【解决方案3】:

      盐一般在生成密钥时使用。

      private SecretKey getKey(final String passPhrase, final String salt)
              throws NoSuchAlgorithmException, InvalidKeySpecException {
          final PBEKeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt.getBytes(), ITERATIONS, 128); // 128bit key length
          SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_FACTORY_MODE);
          final SecretKey key = keyFactory.generateSecret(keySpec);
          return key;
      }
      

      但是,该算法也使用初始化向量“播种”。

      private static final SecureRandom random = new SecureRandom();
      
      private IvParameterSpec getIV(final Cipher cipher) {
          final byte[] ivBytes = new byte[cipher.getBlockSize()];
          random.nextBytes(ivBytes);
          return new IvParameterSpec(ivBytes);
      }
      

      因此,您将按如下方式传递加盐密钥和 IV:

      final SecretKey key = getKey(passPhrase, salt);
      final Cipher cipher = Cipher.getInstance("AES/CTR/NOPADDING");
      final IvParameterSpec iv = getIV(cipher);
      cipher.init(cipherMode, key, iv, random);
      

      【讨论】:

        猜你喜欢
        • 2020-10-14
        • 2021-11-09
        • 2014-12-06
        • 2016-01-16
        • 1970-01-01
        • 1970-01-01
        • 2023-04-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多