【问题标题】:C++/Arduino: strcpy(), strncpy() and memcpy() on unsigned char not workingC++/Arduino:无符号字符上的 strcpy()、strncpy() 和 memcpy() 不起作用
【发布时间】:2018-10-08 23:10:37
【问题描述】:

我正在尝试在 Arduino 上实现 AES-128 和 AES-256(Adafruit Feather M0,适用于使用 SAMD21 处理器的任何其他人!)。加密和解密正在工作,但我无法“保存”加密值。我相信该示例将 char 数组的指针传递给 void encrypt(),但是当使用 strcpystrncpymemcpy 将值从本地 char 数组复制到我的 loop() 中的值时,该值实际上永远不会被复制。

请注意,挂起仅发生在void encrypt() 方法中,我想知道这是否是由于示例代码将数据转换为unsigned char*encode_base64 行所致。我已经能够在void decrypt() 中成功使用strcpystrncpymemcpy,所以我只能认为它是无符号字符类型。

尽管根据this,char 最终在标准库中被视为 unsigned char,我认为 strcpy 函数是标准字符串库的一部分,而不是 Arduino 的特殊功能。

我对 C/C++ 很陌生,离专家还差得很远。我不太确定如何解决这个问题,所以我希望有人能指出我正确的方向。

代码(我在每个 #include 的顶部添加了指向库的链接)

#include <Crypto.h>   // https://github.com/intrbiz/arduino-crypto
#include <base64.hpp> // https://github.com/Densaugeo/base64_arduino


#define BLOCK_SIZE 16

uint8_t key[BLOCK_SIZE] = { 0x1C,0x3E,0x4B,0xAF,0x13,0x4A,0x89,0xC3,0xF3,0x87,0x4F,0xBC,0xD7,0xF3, 0x31, 0x31 };
uint8_t iv[BLOCK_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
char plain_text[] = "1234567890ABCDEF1234567890ABCDEF";

void bufferSize(char* text, int &length)
{
    int i = strlen(text);
    int buf = round(i / BLOCK_SIZE) * BLOCK_SIZE;
    length = (buf <= i) ? buf + BLOCK_SIZE : length = buf;
}

void encrypt(char* plain_text, char* output, int length)
{
    byte enciphered[length];
    // RNG::fill(iv, BLOCK_SIZE); // Using fixed test iv
    AES aesEncryptor(key, iv, AES::AES_MODE_128, AES::CIPHER_ENCRYPT);
    aesEncryptor.process((uint8_t*)plain_text, enciphered, length);
    int encrypted_size = sizeof(enciphered);

    char encoded[encrypted_size];
    encode_base64(enciphered, encrypted_size, (unsigned char*)encoded);

    Serial.print("void encrypt :: Encrypted: ");
    Serial.println(encoded);

    // strcpy(output, encoded); //- Hangs
    // strncpy(output, encoded, strlen((char*)encoded)); - Hangs
    // memcpy(output, encoded, strlen((char*)encoded)); - Hangs
}

void decrypt(char* enciphered, char* output, int length)
{
    length = length + 1; //re-adjust

    char decoded[length];
    decode_base64((unsigned char*)enciphered, (unsigned char*)decoded);
    bufferSize(enciphered, length);
    byte deciphered[length];
    AES aesDecryptor(key, iv, AES::AES_MODE_128, AES::CIPHER_DECRYPT);
    aesDecryptor.process((uint8_t*)decoded, deciphered, length);

    Serial.print("void decrypt :: Decrypted: ");
    Serial.println((char*)deciphered);

    strcpy(output, (char*)deciphered);
    // strncpy(output, (char*)deciphered, strlen((char*)deciphered));
    // memcpy(output, (char*)deciphered, strlen((char*)deciphered));
}

void setup() {
    Serial.begin(115200);
    while (!Serial) {
      ; //wait
    }

    Serial.println("AES128-CBC Test :: Starting...");
    Serial.print("Plaintext input "); Serial.println(plain_text);
}

void loop() {

  Serial.println(" = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = \n");

  // Encrypt
  int length = 0;
  bufferSize(plain_text, length);
  // Serial.print("Buffer length: ");
  // Serial.println(length);

  char encrypted[128];
  encrypt(plain_text, encrypted, length);

  // Serial.println("");
  Serial.print("RETURNED Encrypted Value: ");
  Serial.println(encrypted);


  // Decrypt
  length = 128; // WAS strlen(encrypted);
  char decrypted[length];
  char testEncryptedPayload[] = "pJUX0k/h/63Jywlyvn7vTMa9NdJF9Mz6JOB1T1gDMq+0NUkNycBR780kMvCYILGP"; // Added for testing purposes

  decrypt(testEncryptedPayload, decrypted, length);

  Serial.print("RETURNED Decrypted Value: ");
  Serial.println(decrypted);

  delay(5000);
}

/*
EXAMPLE FROM DOCUMENTATION => loop()

void loop() {
  char plain_text[] = "1234567890ABCDEF1234567890ABCDEF";

  // Encrypt
  int length = 0;
  bufferSize(plain_text, length);
  char encrypted[length];
  encrypt(plain_text, encrypted, length);

  Serial.println("");
  Serial.print("Encrypted: ");
  Serial.println(encrypted);

  // Decrypt
  length = strlen(encrypted);
  char decrypted[length];
  decrypt(encrypted, decrypted, length);

  Serial.print("Decrypted: ");
  Serial.println(decrypted);

  delay(5000);
}

*/

样本输出:

AES128-CBC Test :: Starting...
Plaintext input 1234567890ABCDEF1234567890ABCDEF
 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

void encrypt :: Encrypted: pJUX0k/h/63Jywlyvn7vTMa9NdJF9Mz6JOB1T1gDMq/eQVoPjf/UYv+9SuzV8LQa
RETURNED Encrypted Value: L
void decrypt :: Decrypted: 1234567890ABCDEF1234567890ABCDEF
RETURNED Decrypted Value: 1234567890ABCDEF1234567890ABCDEF
 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

【问题讨论】:

  • 您似乎忘记了关于char 字符串的一件非常重要的事情:它们实际上被称为null-terminated 字节字符串。 null-terminated 是所有字符串函数都起作用的原因,因为它们会寻找 null-terminator 来知道结尾。
  • 仅供参考,byte deciphered[length] - 即使在成熟的 C++ 实现中,这也是一个坏主意。这不是标准的;使用向量。 byte enciphered[length]char encoded[encrypted_size]; 也是如此。此外,其中之一,enciphered,无论如何都可能大小错误。 base64 编码将具有至少输入数据大小的 4/3。
  • @WhozCraig 微控制器上的动态内存分配?也不一定是最好的主意......承认,VLA,无论是否扩展,都会带来类似的问题......
  • memcpy 绝对不是您的问题 - 它接受 anything (void*) 并复制您定义的尽可能多的字节,无论内容是什么。如果您确实复制了太少或太多的字节,那是由于给定的数字错误......
  • 感谢您迄今为止的回复! @Someprogrammerdude 我已经尝试添加 '\0' - 在 pos 0 或 encrypted_length-1 处无效。

标签: c++ arduino strcpy


【解决方案1】:

我没有运行代码,但总的来说它与 M0 “挂起”,并且根据我的经验,所有这些都与内存有关。

这两行:

// strncpy(output, encoded, strlen((char*)encoded)); - Hangs
// memcpy(output, encoded, strlen((char*)encoded)); - Hangs

也许真正失败的是strlen。也许encodednot NULL 终止的?你可以试试实际长度吗? (例如,memcpy(output, encoded, encoded_length);

【讨论】:

    猜你喜欢
    • 2020-07-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-07
    • 2014-10-01
    • 2011-06-03
    • 2016-03-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多