密文比密钥短的AES 128解密

时间:2018-07-21 10:52:49

标签: encryption aes block-cipher key

我们正在开发一个应用程序,该应用程序必须使用LoraWan(https://www.lora-alliance.org)加密的数据

我们已经找到了有关如何加密数据的文档,并且在过去几天(https://www.lora-alliance.org/sites/default/files/2018-04/lorawantm_specification_-v1.1.pdf)进行了仔细阅读,但目前仍无法解决我们的问题。

我们必须使用带有零填充的AES 128位ECB解密来解密消息,但是问题在于它无法正常工作,因为我们接收到的加密消息对于AES 128来说不够长,因此该算法返回“不是最后一行的完整块”。

我们收到的示例密钥如下:D6740C0B8417FF1295D878B130784BC5(不是真实密钥)。它的长度为32个字符,因此为32个字节,但是如果将其视为十六进制,则它将变为16个字节长,这是AES 128位所需的。这是我们用来从字符串转换十六进制的代码:

public static string HextoString(string InputText)
{byte[] hex= Enumerable.Range(0, InputText.Length)
                 .Where(x => x % 2 == 0)
                 .Select(x => Convert.ToByte(InputText.Substring(x, 2), 16))
                 .ToArray();
return System.Text.Encoding.ASCII.GetString(hex);}

(上面的代码需要注意的一点是,我们不确定要使用哪种编码,因为我们在Lora文档中找不到它,他们也没有告诉我们,但是根据这个小的设置,我们可以搞砸了我们的解密(尽管我们已经尝试了所有可能的组合,例如ascii,utf8,utf7等)

我们收到的示例消息是:d3 73 4c,我们假设它也是十六进制的。这只有6个字节,如果将其从六进制转换为普通,则只有3个字节,而与密钥长度匹配,我们需要最少16个字节。

这是我们正在使用的Aes 128解密的代码:

private static string Aes128Decrypt(string cipherText, string key){

string decrypted = null;

var cipherPlainTextBytes = HexStringToByteArray(cipherText);
//var cipherPlainTextBytes = ForcedZeroPadding(HexStringToByteArray(cipherText));
var keyBytes = HexStringToByteArray(key);

using (var aes = new AesCryptoServiceProvider())
{
    aes.KeySize = 128;
    aes.Key = keyBytes;
    aes.Mode = CipherMode.ECB; 
    aes.Padding = PaddingMode.Zeros; 

    ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
    using (MemoryStream ms = new MemoryStream(cipherPlainTextBytes, 0, cipherPlainTextBytes.Length))
    {
        using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
        {
            using (StreamReader sr = new StreamReader(cs))
            {
                decrypted = sr.ReadToEnd();
            }
        }
    }
}
return decrypted;}

因此,很显然,这将在sr.ReadToEnd()处返回“数据是不完整的块”。

从示例中可以看到,在注释掉的那一行中,我们还尝试了使用适当长度的完整零字节数组(16-cipherText)将文本“填充”到正确的大小。该算法运行良好,但返回的是完整的乱码而不是原始文本。

我们已经尝试了所有操作模式,并且还尝试了填充模式。他们没有为我们提供任何信息,而是cipherText和该文本的密钥。也没有初始化向量,因此我们假设每次都应该生成该向量(但是对于ECB,甚至不需要iirc)

更重要的是,他们能够对消息进行加密-解密。对此最令人困惑的是,我已经在谷歌上搜索了好几天,在解密期间,我在google上找不到CIPHERTEXT比密钥短的单个示例。

很明显,我发现了一些示例,其中正在加密的消息比所需消息短,但这就是加密侧的填充内容(对吗?)。这样,当您收到填充的消息时,可以告诉算法使用哪种填充模式来使其长度正确,从而可以将填充与消息分开。但是在所有这些情况下,解密期间收到的消息的长度都是正确的。

问题是-我们在做什么错?有什么方法可以用比密钥短的密文解密?还是他们通过产生太短的密码弄乱了某个地方?

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

在AES-ECB中,唯一小于16字节的有效密文为空。 16字节的限制是AES的块(不是密钥)大小,恰好与AES-128的密钥大小匹配。

因此,问题的

  

我们收到的示例消息是:d3 73 4c

不显示ECB加密消息(因为comment告诉它来自JSON,所以不能是恰巧显示为十六进制的字节)。对于Join-Accept,这太短了,不足以成为FRMPayload(根据此comment),因为spec谈到后面的内容:

  

1625消息长度为16或32个字节。

难道JSON消息包含的内容不是完整的FRMPayload,而是数据包的片段,编码为带有空格分隔符的十六进制对吗?只要不知道如何构建FRMPayload,就没有必要对其进行解密。

更新:如果该神秘消息始终为3个字节,并且对于给定密钥始终相同(或每个密钥一次可用),则根据Maarten Bodewes的{{3} }可能是关键检查值。 KCV通常是每个原始数据块密码(等效地:每个ECB)使用密钥对全零值加密的前3个字节。 comment可以完全脱机工作(这对于不公开密钥是必需的),并且可以用来手动验证假设。它告诉我们对于问题中给出的16字节密钥,KCV将为cd15e1(或下一部分中的每个变体形式为c076fc)。


此外:CreateDecryptor用于制作负责ECB解密的Gizmo。在对LoraWan有效负载进行解密的情况下,这可能是不正确的,这需要ECB encryption 来对某些字段进行解密:

  

1626注:ECB模式下的AES解密操作用于加密加入接受的消息,以便最终设备可以使用AES加密操作来解密消息。这样一来,终端设备仅需实现AES加密,而无需实现AES解密。


在解密LoraWan数据包的情况下,您想使用字节数组而不是字符串与AES引擎进行通信。字符串具有编码,而LoraWan密文和相应的明文则没有。 Herbert Hanewinkel's javascript AES似乎已经成功地强迫了不错的.NET全功能加密API来完成底层工作。


HextoString代码中,我含糊其词意为,也许结果是hex成为了原来的十六进制输入,作为字节数组(完全摆脱了十六进制和其他编码的罪恶;在这种情况下,变量hex应该重命名为pure_bytes。但是后来我迷茫了System.Text.Encoding.ASCII.GetString(hex)。如果它只是从字节数组创建字节字符串,或者将密钥转回十六进制以供以后在HexStringToByteArray中输入Aes128Decrypt,我会感到惊讶。加Others使我担心[0x80..0xFF]中的任何字节都可能会变成0x3F,这对于密钥,密文和相应的LoraWan有效负载来说是不好的。取消十六进制时,它们没有字符编码。

我的结论是,如果HexStringToByteArray遵循其名称的含义,并且考虑到Aes128Decrypt的当前接口,HextoString应该只是删除空格(如果HexStringToByteArray则不需要即时删除空白)。但是我的建议是更改接口以使用字节数组,而不是字符串(请参见上一节)。


顺便说一句:从其密钥创建ICryptoTransform对象应该多次执行该对象。