Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you encrypt / hide the body of an HTTPS call using Retrofit 2 + OkHttp 3?

I am currently working on a project where I am sending data via an https call to our server api. The base URL for the project supports ssl (Our url api endpoint starts with https://api.....). I am using Retrofit 2 and OkHttp3 and am setting up the client like this:

    public static void buildClient(){
        //Misc code here.... not showing for security reasons.
        OkHttpClient client = RetrofitClient.configureClient(new OkHttpClient());
        //I make calls here to update interceptors, timeouts, etc.
        Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create(new Gson()))
            .client(client)
            .build();
    }

    //Setup the ssl stuff here
    public static OkHttpClient configureClient(final OkHttpClient client) {
        final TrustManager[] certs = new TrustManager[]{new X509TrustManager() {
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            @Override
            public void checkServerTrusted(final X509Certificate[] chain,
                                           final String authType)
                    throws CertificateException {
            }

            @Override
            public void checkClientTrusted(final X509Certificate[] chain,
                                           final String authType)
                    throws CertificateException {
            }
        }};

        SSLContext ssl = null;
        try {
            ssl = SSLContext.getInstance("TLS");
            ssl.init(null, certs, new SecureRandom());
        } catch (final java.security.GeneralSecurityException ex) {
        }

        try {
            final HostnameVerifier hostnameVerifier = new HostnameVerifier() {
                @Override
                public boolean verify(final String hostname,
                                      final SSLSession session) {
                    return true;
                }
            };
            client.setHostnameVerifier(hostnameVerifier);
            client.setSslSocketFactory(ssl.getSocketFactory());
        } catch (final Exception e) {
        }

        return client;
    }

So after this, we are all set.

Now, here's what I know:

1) I am sending via HTTPS because if I were not, the server would throw an error, which it is not.

2) My code is working just fine in that it is communicating with the server and the app will work.

The problem here is that the actual Body data is not being encrypted. Here are 2 photo examples to show what I mean.

1) enter image description here

2) enter image description here

The first image shows proper obfuscation of the actual body data in that the data is being converted to encrypted 'stuff' while the second shows plain text. The second one is me sending a POST call to the server with an object.

My question is, how do I go about replicating this so that my body text is hidden / encrypted like the other?

Notes:

1) I am using obfuscation via Proguard

2) I to have minifyEnabled set to true

3) How I found this out is via a packet sniffer

Anyone have any ideas how to accomplish this? Or can anyone point me in the right direction as to what this is called specifically?

Thanks.

EDIT:

So, it looks like I was not understanding a key component here.

Short answer is, the call is already encrypted and is sending Https.

Long answer is, I have been comparing my data calls to ones like these:

1) enter image description here

2) enter image description here

Where I just assumed that These were encrypted, while mine was not. It turns out that the calls I am sending are encrypted just fine, as are these, but this data is zipped / compressed, which makes it unreadable to the eye, which is what made me think that it was what encrypted data looked like from a packet sniffer.

like image 831
PGMacDesign Avatar asked Oct 17 '16 18:10

PGMacDesign


People also ask

How do you pass body in GET request retrofit on Android?

This means your @GET or @DELETE should not have @Body parameter. You can use query type url or path type url or Query Map to fulfill your need. Else you can use other method annotation.

What is the use of OkHttp in retrofit?

Understanding Okio's okhttp3 and retrofit Okio-okhttp3 is a library that works in conjunction with java.io and java. nio to make data access, storage, and processing considerably easier. It started as a component of OkHttp. Retrofit is a type-safe REST client for Java and Android application development.

Which is better retrofit or OkHttp?

OkHttp is a pure HTTP/SPDY client responsible for any low-level network operations, caching, requests and responses manipulation. In contrast, Retrofit is a high-level REST abstraction build on top of OkHttp. Retrofit is strongly coupled with OkHttp and makes intensive use of it.

What is retrofit HTTP client?

Retrofit is a type-safe REST client for Android, Java and Kotlin developed by Square. The library provides a powerful framework for authenticating and interacting with APIs and sending network requests with OkHttp.


1 Answers

Your question is: Why I use HTTPS but the Packet Capture or Charles can view all of the SSL / HTTPS traffic between the client and the Internet?

Because the Packet Capture(the VPN proxy) or Charles cheated your client as an intermediary:

Your client <--> Packet Capture/Charles <--> Your target server.

So the proxy tool can view all your HTTPS content(In fact they are indeed encrypted).

Solution:

You can refer the OkHttp wiki: https://github.com/square/okhttp/wiki/HTTPS

and set a Certificate pinning for your HTTPS checking. For example:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final TextView textView = (TextView) findViewById(R.id.text);

        ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
            .tlsVersions(TlsVersion.TLS_1_2)
            .cipherSuites(
                CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
                CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
            .build();

        OkHttpClient client = new OkHttpClient.Builder()
            .connectionSpecs(Collections.singletonList(spec))
            .certificatePinner(new CertificatePinner.Builder()
                .add("drakeet.me", "sha256/gGOcYKAwzEaUfun6YdxZvFSQq/x2lF/R8UizDFofveY=")
                .build())
            .build();

        Request request = new Request.Builder()
            .url("https://drakeet.me?s=type")
            .post(RequestBody.create(MediaType.parse("text"), "xxx...xxx"))
            .addHeader("token", "xxx")
            .build();

        final Handler handler = new Handler();
        client.newCall(request).enqueue(new Callback() {
            @Override public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }


            @Override public void onResponse(Call call, final Response response)
                throws IOException {
                final String t = response.body().string();
                handler.post(new Runnable() {
                    @Override public void run() {
                        textView.setText(t);
                    }
                });
            }
        });
    }
}

As my above codes, I preset a certificatePinner relate to the true certificatePinner of my target server, so that if I use Packet Capture/Charles now, they will create a false certificatePinner by themselve, and OkHttp will compare the two pinning, if not equal, throw a javax.net.ssl.SSLPeerUnverifiedException: Certificate pinning failure!

And if you close the Packet Capture/Charles, the exception dismiss and send HTTPS content successfully.

like image 197
drakeet Avatar answered Oct 16 '22 17:10

drakeet