【问题标题】:How to store a simple key string inside Java KeyStore?如何在 Java KeyStore 中存储一个简单的密钥字符串?
【发布时间】:2019-09-24 20:08:47
【问题描述】:

我的 FS 上有一个文件(S3 AWS 密钥),其中包含一个字符串,该字符串是我用于加密过程的密钥。

我想将它移动为 Java KeyStore。

我知道如何使用 keytool 将证书导入 KeyStore,但我找不到导入简单字符串密钥的方法。

你能帮忙吗?

【问题讨论】:

  • 只是提醒未来的问题:如果您为您的 java 问题添加 java 标签,您将会有更多的人看到它们。
  • 哦!我没有意识到人们正在通过标签搜索问题......谢谢!

标签: java keystore


【解决方案1】:

您可以使用 PBE 和 JCEKS 做到这一点。我不认为你可以用 JKS 做到这一点。 解决方案:

创建一个密钥库来存储和获取条目:

keytool -keystore clientkeystore -genkey -alias client -storetype jceks

现在有一些代码来测试它。

   public static String getPasswordFromKeystore(String entry, String keystoreLocation, String keyStorePassword) throws Exception{

        KeyStore ks = KeyStore.getInstance("JCEKS");
        ks.load(null, keyStorePassword.toCharArray());
        KeyStore.PasswordProtection keyStorePP = new KeyStore.PasswordProtection(keyStorePassword.toCharArray());

        FileInputStream fIn = new FileInputStream(keystoreLocation);

        ks.load(fIn, keyStorePassword.toCharArray());

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBE");

        KeyStore.SecretKeyEntry ske =
                (KeyStore.SecretKeyEntry)ks.getEntry(entry, keyStorePP);

        PBEKeySpec keySpec = (PBEKeySpec)factory.getKeySpec(
                ske.getSecretKey(),
                PBEKeySpec.class);

        char[] password = keySpec.getPassword();

        return new String(password);

    }

    public static void makeNewKeystoreEntry(String entry, String entryPassword, String keyStoreLocation, String keyStorePassword)
            throws Exception {
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBE");
        SecretKey generatedSecret =
                factory.generateSecret(new PBEKeySpec(
                        entryPassword.toCharArray()));

        KeyStore ks = KeyStore.getInstance("JCEKS");
        ks.load(null, keyStorePassword.toCharArray());
        KeyStore.PasswordProtection keyStorePP = new KeyStore.PasswordProtection(keyStorePassword.toCharArray());

        ks.setEntry(entry, new KeyStore.SecretKeyEntry(
                generatedSecret), keyStorePP);

        FileOutputStream fos = new java.io.FileOutputStream(keyStoreLocation);
        ks.store(fos, keyStorePassword.toCharArray());
    }

【讨论】:

  • 唯一令人讨厌的是您仍然暴露您的密钥库密码。必须存储在环境变量或用户特定的东西中。
  • @JasonG : 存储密码的长度有限制吗?例如。如果使用 128 位密钥存储密码,是否可以包含更长的密码?
  • @dardo 您可以让用户记住密码或将其保存在某处。很遗憾,操作系统没有提供一种只向您的程序公开密码的方法。
  • keytool error: java.io.FileNotFoundException: clientkeystore (Access denied) 是我得到的。密钥库很复杂,我还没有找到一个可行的答案。
  • 我们现在在多个领域使用这样的解决方案来保护环境中的密码。
【解决方案2】:

今天下午我必须这样做,@JasonG 的解决方案有效,但 keytool 选项无效。

从 Java 8 开始,您可以将 -importpass 选项与 Keytool 一起使用,这将帮助您实现所需。

假设我想将敏感密码foobar 保存在名为myks.jceks 的密钥库中的mypass 别名中,此处使用密码password 保护,请执行以下操作:

$ keytool -importpass -storetype pkcs12 -alias mypass -keystore myks.p12
Enter keystore password: <password>
Re-enter new password: <password>
Enter the password to be stored: <foobar>
Re-enter password: <foobar>
Enter key password for <mypass>
    (RETURN if same as keystore password): <password>
Re-enter new password: <password>

然后你可以使用与@JasonG 相同的代码,我的代码中有这个:

private Try<String> loadKey(Resource path, String pw) {
    return Try.of(() -> {
        KeyStore ks = KeyStore.getInstance("PKCS12");
        ks.load(path.getInputStream(), pw.toCharArray());

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBE");
        SecretKeyEntry ske = (SecretKeyEntry) ks.getEntry("mypass",
                new PasswordProtection(pw.toCharArray()));

        PBEKeySpec keySpec = (PBEKeySpec) factory.getKeySpec(
                ske.getSecretKey(), PBEKeySpec.class);

        return new String(keySpec.getPassword());
    });
}

请注意,由于 JCEKS 使用专有格式,因此我使用了 PKCS12,建议迁移到行业标准格式 PKCS12。

此外,我们遇到了一些问题,一些 Windows 机器(运行 Java 8)在尝试加载 JCEKS 存储时卡住,引发异常。 PKCS12 似乎是更好的选择。

【讨论】:

    【解决方案3】:

    我没有看到使用 keytool 的方法,但有些人想知道你是否可以在代码中将它存储和检索为 PasswordBasedEncryption (PBE) SecretKey。 (免责声明:我自己没有尝试过)。

    促成这一想法的资源: PBEKeySpec javadocCryptoSpec - Using Password Based Encryption example

    【讨论】:

    • 查看我的答案 - 您可以使用 PBE。我提供了代码。 JCEKS 将允许您将字符串作为密钥存储在密钥库中。
    • 我只是补充一点,建议使用 PKCS12 而不是 JCEKS,请参阅下面的答案。
    【解决方案4】:

    我知道这是旧的;但我遇到了同样的用例。

    https://docs.oracle.com/javase/9/tools/keytool.htm#JSWOR-GUID-5990A2E4-78E3-47B7-AE75-6D1826259549

    keystore 有一个 importpass 选项,用于存储由别名标识的 KeyStore.SecretKeyEntry。

    就是这样,您可以将字符串存储在别名中。

    【讨论】:

      【解决方案5】:

      您不能在密钥存储中导入任意字符串。在密钥库中,您可以导入 Java 库用于远程主机身份验证的证书密钥。

      【讨论】:

      • 事实上你可以,正如@Charlie 在他上面的回答中描述的那样
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-27
      • 2011-03-03
      • 2013-02-05
      • 2017-10-08
      • 1970-01-01
      • 2020-09-05
      相关资源
      最近更新 更多