AWS SQS,如何计算消息属性的MD5消息摘要

3
我正在尝试弄清如何计算 AWS 消息属性的 MD5 摘要。我正在遵循 URI:SQS 消息元数据 > 计算消息属性的 MD5 消息摘要,但是虽然这似乎很简单,我正在尝试获取以下属性的哈希值。
var messageAttributes = new Dictionary<string, MessageAttributeValue>
{
    {"UserName", new MessageAttributeValue {DataType ="String", StringValue = "Me"}}
};

我发送了这条消息,MD5响应是3a6071d47534e3e07414fea5046fc217

尝试查找文档以确定是否可以解决此问题:

private void CustomCalc()
{
    var verifyMessageAttributes = new List<byte>();
    verifyMessageAttributes.AddRange(EncodeString("UserName"));
    verifyMessageAttributes.AddRange(EncodeString("String"));
    verifyMessageAttributes.AddRange(EncodeString("Me"));
    var verifyMessageAttributesMd5 = GetMd5Hash(verifyMessageAttributes.ToArray());
}

private List<byte> EncodeString(string data)
{
    var result = new List<byte>();
    if (BitConverter.IsLittleEndian)
    {
        result.AddRange(BitConverter.GetBytes(data.Length).Reverse());
    }
    else
    {
        result.AddRange(BitConverter.GetBytes(data.Length));
    }
    result.AddRange(Encoding.UTF8.GetBytes(data));
    return result;

}
public static string GetMd5Hash(byte[] input)
{
    using (var md5Hash = MD5.Create())
    {
        // Convert the input string to a byte array and compute the hash.
        var dataBytes = md5Hash.ComputeHash(input);

        // Create a new string builder to collect the bytes and create a string.
        var sBuilder = new StringBuilder();

        // Loop through each byte of the hashed data and format each one as a hexadecimal string.
        foreach (var dataByte in dataBytes)
        {
            sBuilder.Append(dataByte.ToString("x2"));
        }

        // Return the hexadecimal string.
        return sBuilder.ToString();
    }
}

但是我最终得到了这个cf886cdabbe5576c0ca9dc51871d10ae。有人知道我错在哪里吗?我猜这应该不难,只是我暂时没看出来。


链接中显示的4字节长度怎么样? - jdweng
这个问题在EncodeString方法中已经处理了,但是感谢您指出这个问题。一开始我忽略并误解了其中的一些内容。 - Samyne
2个回答

2
您已经接近成功,但还缺少一步:
编码值的传输类型(字符串或二进制)(1个字节)。
注意 逻辑数据类型String和Number使用String传输类型。
逻辑数据类型Binary使用Binary传输类型。
对于String传输类型,请编码为1。
对于Binary传输类型,请编码为2。
因此,您需要在值之前附加1或2,以指示传输类型。在您的情况下:
var verifyMessageAttributes = new List<byte>();
verifyMessageAttributes.AddRange(EncodeString("UserName"));
verifyMessageAttributes.AddRange(EncodeString("String"));
verifyMessageAttributes.Add(1); // < here
verifyMessageAttributes.AddRange(EncodeString("Me"));
var verifyMessageAttributesMd5 = GetMd5Hash(verifyMessageAttributes.ToArray());

非常感谢,我觉得自己太蠢了,竟然忽略了这个问题。答案一直在我面前。 - Samyne
2
每个人都会遇到这种情况,在这种情况下做的正确之举就是请其他人查看代码。 - Evk

0

这是Node.js中独立的解决方案:

const md5 = require('md5');

const SIZE_LENGTH = 4;
const TRANSPORT_FOR_TYPE_STRING_OR_NUMBER = 1;
const transportType1 = ['String', 'Number'];

module.exports = (messageAttributes) => {
  const buffers = [];
  const keys = Object.keys(messageAttributes).sort();

  keys.forEach((key) => {
    const { DataType, StringValue } = messageAttributes[key];

    const nameSize = Buffer.alloc(SIZE_LENGTH);
    nameSize.writeUInt32BE(key.length);

    const name = Buffer.alloc(key.length);
    name.write(key);

    const typeSize = Buffer.alloc(SIZE_LENGTH);
    typeSize.writeUInt32BE(DataType.length);

    const type = Buffer.alloc(DataType.length);
    type.write(DataType);

    const transport = Buffer.alloc(1);

    let valueSize;
    let value;
    if (transportType1.includes(DataType)) {
      transport.writeUInt8(TRANSPORT_FOR_TYPE_STRING_OR_NUMBER);
      valueSize = Buffer.alloc(SIZE_LENGTH);
      valueSize.writeUInt32BE(StringValue.length);

      value = Buffer.alloc(StringValue.length);
      value.write(StringValue);
    } else {
      throw new Error(
        'Not implemented: MessageAttributes with type Binary are not supported at the moment.'
      );
    }

    const buffer = Buffer.concat([nameSize, name, typeSize, type, transport, valueSize, value]);

    buffers.push(buffer);
  });

  return md5(Buffer.concat(buffers));
};

GitHub的sqslite存储库中查看更多


希望你能够通过我在原问题中添加的C#代码找到解决方法。它包含了编码消息所需的所有方法。 - Samyne
@Samyne,你的代码似乎没有对名称、类型和值进行4位截断。此外,由于缺少一些部分,我也无法运行你的代码。你能告诉我你的截断是否与我在截图中看到的一样吗? - Jenny
我认为你做了错误的假设。你应该考虑你名字值的长度。因此,SellerName的长度为10,值10应该转换为4字节值。然后,SellerName也必须转换为一个UTF8字节数组。 这就是我在EncodeString方法中所做的。 - Samyne
@Samyne 我试过了,但还是感觉不对。我正在分配缓冲区并用零填充它。所以从0000(4个字节)开始。然后注入长度(我尝试在开头和结尾注入),所以前4个字节看起来像1000,然后是0010(如屏幕截图所示)。所有3个值都重复了这种模式。你觉得字符串构造正确吗? - Jenny
你有考虑到像我一样的IsLittleEndian检查吗?因为这也可能会搞砸事情。 我的JavaScript语言知识不足,无法调试你的代码。 - Samyne
@Samyne,最终我解决了问题,我很快会更新我的帖子。问题出在JavaScript中Buffer写入的方式上。它确实使用大端序。 顺便问一下,在你的代码中何时使用LE,请给我一个例子? - Jenny

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接