Making a FormDataBodyPart from a CyperInputStream

39 Views Asked by At

I have an encrypted photo file stored in AW3. I read it this function and decrypt it:

public static InputStream decryptStream(InputStream encryptedInputStream, MultimediaFile document) throws DocumentProcessingException {
    log.debug("Decrypting document {}", document);

    SecretKeySpec secret = new SecretKeySpec(document.getAESKey(), AES);
    byte[] iv = document.getInitializationVector();

    Cipher cipher;
    try {
        cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
    } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException ex) {
        throw new DocumentProcessingException("Error decrypting document " + document, ex);
    }

    return new CipherInputStream(encryptedInputStream, cipher);
}

At this stage, I want to send the decrypted image to an internal micro-service which generates thumbnails for it. I do it in the function below:

public InputStream getThumbnail(InputStream inputStream, int width, int height, String mimeType) {
    ClientConfig clientConfig = new ClientConfig();
    clientConfig.register(MultiPartFeature.class);
    Client client = ClientBuilder.newClient(clientConfig);

    try (FormDataMultiPart formDataMultiPart = new FormDataMultiPart()) {
        String fileExtension = mimeType.split("/")[1];

        FormDataContentDisposition contentDisposition = FormDataContentDisposition
            .name("image")
            .fileName("file." + fileExtension)  // Using the extracted file extension here
            .build();

        FormDataBodyPart filePart = new FormDataBodyPart(contentDisposition, inputStream, MediaType.valueOf(mimeType));
        formDataMultiPart.bodyPart(filePart);

        formDataMultiPart.field("width", String.valueOf(width));
        formDataMultiPart.field("height", String.valueOf(height));

        Response response = client.target(url)
            .request()
            .post(javax.ws.rs.client.Entity.entity(formDataMultiPart, formDataMultiPart.getMediaType()));

        if (response.getStatus() != Response.Status.OK.getStatusCode()) {
            throw new RuntimeException("Failed to get thumbnail from microService, response code: " + response.getStatus());
        }

        return response.readEntity(InputStream.class);
    } catch (IOException e) {
        throw new RuntimeException("Error calling thumbnail service", e);
    } finally {
        client.close();
    }
}

This is the screen shot of my debugging showing the supposedly decrypted image:

enter image description here

The problem is when micro-service receives a file, it has a size of 0. Which shows the file has not been created correctly.

I have tried also the following way of creating the file, but it also doesn't work:

ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int nRead;
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
    buffer.write(data, 0, nRead);
}
buffer.flush();
byte[] byteArray = buffer.toByteArray();
// Now use byteArray with FormDataBodyPart
FormDataBodyPart filePart = new FormDataBodyPart(contentDisposition, 
                                             new ByteArrayInputStream(byteArray), 
                                             MediaType.valueOf(mimeType));

I have checked these links and still haven't been able to solve the issue:

CipherInputStream and CipherOutputStream are not generating files

How to add and get specific number of bytes from a file using file input and output streams? bytes-from-a-file-using-file-input-and-out

1

There are 1 best solutions below

1
Fatima On

The problem was that I have read from the stream prior to this in order to retrieve its size. And once a stream is read, further attempts to read it returns nothing.