fstdtools 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,365 @@
1
+ #!/usr/bin/env python
2
+ # coding: utf-8
3
+
4
+ """
5
+ Copyright by https://github.com/zhansliu/writemdict
6
+
7
+ pureSalsa20.py -- a pure Python implementation of the Salsa20 cipher, ported to Python 3
8
+
9
+ v4.0: Added Python 3 support, dropped support for Python <= 2.5.
10
+
11
+ // zhansliu
12
+
13
+ Original comments below.
14
+
15
+ ====================================================================
16
+ There are comments here by two authors about three pieces of software:
17
+ comments by Larry Bugbee about
18
+ Salsa20, the stream cipher by Daniel J. Bernstein
19
+ (including comments about the speed of the C version) and
20
+ pySalsa20, Bugbee's own Python wrapper for salsa20.c
21
+ (including some references), and
22
+ comments by Steve Witham about
23
+ pureSalsa20, Witham's pure Python 2.5 implementation of Salsa20,
24
+ which follows pySalsa20's API, and is in this file.
25
+
26
+ Salsa20: a Fast Streaming Cipher (comments by Larry Bugbee)
27
+ -----------------------------------------------------------
28
+
29
+ Salsa20 is a fast stream cipher written by Daniel Bernstein
30
+ that basically uses a hash function and XOR making for fast
31
+ encryption. (Decryption uses the same function.) Salsa20
32
+ is simple and quick.
33
+
34
+ Some Salsa20 parameter values...
35
+ design strength 128 bits
36
+ key length 128 or 256 bits, exactly
37
+ IV, aka nonce 64 bits, always
38
+ chunk size must be in multiples of 64 bytes
39
+
40
+ Salsa20 has two reduced versions, 8 and 12 rounds each.
41
+
42
+ One benchmark (10 MB):
43
+ 1.5GHz PPC G4 102/97/89 MB/sec for 8/12/20 rounds
44
+ AMD Athlon 2500+ 77/67/53 MB/sec for 8/12/20 rounds
45
+ (no I/O and before Python GC kicks in)
46
+
47
+ Salsa20 is a Phase 3 finalist in the EU eSTREAM competition
48
+ and appears to be one of the fastest ciphers. It is well
49
+ documented so I will not attempt any injustice here. Please
50
+ see "References" below.
51
+
52
+ ...and Salsa20 is "free for any use".
53
+
54
+
55
+ pySalsa20: a Python wrapper for Salsa20 (Comments by Larry Bugbee)
56
+ ------------------------------------------------------------------
57
+
58
+ pySalsa20.py is a simple ctypes Python wrapper. Salsa20 is
59
+ as it's name implies, 20 rounds, but there are two reduced
60
+ versions, 8 and 12 rounds each. Because the APIs are
61
+ identical, pySalsa20 is capable of wrapping all three
62
+ versions (number of rounds hardcoded), including a special
63
+ version that allows you to set the number of rounds with a
64
+ set_rounds() function. Compile the version of your choice
65
+ as a shared library (not as a Python extension), name and
66
+ install it as libsalsa20.so.
67
+
68
+ Sample usage:
69
+ from pySalsa20 import Salsa20
70
+ s20 = Salsa20(key, IV)
71
+ dataout = s20.encryptBytes(datain) # same for decrypt
72
+
73
+ This is EXPERIMENTAL software and intended for educational
74
+ purposes only. To make experimentation less cumbersome,
75
+ pySalsa20 is also free for any use.
76
+
77
+ THIS PROGRAM IS PROVIDED WITHOUT WARRANTY OR GUARANTEE OF
78
+ ANY KIND. USE AT YOUR OWN RISK.
79
+
80
+ Enjoy,
81
+
82
+ Larry Bugbee
83
+ bugbee@seanet.com
84
+ April 2007
85
+
86
+
87
+ References:
88
+ -----------
89
+ http://en.wikipedia.org/wiki/Salsa20
90
+ http://en.wikipedia.org/wiki/Daniel_Bernstein
91
+ http://cr.yp.to/djb.html
92
+ http://www.ecrypt.eu.org/stream/salsa20p3.html
93
+ http://www.ecrypt.eu.org/stream/p3ciphers/salsa20/salsa20_p3source.zip
94
+
95
+
96
+ Prerequisites for pySalsa20:
97
+ ----------------------------
98
+ - Python 2.5 (haven't tested in 2.4)
99
+
100
+
101
+ pureSalsa20: Salsa20 in pure Python 2.5 (comments by Steve Witham)
102
+ ------------------------------------------------------------------
103
+
104
+ pureSalsa20 is the stand-alone Python code in this file.
105
+ It implements the underlying Salsa20 core algorithm
106
+ and emulates pySalsa20's Salsa20 class API (minus a bug(*)).
107
+
108
+ pureSalsa20 is MUCH slower than libsalsa20.so wrapped with pySalsa20--
109
+ about 1/1000 the speed for Salsa20/20 and 1/500 the speed for Salsa20/8,
110
+ when encrypting 64k-byte blocks on my computer.
111
+
112
+ pureSalsa20 is for cases where portability is much more important than
113
+ speed. I wrote it for use in a "structured" random number generator.
114
+
115
+ There are comments about the reasons for this slowness in
116
+ http://www.tiac.net/~sw/2010/02/PureSalsa20
117
+
118
+ Sample usage:
119
+ from pureSalsa20 import Salsa20
120
+ s20 = Salsa20(key, IV)
121
+ dataout = s20.encryptBytes(datain) # same for decrypt
122
+
123
+ I took the test code from pySalsa20, added a bunch of tests including
124
+ rough speed tests, and moved them into the file testSalsa20.py.
125
+ To test both pySalsa20 and pureSalsa20, type
126
+ python testSalsa20.py
127
+
128
+ (*)The bug (?) in pySalsa20 is this. The rounds variable is global to the
129
+ libsalsa20.so library and not switched when switching between instances
130
+ of the Salsa20 class.
131
+ s1 = Salsa20( key, IV, 20 )
132
+ s2 = Salsa20( key, IV, 8 )
133
+ In this example,
134
+ with pySalsa20, both s1 and s2 will do 8 rounds of encryption.
135
+ with pureSalsa20, s1 will do 20 rounds and s2 will do 8 rounds.
136
+ Perhaps giving each instance its own nRounds variable, which
137
+ is passed to the salsa20wordtobyte() function, is insecure. I'm not a
138
+ cryptographer.
139
+
140
+ pureSalsa20.py and testSalsa20.py are EXPERIMENTAL software and
141
+ intended for educational purposes only. To make experimentation less
142
+ cumbersome, pureSalsa20.py and testSalsa20.py are free for any use.
143
+
144
+ Revisions:
145
+ ----------
146
+ p3.2 Fixed bug that initialized the output buffer with plaintext!
147
+ Saner ramping of nreps in speed test.
148
+ Minor changes and print statements.
149
+ p3.1 Took timing variability out of add32() and rot32().
150
+ Made the internals more like pySalsa20/libsalsa .
151
+ Put the semicolons back in the main loop!
152
+ In encryptBytes(), modify a byte array instead of appending.
153
+ Fixed speed calculation bug.
154
+ Used subclasses instead of patches in testSalsa20.py .
155
+ Added 64k-byte messages to speed test to be fair to pySalsa20.
156
+ p3 First version, intended to parallel pySalsa20 version 3.
157
+
158
+ More references:
159
+ ----------------
160
+ http://www.seanet.com/~bugbee/crypto/salsa20/ [pySalsa20]
161
+ http://cr.yp.to/snuffle.html [The original name of Salsa20]
162
+ http://cr.yp.to/snuffle/salsafamily-20071225.pdf [ Salsa20 design]
163
+ http://www.tiac.net/~sw/2010/02/PureSalsa20
164
+
165
+ THIS PROGRAM IS PROVIDED WITHOUT WARRANTY OR GUARANTEE OF
166
+ ANY KIND. USE AT YOUR OWN RISK.
167
+
168
+ Cheers,
169
+
170
+ Steve Witham sw at remove-this tiac dot net
171
+ February, 2010
172
+ """
173
+ import sys
174
+ assert(sys.version_info >= (2, 6))
175
+
176
+ if sys.version_info >= (3,):
177
+ integer_types = (int,)
178
+ python3 = True
179
+ else:
180
+ integer_types = (int, long)
181
+ python3 = False
182
+
183
+ from struct import Struct
184
+ little_u64 = Struct( "<Q" ) # little-endian 64-bit unsigned.
185
+ # Unpacks to a tuple of one element!
186
+
187
+ little16_i32 = Struct( "<16i" ) # 16 little-endian 32-bit signed ints.
188
+ little4_i32 = Struct( "<4i" ) # 4 little-endian 32-bit signed ints.
189
+ little2_i32 = Struct( "<2i" ) # 2 little-endian 32-bit signed ints.
190
+
191
+ _version = 'p4.0'
192
+
193
+ #----------- Salsa20 class which emulates pySalsa20.Salsa20 ---------------
194
+
195
+ class Salsa20(object):
196
+ def __init__(self, key=None, IV=None, rounds=20 ):
197
+ self._lastChunk64 = True
198
+ self._IVbitlen = 64 # must be 64 bits
199
+ self.ctx = [ 0 ] * 16
200
+ if key:
201
+ self.setKey(key)
202
+ if IV:
203
+ self.setIV(IV)
204
+
205
+ self.setRounds(rounds)
206
+
207
+
208
+ def setKey(self, key):
209
+ assert type(key) == bytes
210
+ ctx = self.ctx
211
+ if len( key ) == 32: # recommended
212
+ constants = b"expand 32-byte k"
213
+ ctx[ 1],ctx[ 2],ctx[ 3],ctx[ 4] = little4_i32.unpack(key[0:16])
214
+ ctx[11],ctx[12],ctx[13],ctx[14] = little4_i32.unpack(key[16:32])
215
+ elif len( key ) == 16:
216
+ constants = b"expand 16-byte k"
217
+ ctx[ 1],ctx[ 2],ctx[ 3],ctx[ 4] = little4_i32.unpack(key[0:16])
218
+ ctx[11],ctx[12],ctx[13],ctx[14] = little4_i32.unpack(key[0:16])
219
+ else:
220
+ raise Exception( "key length isn't 32 or 16 bytes." )
221
+ ctx[0],ctx[5],ctx[10],ctx[15] = little4_i32.unpack( constants )
222
+
223
+
224
+ def setIV(self, IV):
225
+ assert type(IV) == bytes
226
+ assert len(IV)*8 == 64, 'nonce (IV) not 64 bits'
227
+ self.IV = IV
228
+ ctx=self.ctx
229
+ ctx[ 6],ctx[ 7] = little2_i32.unpack( IV )
230
+ ctx[ 8],ctx[ 9] = 0, 0 # Reset the block counter.
231
+
232
+ setNonce = setIV # support an alternate name
233
+
234
+
235
+ def setCounter( self, counter ):
236
+ assert( type(counter) in integer_types )
237
+ assert( 0 <= counter < 1<<64 ), "counter < 0 or >= 2**64"
238
+ ctx = self.ctx
239
+ ctx[ 8],ctx[ 9] = little2_i32.unpack( little_u64.pack( counter ) )
240
+
241
+ def getCounter( self ):
242
+ return little_u64.unpack( little2_i32.pack( *self.ctx[ 8:10 ] ) ) [0]
243
+
244
+
245
+ def setRounds(self, rounds, testing=False ):
246
+ assert testing or rounds in [8, 12, 20], 'rounds must be 8, 12, 20'
247
+ self.rounds = rounds
248
+
249
+
250
+ def encryptBytes(self, data):
251
+ assert type(data) == bytes, 'data must be byte string'
252
+ assert self._lastChunk64, 'previous chunk not multiple of 64 bytes'
253
+ lendata = len(data)
254
+ munged = bytearray(lendata)
255
+ for i in range( 0, lendata, 64 ):
256
+ h = salsa20_wordtobyte( self.ctx, self.rounds, checkRounds=False )
257
+ self.setCounter( ( self.getCounter() + 1 ) % 2**64 )
258
+ # Stopping at 2^70 bytes per nonce is user's responsibility.
259
+ for j in range( min( 64, lendata - i ) ):
260
+ if python3:
261
+ munged[ i+j ] = data[ i+j ] ^ h[j]
262
+ else:
263
+ munged[ i+j ] = ord(data[ i+j ]) ^ ord(h[j])
264
+
265
+ self._lastChunk64 = not lendata % 64
266
+ return bytes(munged)
267
+
268
+ decryptBytes = encryptBytes # encrypt and decrypt use same function
269
+
270
+ #--------------------------------------------------------------------------
271
+
272
+ def salsa20_wordtobyte( input, nRounds=20, checkRounds=True ):
273
+ """ Do nRounds Salsa20 rounds on a copy of
274
+ input: list or tuple of 16 ints treated as little-endian unsigneds.
275
+ Returns a 64-byte string.
276
+ """
277
+
278
+ assert( type(input) in ( list, tuple ) and len(input) == 16 )
279
+ assert( not(checkRounds) or ( nRounds in [ 8, 12, 20 ] ) )
280
+
281
+ x = list( input )
282
+
283
+ def XOR( a, b ): return a ^ b
284
+ ROTATE = rot32
285
+ PLUS = add32
286
+
287
+ for i in range( nRounds // 2 ):
288
+ # These ...XOR...ROTATE...PLUS... lines are from ecrypt-linux.c
289
+ # unchanged except for indents and the blank line between rounds:
290
+ x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 0],x[12]), 7));
291
+ x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[ 4],x[ 0]), 9));
292
+ x[12] = XOR(x[12],ROTATE(PLUS(x[ 8],x[ 4]),13));
293
+ x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[12],x[ 8]),18));
294
+ x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 5],x[ 1]), 7));
295
+ x[13] = XOR(x[13],ROTATE(PLUS(x[ 9],x[ 5]), 9));
296
+ x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[13],x[ 9]),13));
297
+ x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 1],x[13]),18));
298
+ x[14] = XOR(x[14],ROTATE(PLUS(x[10],x[ 6]), 7));
299
+ x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[14],x[10]), 9));
300
+ x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 2],x[14]),13));
301
+ x[10] = XOR(x[10],ROTATE(PLUS(x[ 6],x[ 2]),18));
302
+ x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[15],x[11]), 7));
303
+ x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 3],x[15]), 9));
304
+ x[11] = XOR(x[11],ROTATE(PLUS(x[ 7],x[ 3]),13));
305
+ x[15] = XOR(x[15],ROTATE(PLUS(x[11],x[ 7]),18));
306
+
307
+ x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[ 0],x[ 3]), 7));
308
+ x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[ 1],x[ 0]), 9));
309
+ x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[ 2],x[ 1]),13));
310
+ x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[ 3],x[ 2]),18));
311
+ x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 5],x[ 4]), 7));
312
+ x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 6],x[ 5]), 9));
313
+ x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 7],x[ 6]),13));
314
+ x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 4],x[ 7]),18));
315
+ x[11] = XOR(x[11],ROTATE(PLUS(x[10],x[ 9]), 7));
316
+ x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[11],x[10]), 9));
317
+ x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 8],x[11]),13));
318
+ x[10] = XOR(x[10],ROTATE(PLUS(x[ 9],x[ 8]),18));
319
+ x[12] = XOR(x[12],ROTATE(PLUS(x[15],x[14]), 7));
320
+ x[13] = XOR(x[13],ROTATE(PLUS(x[12],x[15]), 9));
321
+ x[14] = XOR(x[14],ROTATE(PLUS(x[13],x[12]),13));
322
+ x[15] = XOR(x[15],ROTATE(PLUS(x[14],x[13]),18));
323
+
324
+ for i in range( len( input ) ):
325
+ x[i] = PLUS( x[i], input[i] )
326
+ return little16_i32.pack( *x )
327
+
328
+ #--------------------------- 32-bit ops -------------------------------
329
+
330
+ def trunc32( w ):
331
+ """ Return the bottom 32 bits of w as a Python int.
332
+ This creates longs temporarily, but returns an int. """
333
+ w = int( ( w & 0x7fffFFFF ) | -( w & 0x80000000 ) )
334
+ assert type(w) == int
335
+ return w
336
+
337
+
338
+ def add32( a, b ):
339
+ """ Add two 32-bit words discarding carry above 32nd bit,
340
+ and without creating a Python long.
341
+ Timing shouldn't vary.
342
+ """
343
+ lo = ( a & 0xFFFF ) + ( b & 0xFFFF )
344
+ hi = ( a >> 16 ) + ( b >> 16 ) + ( lo >> 16 )
345
+ return ( -(hi & 0x8000) | ( hi & 0x7FFF ) ) << 16 | ( lo & 0xFFFF )
346
+
347
+
348
+ def rot32( w, nLeft ):
349
+ """ Rotate 32-bit word left by nLeft or right by -nLeft
350
+ without creating a Python long.
351
+ Timing depends on nLeft but not on w.
352
+ """
353
+ nLeft &= 31 # which makes nLeft >= 0
354
+ if nLeft == 0:
355
+ return w
356
+
357
+ # Note: now 1 <= nLeft <= 31.
358
+ # RRRsLLLLLL There are nLeft RRR's, (31-nLeft) LLLLLL's,
359
+ # => sLLLLLLRRR and one s which becomes the sign bit.
360
+ RRR = ( ( ( w >> 1 ) & 0x7fffFFFF ) >> ( 31 - nLeft ) )
361
+ sLLLLLL = -( (1<<(31-nLeft)) & w ) | (0x7fffFFFF>>nLeft) & w
362
+ return RRR | ( sLLLLLL << nLeft )
363
+
364
+
365
+ # --------------------------------- end -----------------------------------