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

android, encryption, minify, obfuscation, proguard

Solution

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.

Problem

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) 2) 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) 2) 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.

Original source