Skip to content

Commit 6dd962f

Browse files
gh-66788: Strictly enforce the modified Base64 alphabet in utf-7-imap
Decode the modified Base64 with binascii.a2b_base64() and the modified alphabet directly, instead of base64.b64decode() with altchars. With strict_mode the "/" character (used by standard Base64 but not by the modified alphabet, which uses ",") is now rejected rather than accepted with a DeprecationWarning. Encoding likewise uses binascii.b2a_base64(). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 09ed62f commit 6dd962f

2 files changed

Lines changed: 11 additions & 6 deletions

File tree

Lib/encodings/utf_7_imap.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313

1414
import binascii
1515
import codecs
16-
from base64 import b64encode, b64decode
16+
17+
# The modified Base64 alphabet of RFC 3501: standard Base64 but with "," in
18+
# place of "/".
19+
_alphabet = binascii.BASE64_ALPHABET[:-1] + b','
1720

1821
### Codec APIs
1922

@@ -26,8 +29,9 @@ def utf_7_imap_encode(input, errors='strict'):
2629
def flush(end):
2730
if start < end:
2831
if b64run:
29-
b64 = b64encode(input[start:end].encode('utf-16-be'),
30-
altchars=b'+,', padded=False)
32+
b64 = binascii.b2a_base64(input[start:end].encode('utf-16-be'),
33+
alphabet=_alphabet, padded=False,
34+
newline=False)
3135
res.extend(b'&' + b64 + b'-')
3236
else:
3337
res.extend(input[start:end].encode('ascii'))
@@ -74,8 +78,8 @@ def flush(end):
7478
else:
7579
b64 = input[i + 1:j]
7680
try:
77-
data = b64decode(b64, altchars=b'+,',
78-
validate=True, padded=False)
81+
data = binascii.a2b_base64(b64, alphabet=_alphabet,
82+
strict_mode=True, padded=False)
7983
except binascii.Error:
8084
data = b''
8185
if not data or len(data) % 2:

Lib/test/test_codecs.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1421,7 +1421,7 @@ def test_decode_invalid(self):
14211421
('a\tb', b'a&AAk-b'),
14221422
('\x00', b'&AAA-'),
14231423
('Entw\xfcrfe', b'Entw&APw-rfe'),
1424-
('ϰ', b'&A,A-'), # "," in the modified Base64 alphabet
1424+
('ϰ', b'&A,A-'), # "," in the Base64 alphabet ("&A/A-" is invalid)
14251425
('☃', b'&JgM-'), # snowman
14261426
('\U0001f600', b'&2D3eAA-'), # non-BMP (surrogate pair)
14271427
('Sent &\N{DELETE}', b'Sent &-&AH8-'),
@@ -1441,6 +1441,7 @@ def test_decode(self, uni, encoded):
14411441
(b'x&', 1), # "&" just before the end, unterminated
14421442
(b'&AAAA', 0), # unterminated, though the Base64 is valid
14431443
(b'&AB-', 0), # Base64 length not a multiple of a code unit
1444+
(b'&A/A-', 0), # "/" not in the alphabet ("&A,A-" is valid)
14441445
(b'&@@@-', 0), # invalid Base64
14451446
(b'a\x80b', 1), # 8-bit byte outside a shift sequence
14461447
(b'a\x1fb', 1), # control byte outside a shift sequence

0 commit comments

Comments
 (0)