diff --git a/NOTICE b/NOTICE index 098e4819e..1b0d73e59 100644 --- a/NOTICE +++ b/NOTICE @@ -663,78 +663,35 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******* -pycryptodome +cryptography -The source code in PyCryptodome is partially in the public domain -and partially released under the BSD 2-Clause license. - -In either case, there are minimal if no restrictions on the redistribution, -modification and usage of the software. - -Public domain -============= - -All code originating from PyCrypto is free and unencumbered software -released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to - -BSD license -=========== - -All direct contributions to PyCryptodome are released under the following -license. The copyright of each piece belongs to the respective author. +Copyright (c) Individual contributors. +All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -OCB license -=========== - -The OCB cipher mode is patented in the US under patent numbers 7,949,129 and -8,321,675. The directory Doc/ocb contains three free licenses for implementors -and users. As a general statement, OCB can be freely used for software not meant -for military purposes. Contact your attorney for further information. + 3. Neither the name of PyCA Cryptography nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******* pillow diff --git a/presidio-anonymizer/presidio_anonymizer/operators/aes_cipher.py b/presidio-anonymizer/presidio_anonymizer/operators/aes_cipher.py index 06dc75986..3ccab0d00 100644 --- a/presidio-anonymizer/presidio_anonymizer/operators/aes_cipher.py +++ b/presidio-anonymizer/presidio_anonymizer/operators/aes_cipher.py @@ -1,8 +1,8 @@ import base64 +import os -from Crypto import Random -from Crypto.Cipher import AES -from Crypto.Util.Padding import pad, unpad +from cryptography.hazmat.primitives import padding +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes class AESCipher: @@ -19,10 +19,14 @@ class AESCipher: :returns: The encrypted text. """ encoded_text = text.encode("utf-8") - padded_text = pad(encoded_text, AES.block_size) - iv = Random.new().read(AES.block_size) - cipher = AES.new(key, AES.MODE_CBC, iv) - encrypted_text = base64.b64encode(iv + cipher.encrypt(padded_text)) + padder = padding.PKCS7(algorithms.AES.block_size).padder() + padded_text = padder.update(encoded_text) + padder.finalize() + iv = os.urandom(16) + cipher = Cipher(algorithms.AES(key), modes.CBC(iv)) + encryptor = cipher.encryptor() + encrypted_text = base64.urlsafe_b64encode( + iv + encryptor.update(padded_text) + encryptor.finalize() + ) return encrypted_text.decode() @staticmethod @@ -34,14 +38,14 @@ class AESCipher: :param text: The text for decryption. :returns: The decrypted text. """ - decoded_text = base64.b64decode(text) - iv = decoded_text[: AES.block_size] - cipher = AES.new(key, AES.MODE_CBC, iv) - decrypted_text = unpad( - cipher.decrypt(decoded_text[AES.block_size :]), AES.block_size - ) - return decrypted_text.decode("utf-8") - + decoded_text = base64.urlsafe_b64decode(text) + iv = decoded_text[:16] + ct = decoded_text[16:] + cipher = Cipher(algorithms.AES(key), modes.CBC(iv)) + decryptor = cipher.decryptor() + unpadder = padding.PKCS7(128).unpadder() + decrypted_text = decryptor.update(ct) + decryptor.finalize() + return (unpadder.update(decrypted_text) + unpadder.finalize()).decode("utf-8") @staticmethod def is_valid_key_size(key: bytes) -> bool: """ @@ -50,4 +54,4 @@ class AESCipher: :param key: AES encryption key in bytes. :returns: True if the key is of valid size, False otherwise. """ - return len(key) in AES.key_size + return len(key) * 8 in algorithms.AES.key_sizes diff --git a/presidio-anonymizer/pyproject.toml b/presidio-anonymizer/pyproject.toml index b58f48262..6da7a8cfa 100644 --- a/presidio-anonymizer/pyproject.toml +++ b/presidio-anonymizer/pyproject.toml @@ -22,7 +22,7 @@ readme = "README.md" [tool.poetry.dependencies] python = ">=3.9,<4.0" -pycryptodome = ">=3.10.1" +cryptography = "<44.1" flask = { version = ">=1.1", optional = true } gunicorn = {version = "*", optional = true} diff --git a/presidio-anonymizer/tests/services/test_aes_cypher.py b/presidio-anonymizer/tests/services/test_aes_cypher.py index 9c3963b94..f6949f4b3 100644 --- a/presidio-anonymizer/tests/services/test_aes_cypher.py +++ b/presidio-anonymizer/tests/services/test_aes_cypher.py @@ -31,7 +31,7 @@ def test_given_valid_key_and_text_then_text_encryption_and_decryption_returns_sa def test_given_invalid_key_length_then_value_error_raised(): invalid_length_key = b"1111" - with pytest.raises(ValueError, match="Incorrect AES key length"): + with pytest.raises(ValueError, match="Invalid key size \(32\) for AES"): AESCipher.encrypt(invalid_length_key, "text")