1
- #! /usr/bin/python3.6
1
+ #! /usr/bin/env python3
2
2
3
3
"""Base16, Base32, Base64 (RFC 3548), Base85 and Ascii85 data encodings"""
4
4
16
16
'encode' , 'decode' , 'encodebytes' , 'decodebytes' ,
17
17
# Generalized interface for other encodings
18
18
'b64encode' , 'b64decode' , 'b32encode' , 'b32decode' ,
19
- 'b16encode' , 'b16decode' ,
19
+ 'b32hexencode' , 'b32hexdecode' , ' b16encode' , 'b16decode' ,
20
20
# Base85 and Ascii85 encodings
21
21
'b85encode' , 'b85decode' , 'a85encode' , 'a85decode' ,
22
22
# Standard Base64 encoding
@@ -76,15 +76,16 @@ def b64decode(s, altchars=None, validate=False):
76
76
normal base-64 alphabet nor the alternative alphabet are discarded prior
77
77
to the padding check. If validate is True, these non-alphabet characters
78
78
in the input result in a binascii.Error.
79
+ For more information about the strict base64 check, see:
80
+
81
+ https://docs.python.org/3.11/library/binascii.html#binascii.a2b_base64
79
82
"""
80
83
s = _bytes_from_decode_data (s )
81
84
if altchars is not None :
82
85
altchars = _bytes_from_decode_data (altchars )
83
86
assert len (altchars ) == 2 , repr (altchars )
84
87
s = s .translate (bytes .maketrans (altchars , b'+/' ))
85
- if validate and not re .match (b'^[A-Za-z0-9+/]*={0,2}$' , s ):
86
- raise binascii .Error ('Non-base64 digit found' )
87
- return binascii .a2b_base64 (s )
88
+ return binascii .a2b_base64 (s , strict_mode = validate )
88
89
89
90
90
91
def standard_b64encode (s ):
@@ -135,19 +136,40 @@ def urlsafe_b64decode(s):
135
136
136
137
137
138
# Base32 encoding/decoding must be done in Python
139
+ _B32_ENCODE_DOCSTRING = '''
140
+ Encode the bytes-like objects using {encoding} and return a bytes object.
141
+ '''
142
+ _B32_DECODE_DOCSTRING = '''
143
+ Decode the {encoding} encoded bytes-like object or ASCII string s.
144
+
145
+ Optional casefold is a flag specifying whether a lowercase alphabet is
146
+ acceptable as input. For security purposes, the default is False.
147
+ {extra_args}
148
+ The result is returned as a bytes object. A binascii.Error is raised if
149
+ the input is incorrectly padded or if there are non-alphabet
150
+ characters present in the input.
151
+ '''
152
+ _B32_DECODE_MAP01_DOCSTRING = '''
153
+ RFC 3548 allows for optional mapping of the digit 0 (zero) to the
154
+ letter O (oh), and for optional mapping of the digit 1 (one) to
155
+ either the letter I (eye) or letter L (el). The optional argument
156
+ map01 when not None, specifies which letter the digit 1 should be
157
+ mapped to (when map01 is not None, the digit 0 is always mapped to
158
+ the letter O). For security purposes the default is None, so that
159
+ 0 and 1 are not allowed in the input.
160
+ '''
138
161
_b32alphabet = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
139
- _b32tab2 = None
140
- _b32rev = None
162
+ _b32hexalphabet = b'0123456789ABCDEFGHIJKLMNOPQRSTUV'
163
+ _b32tab2 = {}
164
+ _b32rev = {}
141
165
142
- def b32encode (s ):
143
- """Encode the bytes-like object s using Base32 and return a bytes object.
144
- """
166
+ def _b32encode (alphabet , s ):
145
167
global _b32tab2
146
168
# Delay the initialization of the table to not waste memory
147
169
# if the function is never called
148
- if _b32tab2 is None :
149
- b32tab = [bytes ((i ,)) for i in _b32alphabet ]
150
- _b32tab2 = [a + b for a in b32tab for b in b32tab ]
170
+ if alphabet not in _b32tab2 :
171
+ b32tab = [bytes ((i ,)) for i in alphabet ]
172
+ _b32tab2 [ alphabet ] = [a + b for a in b32tab for b in b32tab ]
151
173
b32tab = None
152
174
153
175
if not isinstance (s , bytes_types ):
@@ -158,9 +180,9 @@ def b32encode(s):
158
180
s = s + b'\0 ' * (5 - leftover ) # Don't use += !
159
181
encoded = bytearray ()
160
182
from_bytes = int .from_bytes
161
- b32tab2 = _b32tab2
183
+ b32tab2 = _b32tab2 [ alphabet ]
162
184
for i in range (0 , len (s ), 5 ):
163
- c = from_bytes (s [i : i + 5 ], ' big' )
185
+ c = from_bytes (s [i : i + 5 ]) # big endian
164
186
encoded += (b32tab2 [c >> 30 ] + # bits 1 - 10
165
187
b32tab2 [(c >> 20 ) & 0x3ff ] + # bits 11 - 20
166
188
b32tab2 [(c >> 10 ) & 0x3ff ] + # bits 21 - 30
@@ -177,29 +199,12 @@ def b32encode(s):
177
199
encoded [- 1 :] = b'='
178
200
return bytes (encoded )
179
201
180
- def b32decode (s , casefold = False , map01 = None ):
181
- """Decode the Base32 encoded bytes-like object or ASCII string s.
182
-
183
- Optional casefold is a flag specifying whether a lowercase alphabet is
184
- acceptable as input. For security purposes, the default is False.
185
-
186
- RFC 3548 allows for optional mapping of the digit 0 (zero) to the
187
- letter O (oh), and for optional mapping of the digit 1 (one) to
188
- either the letter I (eye) or letter L (el). The optional argument
189
- map01 when not None, specifies which letter the digit 1 should be
190
- mapped to (when map01 is not None, the digit 0 is always mapped to
191
- the letter O). For security purposes the default is None, so that
192
- 0 and 1 are not allowed in the input.
193
-
194
- The result is returned as a bytes object. A binascii.Error is raised if
195
- the input is incorrectly padded or if there are non-alphabet
196
- characters present in the input.
197
- """
202
+ def _b32decode (alphabet , s , casefold = False , map01 = None ):
198
203
global _b32rev
199
204
# Delay the initialization of the table to not waste memory
200
205
# if the function is never called
201
- if _b32rev is None :
202
- _b32rev = {v : k for k , v in enumerate (_b32alphabet )}
206
+ if alphabet not in _b32rev :
207
+ _b32rev [ alphabet ] = {v : k for k , v in enumerate (alphabet )}
203
208
s = _bytes_from_decode_data (s )
204
209
if len (s ) % 8 :
205
210
raise binascii .Error ('Incorrect padding' )
@@ -220,7 +225,7 @@ def b32decode(s, casefold=False, map01=None):
220
225
padchars = l - len (s )
221
226
# Now decode the full quanta
222
227
decoded = bytearray ()
223
- b32rev = _b32rev
228
+ b32rev = _b32rev [ alphabet ]
224
229
for i in range (0 , len (s ), 8 ):
225
230
quanta = s [i : i + 8 ]
226
231
acc = 0
@@ -229,18 +234,38 @@ def b32decode(s, casefold=False, map01=None):
229
234
acc = (acc << 5 ) + b32rev [c ]
230
235
except KeyError :
231
236
raise binascii .Error ('Non-base32 digit found' ) from None
232
- decoded += acc .to_bytes (5 , ' big' )
237
+ decoded += acc .to_bytes (5 ) # big endian
233
238
# Process the last, partial quanta
234
239
if l % 8 or padchars not in {0 , 1 , 3 , 4 , 6 }:
235
240
raise binascii .Error ('Incorrect padding' )
236
241
if padchars and decoded :
237
242
acc <<= 5 * padchars
238
- last = acc .to_bytes (5 , ' big' )
243
+ last = acc .to_bytes (5 ) # big endian
239
244
leftover = (43 - 5 * padchars ) // 8 # 1: 4, 3: 3, 4: 2, 6: 1
240
245
decoded [- 5 :] = last [:leftover ]
241
246
return bytes (decoded )
242
247
243
248
249
+ def b32encode (s ):
250
+ return _b32encode (_b32alphabet , s )
251
+ b32encode .__doc__ = _B32_ENCODE_DOCSTRING .format (encoding = 'base32' )
252
+
253
+ def b32decode (s , casefold = False , map01 = None ):
254
+ return _b32decode (_b32alphabet , s , casefold , map01 )
255
+ b32decode .__doc__ = _B32_DECODE_DOCSTRING .format (encoding = 'base32' ,
256
+ extra_args = _B32_DECODE_MAP01_DOCSTRING )
257
+
258
+ def b32hexencode (s ):
259
+ return _b32encode (_b32hexalphabet , s )
260
+ b32hexencode .__doc__ = _B32_ENCODE_DOCSTRING .format (encoding = 'base32hex' )
261
+
262
+ def b32hexdecode (s , casefold = False ):
263
+ # base32hex does not have the 01 mapping
264
+ return _b32decode (_b32hexalphabet , s , casefold )
265
+ b32hexdecode .__doc__ = _B32_DECODE_DOCSTRING .format (encoding = 'base32hex' ,
266
+ extra_args = '' )
267
+
268
+
244
269
# RFC 3548, Base 16 Alphabet specifies uppercase, but hexlify() returns
245
270
# lowercase. The RFC also recommends against accepting input case
246
271
# insensitively.
@@ -320,7 +345,7 @@ def a85encode(b, *, foldspaces=False, wrapcol=0, pad=False, adobe=False):
320
345
global _a85chars , _a85chars2
321
346
# Delay the initialization of tables to not waste memory
322
347
# if the function is never called
323
- if _a85chars is None :
348
+ if _a85chars2 is None :
324
349
_a85chars = [bytes ((i ,)) for i in range (33 , 118 )]
325
350
_a85chars2 = [(a + b ) for a in _a85chars for b in _a85chars ]
326
351
@@ -428,7 +453,7 @@ def b85encode(b, pad=False):
428
453
global _b85chars , _b85chars2
429
454
# Delay the initialization of tables to not waste memory
430
455
# if the function is never called
431
- if _b85chars is None :
456
+ if _b85chars2 is None :
432
457
_b85chars = [bytes ((i ,)) for i in _b85alphabet ]
433
458
_b85chars2 = [(a + b ) for a in _b85chars for b in _b85chars ]
434
459
return _85encode (b , _b85chars , _b85chars2 , pad )
@@ -531,49 +556,36 @@ def encodebytes(s):
531
556
pieces .append (binascii .b2a_base64 (chunk ))
532
557
return b"" .join (pieces )
533
558
534
- def encodestring (s ):
535
- """Legacy alias of encodebytes()."""
536
- import warnings
537
- warnings .warn ("encodestring() is a deprecated alias since 3.1, "
538
- "use encodebytes()" ,
539
- DeprecationWarning , 2 )
540
- return encodebytes (s )
541
-
542
559
543
560
def decodebytes (s ):
544
561
"""Decode a bytestring of base-64 data into a bytes object."""
545
562
_input_type_check (s )
546
563
return binascii .a2b_base64 (s )
547
564
548
- def decodestring (s ):
549
- """Legacy alias of decodebytes()."""
550
- import warnings
551
- warnings .warn ("decodestring() is a deprecated alias since Python 3.1, "
552
- "use decodebytes()" ,
553
- DeprecationWarning , 2 )
554
- return decodebytes (s )
555
-
556
565
557
566
# Usable as a script...
558
567
def main ():
559
568
"""Small main program"""
560
569
import sys , getopt
570
+ usage = """usage: %s [-h|-d|-e|-u|-t] [file|-]
571
+ -h: print this help message and exit
572
+ -d, -u: decode
573
+ -e: encode (default)
574
+ -t: encode and decode string 'Aladdin:open sesame'""" % sys .argv [0 ]
561
575
try :
562
- opts , args = getopt .getopt (sys .argv [1 :], 'deut ' )
576
+ opts , args = getopt .getopt (sys .argv [1 :], 'hdeut ' )
563
577
except getopt .error as msg :
564
578
sys .stdout = sys .stderr
565
579
print (msg )
566
- print ("""usage: %s [-d|-e|-u|-t] [file|-]
567
- -d, -u: decode
568
- -e: encode (default)
569
- -t: encode and decode string 'Aladdin:open sesame'""" % sys .argv [0 ])
580
+ print (usage )
570
581
sys .exit (2 )
571
582
func = encode
572
583
for o , a in opts :
573
584
if o == '-e' : func = encode
574
585
if o == '-d' : func = decode
575
586
if o == '-u' : func = decode
576
587
if o == '-t' : test (); return
588
+ if o == '-h' : print (usage ); return
577
589
if args and args [0 ] != '-' :
578
590
with open (args [0 ], 'rb' ) as f :
579
591
func (f , sys .stdout .buffer )
0 commit comments