1

I'm writing a code that send encrypted file from client to server but first the client send the encrypted message digest of the file to the server and then send the name of the file and at the end it will send the bytes of encrypted file, but in the server side it read all these variables as one variable which is the digest ,

and when the server trying to decrypt the digest it throws Illegal Block Size Exception My question here is how can the server read and save them in different variables ??

Client

            // set mode to encrypt
            AesCipher.init(Cipher.ENCRYPT_MODE, key);

            DataOutputStream toServer = new DataOutputStream(socket.getOutputStream());

            // get the digest of the file
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hash = md.digest(bytes);

            // encrypt digest and write it to file
            byte [] encryptedHash = AesCipher.doFinal(hash);
            toServer.write(encryptedHash);


            // write file name to server
            toServer.writeUTF(fileName);

            //encrypt file
            byte[] encryptedByte = AesCipher.doFinal(bytes);


            // write file to server
            toServer.write(encryptedByte);
            toServer.flush();
            socket.close();

Server

// read digest of the file
        byte [] digest =IOUtils.toByteArray(fromClient);

        // decrypt it
        AesCipher.init(Cipher.DECRYPT_MODE, key);
        byte[] decryptedDigest = AesCipher.doFinal(digest);

        // read file name to be received
        String fileName = fromClient.readUTF();

        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName);
        file.createNewFile();
        FileOutputStream fos = new FileOutputStream(file);
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        // read file bytes from client
        byte[] fileBytes = IOUtils.toByteArray(fromClient);

        AesCipher.init(Cipher.DECRYPT_MODE, key);
        byte[] decryptedByte = AesCipher.doFinal(fileBytes);
        bos.write(decryptedByte, 0, decryptedByte.length);
        bos.close();

also I tried this code but it didn't works too

// read digest of the file
         ByteArrayOutputStream buffer = new ByteArrayOutputStream();

        int nRead;
        byte[] data = new byte[1024];

        while ((nRead = fromClient.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, nRead);
        }

        buffer.flush();
        byte[] digest = buffer.toByteArray();

        // decrypt it
        AesCipher.init(Cipher.DECRYPT_MODE, key);
        byte[] decryptedDigest = AesCipher.doFinal(digest);

        // read file name to be received
        String fileName = fromClient.readUTF();

        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName);
        file.createNewFile();
        FileOutputStream fos = new FileOutputStream(file);
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        // read file bytes from client
        byte[] fileBytes = IOUtils.toByteArray(fromClient);

        AesCipher.init(Cipher.DECRYPT_MODE, key);
        byte[] decryptedByte = AesCipher.doFinal(fileBytes);
        bos.write(decryptedByte, 0, decryptedByte.length);
        bos.close();
5
  • 1
    On the server side you make no attempt to read in the same number of bytes that were written out for each piece, instead you read in the entire amount written out into the digest. If one piece is 16 bytes then you need to read in 16 bytes. If you don't know a prior how many bytes it is then you need to prefix the length of piece to the piece itself. Commented Aug 17, 2017 at 23:17
  • @JamesKPolk how can i=I know how many bytes after encryption the digest ? Commented Aug 17, 2017 at 23:27
  • You'll have to send its length ahead of it. Commented Aug 17, 2017 at 23:27
  • @EJP I wrote this in client toServer.writeInt(encryptedHash.length); and int size = fromClient.readInt(); byte[] data = new byte[size]; in server ,but it did not works too !! Commented Aug 17, 2017 at 23:31
  • You should send a number represent the number of bytes will be sended next time. Commented Aug 17, 2017 at 23:52

1 Answer 1

2

IOUtils.toByteArray(InputStream) reads the entire stream. So instead of just getting the hash bytes, you got the whole stream, and there was nothing left for the filename or the ciphertext, and the hash didn't check.

You don't need external libraries for this. You can do it all with DataInputStream and DataOutputStream. But you do need to send the length of the hash ahead of the hash.

Client:

        // set mode to encrypt
        AesCipher.init(Cipher.ENCRYPT_MODE, key);

        DataOutputStream toServer = new DataOutputStream(socket.getOutputStream());

        // get the digest of the file
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] hash = md.digest(bytes);

        // encrypt digest and write it to file
        byte [] encryptedHash = AesCipher.doFinal(hash);
        toServer.writeInt(encryptedHash.length);
        toServer.write(encryptedHash);

        // write file name to server
        toServer.writeUTF(fileName);

        //encrypt file
        byte[] encryptedByte = AesCipher.doFinal(bytes);

        // write file to server
        toServer.writeInt(encryptedByte.length);
        toServer.write(encryptedByte);
        socket.close();

Server:

    // read digest of the file
    int digestLength = fromClient.readInt();
    byte[] digest = new byte[digestLength];
    fromClient.readFully(digest);

    // decrypt it
    AesCipher.init(Cipher.DECRYPT_MODE, key);
    byte[] decryptedDigest = AesCipher.doFinal(digest);

    // read file name to be received
    String fileName = fromClient.readUTF();

    File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName);
    FileOutputStream fos = new FileOutputStream(file);
    BufferedOutputStream bos = new BufferedOutputStream(fos);

    // read file bytes from client
    int fileLength = fromClient.readInt();
    byte[] fileBytes = new byte[fileLength];
    fromClient.readFully(fileBytes);

    AesCipher.init(Cipher.DECRYPT_MODE, key);
    byte[] decryptedByte = AesCipher.doFinal(fileBytes);
    bos.write(decryptedByte, 0, decryptedByte.length);
    bos.close();

However the encryption and decryption parts of this would be much better done with CipherInputStream and CipherOutputStream. You shouldn't load entire files into memory.

Note that the file.createNewFile() call was redundant before new FileOutputStream(...).

Why you're encrypting a message digest is another mystery. You should be using it as a final step to compare with a locally-generated digest after decryption.

Sign up to request clarification or add additional context in comments.

2 Comments

thanks, I just posted the piece of code that generate the error, client sent encryption MD to the server so server will compare it with a locally-generated digest after decryption.
But you don't need to encrypt the MD. It's not a secret.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.