You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
}

问题分析与修复方案

核心问题点

  1. 未解码Base64:Android端发送的是加密字节的Base64编码字符串,ESP8266直接将该字符串的ASCII字节传入解密函数,而非原始加密字节,这是乱码的主要原因。
  2. AES模式/填充不匹配:Android端Cipher.getInstance("AES")默认使用AES/ECB/PKCS5Padding(Android平台默认实现),需确保ESP8266的AES库使用相同模式和填充。
  3. 字节数组长度错误:解密数组长度应基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 18:52:37