How to Convert a String to a Secretkey

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 key
SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
// get base64 encoded version of the key
String encodedKey = Base64.getEncoder().encodeToString(secretKey.getEncoded());

String to SecretKey:

// decode the base64 encoded string
byte[] decodedKey = Base64.getDecoder().decode(encodedKey);
// rebuild key using SecretKeySpec
SecretKey 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");

Converting string to SecretKey

I would recommend to read Java 256-bit AES Password-Based Encryption. But here a quick overview. You will have to create a SecretKeyFactory, a KeySpec and then you can generate your SecretKey based on the KeySpec. From there, you can specify that your key is an AES through SecretKeySpec. There are some magic numbers here that you will have to consider. One is the password iterations, and the other the key sizes. For the example that I created below, I am using a 128 key instead of a 256. Sorry, I am not an expert in security topics so I used some examples that I have.

public static void main(String[] args) {
try {
//message to be encrypted
final String message = "This is a test message";
final String password = "password";

// Here the magic numbers
final int pswdIterations = 65536;
final int keySize = 128;

final byte[] saltBytes = {0, 1, 2, 3, 4, 5, 6};

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, pswdIterations, keySize);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

// Instantiate the cipher
Cipher cipher = Cipher.getInstance("AES");

// Encrypt
cipher.init(Cipher.ENCRYPT_MODE, secret);
byte[] encrypted = cipher.doFinal(message.getBytes());
System.out.println("Original string: " + message);
System.out.println("Encrypted string: " + Arrays.toString(encrypted));

// Decrypt
cipher.init(Cipher.DECRYPT_MODE, secret);
byte[] decrypt_original = cipher.doFinal(encrypted);
String decrypt_originalString = new String(decrypt_original);
System.out.println("Decrypt string: " + decrypt_originalString);
} catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex) {
Logger.getLogger(Sandbox.class.getName()).log(Level.SEVERE, null, ex);
}
}

Hopefully, this will help you.

String to Secret key conversion/Vice Versa

Just follow below steps.

From key to string

`SecretKey secretKey = KeyGenerator.getInstance("ALGO_SECRET_KEY_GENERATOR").generateKey();
// Crate base64 string
String encodedKey = Base64.getEncoder().encodeToString(secretKey.getEncoded());`

From string to key

`// decode base64 string
byte[] decodedKey = Base64.getDecoder().decode(encodedKey);
// rebuild key using SecretKeySpec
SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "ALGO_SECRET_KEY_GENERATOR"); `

It is available from api version 8

`SecretKey secretKey = null;
try {
secretKey = KeyGenerator.getInstance("AES").generateKey();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}

byte encoded[] = secretKey.getEncoded();
String str = android.util.Base64.encodeToString(encoded , 0);

byte decoded[] = android.util.Base64.decode(str , 0);

SecretKey originalKey = new SecretKeySpec(decoded, 0, decoded.length, "AES");'

Converting String to Secret Key

You've got a few issues here:

  1. sb.getBytes() does not do what you think it does. What you are expecting is a byte array containing { 0xff, 0xfe, 0x7a, 0x50 }. What you are getting is a byte array containing { 0x46, 0x46, 0x46, 0x45, 0x37, 0x61, 0x35, 0x30 } (assuming you're using UTF-8).

    Your choices here would be to either initialise the byte array manually, like so:

    byte[] b = new byte[]{ (byte) 0xff, (byte) 0xfe, (byte) 0x7a, (byte) 0x50 };

    Or to parse the string correctly. I'm not sure exactly how you'd go about that, but it should be doable (and there will likely be an open-source library to do it for you).

  2. The output javax.crypto.spec.SecretKeySpec@183a2 is not writing out the value of the key. All you're seeing is the toString output of the SecretKeySpec, which follows the format <fully-qualified-class-name>@<hashcode> (see here for details on the toString() method), so the numbers you're seeing, 183a2, are just the hashcode of the SecretKeySpec object, which must not be the key - that would very insecure. To see the value of the key it's holding, you'd need to call the SecretKeySpec#getEncoded() method.

    Note that just calling System.out.println(byteArray) will not display the content of the byte array - it will just display the class name and hashcode again. You'll need to either iterate through the array and print out the elements one-by-one, or use another tool to compare the two arrays.

Converted SecretKey into bytes, how to convert it back to a SecretKey?

This should work

    SecretKey key = KeyGenerator.getInstance("DES").generateKey();
byte[] data = key.getEncoded();
SecretKey key2 = new SecretKeySpec(data, 0, data.length, "DES");

How to properly recreate SecretKey from string

One of your problems is here:

String encryptedText = new String(encryptedBytes, "UTF8");

Generally, many byte sequences in cipher text are not valid UTF-8–encoded characters. When you try to create a String, this malformed sequences will be replaced with the "replacement character", and then information from the the cipher text is irretrievably lost. When you convert the String back to bytes and try to decrypt it, the corrupt cipher text raises an error.

If you need to represent the cipher text as a character string, use base-64 encoding, just as you do for the key.

The other principal problem is that you are aren't specifying the full transformation. You should specify the "mode" and "padding" of the cipher explicitly, like "DESede/ECB/PKCS5Padding".

The correct mode will depend on your assignment. ECB is generally not secure, but more secure modes add a bit of complexity that may be outside the scope of your assignment. Study your instructions and clarify the requirements with your teacher if necessary.



Related Topics



Leave a reply



Submit