我有两个ESP8266微控制器板:
Board A正在运行HTTP服务器,并且能够通过来自Board B(即HTTP客户端)的GET请求来切换中继。
为了确保只有Board B和其他人不会在A板上切换继电器,我想实现某种质询响应认证。
我的想法如下:
因此,如果攻击者正在嗅探网络通信,他将同时接收原始字节和加密字节。
我向你提问:
谢谢,克里斯
免责声明:我不是加密专家。
如果攻击者知道原始字节和加密字节,是否(很容易)可以计算XTEA密钥?
不,你仍然需要做一个强力推断使用的钥匙和数量,AFAIK。 (至少如果您使用19轮或更多,因为目前唯一已知的XTEA加密攻击影响18轮或更少,截至2009年。但鉴于默认和推荐的是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:攻击者可能通过请求一次性攻击来攻击你你用完ram或其他任何东西,阻止合法的客户端生成令牌,但是如果令牌的生命周期为1秒,则必须是连续的主动攻击,并在攻击者被阻止/删除后停止工作.3:如果你的命令可能大于65535字节,您可能希望切换到32位大小的标头,或者如果您的命令可能超过4GB,您可能需要切换到64位大小的标头,依此类推。但如果您的命令很小, 65535字节的16位大小标题应该足够吗?)