Two problems encountered in okhttp post request header post parameter encryption

If you have questions about whether it is necessary to encrypt parameters after using https for network requests, you can read my last article: Network Security https. Remember to read it patiently. Let me talk about the questions below:

  1. Caused by: java.lang.IllegalArgumentException: Unexpected char 0x0a At first, I thought it was the okhttp framework that dealt with special characters. Now, other articles on the Internet are talking about Chinese characters. I don’t think I have Chinese here, but I still changed them all to native characters. I tried it, and sure enough, it still reported the same error, what a cheating netizen, haha!
    The following is the code for the test case demo
package com.tcssj.mbjmb;

import android.util.Base64;
import android.view.View;

import java.nio.charset.StandardCharsets;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AESUtil2 {<!-- -->
    public static byte[] base64ToDecode(String str) {<!-- -->
        byte[] byteStr = Base64.decode(str, Base64.DEFAULT);
        return byteStr;
    }

    public static String encode(byte[] key) {<!-- -->
        return Base64.encodeToString(key, Base64.NO_WRAP);
    }

    /**
     * Encryption
     *
     * @param content content that needs to be encrypted
     * @param key encryption password
     * @return
     */
    public static String encrypt(String content, String key) {<!-- -->
        return encrypt(content,key.getBytes());
    }

    public static String encrypt(String content, byte[] key) {<!-- -->
        try {<!-- -->
            //Construct key
            SecretKeySpec skey = new SecretKeySpec(key, "utf-8");
            //Create an initial vector iv to specify the key offset (can be specified by yourself but must be 128 bits). Because AES is block encryption, the next group of ivs is used as the previous group of encrypted ciphertext.
            IvParameterSpec iv = new IvParameterSpec(key, 0, 16);
            //Create AES encryptor
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            byte[] byteContent = content.getBytes(StandardCharsets.UTF_8);
            //Use the encryption mode of the encryptor
            cipher.init(Cipher.ENCRYPT_MODE, skey, iv);
            // Encryption
            byte[] result = cipher.doFinal(byteContent);
            //Use BASE64 to encode the encrypted binary array
            return encode(result);
        } catch (Exception e) {<!-- -->
            e.printStackTrace();
            return content;
        }
    }

    /**
     * Decrypt
     * @param content
     * @param key
     * @return
     */
    public static String decrypt(String content, byte[] key) {<!-- -->
        try {<!-- -->

            SecretKeySpec skey = new SecretKeySpec(key, "utf-8");
            IvParameterSpec iv = new IvParameterSpec(key, 0, 16);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            //Use the decryption mode of the encryptor when decrypting
            // initialization
            cipher.init(Cipher.DECRYPT_MODE, skey, iv);
            byte[] result = cipher.doFinal(base64ToDecode(content));
            // Decrypt
            return new String(result);
        } catch (Exception e) {<!-- -->
            return content;
        }
    }
}

package com.tcssj.mbjmb

import android.os.Bundle
import android.os.Handler
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.tcssj.mbjmb.ui.theme.MbjmbTheme
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import okhttp3.Headers
import okhttp3.MediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import org.json.JSONObject

class MainActivity: ComponentActivity(),test {<!-- -->
    private val TAG = "MainActivity"
    lateinit var text:String
    override fun onCreate(savedInstanceState: Bundle?) {<!-- -->
        super.onCreate(savedInstanceState)
   runBlocking(Dispatchers.IO) {<!-- -->
       val okHttpClient=OkHttpClient()
// val build=okHttpClient.newBuilder()
       val jsonpost=JSONObject()
       jsonpost.put("type","text")
       jsonpost.put("mobile","81991419936")
       val body=RequestBody.create(MediaType.parse("application/json;charset=utf-8"),AESUtil2.encrypt(jsonpost.toString(),AESUtil2.base64ToDecode("allWUzg1eFJ3ekpNQklUeQ==")))

       val json=JSONObject()
       json.put("sourceChannel","Orange")
       json.put("packageName","com.tcssj.mbjmb")
       json.put("adid","")
       json.put("version","12.0.0")
       json.put("uuId","")
       json.put("userId","")
       val request= Request.Builder().url("http://47.101.194.189:10018/auth/v3.1/user/sendVerifiyCode")
           .header("HCFQ",AESUtil2.encrypt(json.toString(), "xDBrgJdnnY2w1Do7Ik6otonXQRgQyt46"))
           .header("packageName","mbjmb")
           .post(body)
           .build()

       val response= okHttpClient.newCall(request).execute()
       response.toString()
       text=AESUtil2.decrypt(response.body().string(), AESUtil2.base64ToDecode("allWUzg1eFJ3ekpNQklUeQ=="))
       Log.i(TAG, "onCreate: " + AESUtil2.decrypt(text, AESUtil2.base64ToDecode("allWUzg1eFJ3ekpNQklUeQ==")))
   }
        setContent {<!-- -->
            MbjmbTheme {<!-- -->
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {<!-- -->
                    Greeting(name=text)
                }
            }
        }



    }
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {<!-- -->
    Text(
        text = "$name!",
        modifier = modifier
    )
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {<!-- -->
    MbjmbTheme {<!-- -->
        Greeting("Android")
    }
}

The reason for the first problem is that there is a newline symbol \\
after our parameters are encrypted. How to solve it? As shown in the figure below, if you use Default for the underlined part, the first error will be reported. You need to use NO_WRAP to not generate newline characters.

The second pitfall is that the returned code is also encrypted garbled code. You need to get back the decrypted code. Then you cannot use the body.toString() method in the picture below. You must use the String() method. (How I found out, I used the apifox tool (if you haven’t used the interface debugging yet, you can take it away, but you still need to use such a tool, otherwise it will be very inefficient for you to start the app debugging interface back and forth, but you will be lazy) It’s human nature to resist learning new things, but you have to overcome it) When debugging the interface, I found that the return results of the tool and Android were inconsistent)

Because look at the picture below, if you use the toString method, the message is empty, and the entire frame is empty. The encrypted content okhttp cannot be converted into its structure, then you have to use string() to get the string and parse it yourself.