AES加密:使用Arduino加密,使用Java解密

AES加密:使用Arduino加密,使用Java解密,java,encryption,arduino,cryptography,aes,Java,Encryption,Arduino,Cryptography,Aes,我想用Arduino加密文本,用Java解密。我从中尝试了此代码,但没有成功 我在Arduino上使用它进行加密,在Java端使用Java加密扩展(JCE)框架 这是Arduino代码: #include <AESLib.h>  //replace the ( with < to compile (forum posting issue) #include <Base64.h> void setup() { Serial.begin(9600); uint

我想用Arduino加密文本,用Java解密。我从中尝试了此代码,但没有成功

我在Arduino上使用它进行加密,在Java端使用Java加密扩展(JCE)框架

这是Arduino代码:

#include <AESLib.h>  //replace the ( with < to compile (forum posting issue)
#include <Base64.h>

void setup() {
  Serial.begin(9600);
  uint8_t key[] = {50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50};
  //expressed in 16 unsigned in characters, be careful not to typecast this as a char in a decrypter
  //16- 50's (uint8) is the way to express 16 2's in ASCII, the encryption matches to what will show up on <a href="http://aesencryption.net/" target="_blank" rel="nofollow">http://aesencryption.net/</a>
  char data[] = "0123456789012345";
  //The message to encrypt, 16 chars == 16 bytes, no padding needed as frame is 16 bytes
  char encryptedData[100];
  int *size;
  Serial.print("Message:");
  Serial.println(data);
  aes128_enc_single(key, data);
  Serial.print("encrypted:");
  Serial.println(data);
  int inputLen = sizeof(data);
  int encodedLen = base64_enc_len(inputLen);
  char encoded[encodedLen];
  base64_encode(encoded, data, inputLen);
  Serial.print("encrypted(base64):"); //used
  Serial.println(encoded);
  Serial.println("***********Decrypter************");
  int input2Len = sizeof(encoded);
  int decodedLen = base64_dec_len(encoded, input2Len);
  char decoded[decodedLen];
  base64_decode(decoded, encoded, input2Len);
  Serial.print("encrypted (returned from Base64):");
  Serial.println(decoded);
  Serial.print("decrypted:");
  Serial.println(decoded);
}

void loop() {
}
#include "mbedtls/aes.h"
#include <Arduino.h>
#include <HTTPClient.h>
#include <base64.h>

void makeUpdateAPICall()
{
  if (WiFi.status() == WL_CONNECTED)
  {
    HTTPClient http;

    // Your Domain name with URL path or IP address with path
    http.begin(serverName); 

    // Specify content-type header
    http.addHeader("Content-Type", "text/plain");
    http.addHeader("Authorization", "Bearer XXXXXXXX [whatever your web token is]");
    http.addHeader("X-Content-Type-Options", "nosniff");
    http.addHeader("X-XSS-Protection", "1; mode=block");

    //AES Encrypt
    esp_aes_context aesOutgoing;
    unsigned char key[32] = "1234567812345678123456781234567" ;
    key[31] = '8';   // we replace the 32th (index 31) which contains '/0' with the '8' char.

    char *input = "Tech tutorials x";
    unsigned char encryptOutput[16];

    mbedtls_aes_init(&aesOutgoing);
    mbedtls_aes_setkey_enc(&aesOutgoing, key, 256);
    int encryptAttempt = mbedtls_aes_crypt_ecb(&aesOutgoing, MBEDTLS_AES_ENCRYPT, (const unsigned char *)input, encryptOutput);
    USE_SERIAL.println();
    USE_SERIAL.println("MBEDTLS_AES_EBC encryption result:\t ");
    USE_SERIAL.print(encryptAttempt); //0 means that the encrypt/decrypt function was successful
    USE_SERIAL.println();
    mbedtls_aes_free(&aesOutgoing);

    int encryptSize = sizeof(encryptOutput) / sizeof(const unsigned char);
    USE_SERIAL.println("Size of AES encrypted output: ");
    USE_SERIAL.println(encryptSize);

    //Base 64 Encrypt
    int inputStringLength = sizeof(encryptOutput);
    int encodedLength = Base64.decodedLength((char *)encryptOutput, inputStringLength);
    char encodedCharArray[encodedLength];
    Base64.encode(encodedCharArray, (char *)encryptOutput, inputStringLength);
    //Send to server
    USE_SERIAL.print("Sending to server.");
    int httpResponseCode = http.POST(encodedCharArray);

    String payload = "{}";

    if (httpResponseCode > 0)
    {
      //Retrieve server response
      payload = http.getString();
    }
    // Free resources
    http.end();
  }
  WiFi.disconnect();
}
有什么想法吗?
谢谢

大约一周后,我就可以让它正常工作了——使用Arduino与其他系统集成的文档是垃圾:)

工作代码:

#include <AESLib.h>  //replace the ( with < to compile (forum posting issue)
#include <Base64.h>

void setup() {
  Serial.begin(9600);
  uint8_t key[] = {50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50};
  //expressed in 16 unsigned in characters, be careful not to typecast this as a char in a decrypter
  //16- 50's (uint8) is the way to express 16 2's in ASCII, the encryption matches to what will show up on <a href="http://aesencryption.net/" target="_blank" rel="nofollow">http://aesencryption.net/</a>
  char data[] = "0123456789012345";
  //The message to encrypt, 16 chars == 16 bytes, no padding needed as frame is 16 bytes
  char encryptedData[100];
  int *size;
  Serial.print("Message:");
  Serial.println(data);
  aes128_enc_single(key, data);
  Serial.print("encrypted:");
  Serial.println(data);
  int inputLen = sizeof(data);
  int encodedLen = base64_enc_len(inputLen);
  char encoded[encodedLen];
  base64_encode(encoded, data, inputLen);
  Serial.print("encrypted(base64):"); //used
  Serial.println(encoded);
  Serial.println("***********Decrypter************");
  int input2Len = sizeof(encoded);
  int decodedLen = base64_dec_len(encoded, input2Len);
  char decoded[decodedLen];
  base64_decode(decoded, encoded, input2Len);
  Serial.print("encrypted (returned from Base64):");
  Serial.println(decoded);
  Serial.print("decrypted:");
  Serial.println(decoded);
}

void loop() {
}
#include "mbedtls/aes.h"
#include <Arduino.h>
#include <HTTPClient.h>
#include <base64.h>

void makeUpdateAPICall()
{
  if (WiFi.status() == WL_CONNECTED)
  {
    HTTPClient http;

    // Your Domain name with URL path or IP address with path
    http.begin(serverName); 

    // Specify content-type header
    http.addHeader("Content-Type", "text/plain");
    http.addHeader("Authorization", "Bearer XXXXXXXX [whatever your web token is]");
    http.addHeader("X-Content-Type-Options", "nosniff");
    http.addHeader("X-XSS-Protection", "1; mode=block");

    //AES Encrypt
    esp_aes_context aesOutgoing;
    unsigned char key[32] = "1234567812345678123456781234567" ;
    key[31] = '8';   // we replace the 32th (index 31) which contains '/0' with the '8' char.

    char *input = "Tech tutorials x";
    unsigned char encryptOutput[16];

    mbedtls_aes_init(&aesOutgoing);
    mbedtls_aes_setkey_enc(&aesOutgoing, key, 256);
    int encryptAttempt = mbedtls_aes_crypt_ecb(&aesOutgoing, MBEDTLS_AES_ENCRYPT, (const unsigned char *)input, encryptOutput);
    USE_SERIAL.println();
    USE_SERIAL.println("MBEDTLS_AES_EBC encryption result:\t ");
    USE_SERIAL.print(encryptAttempt); //0 means that the encrypt/decrypt function was successful
    USE_SERIAL.println();
    mbedtls_aes_free(&aesOutgoing);

    int encryptSize = sizeof(encryptOutput) / sizeof(const unsigned char);
    USE_SERIAL.println("Size of AES encrypted output: ");
    USE_SERIAL.println(encryptSize);

    //Base 64 Encrypt
    int inputStringLength = sizeof(encryptOutput);
    int encodedLength = Base64.decodedLength((char *)encryptOutput, inputStringLength);
    char encodedCharArray[encodedLength];
    Base64.encode(encodedCharArray, (char *)encryptOutput, inputStringLength);
    //Send to server
    USE_SERIAL.print("Sending to server.");
    int httpResponseCode = http.POST(encodedCharArray);

    String payload = "{}";

    if (httpResponseCode > 0)
    {
      //Retrieve server response
      payload = http.getString();
    }
    // Free resources
    http.end();
  }
  WiFi.disconnect();
}
现在正在处理退货流程

使用以下代码调用Java端:

final String decryptedText=AES.decrypt(encryptedStr,“1234567881234567812345678812345678”);
System.out.println(“解密的AES ECB字符串:”);
System.out.println(解密文本);
想为任何发现自己和他/她在同一条船上的可怜的懒汉提供这个:)


希望这有帮助

您尝试对base64进行解码和解密的字符串是
Ouril+UTDF8htLzEhiRj7wA=
,它在base64解码后为17个字节,后面有一个0字节。前面打印的字符串是
Ouril+UTDF8htLzEhiRj7w==
,除了尾随的字节外,它是相同的(在base 64解码后),并且是正确的长度(16字节)。但是为什么在使用arduino和Java在base 64编码后,我得不到相同的结果呢?对于Arduino,我得到了:
Ouril+UTDF8htLzEhiRj7wA=
而对于Java,我得到了
Ouril+UTDF8htLzEhiRj7w==
,我该如何纠正?谢谢Arduino输出引入了一个额外的字节。我不熟悉Arduino语言本身,但快速看一下,它是C/C++的一个子集。C以“空终止”其字符串而闻名(即,为了指示具有任意长度的字符串的结尾,它添加了一个包含值
0x00
)的字节)。在Java代码中,您需要将输入密码文本修剪为
0x00
字节之前的字节。此外,如果输入的明文和密文不是16字节的精确倍数(AES的块大小),
ECB
是最差的密码块模式(相当于在大多数情况下不加密),则您选择的
AES/ECB/NoPadding
将出现严重问题。查看上的Wikipedia条目并选择一个更好的选项(GCM建议用于AEAD属性)。您也可以在源代码处解决此问题,并且仅在Arduino中将密码文本的内容编码到空字节,但我对该语言了解不够,无法确定是否有简单的方法可以做到这一点。在编码之前,您可能只需要从
char[]
中修剪最后一个字节。这对于固定大小的加密输出没有多大用处,所有将密钥作为字符串的把戏都不是必需的:如果您将其保留为OP,则不会出现尾随空问题。@user207421您是完全正确的。然而,我的示例的目的只是提供Arduino和Java之间AES集成的可行方法。那里真的没有文档(至少我能找到)。我的产品代码使用padding、AES-CBC和从服务器上的安全位置提取密钥。从一个安全的位置提取密钥&另一件事更复杂,但诀窍是当解密/加密部分来自其他系统/语言时,让它们工作起来。希望这能帮助某人克服这个障碍。 public static String decrypt(String strToDecrypt, String key) {

    byte[] encryptionKeyBytes = key.getBytes();  
    Cipher cipher;
    try {
        cipher = Cipher.getInstance("AES/ECB/NoPadding");
        SecretKey secretKey = new SecretKeySpec(encryptionKeyBytes, "AES");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);         
        return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt.getBytes("UTF-8"))));
    } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}