在解密字符串末尾需要NULL终止符是什么?

时间:2015-03-25 13:20:01

标签: c++ encryption google-chrome-extension openssl google-nativeclient

我正在开发一个google chrome NaCl扩展,它涉及使用openssl库函数加密和解密数据。加密工作完美,解密也可以正常工作,但为此,我不得不进行一种黑客攻击,但我不确定这是否是处理它的正确方法。

else if(action == "decryption")
    {
      pp::Var content = dict_message.Get("content");

      //aes decryption starts here
      pp::VarArrayBuffer buffer(content);
      const char *password = "password";
      unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
      int cipherlen = buffer.ByteLength();
      int len = cipherlen + EVP_MAX_BLOCK_LENGTH;
      unsigned char *plaintext = (unsigned char*)malloc(len*sizeof(unsigned char));
      unsigned char* ciphertext = static_cast<unsigned char*>(buffer.Map());

      aes_init(password, (int)strlen(password), key, iv);
      len = decrypt(ciphertext, cipherlen, key, iv, plaintext);
      buffer.Unmap();
      plaintext[len]='\0';  //fix a bug of overshooting plaintext sent
      //aes decryption ends here

      pp::VarDictionary reply;
      reply.Set("action","decryption");
      reply.Set("plaintext", (char*)plaintext);
      reply.Set("fileSize", len);
      PostMessage(reply);
      free(plaintext);
    }

现在,此代码解密数据并发送回扩展页面上的javascript。请注意第plaintext[len]='\0';行,如果我没有说出来,那么有时我会在plaintext中的正确解密文本之后收到垃圾,并在我的javascript中反映为null。那么处理错误的正确方法是什么?

3 个答案:

答案 0 :(得分:3)

正如其他人所提到的那样,您使用的C字符串必须以NULL结尾。当您调用pp :: VarDictionary :: Set,the parameters are pp::Vars时,您正在利用implicit conversion constructor from C-string to pp::Var.

如果您将明文设为std::string或使用pp::VarArrayBuffer,则无需进行此操作。 PostMessage()已针对大型VarArrayBuffers进行了优化,因此无论如何您应该更喜欢这样做。所以我建议更换这一行:

unsigned char *plaintext = (unsigned char*)malloc(len*sizeof(unsigned char));

有类似的东西:

pp::VarArrayBuffer plaintext(len);

...并将您的解密行更改为:

len = decrypt(ciphertext, cipherlen, key, iv,\b
              static_cast<unsigned char*>(plaintext.Map()));

注意,这会将JavaScript从字符串接收的类型更改为ArrayBuffer。如果您希望它保留为字符串,则可以使用std :: string代替:

std::string plaintext(len, '\0');

并使用operator []访问字符串的缓冲区。所以解密的调用看起来像这样(我假设len> 0):

len = decrypt(ciphertext, cipherlen, key, iv, &plaintext[0]);

答案 1 :(得分:2)

'\0'是C中所有字符串的终结符。由于输出是字符串,如果缺少'\0'字符,程序将不知道字符串的结束位置,因此在使用它时可能会移动到字符串之外的区域,这对应于接近结尾的垃圾值。

每当声明字符串时,'\0'都放在最后。但是,您首先为解密的文本分配内存,然后写入其中。在这种情况下,你必须注意最后的字符串终止字符。

字符串终止字符存在的原因是字符串以C中的字符数组的形式存储,并且只有指向字符串开头的指针才能知道数组的大小。

答案 2 :(得分:1)

如果{-1}}不在c-string的末尾,代码将不知道字符串何时结束并将走向未知的内存部分。 null终止符让程序知道“这是我的字符串的结尾”。如果没有这个,您将在程序中邀请未定义的行为。