Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/crypto/stream_cipher.py
4045 views
1
"""
2
Stream Ciphers
3
"""
4
#*****************************************************************************
5
# Copyright (C) 2007 David Kohel <[email protected]>
6
#
7
# Distributed under the terms of the GNU General Public License (GPL)
8
#
9
# http://www.gnu.org/licenses/
10
#*****************************************************************************
11
12
from lfsr import lfsr_sequence
13
from cipher import SymmetricKeyCipher
14
from sage.monoids.string_monoid_element import StringMonoidElement
15
16
class LFSRCipher(SymmetricKeyCipher):
17
def __init__(self, parent, poly, IS):
18
"""
19
Create a linear feedback shift register (LFSR) cipher.
20
21
INPUT:
22
23
24
- ``parent`` - parent
25
26
- ``poly`` - connection polynomial
27
28
- ``IS`` - initial state
29
30
31
EXAMPLES::
32
33
sage: FF = FiniteField(2)
34
sage: P.<x> = PolynomialRing(FF)
35
sage: E = LFSRCryptosystem(FF)
36
sage: E
37
LFSR cryptosystem over Finite Field of size 2
38
sage: IS = [ FF(a) for a in [0,1,1,1,0,1,1] ]
39
sage: g = x^7 + x + 1
40
sage: e = E((g,IS))
41
sage: B = BinaryStrings()
42
sage: m = B.encoding("THECATINTHEHAT")
43
sage: e(m)
44
0010001101111010111010101010001100000000110100010101011100001011110010010000011111100100100011001101101000001111
45
sage: FF = FiniteField(2)
46
sage: P.<x> = PolynomialRing(FF)
47
sage: LFSR = LFSRCryptosystem(FF)
48
sage: e = LFSR((x^2+x+1,[FF(0),FF(1)]))
49
sage: B = e.domain()
50
sage: m = B.encoding("The cat in the hat.")
51
sage: e(m)
52
00111001110111101011111001001101110101011011101000011001100101101011001000000011100101101010111100000101110100111111101100000101110101111010111101000011
53
sage: m == e(e(m))
54
True
55
56
TESTS::
57
58
sage: FF = FiniteField(2)
59
sage: P.<x> = PolynomialRing(FF)
60
sage: E = LFSRCryptosystem(FF)
61
sage: E == loads(dumps(E))
62
True
63
"""
64
SymmetricKeyCipher.__init__(self, parent, key = (poly, IS))
65
66
def __call__(self, M, mode = "ECB"):
67
r"""
68
Generate key stream from the binary string ``M``.
69
70
INPUT:
71
72
73
- ``M`` - a StringMonoidElement
74
75
- ``mode`` - ignored (default: 'ECB')
76
77
78
EXAMPLE::
79
80
sage: k = GF(2)
81
sage: P.<x> = PolynomialRing( k )
82
sage: LFSR = LFSRCryptosystem( k )
83
sage: e = LFSR((x^2+x+1,[k(0), k(1)]))
84
sage: B = e.domain()
85
sage: m = B.encoding('The cat in the hat.')
86
sage: e(m)
87
00111001110111101011111001001101110101011011101000011001100101101011001000000011100101101010111100000101110100111111101100000101110101111010111101000011
88
"""
89
B = self.domain() # = plaintext_space = ciphertext_space
90
if not isinstance(M, StringMonoidElement) and M.parent() == B:
91
raise TypeError, "Argument M (= %s) must be a string in the plaintext space." % M
92
(poly, IS) = self.key()
93
n = B.ngens() # two for binary strings
94
N = len(M)
95
Melt = M._element_list
96
Kelt = lfsr_sequence(poly.list(), IS, N)
97
return B([ (Melt[i]+int(Kelt[i]))%n for i in range(N) ])
98
99
def _repr_(self):
100
r"""
101
Return the string representation of this LFSR cipher.
102
103
EXAMPLES::
104
105
sage: FF = FiniteField(2)
106
sage: P.<x> = PolynomialRing(FF)
107
sage: LFSR = LFSRCryptosystem(FF)
108
sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]
109
sage: e1 = LFSR((x^7 + x + 1,IS_1))
110
sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ]
111
sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))
112
sage: E = ShrinkingGeneratorCryptosystem()
113
sage: e = E((e1,e2))
114
sage: e.keystream_cipher()
115
LFSR cipher on Free binary string monoid
116
"""
117
return "LFSR cipher on %s" % self.domain()
118
119
def connection_polynomial(self):
120
"""
121
The connection polynomial defining the LFSR of the cipher.
122
123
EXAMPLE::
124
125
sage: k = GF(2)
126
sage: P.<x> = PolynomialRing( k )
127
sage: LFSR = LFSRCryptosystem( k )
128
sage: e = LFSR((x^2+x+1,[k(0), k(1)]))
129
sage: e.connection_polynomial()
130
x^2 + x + 1
131
"""
132
return self.key()[0]
133
134
def initial_state(self):
135
"""
136
The initial state of the LFSR cipher.
137
138
EXAMPLE::
139
140
sage: k = GF(2)
141
sage: P.<x> = PolynomialRing( k )
142
sage: LFSR = LFSRCryptosystem( k )
143
sage: e = LFSR((x^2+x+1,[k(0), k(1)]))
144
sage: e.initial_state()
145
[0, 1]
146
"""
147
return self.key()[1]
148
149
class ShrinkingGeneratorCipher(SymmetricKeyCipher):
150
def __init__(self, parent, e1, e2):
151
"""
152
Create a shrinking generator cipher.
153
154
INPUT:
155
156
157
- ``parent`` - parent
158
159
- ``poly`` - connection polynomial
160
161
- ``IS`` - initial state
162
163
164
EXAMPLES::
165
166
sage: FF = FiniteField(2)
167
sage: P.<x> = PolynomialRing(FF)
168
sage: LFSR = LFSRCryptosystem(FF)
169
sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]
170
sage: e1 = LFSR((x^7 + x + 1,IS_1))
171
sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ]
172
sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))
173
sage: E = ShrinkingGeneratorCryptosystem()
174
sage: e = E((e1,e2))
175
sage: e
176
Shrinking generator cipher on Free binary string monoid
177
"""
178
if not isinstance(e1, LFSRCipher):
179
raise TypeError, "Argument e1 (= %s) must be a LFSR cipher." % e1
180
if not isinstance(e2, LFSRCipher):
181
raise TypeError, "Argument e2 (= %s) must be a LFSR cipher." % e2
182
SymmetricKeyCipher.__init__(self, parent, key = (e1, e2))
183
184
def keystream_cipher(self):
185
"""
186
The LFSR cipher generating the output key stream.
187
188
EXAMPLE::
189
190
sage: FF = FiniteField(2)
191
sage: P.<x> = PolynomialRing(FF)
192
sage: LFSR = LFSRCryptosystem(FF)
193
sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]
194
sage: e1 = LFSR((x^7 + x + 1,IS_1))
195
sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ]
196
sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))
197
sage: E = ShrinkingGeneratorCryptosystem()
198
sage: e = E((e1,e2))
199
sage: e.keystream_cipher()
200
LFSR cipher on Free binary string monoid
201
"""
202
return self.key()[0]
203
204
def decimating_cipher(self):
205
"""
206
The LFSR cipher generating the decimating key stream.
207
208
EXAMPLE::
209
210
sage: FF = FiniteField(2)
211
sage: P.<x> = PolynomialRing(FF)
212
sage: LFSR = LFSRCryptosystem(FF)
213
sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]
214
sage: e1 = LFSR((x^7 + x + 1,IS_1))
215
sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ]
216
sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))
217
sage: E = ShrinkingGeneratorCryptosystem()
218
sage: e = E((e1,e2))
219
sage: e.decimating_cipher()
220
LFSR cipher on Free binary string monoid
221
"""
222
return self.key()[1]
223
224
def __call__(self, M, mode = "ECB"):
225
r"""
226
INPUT:
227
228
229
- ``M`` - a StringMonoidElement
230
231
- ``mode`` - ignored (default: 'ECB')
232
233
234
EXAMPLES::
235
236
sage: FF = FiniteField(2)
237
sage: P.<x> = PolynomialRing(FF)
238
sage: LFSR = LFSRCryptosystem(FF)
239
sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]
240
sage: e1 = LFSR((x^7 + x + 1,IS_1))
241
sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ]
242
sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))
243
sage: E = ShrinkingGeneratorCryptosystem()
244
sage: e = E((e1,e2))
245
sage: B = BinaryStrings()
246
sage: m = B.encoding("THECATINTHEHAT")
247
sage: c = e(m)
248
sage: c.decoding()
249
"t\xb6\xc1'\x83\x17\xae\xc9ZO\x84V\x7fX"
250
sage: e(e(m)) == m
251
True
252
sage: m.decoding()
253
'THECATINTHEHAT'
254
"""
255
B = self.domain() # = plaintext_space = ciphertext_space
256
if not isinstance(M, StringMonoidElement) and M.parent() == B:
257
raise TypeError, "Argument M (= %s) must be a string in the plaintext space." % M
258
(e1, e2) = self.key()
259
MStream = M._element_list
260
g1 = e1.connection_polynomial()
261
n1 = g1.degree()
262
IS_1 = e1.initial_state()
263
g2 = e2.connection_polynomial()
264
n2 = g2.degree()
265
IS_2 = e2.initial_state()
266
k = 0
267
N = len(M)
268
n = max(n1,n2)
269
CStream = []
270
while k < N:
271
r = max(N-k,2*n)
272
KStream = lfsr_sequence(g1.list(), IS_1, r)
273
DStream = lfsr_sequence(g2.list(), IS_2, r)
274
for i in range(r-n):
275
if DStream[i] != 0:
276
CStream.append(int(MStream[k]+KStream[i]))
277
k += 1
278
if k == N:
279
break
280
IS_1 = KStream[r-n-1:r-n+n1]
281
IS_2 = DStream[r-n-1:r-n+n2]
282
return B(CStream)
283
284
def _repr_(self):
285
r"""
286
Return the string representation of this shrinking generator cipher.
287
288
EXAMPLES::
289
290
sage: FF = FiniteField(2)
291
sage: P.<x> = PolynomialRing(FF)
292
sage: LFSR = LFSRCryptosystem(FF)
293
sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]
294
sage: e1 = LFSR((x^7 + x + 1,IS_1))
295
sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ]
296
sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))
297
sage: E = ShrinkingGeneratorCryptosystem()
298
sage: e = E((e1,e2)); e
299
Shrinking generator cipher on Free binary string monoid
300
"""
301
return "Shrinking generator cipher on %s" % self.domain()
302
303