Symmetric encryption -- method to distrubute key
Hi,
I am new to cryptography. I am developing a utility to do symmetric encryption and decryption. I have generated a key using the following code.
public byte[] generateKey() throws NoSuchAlgorithmException
{
byte[] _key = null;
KeyGenerator keygen = KeyGenerator.getInstance(TripleDESCipherUtility.ALGORITHM);
SecretKey key = keygen.generateKey();
_key = key.getEncoded();
return _key;
}
Where algorithm used is as below,
protected static final String ALGORITHM = "DESede";
After i generate the key, it is a byte array. I was digging through most of the message in the forum which suggested we should not convert the key( byte array) to string.
In symmetric encryption both systems involved in secured communication share the same key. Now my question is, the key which i have generate is a byte array and i need to provide this key to the other system. In which form should i supply this key. As suggested in other messages one should not covert byte array to string as it will have platform dependent character encoding. Please suggest a way to distrubute this key to the other system.
I just tested this method using the code below,
public static void main(String[] args)
{
TripleDESCipherUtility cipherUtility = TripleDESCipherUtility.getInstance();
try
{
byte[] key = cipherUtility.generateKey();
String keyStr = new String(key);
String utfKeyStr = new String(key);
System.out.println("generated key with platform specific encoding : " + keyStr);
System.out.println("key length : " + key.length + "keyStr length : " + keyStr.length());
System.out.println("keyStr.getBytes.length : " + keyStr.getBytes().length);
System.out.println("utfKeyStr : " + utfKeyStr + "utfKeyStr.getBytes.length : " + utfKeyStr.getBytes().length);
System.out.println("utfKeyStr.getBytes.length : " + utfKeyStr.getBytes("UTF8").length);
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
Output is as below,
generated key with platform specific encoding : ?%?珚邈?滞1簚简@?br>key length : 24keyStr length : 24
keyStr.getBytes.length : 24
utfKeyStr : ?%?珚邈?滞1簚简@瀠tfKeyStr.getBytes.length : 24
utfKeyStr : ?%?珚邈?滞1簚简@瀠tfKeyStr.getBytes.length : 41
As seen above, we see the byte size differs when we specify a different encoding. Is it appropriate to distrubute the key as ?%?珚邈?滞1簚简@? which i don't think so.. can anyone suggest a way to distrubute this key in a platform independent manner which should be in non readable formation.. what i mean is it should not in the form for example like 235-23-56-172....etc where each number represents integer value of the byte in the byte array(key).
Message was edited by:
ravindra303
<snip>
> After i generate the key, it is a byte array. I was
> digging through most of the message in the forum
> which suggested we should not convert the key( byte
> array) to string.
Certainly not using new String(keyBytes) but if you really have to have a String version then you could use Base64 or Hex encoding which is independent of the operating system.
>
> In symmetric encryption both systems involved in
> secured communication share the same key. Now my
> question is, the key which i have generate is a byte
> array and i need to provide this key to the other
> system. In which form should i supply this key.
If you are going to deliver it on a removable media then just write the bytes to a file. If you are going to send ot over tcp then re-think your system design. To my mind the best approach would be to use SSL using JSSE. Using this you would not need to explictly encrypt anything. If it is not possible to use SSL then you could create a session keys using the DH (Diffe-Hellman) technique.
Thank you very much, I just tried using Base64 encoder. This solves my problem of getting a string representation of byte[] in a printable character format.
I am currently using SSL which encrypts all the data transmitted over the wire but apart from that we had requirement to add a layer of encrypton on top of that to encrypt all the name value pairs sent in the query string of the request... strange :-) not sure why this was required. Anyway i need to implement this..
so my approach is to encrypt the name value pairs and then convert to string using base64, transfer them over the wire using SSL.... at the other system.. decode from base64.. then decrypt the string.. i guess this will solve my problem... but i would like your suggestion whether my approach is correct.. i would appreciate if you would have better idea.
As far as key is concern yeah writing it to a file would be better idea but when writing it to a file using a writer it will again write using a default character encoding of the platform unless we specify a character encoding.. right ? or should we distrubute the key by using base64 encoding format.. still confused in this part.. any suggesstions.
> Thank you very much, I just tried using Base64
> encoder. This solves my problem of getting a string
> representation of byte[] in a printable character
> format.
>
> I am currently using SSL which encrypts all the data
> transmitted over the wire but apart from that we had
> requirement to add a layer of encrypton on top of
> that to encrypt all the name value pairs sent in the
> query string of the request... strange :-) not sure
> why this was required. Anyway i need to implement
> this..
So you will do DESede encryption in Javascript on the client and then decrypt the values on the server.
>
> so my approach is to encrypt the name value pairs and
> then convert to string using base64, transfer them
> over the wire using SSL.... at the other system..
> decode from base64.. then decrypt the string.. i
> guess this will solve my problem... but i would like
> your suggestion whether my approach is correct.. i
> would appreciate if you would have better idea.
You may have a problem with Base64 encoding because most Base64 encoders break the output into lines at about 76 characters so if your encoded encrypted values have more than 76 characters then you will need to strip out line breaks.
>
> As far as key is concern yeah writing it to a file
> would be better idea
How are you going to get the key to the client computer? You will need to get javascript to read the key from a file on the client but you can't just write it with Javascript because that would mean you would be passing it using the media you consider is insecure in the first place.
Again, consider the user of DH key exchange to get over this problem.
> but when writing it to a file
> using a writer
Writers are for characters. Keys are bytes. Write bytes using an OutputStream.
> it will again write using a default
> character encoding of the platform unless we specify
> a character encoding.. right ? or should we
> distrubute the key by using base64 encoding format..
> still confused in this part.. any suggesstions.
Once again, if you have to have a String version of any bytes then use Base64 or Hex encoding. Keys are just bytes.
I don't understand about encrypting the name-value pairs. Does this mean the name-value pairs in the UURL? and is this to hide them from the user at the browser? because there is no other reason to do it. The entire URL including the N-V pairs is transmitted over SSL, i.e. it is already encrypted.
I would take this up with your requirements authors. At least see whether they know what they are talking about.
> So you will do DESede encryption in Javascript on the
> client and then decrypt the values on the server.
Well there are two systems say server1 (S1) and server2(S2) and a client (C1 - end user using a browser). S1 wants to encrypt this data(name value pairs) and send it over SSL to S2. I assume that S1 will add this encrypted name value pairs as hidden fields to the HTML form and they will get submitted to S2 as a post request upon click of submit. So there is no need of javascript using any encryption on the client side as the data in the hidden fields is already encrypted.. hence we don't have to share the key with clients(browsers). It is going to be post request so length of the URL will not be problem.. any suggestions ? please suggest if i am getting it wrong.
> You may have a problem with Base64 encoding because
> most Base64 encoders break the output into lines at
> about 76 characters so if your encoded encrypted
> values have more than 76 characters then you will
> need to strip out line breaks.
Should we handle this situation programatically ? I mean at S2(server2). Do we have to read byte by byte and check if there is line break? is there a better way to handle this line break situation.
> How are you going to get the key to the client
> computer? You will need to get javascript to read the
> key from a file on the client but you can't just
> write it with Javascript because that would mean you
> would be passing it using the media you consider is
> insecure in the first place.
As discussed above, i guess javascript (client browser) will not encrypt any data so client will not need any key. We can give S1 the key as a file... is it okay?
> Again, consider the user of DH key exchange to get
> over this problem.
Using the discussion above do i have to really consider DH key exchange or the current implementation would be enough to solve the problem.
> Writers are for characters. Keys are bytes. Write
> bytes using an OutputStream.
yes, you are right.
> Once again, if you have to have a String version of
> any bytes then use Base64 or Hex encoding. Keys are
> just bytes.
String version is required because we need to insert them as part of URL in name value pairs, so i think its better to use Base64... what do you think ?
Thank you.
> I don't understand about encrypting the name-value
> pairs. Does this mean the name-value pairs in the
> UURL? and is this to hide them from the user at the
> browser? because there is no other reason to do it.
> The entire URL including the N-V pairs is transmitted
> over SSL, i.e. it is already encrypted.
>
> I would take this up with your requirements authors.
> At least see whether they know what they are talking
> about.
Yes i understand, even i have the same query but its a requirement to be fulfilled.. I am trying to convince them why they require this encryption on top of SSL.. lets see what happens.. :-) Thank you for your response to the query.
So the client relays the data between the two servers. Presumably you need to encrypt the data because don't want the client to be able to read the data.
<quote>String version is required because we need to insert them as part of URL in name value pairs, so i think its better to use Base64... what do you think ?</quote> This is not consistent with your statement <quote>It is going to be post request so length of the URL will not be problem </quote> .
<quote>Do we have to read byte by byte and check if there is line break? </quote>
No, strip them off before you place them in the hidden fields. Even better still, find a Base64 encoder that allows you to disable breaking the result up into lines.
As I see it, you only need one field to contain all your encrypted data.
> So the client relays the data between the two
> servers. Presumably you need to encrypt the data
> because don't want the client to be able to read the
> data.
Yeah thats right, now i understand why we needed to encrypt this data.
> <quote>String version is required because we need to
> insert them as part of URL in name value pairs, so i
> think its better to use Base64... what do you think
> ?</quote> This is not consistent with your statement
> <quote>It is going to be post request so length of
> the URL will not be problem </quote> .
what i ment is, we can use base64 encoding to encode encrypted name value pairs, now if there are say 70 or 80 name value pairs, this will be very long string, that is the reason we are using a post request. I guess i make sense.
> <quote>Do we have to read byte by byte and check if
> there is line break? </quote>
> No, strip them off before you place them in the
> hidden fields. Even better still, find a Base64
> encoder that allows you to disable breaking the
> result up into lines.
>
> As I see it, you only need one field to contain all
> your encrypted data.
I wished the same, to have one field to contain all encrypted data but it doesn't help because if we use one field then at the server we have to tokenizer to extract all the name value pairs. So we will have each name value pair encrypted seperately and added as a seperate hidden field so that the query string would look like ?8ro9Qp5C12LhkpBrC%2BLOdw%3D%3D=ILkxizjwKorhkpBrC%2BLOdw%3D%3D&AqiU178LUoXhkpBrC%2BLOdw%3D%3D=eHY%2Fbtf%2BmBKx67MKnN3VpQ%3D%3D&%2FHLYH5rCRaHhkpBrC%2BLOdw%3D%3D=54hODN9eo1lgxbqdTuH2jA%3D%3D&Bp6UujJMyZLhkpBrC%2BLOdw%3D%3D=o%2FrBrZYCcrRnuE5yPmSdydj%2Bmn7TvIMz
this query string is of the following format
?encoded(encrypted(name1))=encoded(encrypted(value1))&encoded(encrypted(name2))=encoded(encrypted(value2))&encoded(encrypted(name3))=encoded(encrypted(value3))..... and so on.
Assuming we have 40 name value pairs, we see in the above method we have to run encryption 80 times at server1 and run decryption 80 times at server2. At server2 we can directly use HTTPServlet API to get name-value from the request object using getParameterNames and getParameter. But as i have said above the trade off is running encryption and decrytion so manytimes.
what is your opinion, should we use single field to hold the encrypted namevalue pairs and tokenize at server2 or use method i have suggested above. Performance wise which is better ?
<quote>this query string is of the following format
?encoded(encrypted(name1))=encoded(encrypted(value1))&encoded(encrypted(name2))=encoded(encrypted(value2))&encoded(encrypted(name3))=encoded(encrypted(value3))..... and so on.
</quote>
You only get this form of query string using GET, not using POST. Check the HTTP specifications for details.
<quote>should we use single field to hold the encrypted namevalue pairs and tokenize at server2 or use method i have suggested above. </quote>
One field is all you need! I have used this approach on 3 projects.
<quote>Performance wise which is better ?</quote>
Not easy for me to say but I found no performance problem with one field. Rather than have the servlet engine split the body of the post one in effect does it manually. One advantage is that you can use positional parameters rather than name<->value pairs thus saving bandwidth. Using just one ffield, you will also have less encryption overhead since you only have to send one IV rather than 40 and you only have one lot of padding rather than 40.
> <quote>this query string is of the following format
> ?encoded(encrypted(name1))=encoded(encrypted(value1))&
> encoded(encrypted(name2))=encoded(encrypted(value2))&e
> ncoded(encrypted(name3))=encoded(encrypted(value3))...
> .. and so on.
> </quote>
> You only get this form of query string using GET, not
> using POST. Check the HTTP specifications for
> details.
I am aware that using Get request give you the query string as
?encoded(encrypted(name1))=encoded(encrypted(value1))&encoded(encrypted(name2))=encoded(encrypted(value2))&encoded(encrypted(name3))=encoded(encrypted(value3))..... and so on
and this will be visible in the address bar of the browser but we are using POST so this querystring will not be visible in the address bar of the browser and also there is no limit for the URL length.
The way to implement this is as i have said earlier, to use hidden fields with name and value as encrypted text in HTML form with method=POST. This request will not be visible in the address bar as shown above but will be transmitted to the server as above (correct me if i am wrong). I know with post method if you do request.getQueryString() you won't get anything but if you do request.getParameter(parameterName) you will get the value of the parameter. URL pattern shown above is just a illustration of the request but you won't see it anywhere.
<form action="sss" method="POST">
<input type="hidden" name="yn8XtY4K/OutQyQMLXDgRQ==" value="N6kow932EoyN+IrLHfho4A=="> </input>
</form>
where N6kow932EoyN+IrLHfho4A== is encoded(encrypted(value))
I think i am making it clear now.
> <quote>should we use single field to hold the
> encrypted namevalue pairs and tokenize at server2 or
> use method i have suggested above. </quote>
This is a better approach, i think i will go with this.. thank you.
Message was edited by:
ravindra303
