URGENT!!!! Encryption/decryption problem using DES cipher

I am creating a chat program which encrypts on the client and decrypts on the server.

The client side is:

publicvoid sendMessage(String msg){

try{

msg = loginName +"> " + msg;

Cipher c = Cipher.getInstance("DES/CFB32/NoPadding");

c.init(c.ENCRYPT_MODE, key);

byte[] utf8 = msg.getBytes("UTF8");

byte[] enc = c.doFinal(utf8);

String newmsg =new sun.misc.BASE64Encoder().encode(enc);

out.println(newmsg);

The secret key is generated elsewhere. This method just encrypts the message and sends to the server.

The server side is:

publicvoid run(){

byte[] keyBytes;

try{

// Save the input stream so that bytes can easily be read

inStream = socket.getInputStream();

BufferedReader in =new BufferedReader(

new InputStreamReader(inStream));

String receivedMsg;

getkey();

while ((receivedMsg = in.readLine()) !=null){

System.out.println("Start sending messages to the clients");

System.out.println("Message is " + receivedMsg);

Enumeration theClients = records.elements();

// For each client, get the relevant socket and use it to pass the typed message back

// Note that this is all done in the clear

while (theClients.hasMoreElements()){

ClientRecord c = (ClientRecord)theClients.nextElement();

Socket socket = c.getClientSocket();

PrintWriter out =new PrintWriter(socket.getOutputStream(),true);

//try {

//decrypt incoming text

Cipher dcipher = Cipher.getInstance("DES/ECB/PKCS5Padding");

dcipher.init(Cipher.DECRYPT_MODE, secretkey);

byte[] dec =new sun.misc.BASE64Decoder().decodeBuffer(receivedMsg);

// byte[] dec = receivedMsg.getBytes("UTF8");

byte[] utf8 = dcipher.doFinal(dec);

String cleartext =new String(utf8,"UTF8");

out.println(cleartext);

System.out.println(secretkey);

}

}

System.out.println("Close the socket");

socket.shutdownInput();

socket.shutdownOutput();

socket.close();

}catch (IOException e){

e.printStackTrace();

}catch (InvalidKeyException ex){

ex.printStackTrace();

}catch (NoSuchAlgorithmException ex){

ex.printStackTrace();

}catch (NoSuchPaddingException ex){

ex.printStackTrace();

}catch (IllegalBlockSizeException ex){

ex.printStackTrace();

}catch (BadPaddingException ex){

ex.printStackTrace();

}

}

This is trying to decrypt incoming messeges but I get this error:

"input length must be a multiple of 8 when decrypting with a padded cipher."

If any one can help me on how to sort the decryption I will be most grateful.

Thanks

[4635 byte] By [Silverchaira] at [2007-11-27 3:04:04]
# 1

Err... Cipher c = Cipher.getInstance("DES/CFB32/NoPadding");

c.init(c.ENCRYPT_MODE, key);

and err...Cipher dcipher = Cipher.getInstance("DES/ECB/PKCS5Padding");

dcipher.init(Cipher.DECRYPT_MODE, secretkey);

Anything strike you as funny?

sabre150a at 2007-7-12 3:48:20 > top of Java-index,Security,Cryptography...
# 2
sorry about that long hours working on it has made me make some stupid mistakes. Thanks for your help!A quick follow up if you don't mind, would you have any idea how to add a MAC to or with the encrypted message using HmacMD5.Thanks again
Silverchaira at 2007-7-12 3:48:20 > top of Java-index,Security,Cryptography...
# 3

> A quick follow up if you don't mind, would you have

> any idea how to add a MAC to or with the encrypted

> message using HmacMD5.

Yes - but I would first make some fundamental changes to the whole approach.

1) I would not Base64 encode the data. Your code seems to rely on the Base64 data being output as just one line. Most Base64 encoders, and I think it includes the sun.misc one, put in new lines at about 80 characters. I would send the data as bytes prefixed by the the number of bytes being sent. DataOutputStream is good for this as it allows you to send a lengh as an int or short followed by the data. One reads the data using DataInputStream where one can read an int and then use readFully() to read the bytes.

2) I would used CBC mode with PKCS5Padding using a random IV.

3) I would extract all the encryption and decryption code into a class on it's own. In this way you can test it without having to carry the whole of your networking code into the test harness.

4) Get rid of that dreadful exception handling. As a rule, it you can't handle an exception then just throw it a let the caller handle it. If you want to isolate the caller from the detail of what is wrong, just wrap the exception in a home grown exception and throw that.

Mac and HMAC are relatively easy to apply. My standard published HMAC example is

import javax.crypto.*;

import javax.crypto.spec.*;

import sun.misc.*;

public class HmacDigestOfString

{

static public class DigestException extends Exception

{

private DigestException(String text, Exception chain)

{

super(text, chain);

}

}

public HmacDigestOfString(byte[] keyBytes, String mode, String encoding) throws DigestException

{

if ((keyBytes == null) || (keyBytes.length < 1))

throw new IllegalArgumentException("Hmac key must be at least one bytes");

if (mode == null)

throw new IllegalArgumentException("'mode' canot be null");

try

{

final SecretKey key = new SecretKeySpec(keyBytes, mode);

mac_ = Mac.getInstance(mode);

mac_.init(key);

encoding_ = (encoding == null) ? "utf-8" : encoding;

}

catch (Exception e)

{

throw new DigestException("Problem constucting " + this.getClass().getName(), e);

}

}

synchronized public byte[] digestAsBytes(String stringToHash) throws DigestException

{

assert(stringToHash != null);

try

{

mac_.reset();

mac_.update(stringToHash.getBytes(encoding_));

byte[] hashBytes = mac_.doFinal();

return hashBytes;

}

catch (Exception e)

{

throw new DigestException("Problem creating digest", e);

}

}

synchronized public String digestAsBase64(String stringToHash) throws DigestException

{

return encoder_.encode(digestAsBytes(stringToHash));

}

synchronized public String digestAsHex(String stringToHash) throws DigestException

{

return encodeBytesAsHex(digestAsBytes(stringToHash));

}

private final BASE64Encoder encoder_ = new BASE64Encoder();

private final Mac mac_;

private final String encoding_;

private static String encodeBytesAsHex(byte[] bites)

{

final char[] hexChars = new char[bites.length*2];

for (int charIndex = 0, startIndex = 0; charIndex < hexChars.length;)

{

final int bite = bites[startIndex++] & 0xff;

hexChars[charIndex++] = HEX_CHARS[bite >> 4];

hexChars[charIndex++] = HEX_CHARS[bite & 0xf];

}

return new String(hexChars);

}

private static final char[] HEX_CHARS =

{'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};

static public void main(String[] args) throws Exception

{

// Length does not seem to matter as long as it it greater than 0

final byte[] keyBytes = "The quick brown fox jumps over the lazy dog.".getBytes("ASCII");

final HmacDigestOfString shaMacOfStringAgent = new HmacDigestOfString(keyBytes, "HmacSHA256", "UTF-8");

final HmacDigestOfString md5MacOfStringAgent = new HmacDigestOfString(keyBytes, "HmacMD5", "UTF-8");

for (int i = 0; i < 20; i++)

{

final String user = "User "+i;

final String password = "Password";

final String stringToHash = user + "\t" + password;

System.out.println(user + "\t [" + shaMacOfStringAgent.digestAsBase64(stringToHash)+"] [" + shaMacOfStringAgent.digestAsHex(stringToHash)+"]");

System.out.println(user + "\t [" + md5MacOfStringAgent.digestAsBase64(stringToHash)+"] [" + md5MacOfStringAgent.digestAsHex(stringToHash)+"]");

}

}

}

An important note is that you should not use the same key for encryption as is used for the HMAC. Also, the HMAC of the unencrypted data should be used, NOT the encrypted data.

P.S. I have just checked and the sun.misc.Base64 encoder does break it's output into lines.

sabre150a at 2007-7-12 3:48:20 > top of Java-index,Security,Cryptography...
# 4

> Most Base64 encoders, and I think it

> includes the sun.misc one, put in new lines at about

> 80 characters.

To clarify this for the record, a line length limit of 76 characters is part of the MIME 'base 64 Content-Transfer-Encoding' standard, and PEM specifies 64. However RFC4648 says that an implementation MUST NOT insert linefeeds into encoded data unless the surrounding specification (e.g. PEM, MIME) referring to base-64 so directs.

!

ejpa at 2007-7-12 3:48:20 > top of Java-index,Security,Cryptography...