AES Key encoded byte[] to String and back to byte[]
In the similar question "Conversion of byte[] into a String and then back to a byte[]" is said to not to do the byte[] to String and back conversion, what looks like apply to most cases, mainly when you d开发者_如何学Con't know the encoding used.
But, in my case I'm trying to save to a DB the javax.crypto.SecretKey data, and recoverd it after.
The interface provide a method getEncoded() which returns the key data encoded as byte[], and with another class I can use this byte[] to recover the key.
So, the question is, how do I write the key bytes as String, and later get back the byte[] to regenerate the key?
javax.crypto.SecretKey
is binary data, so you can't convert it directly to a String. You can encode it as a hex string or in Base64.
See Apache Commons Codec.
Update: If you dont want to depend on third-party libraries (and can't/don't want to store plain binary data, as Jon suggests) you can do some ad-hoc encoding, for example, following erickson's suggestion:
public static String bytesToString(byte[] b) {
byte[] b2 = new byte[b.length + 1];
b2[0] = 1;
System.arraycopy(b, 0, b2, 1, b.length);
return new BigInteger(b2).toString(36);
}
public static byte[] stringToBytes(String s) {
byte[] b2 = new BigInteger(s, 36).toByteArray();
return Arrays.copyOfRange(b2, 1, b2.length);
}
It's rather, ugly, non-standard and not optimal (in output size). But it's also very small, correct and it has no dependencies; it can be practical, specially if your data is small sized.
Updated: I replaced the Character.MAX_RADIX
by the literal value (36), following GregS's comment. It might seem less elegant but it's actually more secure. (You can also use 32 or 16).
Use a base-64 encoding to safely convert arbitrary binary data to a string and back.
The Apache Commons Codec library provides code for this, as do various others. (I'm not terribly keen on the API to Apache Commons Codec, admittedly. I don't know of any other libraries with this functionality off hand but I'm sure they exist.)
EDIT: This project provides a single file for fast encoding and decoding, and has sane method signatures - as well as plenty of extra options should you need them.
Alternatively, if the point is to save it to a database, why not just use an appropriate binary data field (Image/Blob or whatever applies to your database) rather than storing it as a string in the first place?
How about encoding as a number instead of a character string? It's not quite as compact as Base-64, but you can leave out Apache Commons.
/* Store the key. */
BigInteger n = new BigInteger(1, key.getEncoded()); /* Store as NUMBER, or … */
String s = n.toString(32); /* … store as VARCHAR. */
/* Reconstruct the key (may need to pad most significant bytes with zero). */
BigInteger n = new BigInteger(s); /* Load from VARCHAR, or … */
byte[] raw = n.toByte(); /* … load from NUMBER. */
byte[] original = new byte[16];
System.arraycopy(raw, 0, original, 16 - raw.length, raw.length);
Couldn't you use the String constructor: String(byte[] data,String charsetName) as in:
byte[] data=new byte[1024];
String key=new String(data,"UTF-8");
and later you can do:
String key="mymostsecretaeskey";
byte[] data=key.getBytes("UTF-8");
精彩评论