33
33
* Author(s): AJ Alt, Brent Rubell
34
34
"""
35
35
import struct
36
- from micropython import const
37
36
from io import BytesIO
37
+ from micropython import const
38
+
38
39
39
40
SHA_BLOCKSIZE = 64
40
41
SHA_DIGESTSIZE = 20
45
46
K2 = const (0x8F1BBCDC )
46
47
K3 = const (0xCA62C1D6 )
47
48
48
- def _getbuf (s ):
49
- if isinstance (s , str ):
50
- return s .encode ('ascii' )
51
- return bytes (s )
49
+ def _getbuf (data ):
50
+ """Converts data into ascii,
51
+ returns bytes of data
52
+ """
53
+ if isinstance (data , str ):
54
+ return data .encode ('ascii' )
55
+ return bytes (data )
52
56
53
57
54
58
def _left_rotate (n , b ):
55
- """Left rotate a 32-bit integer, n, by b bits.
56
- :param int n: 32-bit integer
57
- :param int b: Desired rotation amount, in bits.
58
- """
59
- return ((n << b ) | (n >> (32 - b ))) & 0xffffffff
60
-
59
+ """Left rotate a 32-bit integer, n, by b bits.
60
+ :param int n: 32-bit integer
61
+ :param int b: Desired rotation amount, in bits.
62
+ """
63
+ return ((n << b ) | (n >> (32 - b ))) & 0xffffffff
61
64
65
+ # pylint: disable=invalid-name, too-many-arguments
62
66
def _hash_computation (chunk , h0 , h1 , h2 , h3 , h4 ):
63
- """Processes 64-bit chunk of data and returns new digest variables.
64
- Per FIPS [6.1.2]
65
- :param bytes bytearray chunk: 64-bit bytearray
66
- :param list h_tuple: List of hash values for the chunk
67
- """
68
- assert len (chunk ) == 64 , "Chunk should be 64-bits"
69
-
70
- w = [0 ] * 80
71
-
72
- # Break chunk into sixteen 4-byte big-endian words w[i]
73
- for i in range (16 ):
74
- w [i ] = struct .unpack (b'>I' , chunk [i * 4 :i * 4 + 4 ])[0 ]
75
-
76
- # Extend the sixteen 4-byte words into eighty 4-byte words
77
- for i in range (16 , 80 ):
78
- w [i ] = _left_rotate (w [i - 3 ] ^ w [i - 8 ] ^ w [i - 14 ] ^ w [i - 16 ], 1 )
79
-
80
- # Init. hash values for chunk
81
- a = h0
82
- b = h1
83
- c = h2
84
- d = h3
85
- e = h4
86
-
87
- for i in range (80 ):
88
- if 0 <= i <= 19 :
89
- # Use alternative 1 for f from FIPS PB 180-1 to avoid bitwise not
90
- f = d ^ (b & (c ^ d ))
91
- k = K0
92
- elif 20 <= i <= 39 :
93
- f = b ^ c ^ d
94
- k = K1
95
- elif 40 <= i <= 59 :
96
- f = (b & c ) | (b & d ) | (c & d )
97
- k = K2
98
- elif 60 <= i <= 79 :
99
- f = b ^ c ^ d
100
- k = K3
101
-
102
- a , b , c , d , e = ((_left_rotate (a , 5 ) + f + e + k + w [i ]) & 0xffffffff ,
103
- a , _left_rotate (b , 30 ), c , d )
104
-
105
- # Add to chunk's hash result so far
106
- h0 = (h0 + a ) & 0xffffffff
107
- h1 = (h1 + b ) & 0xffffffff
108
- h2 = (h2 + c ) & 0xffffffff
109
- h3 = (h3 + d ) & 0xffffffff
110
- h4 = (h4 + e ) & 0xffffffff
111
-
112
- return h0 , h1 , h2 , h3 , h4
67
+ """Processes 64-bit chunk of data and returns new digest variables.
68
+ Per FIPS [6.1.2]
69
+ :param bytes bytearray chunk: 64-bit bytearray
70
+ :param list h_tuple: List of hash values for the chunk
71
+ """
72
+ assert len (chunk ) == 64 , "Chunk should be 64-bits"
73
+
74
+ w = [0 ] * 80
75
+
76
+ # Break chunk into sixteen 4-byte big-endian words w[i]
77
+ for i in range (16 ):
78
+ w [i ] = struct .unpack (b'>I' , chunk [i * 4 :i * 4 + 4 ])[0 ]
79
+
80
+ # Extend the sixteen 4-byte words into eighty 4-byte words
81
+ for i in range (16 , 80 ):
82
+ w [i ] = _left_rotate (w [i - 3 ] ^ w [i - 8 ] ^ w [i - 14 ] ^ w [i - 16 ], 1 )
83
+
84
+ # Init. hash values for chunk
85
+ a = h0
86
+ b = h1
87
+ c = h2
88
+ d = h3
89
+ e = h4
90
+
91
+ for i in range (80 ):
92
+ if 0 <= i <= 19 :
93
+ # Use alternative 1 for f from FIPS PB 180-1 to avoid bitwise not
94
+ f = d ^ (b & (c ^ d ))
95
+ k = K0
96
+ elif 20 <= i <= 39 :
97
+ f = b ^ c ^ d
98
+ k = K1
99
+ elif 40 <= i <= 59 :
100
+ f = (b & c ) | (b & d ) | (c & d )
101
+ k = K2
102
+ elif 60 <= i <= 79 :
103
+ f = b ^ c ^ d
104
+ k = K3
105
+
106
+ a , b , c , d , e = ((_left_rotate (a , 5 ) + f + e + k + w [i ]) & 0xffffffff ,
107
+ a , _left_rotate (b , 30 ), c , d )
108
+
109
+ # Add to chunk's hash result so far
110
+ h0 = (h0 + a ) & 0xffffffff
111
+ h1 = (h1 + b ) & 0xffffffff
112
+ h2 = (h2 + c ) & 0xffffffff
113
+ h3 = (h3 + d ) & 0xffffffff
114
+ h4 = (h4 + e ) & 0xffffffff
115
+
116
+ return h0 , h1 , h2 , h3 , h4
113
117
114
118
115
119
# pylint: disable=too-few-public-methods, invalid-name
116
120
class sha1 ():
117
- digest_size = SHA_DIGESTSIZE
118
- block_size = SHA_BLOCKSIZE
119
- name = "sha1"
120
- def __init__ (self , s = None ):
121
- """Construct a SHA-1 hash object.
122
-
123
- """
124
- # Initial Digest Variables
125
- self ._h = (0x67452301 ,
126
- 0xEFCDAB89 ,
127
- 0x98BADCFE ,
128
- 0x10325476 ,
129
- 0xC3D2E1F0 )
130
-
131
- self ._unprocessed = b''
132
- self ._msg_byte_len = 0
133
-
134
- def _create_digest (self ):
135
- """Returns finalized digest variables for the data processed so far.
136
-
137
- """
138
- # pre-processing
139
- message = self ._unprocessed
140
- message_len = self ._msg_byte_len + len (message )
141
-
142
- # add trailing '1' bit (+ 0's padding) to string [§5.1.1]
143
- message += b'\x80 '
144
-
145
- # append 0 <= k < 512 bits '0', so that the resulting message length (in bytes)
146
- # is congruent to 56 (mod 64)
147
- message += b'\x00 ' * ((56 - (message_len + 1 ) % 64 ) % 64 )
148
-
149
-
150
- # append ml, the original message length, as a 64-bit big-endian integer.
151
- message_bit_length = message_len * 8
152
- message += struct .pack (b'>Q' , message_bit_length )
153
-
154
- # Process the final chunk
155
- # At this point, the length of the message is either 64 or 128 bytes.
156
- h = _hash_computation (message [:64 ], * self ._h )
157
- if len (message ) == 64 :
158
- return h
159
- return _hash_computation (message [64 :], * h )
160
-
161
- def update (self , data ):
162
- """Updates the hash object with bytes-like object, data.
163
- :param bytes data: bytearray or bytes object
164
-
165
- """
166
- # if we get a string, convert to a bytearray objects
167
- data = _getbuf (data )
168
-
169
- # switch input to bytesio api for easier reading
170
- if isinstance (data , (bytes , bytearray )):
171
- data = BytesIO (data )
172
-
173
- # Try to build a chunk out of the unprocessed data, if any
174
- chunk = self ._unprocessed + data .read (64 - len (self ._unprocessed ))
175
-
176
- while len (chunk ) == 64 :
177
- self ._h = _hash_computation (chunk , * self ._h )
178
- self ._msg_byte_len += 64
179
- # read the next 64 bytes
180
- chunk = data .read (64 )
181
-
182
- self ._unprocessed = chunk
183
- return self
184
-
185
- def digest (self ):
186
- """Returns the digest of the data passed to the update()
187
- method so far.
188
-
189
- """
190
- return b'' .join (struct .pack (b'>I' , h ) for h in self ._create_digest ())
191
-
192
- def hexdigest (self ):
193
- """Like digest() except the digest is returned as a string object of
194
- double length, containing only hexadecimal digits.
121
+ """SHA-1 Hash Object
195
122
196
123
"""
197
- return '' .join (['%.2x' % i for i in self .digest ()])
124
+ digest_size = SHA_DIGESTSIZE
125
+ block_size = SHA_BLOCKSIZE
126
+ name = "sha1"
127
+ def __init__ (self ):
128
+ """Construct a SHA-1 hash object.
129
+
130
+ """
131
+ # Initial Digest Variables
132
+ self ._h = (0x67452301 ,
133
+ 0xEFCDAB89 ,
134
+ 0x98BADCFE ,
135
+ 0x10325476 ,
136
+ 0xC3D2E1F0 )
137
+
138
+ self ._unprocessed = b''
139
+ self ._msg_byte_len = 0
140
+
141
+ def _create_digest (self ):
142
+ """Returns finalized digest variables for the data processed so far.
143
+
144
+ """
145
+ # pre-processing
146
+ message = self ._unprocessed
147
+ message_len = self ._msg_byte_len + len (message )
148
+
149
+ # add trailing '1' bit (+ 0's padding) to string [§5.1.1]
150
+ message += b'\x80 '
151
+
152
+ # append 0 <= k < 512 bits '0', so that the resulting message length (in bytes)
153
+ # is congruent to 56 (mod 64)
154
+ message += b'\x00 ' * ((56 - (message_len + 1 ) % 64 ) % 64 )
155
+
156
+
157
+ # append ml, the original message length, as a 64-bit big-endian integer.
158
+ message_bit_length = message_len * 8
159
+ message += struct .pack (b'>Q' , message_bit_length )
160
+
161
+ # Process the final chunk
162
+ # At this point, the length of the message is either 64 or 128 bytes.
163
+ h = _hash_computation (message [:64 ], * self ._h )
164
+ if len (message ) == 64 :
165
+ return h
166
+ return _hash_computation (message [64 :], * h )
167
+
168
+ def update (self , data ):
169
+ """Updates the hash object with bytes-like object, data.
170
+ :param bytes data: bytearray or bytes object
171
+
172
+ """
173
+ # if we get a string, convert to a bytearray objects
174
+ data = _getbuf (data )
175
+
176
+ # switch input to bytesio api for easier reading
177
+ if isinstance (data , (bytes , bytearray )):
178
+ data = BytesIO (data )
179
+
180
+ # Try to build a chunk out of the unprocessed data, if any
181
+ chunk = self ._unprocessed + data .read (64 - len (self ._unprocessed ))
182
+
183
+ while len (chunk ) == 64 :
184
+ self ._h = _hash_computation (chunk , * self ._h )
185
+ self ._msg_byte_len += 64
186
+ # read the next 64 bytes
187
+ chunk = data .read (64 )
188
+
189
+ self ._unprocessed = chunk
190
+ return self
191
+
192
+ def digest (self ):
193
+ """Returns the digest of the data passed to the update()
194
+ method so far.
195
+
196
+ """
197
+ return b'' .join (struct .pack (b'>I' , h ) for h in self ._create_digest ())
198
+
199
+ def hexdigest (self ):
200
+ """Like digest() except the digest is returned as a string object of
201
+ double length, containing only hexadecimal digits.
202
+
203
+ """
204
+ return '' .join (['%.2x' % i for i in self .digest ()])
0 commit comments