存储/恢复加密密钥的简单方法,用于在java中解密字符串

2022-09-02 23:23:56

对于加密,我使用类似这样的东西:

SecretKey aesKey = KeyGenerator.getInstance("AES").generateKey();
StringEncrypter aesEncrypt = new StringEncrypter(aesKey, aesKey.getAlgorithm());
String aesEncrypted= aesEncrypt.encrypt(StringContent);

如果我打印出aesKey,我得到:“javax.crypto.spec.SecretKeySpec@1708d”。

因此,对于加密,我想向用户询问密钥,但不知道如何以及应该采用什么格式。我的计划是这样的:

SecretKey aesKey = javax.crypto.spec.SecretKeySpec@1708d;
StringEncrypter aesEncrypt = new StringEncrypter(aesKey, aesKey.getAlgorithm());
String aesDecrypt = aesEncrypt.decrypt(aesEncrypted);

但似乎它不起作用。有没有一些简单的方法可以在加密后将密钥打印到控制台,以便用户可以保存它(或记住它),然后用于解密?

整个代码在这里:无法从文本文件中解密密码文本,对称密钥实现。 在java中,所以我很抱歉再次发布,但我不确定代码是否可读(我是新手)。


答案 1

我最近不得不自己做这件事。虽然这里的其他答案引导我朝着正确的方向前进,但它本来可以更容易。因此,这是我当天的“分享”,几个用于简单AES密钥操作的帮助器方法。(注意对Apache Commons和Codec的依赖性。

现在,这一切都在git存储库中:github.com/stuinzuri/SimpleJavaKeyStore

import static org.apache.commons.codec.binary.Hex.*;
import static org.apache.commons.io.FileUtils.*;
import java.io.*;
import java.security.NoSuchAlgorithmException;
import javax.crypto.*;
import org.apache.commons.codec.DecoderException;

public static SecretKey generateKey() throws NoSuchAlgorithmException
{
    KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
    keyGenerator.init(256); // 128 default; 192 and 256 also possible
    return keyGenerator.generateKey();
}

public static void saveKey(SecretKey key, File file) throws IOException
{
    char[] hex = encodeHex(key.getEncoded());
    writeStringToFile(file, String.valueOf(hex));
}

public static SecretKey loadKey(File file) throws IOException
{
    String data = new String(readFileToByteArray(file));
    byte[] encoded;
    try {
        encoded = decodeHex(data.toCharArray());
    } catch (DecoderException e) {
        e.printStackTrace();
        return null;
    }
    return new SecretKeySpec(encoded, "AES");
}

答案 2

大多数 Java 实例表示为由其 getEncoded() 方法生成的字节字符串。这是需要存储的内容,以便以后重建密钥。Key

但是,要以电子形式安全地存储密钥,应对其进行加密。当然,加密密钥将需要另一个密钥(或密码)...所以你有一个无限的倒退。Java可用于以这种方式存储对象,当您有许多密钥都受单个“主”密码保护时,这很有用。但是对于保护单个密钥,它没有多大意义。KeyStoreSecretKey

一种替代方法是以一种可以以某种安全方式存储的形式向用户呈现密钥(在许多应用程序中,这可能在钱包中的纸条上)。这可以像显示以十六进制、Base-64 或其他文本编码编码的密钥的字节一样简单,并要求用户将其写下来。

另一种方法是允许用户选择一个令人难忘的密码,并使用PBKDF2等算法生成密钥。但是,用于键派生的盐(也许还有迭代计数)需要在某个地方记录下来。另一个缺点是,人们倾向于从可用密码总数中相对有限的数量中进行选择。因此,从密码派生的密钥可能比密钥大小所暗示的更容易猜测。


下面是用于持久保存和重新构造密钥的基本技术的说明。

byte[] encoded = aesKey.getEncoded();
/* Now store "encoded" somewhere. For example, display the key and 
   ask the user to write it down. */
String output = Base64.getEncoder().withoutPadding().encodeToString(encoded);
System.out.println("Keep it secret, keep it safe! " + output);

...

/* At some point, you need to reconstitute the key. Let's say the user 
   enters it as a base-64 number that you convert to bytes. */
String input = ... ;
byte[] encoded = Base64.getDecoder().decode(input);
SecretKey aesKey = new SecretKeySpec(encoded, "AES");