strobe——面向IoT物联网应用的密码学协议框架

1. What is strobe?

strobe为面向IoT物联网密码学协议框架,使其在小的IoT设备上更易于开发、部署和分析。strobe适于在16位或32位的微处理器上运行。

strobe同时也是一种轻量级的网络协议,可作为TLS的替换。因为对于资源有限的IoT设备来说,可能无法运行TLS协议。

strobe基于SHA-3 KECCAK-f函数来进行消息的加密和认证。

目前有NACL, Noise, BLINKER等多种协议框架,strobe跟BLINKER是同一家族的。
目前的现状为:

由此可知,主要考虑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 202SP 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函数时,可通过由密码生成密钥来实现相同的功能。
  • KEYAD操作具有相同的数据刘翔,两者均是对随机预言机的输入。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,实际即为从应用层看到的一序列所有的操作和数据。其中的操作包含KEYAD等不给传输层数据的操作。

protocol transcript为一系列组合对:
( A d j D i r ( I 0 ; o p e r a t i o n ) , A p p D a t a ) (AdjDir(I_0;operation),AppData) (AdjDir(I0;operation),AppData)
( A d j D i r ( I 0 ; . ) (AdjDir(I_0;.) (AdjDir(I0;.)函数可adjusts the operations so that when Alice sends a message (with I = 0 I=0 I=0) and Bob receives it (with I = 1 I=1 I=1), the two protocol transcripts will match.
A d j D i r ( I 0 , ( I , A , C , T , M , K ) ) : = ( I ⊕ ( T ⋅ I 0 ) , A , C , T , M , K ) AdjDir(I_0,(I,A,C,T,M,K)):=(I\oplus (T\cdot I_0), A,C,T,M,K) AdjDir(I0,(I,A,C,T,M,K)):=(I(TI0),A,C,T,M,K)
where I 0 I_0 I0 is the value of the I I I flag in the first operstion that has T = 1 T=1 T=1.也就是说,对于发起者来说 I 0 = 0 I_0=0 I0=0,对于接收者来说 I 0 = 1 I_0=1 I0=1

  • A = 1 A=1 A=1时,若 I = 0 I=0 I=0 A p p D a t a AppData AppData将从应用层发出;若 I = 1 I=1 I=1,则 A p p D a t a AppData AppData将由应用层接受。
  • A = 0 A=0 A=0时,则 A p p D a t a : = L × [ [ 0 ] ] AppData:=L\times[[0]] AppData:=L×[[0]] (为L-byte操作),也就是说,此时protocol transcript包含了MACs的长度,但是没有相应的值,即所有的值都重置为了0。通过这种方式,当接收到不正确的MACs时,protocol会进行终止操作。

i i i个block的输出,取决于操作 o p ∈ { E N C , M A C , P R F } op\in\{ENC,MAC,PRF\} op{ENC,MAC,PRF},输入有:前序的protocol transcript T r Tr Tr;当前block的input;前序block的application data。详细可表示为:
O u t p u t i = I n p u t i ⊕ G ( T r , A d j D i r ( I 0 , o p e r a t i o n ) , ( A p p D a t a 1 ∣ ∣ . . . ∣ ∣ A p p D a t a i − 1 ) ) Output_i=Input_i\oplus G(Tr, AdjDir(I_0,operation),(AppData_1||...||AppData_{i-1})) Outputi=InputiG(Tr,AdjDir(I0,operation),(AppData1...AppDatai1))

其中 G G G为随机函数, ϵ \epsilon ϵ-indifferenctiable。
在这里插入图片描述

所有的STROBE协议,都必须以 A D AD AD操作开始,且在 A D AD AD操作中应有不同domain的分隔符。该分隔符需为通一资源标志符(Universal Resource Identifier, URI),以保证能唯一描述协议,防止各种跨协议攻击。

对于简单的协议,每个操作应在上下文中具有唯一的涵义,使得transcript可解析。对于复杂的协议,相同的操作可能有多重涵义,此时要想解析transcript,一种简单的方法时在transcript中做备注来区分。此时信息可以通过协议帧来传输,如TCP stream中的tag-length-value帧(tag表明message type)。在STROBE协议中,通过 m e t a d a t a metadata metadata来区分,通过 M M M标签来标记,对操作无任何影响,仅仅用于hashed into the protocol transcript,这样的操作页可称为 m e t a − o p meta-op metaop操作。
大多数协议,都是以明文格式来发送帧数据,这时会使用 m e t a − C L R meta-CLR metaCLR transaction(除了在transcript中具有 M M M标签外,与 C L R CLR CLR操作类似)。
若使用 m e t a − E N C meta-ENC metaENC操作,则相应的帧信息将被加密,这在图片隐写术和长度填充中有用。
在协议中若未传输足够的帧信息来保证完全可解析,可通过 m e t a − A D meta-AD metaAD操作来补充传送帧信息。

推荐的做法为:对于每个non-metadata操作,后面都紧跟一个metadata操作来做补充描述。
以OP来表示操作,info标签来描述协议中消息message的含义。则在Info标签中应包含消息的长度(除非在协议中为固定值或不可知)。同时以标签-操作符来描述帧信息及对应的操作符。(如meta-CLR,meta-AD,meta-CLR等)。

举例:ENC[app-ciphertext] (“hello”)可拆分为两个动作:
meta-CLR([[0x03,0x05,0x00]]); ENC(“hello”)

其中 0 x 03 0x03 0x03标签代表app-ciphertext,[[0x05,0x00]]为length标签,代表的时5个bytes。

5. strobe的实例化

论文《The Strobe protocol framework》的附录B.1中指出,当采用keccak-f[1600]时,即 b = 1600 b=1600 b=1600,STROBE security为 λ \lambda λ,有 c = 2 λ , r + c = b , F = f [ b ] c=2\lambda,r+c=b,F=f[b] c=2λ,r+c=b,F=f[b],于是有 r = b − c = 1600 − 2 λ r=b-c=1600-2\lambda r=bc=16002λ

根据附录A.1可知, r r r为sponge rate, c c c为capacity。 r r r的取值范围为 3 ≤ r ≤ 256 3\leq r\leq256 3r256,为了减小功耗分析攻击,sponge rate会调整为 r ^ = r / 8 − 2 = 200 − λ / 4 − 2 , r / 8 = r ^ + 2 \hat{r}=r/8-2=200-\lambda/4-2, r/8=\hat{r}+2 r^=r/82=200λ/42,r/8=r^+2,对应的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即为上文的 r ^ \hat{r} r^
初始化状态为:在这里插入图片描述
对应的代码实现为:

 		// 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/

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值