Das Knapsack-Kryptosystem

Werbung
Das Knapsack-Kryptosystem
Frank Hellweg
21. Februar 2006
1
Einleitung
Das Knapsack-Kryptosystem wurde 1978 von den amerikanischen Kryptologen
Martin Hellman und Ralph Merkle entwickelt [MH78] und war eines der ersten
Public-Key-Kryptosysteme. Wegen seiner Unkompliziertheit (z.B. müssen im
Gegensatz zum RSA-System keine großen Primzahlen gesucht werden) erfreute
es sich anfangs großer Beliebtheit.
Andere Kryptologen wiesen allerdings schon von Beginn an darauf hin, dass das
Verfahren möglicherweise nicht sicher sei; beweisen konnte dies jedoch erst Adi
Shamir, der 1982 das originale System von Merkle und Hellman brechen konnte
[S82]. In der Folge gab es eine Vielzahl von ähnlichen Kryptosystemen, jedoch
konnten bis auf eine, das Chor-Rivest-Kryptosystem [CR88], alle Varianten der
Rucksackkryptographie gebrochen werden. Diese Ausarbeitung befasst sich mit
dem von Merkle und Hellman stammende Originalsystem, der vorgestellte L3 Angriff funktioniert aber auch mit anderen Knapsack-Systemen.
2
2.1
Grundlagen
Das Subset-Sum-Problem
Das Knapsack-Kryptosystem beruht auf dem mathematischen Problem SubsetSum, das einen Spezialfall des Rucksackproblems (engl. Knapsack, daher auch
der Name des Kryptosystems) darstellt:
Definition 1 (Subset-Sum). Seien S, n ∈ N, a ∈ Nn . Gesucht ist ein Vektor
x ∈ {0, 1}n , so dass a · x = S.
Mit anderen Worten: Wir suchen für eine gegebene Summe S und einen Vektor a aus positiven ganzen Zahlen eine Auswahl dieser Zahlen, die aufsummiert
genau S ergibt. Eine 1 im i-ten Element des Vektors x bedeutet dabei, dass die
i-te Zahl in die Summe einbezogen wird, eine 0, dass sie in der Summe nicht
enthalten ist.
Vom Subset-Sum-Problem wird angenommen, dass es sich deterministisch im
Allgemeinen nicht in polynomieller Zeit lösen lässt. Eine Reduktion von 3-SAT
1
auf Subset-Sum wird in [CLRS01] angegeben. Wie wir gleich sehen werden, betrachten wir jedoch nur eine bestimmte Unterklasse von Problemen.
Im folgenden werde ich ein Tupel (a, S) aus Vektor a und Summe S kurz Knapsack nennen.
Definition 2. Sei a ∈ Nn . Dann heißt a extra simpel, falls für alle 1 ≤ i ≤ n
gilt:
X
aj < ai
1≤j<i
Wir setzen also voraus, dass jedes Element des Vektors echt größer ist als die
Summe aller vorhergehenden Elemente.
Beispiel. Der Vektor a = (1, 2, 4, 8) ist extra simpel, da 2 > 1, 4 > 2 + 1 =
3, 8 > 4 + 2 + 1 = 7. Nebenbei sei erwähnt, dass das Lösen des Knapsacks
(a, S) für ein beliebiges S dem Finden einer vierstelligen Binärdarstellung von S
entspricht. Außerdem fällt auf, dass es sich bei a um den kleinsten
extra simplen
P
Vektor mit vier Stellen handelt, denn für 1 ≤ i ≤ n gilt: 1≤j<i aj = ai − 1.
n
Satz 1. Ein Knapsack (a, S) ∈ {(c, K) | c ∈ Z>0
, S ∈ Z>0 } lässt sich in polynomieller Zeit lösen, falls a extra simpel ist.
Beweis: Betrachte Algorithmus 1.
Algorithmus 1
1: function KnapsackGreedy(a, S)
2:
for i ← n downto 1 do
3:
if a[i] ≤ S then
4:
x[i] ← 1
5:
S ← S − a[i]
6:
else
7:
x[i] ← 0
8:
return x
Der Algorithmus durchläuft den übergebenen Vektor a von hinten nach vorne,
d.h. vom größten zum kleinsten Element. Ist das aktuelle Element ai kleiner oder
gleich der Restsumme S, dann wird das entsprechende Bit xi im Ergebnisvektor
x auf 1 gesetzt und die Restsumme um ai verringert. Andernfalls wird das
entsprechende Ergebnisbit auf 0 gesetzt.
Lemma 1. Algorithmus 1 hat polynomielle Laufzeit.
Beweis: Der Algorithmus beinhaltet nur eine Schleife, die n mal durchlaufen
wird. Im Inneren dieser Schleife werden nur Vergleiche und Divisionen ausgeführt, weswegen wir bei kleinen Zahlen eine worst-case-Laufzeit von O(n)
erhalten, bei großen Zahlen, für die Vergleiche und Divisionen nicht als einfache Prozessoroperationen durchführbar sind, eine worst-case-Laufzeit von O(n ·
2
log m), in Abhängigkeit von der größten beteiligten Zahl m. Die ermittelte Laufzeit ist polynomiell.
2
Lemma 2. Falls a extra simpel ist, kann der Knapsack (a, S) höchstens eine
Lösung haben. Gibt es eine solche, so ermittelt Algorithmus 1 sie.
Beweis: Sei x die Ausgabe des Algorithmus. Wir nehmen an, x sei keine korrekte Lösung des Knapsacks (a, S). Vorausgesetzt, (a, S) hat eine Lösung, gibt
es y ∈ {0, 1}n mit a · y = S, d.h. y ist Lösung von (a, S) und y 6= x.
Betrachte nun i = max{j | xj 6= yj }. Es gilt
X
X
Ki :=
aj · xj =
aj · yj ,
i<j≤n
i<j≤n
da i die am weitesten rechts stehende Stelle ist, an der sich x und y unterscheiden. Außerdem ist S − Ki gleich dem Rest der Summe S im Iterationsschritt i.
Wir unterscheiden zwei Fälle:
Fall 1: xi = 1, yi = 0.
Da xi = 1, muss laut Algorithmus S − Ki ≥ ai gelten. Da a extra simpel ist,
gilt:
X
aj < ai ≤ S − Ki
1≤j<i
X
=⇒
aj · yj + 0 · ai < S − Ki
1≤j<i
=⇒
X
aj · yj + 0 · ai + Ki = y · a < S
1≤j<i
=⇒ y ist keine Lösung von (a, S) Fall 2: xi = 0, yi = 1.
Da xi = 0, muss laut Algorithmus S − Ki < ai gelten.
=⇒ 1 · ai + Ki > S
=⇒
X
aj · yj + 1 · ai + Ki = y · a > S
1≤j<i
=⇒ y ist keine Lösung von (a, S) Aus Fall 1 und 2 folgt, dass x Lösung von (a, S) ist. Der Beweis, dass x die
einzige Lösung von (a, S) ist, folgt analog.
Korrolar: Aus Lemma 1 und Lemma 2 folgt die Korrektheit von Satz 1.
3
2
3
Funktionsweise
Wir kennen nun ein NP-schweres Problem, Subset-Sum, und eine Teilmenge von
Problemen, die wir in polynomieller Zeit lösen können, nämlich die auf extra
simplen Vektoren basierenden Subset-Sum-Probleme. Diesen Umstand können
wir für ein asymmetrisches Kryptosystem nutzen, indem wir privat einen extra
simplen Knapsack nutzen, diesen aber nur nach Verstecken seiner Eigenschaften
als öffentlichen Schlüssel freigeben. Dieses Verstecken werden wir durch eine
modulare Multiplikation des extra simplen Vektors erreichen.
3.1
Initialisierung
Zum Initialisieren des Knapsack-Systems sind folgende Schritte nötig:
1. Wähle extra simplen Vektor a ∈ Zn>0
P
2. Wähle Modul m mit m >
1≤i≤n ai
3. Wähle w ∈ Zm mit ggT (m, w) = 1
4. Berechne w−1 mod m
5. Berechne a0 = a · w mod m
6. Veröffentliche a0 als public key; behalte a, w, w−1 und m als private key.
Beispiel. Wähle a = (1, 4, 6, 15), m = 30. Wähle außerdem w = 7 mit
w−1 ≡ 13 mod m. Dann ist a0 = w · a ≡ (7, 28, 12, 15).
Laufzeit: Zum Berechnen von w−1 kann der erweiterte euklidische Algorithmus
angewendet werden. Dieser hat eine Laufzeit von O(log 2 m), d.h. quadratisch zur
Länge der eingegebenen Zahlen. Für das Ermitteln der restlichen Werte ist eine
Laufzeit von höchstens O(n · log 2 m) anzusetzen. Da n ≤ log2 m, ergibt sich eine
Gesamtlaufzeit von O(log 3 m).
3.2
Chiffrierung
Sobald der öffentliche Schlüssel bekannt ist, können wir mit seiner Hilfe eine
Nachricht verschlüsseln:
1. Teile die zu verschlüsselnde Nachricht in Blöcke der Größe n Bits auf
2. Berechne für jeden
b ∈ {0, 1}n die Summe
P Block
0
0
S = a · b = 1≤i≤n ai · bi .
3. Gib S weiter.
Beispiel(Fortsetzung). Wir wollen die Nachricht b = (1, 1, 0, 1) verschlüsseln.
Dazu berechnen wir S = a0 · b = 1 · 7 + 1 · 28 + 0 · 12 + 1 · 15 = 50.
Laufzeit: Bei der Chiffrierung müssen wir für Pakete der Größe n jeweils O(n)
Additionen durchführen, die jeweils eine Laufzeit von O(log m) haben. Es ergibt
sich also eine Laufzeit von O(n · log m) = O(log 2 m).
4
3.3
Dechiffrierung
Erhält der Besitzer des privaten Schlüssels eine wie oben beschrieben chiffrierte
Nachricht S, ergibt sich der zugehörige Klartext wie folgt:
1. Berechne S 0 = S · w−1 mod m.
2. Löse den Knapsack (a, S 0 ).
Da a extra simpel ist, können wir zum Lösen des Knapsacks (a, S) die Funktion
KnapsackGreedy (siehe Algorithmus 1) verwenden.
Beispiel(Fortsetzung). Um S 0 zu dechiffrieren, berechnen wir S 0 · w−1 =
50 · 13 = 650 ≡ 20 mod 30. Für den so erhaltenen Knapsack (a, 20) mit a =
(1, 4, 6, 15) liefert uns KnapsackGreedy den Vektor x = (1, 0, 1, 1) als Lösung.
Das entspricht dem oben chiffrierten Klartextvektor b.
Laufzeit: Im ersten Schritt führen wir eine Multiplikation und eine Division
durch, was eine Laufzeit von O(log 2 m) ergibt. Der KnapsackGreedy-Algorithmus
hat hier eine Laufzeit von O(n · log m), da m die größte Zahl der Eingabe ist.
Das führt zu einer Gesamtlaufzeit von O(n · log m + log 2 m) = O(log 2 m).
Satz 2. Der Algorithmus arbeitet korrekt, d.h. als Lösung des Knapsacks (a, S 0 )
erhält man b.
Beweis: Zu zeigen ist: a0 · b = S =⇒ a · b = S 0 und b ist die einzige Lösung
von (a, S 0 ).
a0 · b = S
=⇒ a0 · b ≡ S mod m
=⇒ a · w−1 · b ≡ S 0 · w−1 mod m
=⇒ a · b ≡ S 0 mod m.
P
0
Da m >
1≤i≤n ai , gilt auch a · b = S . Dass b die einzige Lösung ist, folgt
aus Lemma 2.
2
4
Sicherheit
Bevor wir mit dem L3 -Angriff eine konkrete Angriffsmethode kennen lernen
werden, folgen einige allgemeine Sicherheitsaspekte des Knapsack-Kryptosystems.
Zum Ersten ist darauf zu achten, dass der öffentliche Schlüssel kein extra simpler Vektor ist. Würden wir im obigen Beispiel m = 31 und w = 2 wählen, dann
wäre a0 = (2, 8, 12, 30) selbst extra simpel. Dadurch könnte natürlich auch der
Knapsack (a0 , S) einfach gelöst werden. Auch wenn der Angreifer durch irgendeine modulare Vervielfachung von a0 einen extra simplen Vektor erhält, kann er
damit die Chiffre brechen.
5
Ein Angreifer könnte sich zudem einige Eigenschaften von a0 (Teilbarkeit, Reihenfolge) zunutze machen, um a und m zu bestimmen. Hellman und Merkle
empfehlen deswegen, zusätzliche modulare Vervielfachungen zu anderen Moduln durchzuführen und die Elemente von a0 zu permutieren.
Zu guter Letzt ist nie bewiesen worden, dass die Unterklasse von Subset-Sum,
die aus den auf modularen Vielfachen von extra simplen Vektoren basierenden
Probleme besteht, selbst NP-vollständig ist. Auch hier liegt also ein Risiko, da es
gelingen könnte, einen polynomiellen Algorithmus zum Lösen dieser Probleme
zu finden.
4.1
Der L3 -Angriff
Wie oben schon erwähnt, sind bis auf eins, nämlich das Chor-Rivest-Kryptosystem
[CR88], alle Knapsack-Verschlüsselungssysteme gebrochen worden, das von Merkle und Hellman vorgestellte Originalsystem 1982 von Shamir [S82]. Auch für
das Chor-Rivest-Kryptosystem existiert ein Angriff bei bestimmten Parametern
[SH95]. Ein sehr allgemeiner Angriff auf Knapsack-Systeme ist der L3 -Angriff,
der 1985 von Lagarias und Odlyzko entdeckt wurde und der bei der Lösung des
Subset-Sum-Problems ansetzt [LO85].
Die Idee hinter diesem Angriff ist, das Knapsackproblem (a0 , S), das sich aus
dem öffentlichen Schlüssel a0 und dem Geheimtext S ergibt, als Problem der
linearen Algebra darzustellen. Man definiert dazu folgende Vektoren:
v1
v2
vn−1
vn
vn+1
= (1 0 . . . 0 0
a1 )
= (0 1 . . . 0 0
a2 )
..
..
.
.
= (0 0 . . . 1 0 an−1 )
= (0 0 . . . 0 1
an )
= (0 0 . . . 0 0
−S)
Definition 3. Gegeben ist eine Menge von linear unabhängigen Vektoren {x1 , . . . , xk }.
Die Menge aller Punkte, die sich als ganzzahlige Linearkombinationen von x1 , . . . xk
darstellen lassen, wird Gitter genannt. Die Vektoren x1 , . . . , xk heißen Basis
dieses Gitters.
Die Vektoren v1 , . . . , vn+1 sind offensichtlich linear unabhängig, sie bilden zusammen also die Basis für ein Gitter.
Es fällt auf, dass sich die korrekte Lösung unseres Knapsacks als Linearkombination der Vektoren v1 . . . vn+1 darstellen lässt, nämlich
v1 · x1 + v2 · x2 + . . . + vn · xn − vn+1 = (x1 , x2 , . . . , xn , 0)
mit xi ∈ {0, 1} für 1 ≤ i ≤ n. Der Vektor (x1 , x2 , . . . , xn ) ist dann die Lösung des
Knapsacks. Es stellt sich jedoch die Frage, wie wir eine solche Linearkombination
erhalten können. Der naive“ Ansatz, alle in Frage kommenden Linearkombina”
tionen durchzuprobieren, hat natürlich genausowenig polynomielle Laufzeit wie
das Lösen des Knapsacks.
6
Wenn wir allerdings die Vektoren v1 . . . vn+1 betrachten, stellen wir fest, dass
sie für große n sehr lang werden, da der Vektor a ja extra simpel ist, d.h. die ai
für steigendes i exponentiell größer werden. Unsere gesuchte Linearkombination ist hingegen sehr kurz. Wenn wir für unser Gitter also eine reduzierte Basis
berechnen, könnte unser Lösungsvektor dabei sein. Ein effizienter Algorithmus
hierfür ist der L3 -Algorithmus. Dieser liefert für ein Gitter eine reduzierte Basis.
Eine genaue Definition der Eigenschaften dieser Basis findet sich in [MOV96];
für uns ist an dieser Stelle wichtig, dass die Vektoren der so erzeugten Basis
signifikant kürzer sind als die unserer Eingabebasis und dass wir tatsächlich mit
einer hohen Wahrscheinlichkeit unseren Lösungsvektor darunter finden.
Natürlich liegt die reduzierte Basis selbst auch wieder im Gitter, so dass der
gefundene Vektor eine Linearkombination der Ausgangsvektoren ist.
Folgender Algorithmus nutzt diesen Umstand für einen Angriff auf das KnapsackSystem:
Algorithmus 2
1: function L3 -Attack(v, a, S)
2:
w ← L3 (v)
3:
for all wi ∈ w do
4:
if wi is like (y1 , y2 , ..., yn , 0), yi ∈ {0, b}; ∀ 1 ≤ i ≤ n, b ∈ Z\{0} then
5:
x ← 1b · wi
6:
if a · x = S then
7:
return x
8:
return NULL
Der Algorithmus lässt sich zuerst vom L3 -Algorithmus für das durch v beschriebene Gitter eine reduzierte Basis geben. Für diese Basis prüft er nun für jeden
Vektor, ob er von der Form ist, dass auf den vorderen n Stellen entweder eine
ganze Zahl b oder 0 steht und die letzte Stelle 0 ist. Ist dies der Fall, dann
wird der gefundene Vektor mit 1b multipliziert und dann getestet, ob er auch
eine Lösung für den übergebenen Knapsack (a, S) ist. Das muss nicht immer
der Fall sein, denn vn+1 könnte in der zugehörigen Linearkombination auch mit
einem anderen Faktor als b vorkommen.
Haben wir eine Lösung gefunden, dann sind wir an dieser Stelle fertig. Ansonsten wird mit dem nächsten Vektor der reduzierten Basis fortgefahren.
Laufzeit: Der L3 -Algorithmus hat eine Laufzeit von O(n4 + log2 m) [MOV96].
Da n ≤ log2 m gilt, ist die Laufzeit in diesem Fall O(log 4 n). Der Rest des Algorithmus hat eine Laufzeit von O(log 3 m), also ergibt sich als Gesamtlaufzeit
O(log 4 m).
Nun bleibt noch die Frage offen, mit welcher Erfolgswahrscheinlichkeit bei diesem Angriff zu rechnen ist.
7
Definition 4. Die Dichte eines Vektors a ist definiert als
d(a) =
n
max1≤i≤n log2 ai
.
Für einen Knapsack (a, S) findet der L3 -Angriff mit hoher Wahrscheinlichkeit
eine Lösung, wenn d(a) < 0, 9408 [MOV96]. Für einen Knapsack, bei dem a
aus aufeinanderfolgenden Zweierpotenzen besteht, also den dichtestmöglichen
Knapsack, geht die Dichte für n → ∞ gegen 1. In der Praxis sind Dichten
größer als 0, 9408 also zu vernachlässigen.
Für das obige Beispiel funktioniert der Angriff übrigens, obwohl die Dichte
größer als 0, 9408 ist. Das kann man mit der Maple-Funktion Lattice, die eine L3 -Reduktion durchführt, leicht überprüfen:
Beispiel(Fortsetzung). Für das Beispiel aus Kapitel 3 (a0 = (7, 28, 12, 15);
S = 50) erzeugt der Maple-Befehl
lattice([[1, 0, 0, 0, 7], [0, 1, 0, 0, 28], [0, 0, 1, 0, 12], [0, 0, 0, 1, 15], [0, 0, 0, 0, −50]]);
eine reduzierte Basis bestehend aus den Vektoren (0, −1, 1, 1, −1), (1, 1, 0, 1, 0),
(−1, 2, 0, 0, −1), (−2, 0, 0, 1, 1) und (0, 1, 2, 0, 2). Der Vektor (1, 1, 0, 1, 0) ist dabei von der von uns gewünschten Form. Die Überprüfung ergibt, dass 1 · 7 + 1 ·
28 + 0 · 12 + 1 · 15 = 50 gilt. Also ist der Vektor (1, 1, 0, 1) die Lösung für den
Knapsack.
5
Fazit
Wir haben das NP-schwere Problem Subset-Sum benutzt, um über eine Trapdoor ein asymmetrisches Kryptosystem aufzubauen. Auch, wenn die verwendete
Unterklasse von Problemen nicht erwiesenermaßen NP-schwer ist - es ist kein
polynomieller Algorithmus bekannt, der diese Probleme löst. Trotzdem ist unser System nicht sicher, denn wir können das Problem mit nichttrivialer Wahrscheinlichkeit in polynomieller Laufzeit lösen: Unsere Worst-Case-Laufzeit ist
nicht polynomiell, aber im Normalfall finden wir schneller eine Lösung.
Wir stellen also fest, dass die Worst-Case-Zeitkomplexität der zugrundeliegenden Probleme keine Antwort auf die Frage gibt, ob ein Kryptosystem sicher ist.
Entscheidend ist die Frage, ob diese Probleme mit einer gewissen Wahrscheinlichkeit oder sogar im Average Case schnell gelöst werden können.
8
6
Quellen
[M OV 96] Menezes, van Oorschot, Vanstone – Handbook of Applied Cryptography, CRC 1996; S. 118ff
[CR88] B. Chor, R.L. Rivest - A knapsack-type public-key cryptosystem based
on arithmetic in finite fields, IEEE Transactions on Information Theory, Vol.
34, Nr. 5, 1988; S. 901-909.
[SH95] C.P. Schnorr, H.H. Hörner - Attacking the Chor-Rivest cryptosystem by
improved lattice reduction, Advances in Cryptology - Eurocrypt ’95, SpringerVerlag 1995.
[M H78] Ralph C. Merkle, Martin E. Hellman - Hiding Information and Signatures in Trapdoor Knapsacks, IEEE Transactions on Information Theory, Vol.
24, Nr. 5, 1978; S. 525-530
[S82] Adi Shamir - A polynomial time algorithm for breaking the basic MerkleHellman Cryptosystem, Proceedings of the 23rd FOCS Symposium, 1982, S.
145-152
[LO85] J. C. Lagarias, A. M. Odlyzko - Solving Low Density Subset Sum Problems, Journal of the Association for Computing Machinery, Vol. 32, 1985; S.
229-246.
[CLRS01] T. H. Cormen, C. E. Leiserson, R. L. Rivest, C. Stein - Introduction
to Algorithms, second edition, MIT Press 2001; S. 1013ff
9
Herunterladen