• Aucun résultat trouvé

Nous avons modélisé les données, les opérations cryptographiques et les messages échangés sur le réseau. Il reste à définir les relations entre les primitives, qui seront représentées par des règles de réécriture. Plus précisément, soit Σ = Σc] Σd une signature. Une règle de réécriture est de la forme ` → r avec ` = des(t1, . . . , tn) et r = t0, où des ∈ Σd est d’arité n, et pour chaque i, ti ∈ T0c, N ] Σ0 ] X ). Soit R un ensemble de règles de réécriture. R définit un système de réécriture : pour tout terme u, on note u → v s’il existe p une position de u, σ une substitution avec dom(σ) = vars(`), ` → r dans R tels que u|p= des(t1, . . . , tn)σ avec tiσ un Σ+0-message pour chaque i, rσ est un Σ+0-message et v = u[rσ]p. Ainsi, si un terme t s’unifie avec ` sans que chaque tiσ soit un message, il ne se réduit pas.

On étend → à sa clôture réflexive et transitive. On dit que (Σ, R) est une théorie à constructeurs. Le système de réécriture associé à chaque théorie à constructeurs termine, puisque chaque réécriture fait disparaître un destructeur. Ainsi, un système de réécriture est convergent si, et seulement si, il est confluent , c’est-à-dire si et seulement si, chaque fois que t → u et t → v, il existe w tel

que u → w et v → w. On dit qu’une théorie à constructeurs (Σ, R) admet une paire critique s’il existe deux règles ` → r et `0 → r0 telles que ` et `0 sont unifiables. Il est clair qu’une théorie à constructeurs qui n’admet pas de paire critique est convergente. Pour une théorie à constructeurs (Σ, R) convergente, et pour tout terme t, on notera t↓ sa forme normale.

Dans toute la suite, tous les résultats positifs vaudront uniquement pour des théories à construc-teurs convergentes. Les exemples suivants présentent quelques primitives qui peuvent être facile-ment modélisées par des théories à constructeurs pour lesquelles nous pouvons donner un sens aux hypothèses sur les sortes et les contours. La liste n’est pas exhaustive.

Exemple 1.7. Reprenons l’ensemble de symboles constructeurs Σc de l’exemple 1.5, et ajoutons les destructeurs Σd= {adec, sdec, proj1, proj2}. Les règles de réécriture associées sont :

adec(aenc(y, pub(x)), x) → y sdec(senc(y, x), x) → y

proji(hx1, x2i) → xi pour i ∈ {1, 2} avec x, x1, x2, y ∈ X .

Posons t = adec(aenc(proj1(hn, mi), pub(s)), s) avec n, m, s ∈ N . Le terme t n’est pas un Σ+0 -message car ce n’est pas un terme constructeur, mais sa forme normale t↓ = n est un -message. Dans certains cas, il peut être intéressant de donner à l’attaquant la possibilité de savoir si deux textes chiffrés ont la même clé ou non, ou si un texte chiffré correspond bien à une clé publique donnée. Pour ce faire, nous pouvons compléter Σd par Σ0d = {samekey/2, rightkey/2}, ajouter un constructeur ok/0 supplémentaire et considérer les règles de réécriture suivantes, avec x, y, y0 ∈ X .

samekey(aenc(y, pub(x)), aenc(y0, pub(x))) → ok rightkey(aenc(y, pub(x)), pub(x)) → ok

La règle de samekey peut également être formulée pour le chiffrement symétrique (avec x, y, y0∈ X ) samekey(senc(y, x), senc(y0, x)) → ok

Dans certains développements techniques, nous supposerons que toutes les règles ont des destruc-teurs distincts. Dans ce cas nous devrons distinguer entre, par exemple, samekeyaenc et samekeysenc. Le reste du temps, ces deux règles ne sont pas exclusives l’une de l’autre, d’autant qu’elles ne forment pas de paire critique car senc(x, y) et aenc(x, y) ne sont pas unifiables. La règle de rightkey pourrait aussi se formuler pour le chiffrement symétrique, mais comme la connaissance de la clé symétrique permet d’ouvrir le chiffrement, une telle règle n’apporterait rien.

Il est clair que l’on peut aussi modéliser des tuples de taille arbitraire.

Exemple 1.8. Soit n> 2 un entier. Les tuples de taille n sont modélisés par le symbole h·, . . . , ·in/n et l’ensemble de destructeurs Σd= {proj1, . . . , projn}. La sorte de h in est bitstring×· · ·×bitstring → bitstring et son contour est trivial. Pour chaque 1 6 i 6 n, on a la règle

proji(hx1, . . . , xnin) → xi

avec xi ∈ X pour chaque i. On obtient Σn = Σc∪ Σd. Comme Σn a été défini pour chaque n, on peut poser

Σtuplen = ∪ni=2Σi

L’exemple suivant montre comment modéliser les chiffrements symétrique et asymétrique ran-domisés.

Exemple 1.9. Posons Σc = {rsenc/3, raenc/3, pub/2} et Σd = {rsdec/2, radec/2}. rsenc désigne le chiffrement symétrique randomisé et raenc le chiffrement asymétrique randomisé. rsdec est le déchiffrement de rsenc et radec celui de raenc. Nous pouvons proposer ici les sortes suivantes.

raenc : bitstring × atom × bitstring → bitstring rsenc : bitstring × atom × atom → bitstring

pub : atom → bitstring

Une autre possibilité aurait consisté à donner la sorte bitstring à l’aléa. Seul le contour shraenc= raenc(y, r, pub(x)) (avec x, r, y ∈ X ) de raenc n’est pas trivial. Les règles de réécriture associées sont comme suit, avec x, r, y ∈ X .

radec(raenc(y, r, pub(x)), x) → y rsdec(rsenc(y, r, x), x) → y

Nous pouvons également modéliser la signature, comme détaillé dans l’exemple suivant. Exemple 1.10. Considérons Σsign

c = {sign/2, vk/1, ok/0}. Les sortes de ces constructeurs sont sign : bitstring × atom → bitstring

vk : atom → bitstring ok : → bitstring

et leurs contours sont tous triviaux. L’ensemble de destructeurs associés est : Σsignd = {check/2, getmsg/1}

check permet de vérifier la signature et getmsg est une fonction de récupération du message signé. Les règles associées sont, avec x, y ∈ X :

check(sign(y, x), vk(x)) → ok getmsg(sign(y, x)) → y

Enfin, les théories à constructeurs permettent aussi de modéliser certaines primitives plus exo-tiques. L’exemple suivant s’inspire du partage de secret de Shamir [96].

Exemple 1.11. Posons Σc = {onekey/2, k1/1, k2/1}, et Σd = {get/2}. onekey est la fonction de chiffrement, et ki (i ∈ {1, 2}) représente les fonctions de clé. get permet de révéler le message en possédant seulement une clé. Les sortes sont :

onekey : bitstring × atom → bitstring ki : atom → bitstring pour i ∈ {1; 2}

Les contours sont tous triviaux, et l’on pose la règle de réduction suivante pour chaque i ∈ {1, 2} (avec x, y ∈ X )

get(onekey(y, x), ki(x)) → y

Comme get apparaît dans deux règles, il peut être intéressant de distinguer entre deux destructeurs get1 et get2. Ce n’est pas nécessaire pour le moment, car les deux règles ne forment pas de paire critique.

Il est possible de généraliser cette construction pour ne révéler le secret que si l’on possède k clés parmi n, avec k6 n, par exemple pour k = 2 :

Une autre variante notable repose sur l’utilisation, pour chaque i, de la règle get(onekey(y, x1, . . . , xn), xi) → y

où onekey est un constructeur d’arité n + 1, et y, x1, . . . , xn∈ X .

Les primitives présentées dans les différents exemples de cette section peuvent être utilisées simultanément. En particulier, on peut confondre les constructeurs qui ont le même nom (c’est le cas de ok et pub). Lorsque les destructeurs ont le même nom, comme c’est le cas des projections associées aux différents tuples, il peut être utile de les distinguer, et on appellera projni la ième projection du tuple de taille n. La confusion ne créerait pas de paires critiques, puisque les tuples de taille différente ne sont pas unifiables, mais nous retenons la variante la plus claire.

Dans la suite, nous utiliserons à plusieurs reprises la signature classique Σstd

n (avec n ∈ N) définie comme suit.

Σstdn = {senc, sdec, aenc, adec, pub, check, getmsg, ok, vk, hash} ∪ Σtuplen Σtuple

n a été défini dans l’exemple 1.8, et les autres primitives, ainsi que leurs contours, leurs sortes et les règles de réécriture associées, notées Rstd

n , ont été exposées dans les exemples 1.7 et 1.10. Comme chaque tuple est d’arité différente, il n’y a pas de confusion possible entre les différents symboles constructeurs hi2, . . . , hin. Parfois, pour alléger la présentation, nous noterons simplement hi pour hik avec 16 k 6 n.