简体   繁体   中英

Easy way to store/restore encryption key for decrypting string in java

For encryption I use something like this:

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

If I print out aesKey I get: "javax.crypto.spec.SecretKeySpec@1708d".

So for encryption I would like to ask user for key but dont know how and what format should it be. My plan was something like this:

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

But seems its not working. Is there some easy way to print out the key after encryption to console so user can save it(or remember it) and then Use for Decryption ?

Whole code is here: Cannot decrypt cyphertext from text file, symmetric key implement. in java So Im sorry for posting again but Im not sure If the code is even readable(I'm newbie).

I've had to do this myself recently. And while the other answers here led me in the right direction, it could have been easier. So here is my "share" for the day, a couple of helper methods for simple AES key manipulation. (Note the dependency on Apache Commons and Codec.)

This is all in a git repo now: 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");
}

Most Java Key instances are represented as a string of bytes resulting from their getEncoded() method. This is what needs to be stored in order to reconstruct the key later.

However, to store a key safely in electronic form, it should be encrypted. Of course, encrypting the key would require another key (or password)… and so you have an infinite regress. A Java KeyStore can be used to store SecretKey objects in this manner, and that is useful when you have many secret keys that are all protected by a single "master" password. But for protecting a single key, it doesn't make a lot of sense.

One alternative is to present the key to the user in a form that can be stored in some safe manner (in many applications, that might be on a slip of paper in their wallet). This could be as simple as displaying the bytes of the key encoded in hexadecimal, Base-64, or other text encoding, and asking the user to write it down.

Another approach is to allow the user to choose a memorable password, and generate a key with that, using an algorithm like PBKDF2. The salt (and maybe the iteration count) used for key derivation would need to be recorded somewhere though. Another drawback is that people tend to choose from a relatively limited number of passwords out of the total available. So keys derived from passwords may be easier guess than than the key size suggests.


Here is an illustration of the basic technique for persisting and reconstituting a secret key.

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");

I've stored keys in java keystore files. Here's an article that may help you out

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

Just for reference, the output you're seeing is the result of the default toString method and the funny number on the end is a hash code. See here . Hash codes are by design not reversible, and toString is not necessarily guaranteed to give you enough information to reconstruct the original object (although it does for certain classes).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM