存储/恢复加密密钥以便在java中解密字符串的简便方法

dav*_*e91 15 java encryption key

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

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

如果我打印出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);
Run Code Online (Sandbox Code Playgroud)

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

整个代码在这里:无法解密来自文本文件,对称密钥工具的密文.在java 所以我很抱歉再次发布但我不确定如果代码甚至可读(我是新手).

Stu*_*son 22

我最近自己不得不这样做.虽然这里的其他答案让我朝着正确的方向前进,但它可能会更容易.所以这是我今天的"份额",一些简单的AES键操作的辅助方法. (注意对Apache Commons和Codec的依赖.)

现在这都是git repo: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");
}
Run Code Online (Sandbox Code Playgroud)

  • 如果`getEncoded()`返回的数组有前导空字节或者第一个字节的位设置最高,那么这不会失败吗? (2认同)
  • _我是静态实用函数和静态导入的粉丝_ :) (2认同)

eri*_*son 14

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

但是,要以电子形式安全地存储密钥,应加密.当然,加密密钥需要另一个密钥(或密码)......所以你有一个无限的回归.Java KeyStore可用于以SecretKey这种方式存储对象,当您拥有许多受单个"主"密码保护的密钥时,这非常有用.但是为了保护单个密钥,它没有多大意义.

一种替代方案是以可以以某种安全方式存储的形式向用户呈现密钥(在许多应用中,可能在其钱包中的纸上).这可以像显示以十六进制,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");
Run Code Online (Sandbox Code Playgroud)

  • @sapatos如果设置了密钥的高位,`BigInteger`将在字节数组的开头添加一个零字节,以防止它被解释为负数.也许不是`new BigInteger(1,encoded)`,你应该允许字符串为负数:`new BigInteger(encoded)` (2认同)

Bil*_*Man 4

我已将密钥存储在 java 密钥库文件中。这里有一篇文章可能对你有帮助

http://www.informit.com/articles/article.aspx?p=170967&seqNum=3