From c31fa58c85e866b3a5ab04882c7aff655f0b5477 Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Tue, 30 Apr 2024 11:39:20 +0200 Subject: Implement etoolkit encryption protocol v2 --- tests/test_envtoolkit_instance_static.py | 114 ++++++++++++++++++++++++++----- 1 file changed, 97 insertions(+), 17 deletions(-) (limited to 'tests/test_envtoolkit_instance_static.py') diff --git a/tests/test_envtoolkit_instance_static.py b/tests/test_envtoolkit_instance_static.py index 73a5f36..5fb9451 100644 --- a/tests/test_envtoolkit_instance_static.py +++ b/tests/test_envtoolkit_instance_static.py @@ -1,5 +1,5 @@ # etoolkit -# Copyright (C) 2021-2022 Simeon Simeonov +# Copyright (C) 2021-2024 Simeon Simeonov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -14,6 +14,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Tests for etoolkit.EtoolkitInstance static methods""" + import unittest.mock import pytest @@ -35,7 +36,7 @@ def test_confirm_password_prompt(getpass, password_hash): ) -def test_decrypt(): +def test_decrypt_v1(): """Tests the static EtoolkitInstance.decrypt method""" assert ( etoolkit.EtoolkitInstance.decrypt( @@ -49,39 +50,118 @@ def test_decrypt(): ) # now test with modified edata + edata = ( + 'enc-val$1$/cXpEMoZrTlb9yokGhw8tLTSUkqnqJ5ZoAkurNgMYx' + 'w=$1VdkSMcZnLRwLiu1M8VlYcbelwmiVNY=' + ) with pytest.raises(etoolkit.EtoolkitInstanceError) as exc_info: - edata = ( - 'enc-val$1$/cXpEMoZrTlb9yokGhw8tLTSUkqnqJ5ZoAkurNgMYx' - 'w=$1VdkSMcZnLRwLiu1M8VlYcbelwmiVNY=' + etoolkit.EtoolkitInstance.decrypt('The very secret passwd', edata) + assert exc_info.type is etoolkit.EtoolkitInstanceError + assert exc_info.value.args[0] == f'Invalid tag when decrypting: {edata}' + + +def test_decrypt_v2_no_padding(): + """Tests the static EtoolkitInstance.decrypt method for v2 - no padding""" + assert ( + etoolkit.EtoolkitInstance.decrypt( + 'The very secret passwd', + ( + 'enc-val$2$Wer5lECGyeZhhYS58N18WVx5Zzy+rrC+BPlq3Dw89wQ=$' + 'SQc0ox6Emf2m5rrumsiptpIZEujdpXXSR/' + '1VcfEZeBz4+KDSagr9ID+bkc4R2yFdxHnhig1eqQ8=' + ), ) + == 'Nobody expects the Spanish inquisition' + ) + + # now test with modified edata + edata = ( + 'enc-val$2$Wer5lECGyeZhhYS58N18WVx5Zzy+rrC+BPlq3Dw89wQ=$' + 'SQc0ox6Emf2m4rrumsiptpIZEujdpXXSR/' + '1VcfEZeBz4+KDSagr9ID+bkc4R2yFdxHnhig1eqQ8=' + ) + with pytest.raises(etoolkit.EtoolkitInstanceError) as exc_info: + etoolkit.EtoolkitInstance.decrypt('The very secret passwd', edata) + assert exc_info.type is etoolkit.EtoolkitInstanceError + assert exc_info.value.args[0] == f'Invalid tag when decrypting: {edata}' + + +def test_decrypt_v2_with_padding(): + """Tests the static EtoolkitInstance.decrypt method for v2 with padding""" + assert ( etoolkit.EtoolkitInstance.decrypt( - 'The very secret passwd', edata - ) == 'secret1' + 'The very secret passwd', + ( + 'enc-val$2$//kzyUbDEWNoPC5dyukhB8de8+IVaLR2ngx2HwkfOuM=$' + 'rhRona4wP9nhnXjcHqwkjFDsiVVVjYanAs' + 'N4kknNkgC0ix4RtJQHYDeTzw1rrR1vb2w=' + ), + ) + == 'secret1' + ) + + # now test with modified edata + edata = ( + 'enc-val$2$//kzyUbDEWNoPC5dyukhB8de8+IVaLR2ngx2HwkfOuM=$' + 'rhRona4wP8nhnXjcHqwkjFDsiVVVjYanAsN4kknNkgC0ix4RtJQHYDeTzw1rrR1vb2w=' + ) + with pytest.raises(etoolkit.EtoolkitInstanceError) as exc_info: + etoolkit.EtoolkitInstance.decrypt('The very secret passwd', edata) assert exc_info.type is etoolkit.EtoolkitInstanceError assert exc_info.value.args[0] == f'Invalid tag when decrypting: {edata}' -def test_encrypt(): - """Tests the static EtoolkitInstance.encrypt method""" +def test_encrypt_no_padding(): + """Tests the static EtoolkitInstance.encrypt method with a long string""" + edata = etoolkit.EtoolkitInstance.encrypt( + 'foo', 'Nobody expects the Spanish inquisition' + ) + assert edata.startswith('enc-val$2$') + assert len(edata) == 131 + # the edata should always be different because of random salting + assert edata != etoolkit.EtoolkitInstance.encrypt( + 'foo', 'Nobody expects the Spanish inquisition' + ) + + +def test_encrypt_with_padding(): + """Tests the static EtoolkitInstance.encrypt method with a short string""" edata = etoolkit.EtoolkitInstance.encrypt('foo', 'bar') - assert edata.startswith('enc-val$') - assert len(edata) == 83 + assert edata.startswith('enc-val$2$') + assert len(edata) == 123 # the edata should always be different because of random salting assert edata != etoolkit.EtoolkitInstance.encrypt('foo', 'bar') @unittest.mock.patch('os.urandom') -def test_encrypt_staticly(urandom, non_random_bytes_32): +def test_encrypt_staticly_no_padding(urandom, non_random_bytes_32): """Tests the EtoolkitInstance.encrypt method always with the same salt""" urandom.return_value = non_random_bytes_32 + edata = etoolkit.EtoolkitInstance.encrypt( + 'The very secret passwd', 'Nobody expects the Spanish inquisition' + ) + assert edata == ( + 'enc-val$2$uYpZM1VfAGq0CDZL2duITs076CQj+hIFEgx+F4mn80o=$' + 'UX/5YeRsh5/2vZ2J1UOS+BJti73Kbp6C1pJmC' + 'o8hFSujpe35X/XpzAiYv4BV1LNwnSYECsotsgs=' + ) + assert len(edata) == 131 + assert edata == etoolkit.EtoolkitInstance.encrypt( + 'The very secret passwd', 'Nobody expects the Spanish inquisition' + ) + + +@unittest.mock.patch('os.urandom') +def test_encrypt_staticly_with_padding(urandom, non_random_bytes_61): + """Tests the EtoolkitInstance.encrypt method always with the same salt""" + urandom.return_value = non_random_bytes_61 edata = etoolkit.EtoolkitInstance.encrypt('The very secret passwd', 'bar') assert edata == ( - 'enc-val$1$uYpZM1VfAGq0CDZL2duITs076CQj+hIFEgx+F4mn80' - 'o=$HjPFNv6xC5hbMrFc0L5lSkWdfQ==' + 'enc-val$2$RCSZqq9pWrRDoCVYVHopyu1LzaJGfv8roVviqrLTBxM=$' + '+Yo6Ya2MAVcBLTQHuATkyFc+dzYsL/ESvA6ofOUDsiKZvIff35cUHAmoNxVuGG+MXv4=' ) assert edata == etoolkit.EtoolkitInstance.encrypt( - 'The very secret passwd', - 'bar', + 'The very secret passwd', 'bar' ) @@ -91,7 +171,7 @@ def test_get_new_password_hash(): 'The very secret passwd' ) # all pbkdf2 params are the same / hardcoded for the time being - assert new_hash.startswith('pbkdf2_sha256$100000$') + assert new_hash.startswith('pbkdf2_sha256$500000$') assert len(new_hash) == 110 # the hash should always be different because of random salting assert new_hash != etoolkit.EtoolkitInstance.get_new_password_hash( -- cgit v1.3