3

我正在寻找在java(在windows上)中执行以下当前任务的最佳方法:

由于用户输入的特定字符串,在程序“内部”创建一个随机的其他字符串/键(字母数字),并且用户不可见。

如果我们输入相同的字符串,则密钥必须相同。

所以基本上,我看到了如何制作一个随机字符串,但我想确保这个程序的用户无法找到内部返回的密钥(我实际上然后使用这个密钥来加密数据,因此我不'不希望简单的用户访问此密钥)。

我怎样才能做到这一点?您能否向我展示一个正确解决方案的运行代码示例?

编辑:我要求用户输入的相同字符串具有相同的密钥,因为我需要知道这个生成的密钥,以便下次在我的计算机上使用另一个客户端。

4

4 回答 4

2

我真的不太了解您的用例,无法从安全角度提出建议。但是,要直接解决从用户提供的输入生成可重现密钥的问题,您可以使用基于密码的密钥派生,其中我们将用户提供的输入视为密码(编辑为完整示例):

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

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

import sun.security.provider.SecureRandom;

public class DerivationExample {

  private static SecretKey makeKeyFromUserInput(String userInput, byte[] salt)
      throws NoSuchAlgorithmException, InvalidKeySpecException {

    SecretKeyFactory factory = SecretKeyFactory
        .getInstance("PBKDF2WithHmacSHA1");
    KeySpec keySpec = new PBEKeySpec(userInput.toCharArray(), salt, 1024, 256);
    byte[] derivedKey = factory.generateSecret(keySpec).getEncoded();
    return new SecretKeySpec(derivedKey, "AES");
  }

  public static void main(String[] args) throws Exception {
    String userInput = "foo";

    // PBKDF2 standard recommends at least 64-bit salt
    // Note: you want to randomly generate this elsewhere and keep it constant
    byte[] salt = new byte[8];
    new SecureRandom().engineNextBytes(salt);

    SecretKey derivedKey = makeKeyFromUserInput(userInput, salt);

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, derivedKey, new IvParameterSpec(
        new byte[16]));

    String plaintext = "Hello, World!";
    byte[] cipherText = cipher.doFinal(plaintext.getBytes());

    // Derive key again to demonstrate it is the same
    SecretKey derivedKey2 = makeKeyFromUserInput(userInput, salt);
    cipher.init(Cipher.DECRYPT_MODE, derivedKey2, new IvParameterSpec(
        new byte[16]));

    byte[] plainText = cipher.doFinal(cipherText);
    // Prints "Hello, World!"
    System.out.println(new String(plainText));
  }
}

如果盐保持不变,则生成的密钥将是可重现的。在需要生成相同密钥的任何其他设备之间共享盐。

注意:您需要安装不受限制的策略文件(请参阅本页底部)才能使本示例正常工作。

请记住,由“安全”点点滴滴组成的安全系统不能保证从整体上看是安全的。我们只看到了您的一小部分要求,因此我们的建议应该持保留态度(不是双关语)。要获得更完整的答案,我们需要了解您尝试保护的端到端流程。

但是,由于 StackOverflow 不是设计安全系统的地方,您可能需要在其他地方寻求帮助。

于 2012-08-24T09:36:18.483 回答
2

也许是盐渍哈希函数?

获取用户输入,添加一些秘密输入,然后对事物进行哈希处理。

(没有秘密输入,用户可以自己弄清楚如何创建它)。

当然,这个字符串根本不是随机的。具有这种可重复性的要求排除了随机性。但是,这些字符串不会有可辨别的模式,所以它看起来是“随机的”。

于 2012-08-24T09:01:21.867 回答
0

如果您只期望相对少量的输入,您可以使用字符的 unicode 和 Random 来生成随机数,但将所有结果存储在地图中。这样,如果已经生成值,您就不会重复生成值,而是使用缓存的值。

于 2012-08-24T09:10:21.730 回答
0

我不太确定你想要实现什么,但我认为你可以使用哈希来加密你的字符串。

也许此链接可以提供帮助:如何生成 MD5 哈希?

在散列字符串之前先“加盐”字符串会更好。

于 2012-08-24T09:01:25.047 回答