1# All Rights Reserved.
2#
3#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4#    not use this file except in compliance with the License. You may obtain
5#    a copy of the License at
6#
7#         http://www.apache.org/licenses/LICENSE-2.0
8#
9#    Unless required by applicable law or agreed to in writing, software
10#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12#    License for the specific language governing permissions and limitations
13#    under the License.
14
15"""
16Secret utilities.
17
18.. versionadded:: 3.5
19"""
20
21import hashlib
22import hmac
23
24
25def _constant_time_compare(first, second):
26    """Return True if both string or binary inputs are equal, otherwise False.
27
28    This function should take a constant amount of time regardless of
29    how many characters in the strings match. This function uses an
30    approach designed to prevent timing analysis by avoiding
31    content-based short circuiting behaviour, making it appropriate
32    for cryptography.
33    """
34    first = str(first)
35    second = str(second)
36    if len(first) != len(second):
37        return False
38    result = 0
39    for x, y in zip(first, second):
40        result |= ord(x) ^ ord(y)
41    return result == 0
42
43
44try:
45    constant_time_compare = hmac.compare_digest
46except AttributeError:
47    constant_time_compare = _constant_time_compare
48
49try:
50    _ = hashlib.md5(usedforsecurity=False)  # nosec
51
52    def md5(string=b'', usedforsecurity=True):
53        """Return an md5 hashlib object using usedforsecurity parameter
54
55        For python distributions that support the usedforsecurity keyword
56        parameter, this passes the parameter through as expected.
57        See https://bugs.python.org/issue9216
58        """
59        return hashlib.md5(string, usedforsecurity=usedforsecurity)  # nosec
60except TypeError:
61    def md5(string=b'', usedforsecurity=True):
62        """Return an md5 hashlib object without usedforsecurity parameter
63
64        For python distributions that do not yet support this keyword
65        parameter, we drop the parameter
66        """
67        return hashlib.md5(string)  # nosec
68