Java: Sending byte[] with other parameters in HTTP Post - java

I am working on a Java Client Library for the recently exposed unofficial Snapchat API. As an aside, the GitHub for my library so far is here: https://github.com/hatboysam/JavaSnap
I have most requests working fine, I can log in, download images, etc. I am using UniRest for all of those requests so far because I like the simplicity of the API.
I am trying to upload media following the format outlined here: http://gibsonsec.org/snapchat/fulldisclosure/#uploading-and-sending-snaps-phupload-phsend
I have no problem generating any of the fields. The data is a byte[] of AES-ECB encrypted data that I read from a file and ran through the specified encryption algorithm.
I have tried a few things:
Use UniRest's .field(String name, File file) method to add the file as a parameter. I use a temporary Dile I create from the byte[]. This gets me a 401 UNAUTHORIZED from the server, so I think UniRest is adding some headers I don't want when I do this.
Serialize the byte[] as a String using the String(byte[] bytes, String encoding) constructor with the UTF-8 encoding. This gets me a 500 SERVER ERROR.
Not send the data field at all, just to see what happens. This gets me a 400 BAD REQUEST.
If you look at the upload method in the Python library pysnap (init.py">https://github.com/martinp/pysnap/blob/master/pysnap/init.py) you can see that what I am trying to do has been done before very simply with Python's requests library. I can't figure out how to get the same behavior in Java.

My understanding is that you need to encode the byte[] data as a string using base-64 encoding. Try using javax.xml.bind.DatatypeConverter.printBase64Binary or a third-party library for base-64.
Converting to a string using String(byte[] bytes, String encoding) is completely different.

Related

Which one is better for Creating an JAVA Springboot Rest Endpoint to upload file - Multipart file vs base 64 encoded byte array in the POST body

I am trying to create an application, where documents are uploaded from the Angular application and send to the Spring Rest Endpoint, which will save the document in Database. I could see two options
Creating an endpoint which accepts base encoded array of bytes in the body of the POST request.
Creating the endpoint to accept Multipart file
Which one is better in terms of performance and why ? Please note, my document size can be from a couple of MBs to 25 MB.
Base64 is a way to encode binary data into an ASCII character format by translating it into a radix-64 representation.
I recommend you that never use Base64 for large file/data upload to the server because it converts whole data and posts it to the server.
An the other hand, Multipart is a way to upload the file to a server in the form of parts which are in bytes. Multipart/form-data is applied to a form though, so you can send everything in a multi-part form, including "regular" data also.
So, I think this can be useful for you:
#PostMapping("/api/update")
public ResponseEntity upload(#NotNull #NotEmpty #RequestParam("file") MultipartFile file) {}

Streaming [Random Access] encrypted (AES-CTR) video on the fly using web proxy (nanoHTTPD)

I have an encrypted (128-AES-CTR-NoPadding) video residing on a server which I need to decrypt as it downloads, so that user can stream it (in normal players/web).
I understand the components of this solution and how they should be put together to make this work. It partially works but for the rest I just can't implement streaming right. I have been reading and learning from examples (most of which is playing a file on disk, which is not the case here) on this for the past week and have come to conclusion this is beyond me and I need some help.
Details
I am using a Lightweight webserver (nanoHttpd) acting as a proxy to download the encrypted data from remote server and serve decrypted data. Below are the main codes inside my NanoHTTPD.serve method.
//create urlConnection to encrypted video file with proper headers (ie range headers) as request received by the proxy server
InputStream inputStream = new CipherInputStream(cipher, urlConnection.getInputStream());
return newChunkedResponse(status, contentType,inputStream);
So now if I go to my NanoHttpd webserver (http://localhost:9000), the file starts downloading and after the download completes, the file is fully decrypted and playable as expected.
So this ensures that getting encrypted data from the server and serving decrypted data is working correctly.
But when any video player (html5, vlc) is asked to stream the video from that url, it simply does not work.
If the above code in NanoHTTPD.serve changed to
//create urlConnection to cleardata video file with proper headers (ie range headers) as request received by the proxy server
InputStream inputStream = urlConnection.getInputStream();
return newChunkedResponse(status, contentType,inputStream);
And then try to stream from the aforementioned players, it'll work just fine.
So this ensures that the web proxy is correcting retrieving and feeding data.
Potential problem
To support range requests from the video player we will need to correctly skip to block boundary that is a multiple of cipher block size. So it's possible that when video player is requesting data with header (range: bytes 34-44), the CipherInputStream is probably failing to decrypt the data since the inputstream has data from 34-44. But I am at a loss on how to do this with urlConnection.getInputStream() and CipherInputStream.
But even without this, it should at least start playing the first few seconds because the first request video player sends is (range: 0-) which means inputStream is starting from index 0 so CipherInputStream should be able to decrypt and serve those initial bytes and the video should continue playing.
I am at a complete loss because I don't know how to debug this. Any ideas, sample codes are welcome, I'll try them out and post the results here.
I have figure this out. I'll post the solution here for others.
The problem here was the ranged requests. If the proxy does not send proper responses to these range requests, the playback will fail. This can fail due to a number of reasons.
Your requests to remote server is missing proper range headers.
Your requests to remote server is returning proper ranged data, but you are not decrypting it correctly. This was my case. Of course this decryption process will vary cipher to cipher. For me, I used (AES/CRT/NOPADDING), I was supplying correct iv for the offset. How to calculate iv for offset is described here.
As far as code samples go, I only had to add one line before
InputStream inputStream = new CipherInputStream(cipher, urlConnection.getInputStream());
return newChunkedResponse(status, contentType,inputStream);
which is
jumpToOffset(cipher,....);
After this everything was working correctly including seeking of the video.

Send image using http

I've got the following setup. I have to send an image over http to a browser or other device. The tricky thing about the whole it is, that I have very limited control over the http-packet creation.
I only can provide the content type field and the message body as a string.
Is there a way how I could create an http-packet containing a image with this limited configuration facilities?
You need to have:
Content-Type as 'application/image'
data in body as binary
With your limitation as you can have only strings in body, an image cannot be sent in response.
You could convert your image to a base64 string: http://www.base64-image.de/

How to decode the message sent from NetConnection.call(methodName, responder, parameter) by Java

I am using Java Servlet as my server side. However I don't know how to decode the message sent from the function NetConnection.call of Flash.
I download BlazeDS as my AMF3 decoder. But how can I read "methodName" and parameters from the byteArray.
This probably should have been a comment, as I'm not sure how BlazeDS works. I've used NetConnection.call() with Flash Media Server (FMS). However, it might work the same way with any other AMF server:
With FMS, you don't try to read the method name or the parameters from a byte array. Instead, you define a method on the server that so this method has the same name and accepts the same parameters that you are passing when you use NetConnection.call().

The best way to send a file over a Network

I want to send a file to the Browser via the REST Interface.
Can you suggest the most efficient way to do it, Keeping in mind the following?
Not much traffic.
I am fetching the file from HBase which means when I fetch it from HBase I get it in Byte Array.
The files are not in any folder in the server. The files can only be fetched from the HBase table.
The Front end is PHP and I do not know PHP.
In the REST api you can just pass the byte array to Response and it takes care of itself.
Using the following code -
#Produces("image/jpg")
public Response getImage() {
<Fetch it from where ever you have it>
Response.ok(<byteArrayOfTheFile>).build();
}
I am giving case study of WebService by which i send file:
It is always good to encode the file content and send it to the destination where they will be decode it and read the content.
Sending as an attachment is always open to the world becasue it is not encrypted.And if the network having high trafic chances of failure is high.

Categories