2009-10-05 43 views
1

我需要生成一个随机密钥,在Java中,我将能够在未来的某个点再生。这个想法是,这个密钥对于它所创建的机器是独一无二的,并且不存储在任何地方。我试图这样的事情:生成相同的随机密钥两次

KeyGenerator keyGen = KeyGenerator.getInstance("DESede"); 

String hostname = InetAddress.getLocalHost().getHostName(); 
SecureRandom random = new SecureRandom(hostname.getBytes()); 
keyGen.init(random); 

secretKey = keyGen.generateKey(); 

显然,这不起作用,因为设置一个SecureRandom的种子不会在我以为它做的方式工作,每一次我得到一个不同的SecretKey的。也许我试图做的事情永远不会奏效(我知道它看起来像是一件奇怪的事情,想要做......)但如果有办法,我会真的很感激它,如果有人能告诉我这是什么方式!

+1

你想做什么?什么是关键?你能解释一下你的整个环境吗?可能有更好的方法来解决这个问题。 – 2009-10-05 11:14:16

回答

3

有两种方法以编程方式确保关键:

  • 保持密钥本身的秘密,或
  • 保持算法的秘密。

密码学家(和常识)会告诉你,在这两者中,第二种安全性要差得多,因为反向工程代码相对容易。所以你留下了第一种方法。

如果我正确地读你的要求,你需要一个关键就是

  1. 保证是唯一的每台机器。
  2. 随机。
  3. 不存储在任何地方。
  4. 可复制(通过您的软件)。

但是不可能满足所有这些。例如,一个真正随机的密钥不能存储在任何地方(无论是作为数据还是嵌入算法中)都不能随意复制。所以,如果我可以采取一些回旋余地,我会读入你的使用情况,并替换这些不太严格的要求:

  1. 绑主机:从一台机器的密钥无法被另一个使用。
  2. 安全:不可能被复制,猜测,反向工程,
  3. 安全:不可能在您的程序中被发现。
  4. 可重复性:您的应用程序必须能够根据需要重新生成密钥。

所有这些新的要求,用#3之外,能满足此程序:


  1. 生成秘密随机种子将每台机器上使用。
  2. 选择一个机器相关的签名,它对每个主机都是唯一的,并将其附加到种子。典型的例子是一个MAC地址,但在具有两个或更多NIC的机器上,每次必须小心使用相同的NIC!
  3. Hash结果与算法(如SHA),将产生一个合理的独特和不可逆的结果。

现在,所有剩下的就是通过使合理的攻击者难以猜测的一个项目必须是秘密的,以满足第三个要求:种子。而这正是这个过程变得更像是一场宗教争论而不是技术争论的地方,因为“相当困难”取决于攻击者想要发现密钥的严重程度以及如果他/她成功的话会面临风险。

为了尽可能安全,密钥必须存储在应用程序外部,例如在你的大脑中,并在每次需要时提供。但通常一些形式较为薄弱的安全通过默默无闻的机制是可以接受的;我最喜欢的一种是使用类似0x%-6.2d这种可能被忽略的格式为printf()格式。如果你偏执狂,将其存储在一块,并将其重新创建在应用程序的一部分中,而这部分应用程序与密钥处理模块没有关联。

如果您需要更具体的建议,请告诉我们更多关于您的应用程序及其使用案例。

祝你好运!

+0

非常感谢,这看起来像我需要的那种信息。请放心,我知道我正在做的事情很容易妥协,但我被要求找到一种方法来保护用于保护访问其他密钥的密码,要求它不应该是“平凡的”可发现的 - 即不可能偶然以纯文本形式偶然发现密码。 – AndyB 2009-10-05 13:34:45

+0

然后你正在寻找一个KeyStore。 (没有双关语意) – 2009-10-15 02:22:23

3

即使它确实为工作,你不会真的有一个“秘密”键 - 你有一个密钥是完全可以从主机名导出。这不是一个秘密 - 它就像每个人使用他们的名字作为他们的密码。任何想要攻击加密数据的人都必须知道创建密钥的机器的名称,然后才能访问。

密钥的最终形式几乎与您需要重新创建的信息无关。要使密钥有效,基本上这些信息必须是秘密的。

+0

但他可以使用一些盐来使它私密?或者这不是一个好主意? – codevour 2009-10-05 11:13:27

+0

chrsk:好的,但是每个机器上的密钥都会有所不同。即便如此,这仍然不是一个好主意,因为如果你知道关键的模式,你就可以蛮横地强制它。 – 2009-10-05 11:17:44

3

您无法生成两次随机密钥,因为它是随机的。

如果InetAddress.getLocalHost()。getHostName()对于您的目的而言足够独特,则计算一个散列值并将其用作关键字。正如乔恩所说,关键是任何知道实现的人都可以推导出来。