使用XTEA进行挑战响应认证

时间:2018-03-26 20:48:56

标签: encryption esp8266 challenge-response xtea

我有两个ESP8266微控制器板:

Board A正在运行HTTP服务器,并且能够通过来自Board B(即HTTP客户端)的GET请求来切换中继。

为了确保只有Board B和其他人不会在A板上切换继电器,我想实现某种质询响应认证。

我的想法如下:

  1. B板要求A板切换继电器
  2. Board A发送一些随机字节作为挑战
  3. Board B使用XTEA算法加密这些原始字节,并将值返回到Board A
  4. 董事会A解析董事会B的回复并将其与自己的结果进行比较。如果响应太晚(例如在一秒钟之后)到达或响应无效,则将中止认证并且下次将生成新的挑战。如果响应有效,继电器将切换,下一次尝试也会有新的挑战。
  5. 因此,如果攻击者正在嗅探网络通信,他将同时收到原始字节和加密字节。

    我向你提问:

    1. 如果攻击者知道原始字节和加密字节,是否(很容易)可以计算XTEA密钥?
    2. 描述的方法是否是我问题的合理解决方案?
    3. 提前致谢, 克里斯

1 个答案:

答案 0 :(得分:0)

免责声明:我不是密码专家。

  

如果攻击者知道原始字节并加密了原始字节,是否可以轻松地计算XTEA密钥?

不,您仍然必须进行暴力破解才能推断出所使用的回合的关键和次数,即AFAIK。 (至少,如果您使用的是19轮或更多轮,截至2009年,目前唯一已知的XTEA加密攻击影响的轮数是18轮或更少。但是鉴于默认和推荐的轮数是32轮,因此不应将除非您使用自定义且轮数较少。.例如18)

  

所描述的方法是否可以解决我的问题?

您的协议容易受到来自MITM攻击者的比特翻转攻击,并且提供针对侦听/监视的保护,MITM攻击者将知道您正在发出什么命令,并且能够更改给定的命令,可以很容易地避免这两种情况……

我认为,如果客户端只要求随机字节作为令牌,然后将实际命令与加密的令牌一起发送,那会更好。这样可以保护您的命令免于监听,即使攻击者知道协议的工作原理,它也会使MITM攻击者无法推断出您发送了什么命令,因为令牌现在充当加密命令的盐。.但是您仍然即使攻击者不知道密钥也容易遭受来自MITM攻击者的比特翻转,因此您还应该添加一个校验和,以确保密文没有被篡改...客户端的情况如何:

// start with the actual command
$data=encrypt("switch_relay(5);"); // or whatever
function encrypt(string $command){
// because of XTEA length padding, we need to tell the server the inner command length, so add a big endian 16 bit `size header`
$data=to_big_endian_uint16_t(strlen($data)).$data;
// get a unique 1-time-token? this should serve as salt AND protect against replay attack
$token=fetchToken();
// add the token
$data=$token.$data;
// now calculate a checksum to protect against bit-flipping attacks
$checksum=hash('adler32be',$data); // or whatever checksum you prefer. just has to be strong enough to detect random bit-flipping from attackers that can't decrypt-modify-encrypt because they don't know the encryption key, see https://en.wikipedia.org/wiki/Malleability_(cryptography) / https://en.wikipedia.org/wiki/Bit-flipping_attack

// add checksum
$data=$checksum.$data;
// encrypt data
$data=XTEA::encrypt($data, $key, XTEA::PAD_RANDOM, 32);
return $data;
}

在此之后,我通常会 添加另一个大小标头,以便服务器知道要为整个数据包读取的字节数,但是由于您说的是使用HTTP协议,因此我假设您会使用Content-Length: X标头作为外部尺寸标头。(或者,如果不这样做,则在对xtea进行加密后,您可能还应该再做一个$data=big_endian_uint16_t(strlen($data)).$data;

和服务器一样

function decrypt(string $data){
     // 4=checksum 8=token 2=inner_command_length
     if(strlen($data) < (4+8+2) || strlen($data) % 8 !== 0){
         // can't be an xtea-encrypted command, wrong length.
         return ERR_INVALID_LENGTH;
     }
    $data=XTEA::decrypt($data,$key,32);
    $checksum=substr($data,0,4);
    $data=substr($data,4);
    if(hash('adler32be',$data)!=$checksum){
        // checksum fail, can't be an xtea-encrypted command (or maybe it was corrupted or tampered with?)
       return ERR_INVALID_CHECKSUM;
    }
    $token=substr($data,0,8);
    $data=substr($data,8);
    if(!is_valid_token($token)){
        return ERR_INVALID_TOKEN;
    }
    $inner_size_len=big_endian_uint16_t_to_native_number(substr($data,0,2));
    $data=substr($data,2);
    if(strlen($data) < $inner_size_len){
        return ERR_INVALID_INNER_SIZE;
    }
    // remove padding bytes
    $data=substr($data,0,$inner_size_len);
    return $data; // the actual decrypted command
}

..?

(我仍然看到3个潜在的问题:1:未提供前向保密性,因为我认为您需要更复杂的东西。2:攻击者也许可以通过请求一次DoS攻击您-令牌,直到用完ram或其他东西,阻止合法客户端生成令牌为止,但鉴于令牌生存期为1秒,则必须是连续的主动攻击,并在阻止/移除攻击者后停止工作:3:如果您的命令可以大于65535字节,则可能要切换到32位大小的标头,或者如果命令可以超过4GB,则可能要切换到64位大小的标头,依此类推。很小,一个65535字节的16位头就足够了吗?)