Take the 2-minute tour ×

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 don'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?

share|improve this question
add comment

4 Answers

up vote 5 down vote accepted

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).

share|improve this answer
A nice solution, it even accounts for leading zeros. If I may nitpick, I would choose my own constant, probably 32 or 16, rather than Character.MAX_RADIX. It's possible that some future version of java.lang.Character will use a larger value than 36. –  GregS May 26 '10 at 23:28
@GregS: you are right. BTW, Character.MAX_RADIX is 36 presently –  leonbloy May 27 '10 at 0:55
Although the answer is correct and working, I'm wondering: what you mean with "SecretKey is binary data"? For me, at some level, everything is binary data.. Could you give an example of data that isn't binary data? Thanks! –  Tom Brito Jun 2 '10 at 18:52
@Tom: it just depends on what level the concept is defined. For example, when we speak of a HTML page, a JSON piece of data, a Java String, a pattern in a regular expression, a web.xml file, etc, we deal with some syntax that makes sense in the textual world (one could also specify some way -encoding- to represent is a binary, but that would fall outside the definition -and frequently one has freedom to use several binary encodings).. –  leonbloy Jun 2 '10 at 19:09
add comment

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");
share|improve this answer
Very bad idea - the data will be arbitrary binary data, and that won't always be a valid UTF-8 sequence. –  Jon Skeet May 26 '10 at 17:21
ah ok now i get the problem...yeah forget this answer :) –  fasseg May 26 '10 at 17:23
But wouldn't the key be encoded using the system default charset when one calls getEncoded()? then you could just call key.getBytes() and new String(byte[] data)... –  fasseg May 26 '10 at 17:26
@smeg4brains: What makes you think that? Secret keys don't have to have any text representation at all, as far as I'm aware. –  Jon Skeet May 26 '10 at 17:28
@smeg4brains - some encodings (US-ASCII, for example) don't map a character to every value in the range from 0–255. When the decoder finds a byte outside this domain, it substitutes a "replacement character" (�) When the String is encoded to bytes again, they won't be the original bytes. –  erickson May 26 '10 at 17:34
show 3 more comments

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?

share|improve this answer
its becouse I'm new to DB, and I'm using Derby and hard coded SQL (which takes String as parameter). A may work better with DBs with time.. :) –  Tom Brito May 26 '10 at 17:38
@Tom: I would try to fix the SQL rather than converting to a string, unless Derby doesn't support binary data. Base64 would certainly work if you really really want to stick to a string though. –  Jon Skeet May 26 '10 at 17:46
Derby sql statments support only Strings as arguments, I choose to decode with the Apache Commons Code Hex class, as I am already some familiar with it. –  Tom Brito May 26 '10 at 18:49
I'm a fan of the iharder solution also. –  GregS May 26 '10 at 23:29
add comment

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);
share|improve this answer
Sensible idea, in some situations (I've used it once). I made some corrections (for example, this code does not keep zero bytes at the beginning, I think) and added to my post. –  leonbloy May 26 '10 at 18:49
It restores zero bytes at the beginning by copying the value into the least significant bytes of the destination array. –  erickson May 26 '10 at 22:23
add comment

Your Answer


