Android向AP模式ESP8266发送AES加密数据解密失败求助
问题:AES加密后ESP8266解密结果为乱码
Android端通过AES加密字符串后发送给AP模式的ESP8266,ESP8266能正常接收加密值(Base64格式:hYRPznVRiPVGVV0NkOy4XpVPZPLk6G6e7oLSAhZoSJk=),但解密输出为乱码,需排查并修复问题。
Android端加密发送代码
new Thread(new Runnable() { @Override public void run() { byte[] key = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; String data = "thats my kung fu"; try { SecretKeySpec secretKey = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); byte[] encryptedData = cipher.doFinal(data.getBytes()); Log.d("EncryptedData", Base64.encodeToString(encryptedData, Base64.DEFAULT)); OkHttpClient client = new OkHttpClient.Builder() .callTimeout(40, TimeUnit.SECONDS) .build(); RequestBody formBody = new FormBody.Builder() .add("data", Base64.encodeToString(encryptedData, Base64.DEFAULT)) .build(); Request request = new Request.Builder() .url("http://192.168.4.1/post") .post(formBody) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onResponse(okhttp3.Call call, Response response) throws IOException { if (response.isSuccessful()) { String myResponse = response.body().string(); Log.i("POST", myResponse); Log.d("TAG", "data: " + data); } else { Log.d("POST", "response code: " + response.code() + " response message: " + response.message()); } } @Override public void onFailure(okhttp3.Call call, IOException e) { e.printStackTrace(); Log.e("TAG", "Post request failed"); } }); } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { e.printStackTrace(); } } }).start();
ESP8266端接收解密代码(原错误版本)
#include <AES.h> #include <AESLib.h> #include <AES_config.h> #include <xbase64.h> #include <ESP8266WebServer.h> ESP8266WebServer server(80); AES aes; const char* ssid = "ESP8266-AP"; const char* password = "password"; const byte key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; void handlePost() { String val = server.arg("data"); byte decrypted[val.length()]; aes.set_key(key, sizeof(key)); aes.decrypt((byte*)val.c_str(), decrypted); String decryptedVal = String((char*)decrypted); Serial.println("Received value: " + decryptedVal); Serial.println("Encrypted value: " + val); server.send(200, "text/plain", "Value Received"); } void setup() { //Set ESP as AP Serial.begin(9600); WiFi.mode(WIFI_AP); WiFi.softAP(ssid, password); //Initialize server server.begin(); server.on("/post", HTTP_POST, handlePost); Serial.println("Server started"); } void loop() { server.handleClient(); }
问题分析与修复方案
核心问题点
- 未解码Base64:Android端发送的是加密字节的Base64编码字符串,ESP8266直接将该字符串的ASCII字节传入解密函数,而非原始加密字节,这是乱码的主要原因。
- AES模式/填充不匹配:Android端
Cipher.getInstance("AES")默认使用AES/ECB/PKCS5Padding(Android平台默认实现),需确保ESP8266的AES库使用相同模式和填充。 - 字节数组长度错误:解密数组长度应基于Base64解码后的加密字节长度,而非Base64字符串长度。
修改后的ESP8266代码
#include <AES.h> #include <AESLib.h> #include <AES_config.h> #include <xbase64.h> #include <ESP8266WebServer.h> ESP8266WebServer server(80); AES aes; const char* ssid = "ESP8266-AP"; const char* password = "password"; const byte key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; void handlePost() { String base64Val = server.arg("data"); // 1. 计算Base64解码后的字节长度 int encryptedLen = base64_dec_len(base64Val.c_str(), base64Val.length()); byte encrypted[encryptedLen]; // 2. 解码Base64得到原始加密字节 base64_decode(encrypted, base64Val.c_str(), base64Val.length()); // 3. 初始化AES密钥,确保使用ECB模式(匹配Android默认) aes.set_key(key, sizeof(key)); // 4. 解密,解密后长度与加密前原始数据长度一致(需考虑PKCS5Padding的自动去除) byte decrypted[encryptedLen]; aes.decrypt(encrypted, decrypted); // 5. 转换为字符串,原始数据"thats my kung fu"长度为16,直接取前16字节即可 String decryptedVal = String((char*)decrypted, 16); Serial.println("Decrypted value: " + decryptedVal); Serial.println("Received Base64 value: " + base64Val); server.send(200, "text/plain", "Value Received"); } void setup() { Serial.begin(9600); WiFi.mode(WIFI_AP); WiFi.softAP(ssid, password); server.begin(); server.on("/post", HTTP_POST, handlePost); Serial.println("Server started"); } void loop() { server.handleClient(); }
额外注意事项
- 若Android端后续修改AES模式(如使用CBC),需同步修改ESP8266端代码,添加IV向量处理。
- 确保ESP8266使用的AES库支持PKCS5Padding自动去除,若不支持,需手动处理解密后的补位字节。
内容的提问来源于stack exchange,提问作者user21054032
相关产品推荐
相关产品推荐

