- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在使用维基百科的 xtea 加密版本,它是用 C++ 编写的。我写了一个函数来加密一个字符串
const char* charPtrDecrypt(const char* encString, int len, bool encrypt)
{
/********************************************************
* This currently uses a hard-coded key, but I'll implement
* a dynamic key based on string length or something.
*********************************************************/
unsigned int key[4] = { 0xB5D1, 0x22BA, 0xC2BC, 0x9A4E };
int n_blocks=len/BLOCK_SIZE;
if (len%BLOCK_SIZE != 0)
++n_blocks;
for (int i = 0; i < n_blocks; i++)
{
if (encrypt)
xtea::Encrypt(32, (uint32_t*)(encString + (i*BLOCK_SIZE)), key);
else
xtea::Decrypt(32, (uint32_t*)(encString + (i*BLOCK_SIZE)), key);
}
return encString;
}
当我提供一个 const char encString[] = "Hello, World!"
时它起作用,但是当我提供一个原始字符串时,例如const char* a = charPtrDecrypt("Hello, World!", 14, true)
它崩溃了。
最佳答案
有一句老话(我知道这句话很老,因为我在 1992 年左右第一次将它发布到 Usenet 上)是:“如果你对编译器撒谎,它会报复的。”这就是这里发生的事情。
这里:
const char* charPtrDecrypt(const char* encString, int len, bool encrypt)
...您保证不会修改encString
指向的字符。这就是 const
所说/意味着/所做的。
然而,这里:
xtea::Encrypt(32, (uint32_t*)(encString + (i*BLOCK_SIZE)), key);
...您抛弃了 const
ness(转换为 uint32_t *
,没有 const
限定符),并将指针传递给修改它指向的缓冲区的函数。
然后编译器开始报复:它允许您将指针传递给您不能修改的数据,因为您 promise 不修改它——但是当您转身尝试修改它时无论如何修改它,你的程序会崩溃并烧毁,因为你试图修改只读数据。
这可以通过多种方式避免。一种是摆脱你现在使用的相对低级的构造,并传递/返回 std::string
而不是指向 [const
] 字符
。
代码的问题远不止于此。一方面,它将输入视为 uint32_t 项的 block ,并将其长度 up 的 View 舍入到 uint32_t 大小的下一个倍数(通常为 4)。不幸的是,它实际上并没有改变缓冲区的大小,所以即使缓冲区是可写的,它也不能真正正常工作——它仍然会读取和写入缓冲区的末尾。
这里,std::string
将再次提供帮助:它让我们将字符串的大小调整为正确的大小,而不是仅仅读取/写入超过固定大小缓冲区的末尾。
除此之外,有一个事实编译器不会关心,但您(和这段代码的任何读者)会(或至少应该):函数的名称具有误导性,并且具有含义不正确的参数一点都不明显——尤其是控制是加密还是解密的 bool 值。我建议改用枚举,并将函数重命名为可以包含加密或解密的内容:
最后,我将确定是在循环外加密还是解密的 if
语句移动,因为我们不会在处理一个输入字符串时从一个更改为另一个。
考虑到所有这些因素,我们最终可以得到如下代码:
enum direction { ENCRYPT, DECRYPT };
std::string xtea_process(std::string enc_string, direction d) {
unsigned int key[4] = { 0xB5D1, 0x22BA, 0xC2BC, 0x9A4E };
size_t len = enc_string.size();
len += len % BLOCK_SIZE; // round up to next multiple of BLOCK_SIZE
enc_string.resize(len); // enlarge the string to that size, if necessary
if (direction == DECRYPT)
for (size_t i = 0; i < len; i+=BLOCK_SIZE)
xtea::Decrypt(32, reinterpret_cast<uint32_t *>(&encString[i]), key);
else
for (size_t i = 0; i < len; i += BLOCK_SIZE)
xtea::Encrypt(32, reinterpret_cast<uint32_t *>(&encString[i]), key);
}
return encString;
}
这仍然(至少)留下一点我没有费心去处理:一些机器对 uint32_t
的对齐要求可能比对 char
的对齐要求更严格, 从理论上讲, string
中使用的缓冲区可能无法满足那些更严格的对齐要求。您可能会遇到需要将数据从 string
复制到为 uint32_t
访问正确对齐的缓冲区,进行加密/解密,然后复制结果返回。
关于c++ - 字符串加密函数适用于 char[],但不适用于普通字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37054522/
如何使用 SPListCollection.Add(String, String, String, String, Int32, String, SPListTemplate.QuickLaunchO
我刚刚开始使用 C++ 并且对 C# 有一些经验,所以我有一些一般的编程经验。然而,似乎我马上就被击落了。我试过在谷歌上寻找,以免浪费任何人的时间,但没有结果。 int main(int argc,
这个问题已经有答案了: In Java 8 how do I transform a Map to another Map using a lambda? (8 个回答) Convert a Map>
我正在使用 node + typescript 和集成的 swagger 进行 API 调用。我 Swagger 提出以下要求 http://localhost:3033/employees/sear
我是 C++ 容器模板的新手。我收集了一些记录。每条记录都有一个唯一的名称,以及一个字段/值对列表。将按名称访问记录。字段/值对的顺序很重要。因此我设计如下: typedef string
我需要这两种方法,但j2me没有,我找到了一个replaceall();但这是 replaceall(string,string,string); 第二个方法是SringBuffer但在j2me中它没
If string is an alias of String in the .net framework为什么会发生这种情况,我应该如何解释它: type JustAString = string
我有两个列表(或字符串):一个大,另一个小。 我想检查较大的(A)是否包含小的(B)。 我的期望如下: 案例 1. B 是 A 的子集 A = [1,2,3] B = [1,2] contains(A
我有一个似乎无法解决的小问题。 这里...我有一个像这样创建的输入... var input = $(''); 如果我这样做......一切都很好 $(this).append(input); 如果我
我有以下代码片段 string[] lines = objects.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.No
这可能真的很简单,但我已经坚持了一段时间了。 我正在尝试输出一个字符串,然后输出一个带有两位小数的 double ,后跟另一个字符串,这是我的代码。 System.out.printf("成本:%.2
以下是 Cloud Firestore 列表查询中的示例之一 citiesRef.where("state", ">=", "CA").where("state", "= 字符串,我们在Stack O
我正在尝试检查一个字符串是否包含在另一个字符串中。后面的代码非常简单。我怎样才能在 jquery 中做到这一点? function deleteRow(locName, locID) { if
这个问题在这里已经有了答案: How to implement big int in C++ (14 个答案) 关闭 9 年前。 我有 2 个字符串,都只包含数字。这些数字大于 uint64_t 的
我有一个带有自定义转换器的 Dozer 映射: com.xyz.Customer com.xyz.CustomerDAO customerName
这个问题在这里已经有了答案: How do I compare strings in Java? (23 个回答) 关闭 6 年前。 我想了解字符串池的工作原理以及一个字符串等于另一个字符串的规则是
我已阅读 this问题和其他一些问题。但它们与我的问题有些无关 对于 UILabel 如果你不指定 ? 或 ! 你会得到这样的错误: @IBOutlet property has non-option
这两种方法中哪一种在理论上更快,为什么? (指向字符串的指针必须是常量。) destination[count] 和 *destination++ 之间的确切区别是什么? destination[co
This question already has answers here: Closed 11 years ago. Possible Duplicates: Is String.Format a
我有一个Stream一个文件的,现在我想将相同的单词组合成 Map这很重要,这个词在 Stream 中出现的频率. 我知道我必须使用 collect(Collectors.groupingBy(..)
我是一名优秀的程序员,十分优秀!