Converting Secret Key into a String and Vice Versa
You can convert the SecretKey
to a byte array (byte[]
), then Base64 encode that to a String
. To convert back to a SecretKey
, Base64 decode the String and use it in a SecretKeySpec
to rebuild your original SecretKey
.
For Java 8
SecretKey to String:
// create new keySecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();// get base64 encoded version of the keyString encodedKey = Base64.getEncoder().encodeToString(secretKey.getEncoded());
String to SecretKey:
// decode the base64 encoded stringbyte[] decodedKey = Base64.getDecoder().decode(encodedKey);// rebuild key using SecretKeySpecSecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
For Java 7 and before (including Android):
NOTE I: you can skip the Base64 encoding/decoding part and just store the byte[]
in SQLite. That said, performing Base64 encoding/decoding is not an expensive operation and you can store strings in almost any DB without issues.
NOTE II: Earlier Java versions do not include a Base64 in one of the java.lang
or java.util
packages. It is however possible to use codecs from Apache Commons Codec, Bouncy Castle or Guava.
SecretKey to String:
// CREATE NEW KEY// GET ENCODED VERSION OF KEY (THIS CAN BE STORED IN A DB) SecretKey secretKey; String stringKey; try {secretKey = KeyGenerator.getInstance("AES").generateKey();} catch (NoSuchAlgorithmException e) {/* LOG YOUR EXCEPTION */} if (secretKey != null) {stringKey = Base64.encodeToString(secretKey.getEncoded(), Base64.DEFAULT)}
String to SecretKey:
// DECODE YOUR BASE64 STRING// REBUILD KEY USING SecretKeySpec byte[] encodedKey = Base64.decode(stringKey, Base64.DEFAULT); SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
To show how much fun it is to create some functions that are fail fast I've written the following 3 functions.
One creates an AES key, one encodes it and one decodes it back. These three methods can be used with Java 8 (without dependence of internal classes or outside dependencies):
public static SecretKey generateAESKey(int keysize) throws InvalidParameterException { try { if (Cipher.getMaxAllowedKeyLength("AES") < keysize) { // this may be an issue if unlimited crypto is not installed throw new InvalidParameterException("Key size of " + keysize + " not supported in this runtime"); } final KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(keysize); return keyGen.generateKey(); } catch (final NoSuchAlgorithmException e) { // AES functionality is a requirement for any Java SE runtime throw new IllegalStateException( "AES should always be present in a Java SE runtime", e); }}public static SecretKey decodeBase64ToAESKey(final String encodedKey) throws IllegalArgumentException { try { // throws IllegalArgumentException - if src is not in valid Base64 // scheme final byte[] keyData = Base64.getDecoder().decode(encodedKey); final int keysize = keyData.length * Byte.SIZE; // this should be checked by a SecretKeyFactory, but that doesn't exist for AES switch (keysize) { case 128: case 192: case 256: break; default: throw new IllegalArgumentException("Invalid key size for AES: " + keysize); } if (Cipher.getMaxAllowedKeyLength("AES") < keysize) { // this may be an issue if unlimited crypto is not installed throw new IllegalArgumentException("Key size of " + keysize + " not supported in this runtime"); } // throws IllegalArgumentException - if key is empty final SecretKeySpec aesKey = new SecretKeySpec(keyData, "AES"); return aesKey; } catch (final NoSuchAlgorithmException e) { // AES functionality is a requirement for any Java SE runtime throw new IllegalStateException( "AES should always be present in a Java SE runtime", e); }}public static String encodeAESKeyToBase64(final SecretKey aesKey) throws IllegalArgumentException { if (!aesKey.getAlgorithm().equalsIgnoreCase("AES")) { throw new IllegalArgumentException("Not an AES key"); } final byte[] keyData = aesKey.getEncoded(); final String encodedKey = Base64.getEncoder().encodeToString(keyData); return encodedKey;}
Actually what Luis proposed did not work for me. I had to figure out another way. This is what helped me. Might help you too. Links:
*.getEncoded(): https://docs.oracle.com/javase/7/docs/api/java/security/Key.html
Encoder information: https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Encoder.html
Decoder information: https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Decoder.html
Code snippets:For encoding:
String temp = new String(Base64.getEncoder().encode(key.getEncoded()));
For decoding:
byte[] encodedKey = Base64.getDecoder().decode(temp);SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "DES");