1. What is strobe?
strobe为面向IoT物联网密码学协议框架,使其在小的IoT设备上更易于开发、部署和分析。strobe适于在16位或32位的微处理器上运行。
strobe同时也是一种轻量级的网络协议,可作为TLS的替换。因为对于资源有限的IoT设备来说,可能无法运行TLS协议。
strobe基于SHA-3 KECCAK-f
函数来进行消息的加密和认证。
目前有NACL, Noise, BLINKER等多种协议框架,strobe跟BLINKER是同一家族的。
目前的现状为:
- NACL:基于2012年论文《The security impact of a new cryptographic library》,基于rust语言的实现有
https://github.com/Yawning/rust-crypto-nacl
自2015年起就不再更新了; - Noise:基于论文(2016年发布,2018年有修订)《The Noise Protocol Framework》,其rust代码库
https://github.com/mcginty/snow
仍很活跃,且在各大密码学学术会议上,基于Noise协议不断有新的研究成果展示。Noise协议已在WhatsAPP上落地应用。 - BLINKER:基于2013年论文《Beyond Modes: Building a Secure Record Protocol from a Cryptographic Sponge Permutation》,暂未找到实现源代码。
- strobe:基于2017年论文《The Strobe protocol framework》,rust代码实现有
https://github.com/rozbb/strobe-rs
。strobe视频解说:https://www.youtube.com/watch?v=l7xV5z1eJLw 。
由此可知,主要考虑noise和strobe两个协议。
2017年,Facebook工程师有博客专门讨论Noise+Strobe=Disco,对noise(非对称加密)和strobe(对称加密)做了对比,并用go语言做了一个实现,代码仓库为:https://github.com/mimoo/disco ,该仓库至今仍较活跃。
2. KECCAK-f
2012年10月,美国NIST选择了Keccak算法作为SHA-3的标准算法,Keccak拥有良好的加密性能以及抗解密能力。
Keccak算法已经作为面向移动通信(TUAK)3GPP TS 35.231的标准,以及NIST FIPS 202和SP 800-185中的标准,经过了大量公开的密码学审查和第三方密码学分析。
KECCAK-f主要有KECCAK-f[25]、KECCAK-f[50]、KECCAK-f[100]、KECCAK-f[200]、KECCAK-f[400]、KECCAK-f[800]、KECCAK-f[1600]这几种。
Keccak[r, c]与KECCAK-f的关系为:f=r+c
Keccak的一些实例标准有:
3. strobe的作用
4. strobe的设计思想
论文《The Strobe protocol framework》中指出,strobe的主要设计原则为:在任意阶段的密码学输出,除依赖于密钥外,还依赖于之前所有的输入。比如,加密一个消息,所生成的密文除依赖于key和明文外,还依赖于之前的数据如nonces和关联数据等。为实现该设计原则,strobe一直在keep a running hash of the protocol transcript。
strobe的该设计原则更侧重于简单和安全,而不是速度。
因为有running hash的缘故,strobe特别适于保证在传输层消息的有序传输的可靠性;strobe也适于半双工模式,即双方依次发送消息而不是同时发送。如TLS安全传输协议在握手阶段采用的就是半双工模式,当信道打开后才是全双工模式。在握手阶段,通常需要两个不同的密钥key,一个用于从Alice给Bob发消息,另一个用于从Bob给Alice发消息。
strobe主要承担协议中的对称加密部分,公钥加密和签名等仍需要借助其它密码学原型,如RSA或椭圆曲线等。
4.1 strobe的oprations
strobe框架主要位于两个领域:
- 应用层:应用层有直接使用的数据,如密钥、铭文消息、nonces随机数和关联数据。需要保护这些数据的隐私和完整。
- 传输层:主要有各方传输的数据,以及需要存储或从不可信内存恢复的数据。这些数据包括密文,传输中的可读消息,MACs和签名。
应用层不直接操作传输层,应用层读写数据均借助strobe的加解密操作。
在上述图中,做了一个假设,即传输层不可信,而应用层是可信的。
通过strobe交互的信息可分为四大类:
上图中的:
RATCHET
既没有输入也没有输出,用于防止回滚攻击。RATCHET
通常会清理掉部分状态,当设备太小无法运行memory-hard函数时,可通过由密码生成密钥来实现相同的功能。KEY
和AD
操作具有相同的数据刘翔,两者均是对随机预言机的输入。KEY
操作会用新key重写overwrite部分状态,所以只要新key一直存在,就可像RATCHET
一样防止回滚。strobe仅在新block开始时才会有重写操作,所以KEY
操作比AD
更安规。non-sponge framework非海绵框架如Noise协议,也会做key和associated data的区分。strobe做该区分有利于其与其它协议的对接移植。
(I,A,C,T)
为4个bit位,实际执行时采用的是一整个byte,共8个bit位。剩余的4个bit位中有一个表示为M
,用于区分metadata,对I/A/C/T等操作无影响,仅用于hashed into the protocol transcript;有一个表示为K
,作为DPA-resistant \key tree" extension,对I/A/C/T等操作有影响;剩余的2个bit作为保留位,目前暂未使用。
4.2 strobe的protocol transcripts
strobe一直在维护 a running hash of the protocol transcript,实际即为从应用层看到的一序列所有的操作和数据。其中的操作包含KEY
和AD
等不给传输层数据的操作。
protocol transcript为一系列组合对:
函数可adjusts the operations so that when Alice sends a message (with ) and Bob receives it (with ), the two protocol transcripts will match.
where is the value of the flag in the first operstion that has .也就是说,对于发起者来说,对于接收者来说。
- 当时,若,将从应用层发出;若,则将由应用层接受。
- 当时,则 (为L-byte操作),也就是说,此时protocol transcript包含了MACs的长度,但是没有相应的值,即所有的值都重置为了0。通过这种方式,当接收到不正确的MACs时,protocol会进行终止操作。
第个block的输出,取决于操作,输入有:前序的protocol transcript ;当前block的input;前序block的application data。详细可表示为:
其中为随机函数,-indifferenctiable。
所有的STROBE协议,都必须以操作开始,且在操作中应有不同domain的分隔符。该分隔符需为通一资源标志符(Universal Resource Identifier, URI),以保证能唯一描述协议,防止各种跨协议攻击。
对于简单的协议,每个操作应在上下文中具有唯一的涵义,使得transcript可解析。对于复杂的协议,相同的操作可能有多重涵义,此时要想解析transcript,一种简单的方法时在transcript中做备注来区分。此时信息可以通过协议帧来传输,如TCP stream中的tag-length-value帧(tag表明message type)。在STROBE协议中,通过来区分,通过标签来标记,对操作无任何影响,仅仅用于hashed into the protocol transcript,这样的操作页可称为操作。
大多数协议,都是以明文格式来发送帧数据,这时会使用 transaction(除了在transcript中具有标签外,与操作类似)。
若使用操作,则相应的帧信息将被加密,这在图片隐写术和长度填充中有用。
在协议中若未传输足够的帧信息来保证完全可解析,可通过操作来补充传送帧信息。
推荐的做法为:对于每个non-metadata操作,后面都紧跟一个metadata操作来做补充描述。
以OP来表示操作,info标签来描述协议中消息message的含义。则在Info标签中应包含消息的长度(除非在协议中为固定值或不可知)。同时以标签-操作
符来描述帧信息及对应的操作符。(如meta-CLR,meta-AD,meta-CLR等)。
举例:ENC[app-ciphertext] (“hello”)可拆分为两个动作:
meta-CLR([[0x03,0x05,0x00]]); ENC(“hello”)
其中标签代表app-ciphertext,[[0x05,0x00]]为length标签,代表的时5个bytes。
5. strobe的实例化
论文《The Strobe protocol framework》的附录B.1中指出,当采用keccak-f[1600]时,即,STROBE security为,有,于是有。
根据附录A.1可知,为sponge rate,为capacity。的取值范围为,为了减小功耗分析攻击,sponge rate会调整为,对应的https://github.com/rozbb/strobe-rs
中代码实现为:
let rate = KECCAK_BLOCK_SIZE * 8 - (sec as usize) / 4 - 2; //KECCAK_BLOCK_SIZE =25, rate即为上文的$\hat{r}$
assert!(rate >= 1);
assert!(rate < 254);
rate即为上文的。
初始化状态为:
对应的代码实现为:
// Initialize state: st = F([0x01, R+2, 0x01, 0x00, 0x01, 0x60] + b"STROBEvX.Y.Z")
let mut st_buf = [0u8; KECCAK_BLOCK_SIZE * 8];
st_buf[0..6].copy_from_slice(&[0x01, (rate as u8) + 2, 0x01, 0x00, 0x01, 0x60]);
st_buf[6..13].copy_from_slice(b"STROBEv");
st_buf[13..18].copy_from_slice(STROBE_VERSION.as_bytes());
//运行F函数,keccak-f[1600]
let mut st = AlignedKeccakState(st_buf);
keccakf_u8(&mut st);
let mut strobe = Strobe {
st: st,
sec: sec,
rate: rate,
pos: 0,
pos_begin: 0,
is_receiver: None,
};
// Mix the protocol into the state
let _ = strobe.meta_ad(proto, false);
//对应地:
def_op_no_mut!(
ad,
meta_ad,
OpFlags::A,
"Mixes associated data into the internal state."
);
// This defines an operation and meta-operation that does not mutate its input
macro_rules! def_op_no_mut {
($name:ident, $meta_name:ident, $flags:expr, $doc_str:expr) => (
#[doc = $doc_str]
pub fn $name(&mut self, data: &[u8], more: bool) {
let flags = $flags;
self.operate_no_mutate(flags, data, more);
}
#[doc = $doc_str]
pub fn $meta_name(&mut self, data: &[u8], more: bool) {
let flags = $flags | OpFlags::M;
self.operate_no_mutate(flags, data, more);
}
)
}
/// Performs the state transformation that corresponds to the given flags. If `more` is given,
/// this will treat `data` as a continuation of the data given in the previous call to
/// `operate`. This uses non-mutating variants of the specializations of the `duplex` function.
pub(crate) fn operate_no_mutate(&mut self, flags: OpFlags, data: &[u8], more: bool) {
assert!(!flags.contains(OpFlags::K), "Op flag K not implemented");
if !more {
self.begin_op(flags);
}
// There are no non-mutating variants of things with flags & (C | T | I) == C | T
if flags.contains(OpFlags::C) && flags.contains(OpFlags::T) && !flags.contains(OpFlags::I) {
panic!("operate_no_mutate called on something that requires mutation");
} else if flags.contains(OpFlags::C) {
// This is equivalent to a non-mutating form of the `duplex` operation in the Python
// implementation, with `cbefore = True`
self.overwrite(data);
} else {
// This is equivalent to the `duplex` operation in the Python implementation, with
// `cbefore = cafter = False`
self.absorb(data);
};
}
参考资料:
[1] https://strobe.sourceforge.io/
[2] https://github.com/rozbb/strobe-rs
[3] https://keccak.team/keccak.html
[4] 论文《The Strobe protocol framework》
[5] strobe视频解说:https://www.youtube.com/watch?v=l7xV5z1eJLw
[6] https://www.cryptologie.net/article/408/noisestrobedisco/
[7] https://noisesocket.org/post/1/
来源:CSDN
作者:mutourend
链接:https://blog.csdn.net/mutourend/article/details/100558422