proverif-系列文章目录
- 【proverif】proverif的下载安装和初使用
- 【proverif】proverif的语法1-解决中间人攻击-代码详解
- 【proverif】proverif的语法2-各种密码原语的编码
- 【proverif】proverif的语法3-认证协议的验证代码-案例分析 (本文)
文章目录
- proverif-系列文章目录
- 前言
- 一、proverif和CryptoVerif的区别
- 二、事件
- 2. 安全性分析
- proverif长什么样?
- 强安全
- 2. 案例分析-认证协议的proverif编码
前言
本文介绍proverif和CryptoVerif的区别,进而对协议设计proverif验证的实战分析。
一、proverif和CryptoVerif的区别
1.适用领域:
- ProVerif: 主要用于验证各种协议的安全性,包括身份验证协议、密钥交换协议等。它强调对协议中的逻辑安全性属性的验证。
- CryptoVerif: 专注于协议中的密码学安全性,特别是对于一些基本的密码学概念(如加密、签名、密钥协商等)的形式化证明。
2.安全性属性:
- ProVerif: 主要关注协议的逻辑安全性,例如认证、保密性、一致性等。
- CryptoVerif: 更侧重于密码学的安全属性,例如对抗模型下的保密性、不可伪造性、前向保密性等。
3.形式化方法:
- ProVerif: 使用可判定性的符号模型来表示协议和攻击模型,利用逻辑推理和自动搜索来检查协议的安全性。
- CryptoVerif: 强调对密码学协议的形式化证明,使用可考察性的密码模型进行分析,证明密码学协议满足一些关键的安全属性。
4.支持的密码学理论:
- ProVerif: 对于密码学方面提供了一些基本的支持,但它的主要焦点是在更一般的协议安全性上。
- CryptoVerif: 针对密码学属性提供了更丰富的支持,可以处理一些复杂的密码学构造和协议。
5.使用语言:
- ProVerif: 使用自己的专有语言,该语言对于描述协议和攻击模型非常适用。
- CryptoVerif:也有自己的语言,但它更强调对密码学定义和性质的直接建模。
6.工具的发展状态:
- ProVerif: 是一个相对成熟和稳定的工具,一直在不断发展和改进。
- CryptoVerif: 在我知识截止日期(2022年)时仍在发展,并可能有了新的功能和改进。
如果你的主要兴趣是协议的逻辑安全性,那么 ProVerif 可能更适合;如果你更关注密码学的安全性属性,那么 CryptoVerif 可能更适合。
二、事件
代码如下:
(* 1. 在事件执行之前,有e1和e2均被执行。连词:&& *)
query event(e0)==>event(e1) && event(e2).
(* 2. 在事件执行之前,有e1或e2均被执行。析词:|| *)
query event(e0)==>event(e1) || event(e2).
(* 3. 连词、析词同时出现 *)
query event(e0)==>event(e1) || (event(e2) && event(e3)).
(*4. 连接比析取具有更高的优先级,但是应该使用括号来消除表达式的歧义。事件当然可以有参数,也可以是内射事件。*)
(*解释:e0执行前e1已执行一次;e0不执行对应e2和e3都没执行*)
query inj-event(e0)==>event(e1) || (inj-event(e2) && event(e3)).
(* 5.当攻击者知道M时,事件e1已经被执行。 *)
query attacker(M)==>event(e1).
(* 6.事件e(x)只能在x=a时执行。 *)
query x:t;event(e(x)) ==> x=a.
内射事件相关事项:
==>
后面是inj-event
,自动将==>
前面变成是inj-event
。- 要求如果事件e1执行了n1次,事件e2执行了n2次,那么事件e3至少执行了n1 × n2次。
inj-event(e1) && inj-event(e2)==>inj-event(e3).
noninterf
的使用:
- bool型可以表示为
noninterf b among (true,false).
2. 安全性分析
proverif长什么样?
组成部分:加密操作、描述参与者行为过程、安全查询、场景。
强安全
强保密性查询可用于显示在会话密钥下加密发送的有效负载的保密性。强保密性意味着攻击者无法分辨秘密何时发生变化。
free c:channel.
type key.
fun senc(bitstring, key): bitstring.
reduc forall m: bitstring, k: key; sdec(senc(m,k),k) = m.
free k:key [private].
free secret_msg:bitstring [private].
noninterf secret_msg.
process (!out(c,senc(secret_msg, k))) | (!in(c,x:bitstring); let s=sdec(x,k)in 0)
输出结果:
首先,process给出proverif运行代码的顺序,然后给出总结,总结表示,密文 secret_msg
不被干涉是true,证明敌手无法获取密文。
2. 案例分析-认证协议的proverif编码
前三节已经把proverif的语法介绍得差不多了,这个时候拿一个真正的协议的验证代码过来实战一下,通过分析协议的proverif的验证代码,进一步加深学习。
案例代码来自github良心学者:GitHub地址链接
还有许多官方文档给出的案例代码在proverif的examples
文件下,地址:proverif2.04\examples\pitype\choice
,将所有.pv文件复制到exe文件下(地址是:\proverif2.04
)才能运行。
先上代码:智能手机和服务器之间的认证协议验证
(*Ebuka Philip Oguchi: Mutual authentication between the smartphone user and the server*)
(* Define types and cryptographic operations------------------------- *)
(* Define communication channel *)
free c:channel.
(* Define types for cryptographic keys and hosts *)
type key.
type PRkey.
type PUkey.
type host.
type nonce.
(* Define hosts A and S for the smartphone user and server *)
free A,S:host.
(* Define cryptographic functions *)
fun senc(bitstring,key):bitstring.
reduc forall m:bitstring,k:key; sdec(senc(m,k),k) = m.
(* Public key extraction *)
fun pk(PRkey):PUkey.
(* Asymmetric encryption *)
fun aenc(bitstring,PUkey):bitstring.
reduc forall m:bitstring,k:PRkey; adec(aenc(m,pk(k)),k) = m.
(* Data Type Converters *)
(* Convert a nonce to a bitstring *)
fun nonce_to_bitstring(nonce):bitstring [data,typeConverter].
(* Convert a nonce to a key *)
fun nonce_to_key(nonce):key [data,typeConverter].
(* 事件---------------------------------------------------------------*)
(* Define authentication and communication events *)
event smartPhoneAccepts(nonce,nonce,PUkey).
event smartPhoneTerms(nonce,nonce,PUkey).
event serverAccepts(nonce,nonce,PUkey).
event serverTerms(nonce,nonce,PUkey).
(* 安全性查询---------------------------------------------------------------*)
free s:bitstring [private].
(* Attacker queries *)
query attacker(s).
query N1,N2:nonce,puX:PUkey; inj-event(smartPhoneTerms(N1,N2,puX)) ==> inj-event(serverAccepts(N1,N2,puX)).
query N1,N2:nonce,puX:PUkey; inj-event(serverTerms(N1,N2,puX)) ==> inj-event(smartPhoneAccepts(N1,N2,puX)).
(* Define secret bitstrings *)
free secretAN1,secretAN2:bitstring [private].
free secretBN1,secretBN2:bitstring [private].
query attacker(secretAN1); attacker(secretAN2);
attacker(secretBN1);attacker(secretBN2).
(* 参与者之间行为过程---------------------------------------------------------------*)
(* Define behavior of the smartphone *)
let smartPhone(puS:PUkey,prA:PRkey) =
(* Smartphone receives public key of the server *)
in(c,puX:PUkey);
(* Check if received public key matches server's public key *)
if puX = puS then
(* Generate a new nonce for the smartphone *)
new N1:nonce;
(* Encrypt the nonce and smartphone's private key with server's public key *)
let m = aenc((N1,pk(prA)),puX) in
out(c,m);
(* Receive the encrypted message from the server *)
in(c,m2:bitstring);
(* Decrypt the message to extract nonces and keys *)
let (=N1,N2:nonce,puX2:PUkey) = adec(m2,prA) in
if puX2 = puS then
(* Smartphone accepts terms *)
event smartPhoneAccepts(N1,N2,puX2);
(* Encrypt the second nonce with smartphone's public key *)
let m3 = aenc(nonce_to_bitstring(N2),puX2) in
out(c,m3);
(* Present terms to server *)
event smartPhoneTerms(N1,N2,pk(prA));
(* Encrypt and send secret bitstrings with nonces as keys *)
out(c,senc(secretAN1,nonce_to_key(N1)));
out(c,senc(secretAN2,nonce_to_key(N2))).
(* Define behavior of the server *)
let server(puA:PUkey,prS:PRkey) =
(* Receive the encrypted message from the smartphone *)
in(c,m:bitstring);
(* Decrypt the message to extract nonce and smartphone's public key *)
let (N1:nonce,puX:PUkey) = adec(m,prS) in
(* Generate a new nonce for the server *)
new N2:nonce;
(* Server accepts terms *)
event serverAccepts(N1,N2,puX);
(* Encrypt the nonces and server's public key with smartphone's public key *)
let m2 = aenc((N1,N2,pk(prS)),puX) in
out(c,m2);
(* Receive the encrypted nonce from the smartphone *)
in(c,m3:bitstring);
(* Compare the decrypted nonce with the second generated nonce *)
if nonce_to_bitstring(N2) = adec(m3,prS) then
(* Check if received public key matches smartphone's public key *)
if puX = puA then
(* Server presents terms to the smartphone *)
event serverTerms(N1,N2,pk(prS));
(* Encrypt and send secret bitstrings with nonces as keys *)
out(c,senc(secretBN1,nonce_to_key(N1)));
out(c,senc(secretBN2,nonce_to_key(N2))).
(* Define the main process--------------------------------------------- *)
process
new prA:PRkey; new prS:PRkey;
(* Generate public keys from private keys *)
let puA = pk(prA) in out(c,puA);
let puS = pk(prS) in out(c,puS);
(* Execute the smartphone and server processes concurrently *)
( (! smartPhone(puS,prA)) | (! server(puA,prS)))
编译结果:
- 编译过程process:
- 创建一个公共通道c,两个host类型A,S分别代表智能手机和服务器;
- 加密操作:对称加密、将随机数变成字符串、将随机数变成密钥;
- 四个事件:
event smartPhoneAccepts(nonce,nonce,PUkey). //客户端接受服务器
event smartPhoneTerms(nonce,nonce,PUkey). //客户端终止与服务器之间的协议
event serverAccepts(nonce,nonce,PUkey). //服务器接受客户端
event serverTerms(nonce,nonce,PUkey).//服务器终止与客户端的协议
- 查询:
- 密文s是否会被泄露;
- 内射:
在客户端终止协议前,已执行服务器接受客户端的协议,且事件
serverAccepts(N1,N2,puX)
执行的次数 ≥smartPhoneTerms(N1,N2,puX)
执行的次数;
在服务器终止协议前,已执行客户端接受的协议,且事件
smartPhoneAccepts(N1,N2,puX)
执行的次数 ≥serverTerms(N1,N2,puX)
执行的次数;
- 参与者行为过程:智能手机和服务器两个进程是同时进行的。
- 安全性查询:
- 总结