Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions tests/pytests/unit/crypt/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
try:
import M2Crypto

HAS_M2 = True
except ImportError:
HAS_M2 = False

try:
from Cryptodome.PublicKey import RSA

HAS_PYCRYPTO_RSA = True
except ImportError:
HAS_PYCRYPTO_RSA = False

if not HAS_PYCRYPTO_RSA:
try:
from Crypto.PublicKey import RSA # nosec

HAS_PYCRYPTO_RSA = True
except ImportError:
HAS_PYCRYPTO_RSA = False
130 changes: 130 additions & 0 deletions tests/pytests/unit/crypt/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import pytest

import salt.utils.files


@pytest.fixture
def priv_key():
return (
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEpAIBAAKCAQEA75GR6ZTv5JOv90Vq8tKhKC7YQnhDIo2hM0HVziTEk5R4UQBW\n"
"a0CKytFMbTONY2msEDwX9iA0x7F5Lgj0X8eD4ZMsYqLzqjWMekLC8bjhxc+EuPo9\n"
"Dygu3mJ2VgRC7XhlFpmdo5NN8J2E7B/CNB3R4hOcMMZNZdi0xLtFoTfwU61UPfFX\n"
"14mV2laqLbvDEfQLJhUTDeFFV8EN5Z4H1ttLP3sMXJvc3EvM0JiDVj4l1TWFUHHz\n"
"eFgCA1Im0lv8i7PFrgW7nyMfK9uDSsUmIp7k6ai4tVzwkTmV5PsriP1ju88Lo3MB\n"
"4/sUmDv/JmlZ9YyzTO3Po8Uz3Aeq9HJWyBWHAQIDAQABAoIBAGOzBzBYZUWRGOgl\n"
"IY8QjTT12dY/ymC05GM6gMobjxuD7FZ5d32HDLu/QrknfS3kKlFPUQGDAbQhbbb0\n"
"zw6VL5NO9mfOPO2W/3FaG1sRgBQcerWonoSSSn8OJwVBHMFLG3a+U1Zh1UvPoiPK\n"
"S734swIM+zFpNYivGPvOm/muF/waFf8tF/47t1cwt/JGXYQnkG/P7z0vp47Irpsb\n"
"Yjw7vPe4BnbY6SppSxscW3KoV7GtJLFKIxAXbxsuJMF/rYe3O3w2VKJ1Sug1VDJl\n"
"/GytwAkSUer84WwP2b07Wn4c5pCnmLslMgXCLkENgi1NnJMhYVOnckxGDZk54hqP\n"
"9RbLnkkCgYEA/yKuWEvgdzYRYkqpzB0l9ka7Y00CV4Dha9Of6GjQi9i4VCJ/UFVr\n"
"UlhTo5y0ZzpcDAPcoZf5CFZsD90a/BpQ3YTtdln2MMCL/Kr3QFmetkmDrt+3wYnX\n"
"sKESfsa2nZdOATRpl1antpwyD4RzsAeOPwBiACj4fkq5iZJBSI0bxrMCgYEA8GFi\n"
"qAjgKh81/Uai6KWTOW2kX02LEMVRrnZLQ9VPPLGid4KZDDk1/dEfxjjkcyOxX1Ux\n"
"Klu4W8ZEdZyzPcJrfk7PdopfGOfrhWzkREK9C40H7ou/1jUecq/STPfSOmxh3Y+D\n"
"ifMNO6z4sQAHx8VaHaxVsJ7SGR/spr0pkZL+NXsCgYEA84rIgBKWB1W+TGRXJzdf\n"
"yHIGaCjXpm2pQMN3LmP3RrcuZWm0vBt94dHcrR5l+u/zc6iwEDTAjJvqdU4rdyEr\n"
"tfkwr7v6TNlQB3WvpWanIPyVzfVSNFX/ZWSsAgZvxYjr9ixw6vzWBXOeOb/Gqu7b\n"
"cvpLkjmJ0wxDhbXtyXKhZA8CgYBZyvcQb+hUs732M4mtQBSD0kohc5TsGdlOQ1AQ\n"
"McFcmbpnzDghkclyW8jzwdLMk9uxEeDAwuxWE/UEvhlSi6qdzxC+Zifp5NBc0fVe\n"
"7lMx2mfJGxj5CnSqQLVdHQHB4zSXkAGB6XHbBd0MOUeuvzDPfs2voVQ4IG3FR0oc\n"
"3/znuwKBgQChZGH3McQcxmLA28aUwOVbWssfXKdDCsiJO+PEXXlL0maO3SbnFn+Q\n"
"Tyf8oHI5cdP7AbwDSx9bUfRPjg9dKKmATBFr2bn216pjGxK0OjYOCntFTVr0psRB\n"
"CrKg52Qrq71/2l4V2NLQZU40Dr1bN9V+Ftd9L0pvpCAEAWpIbLXGDw==\n"
"-----END RSA PRIVATE KEY-----"
)


@pytest.fixture
def pub_key():
return (
"-----BEGIN PUBLIC KEY-----\n"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA75GR6ZTv5JOv90Vq8tKh\n"
"KC7YQnhDIo2hM0HVziTEk5R4UQBWa0CKytFMbTONY2msEDwX9iA0x7F5Lgj0X8eD\n"
"4ZMsYqLzqjWMekLC8bjhxc+EuPo9Dygu3mJ2VgRC7XhlFpmdo5NN8J2E7B/CNB3R\n"
"4hOcMMZNZdi0xLtFoTfwU61UPfFX14mV2laqLbvDEfQLJhUTDeFFV8EN5Z4H1ttL\n"
"P3sMXJvc3EvM0JiDVj4l1TWFUHHzeFgCA1Im0lv8i7PFrgW7nyMfK9uDSsUmIp7k\n"
"6ai4tVzwkTmV5PsriP1ju88Lo3MB4/sUmDv/JmlZ9YyzTO3Po8Uz3Aeq9HJWyBWH\n"
"AQIDAQAB\n"
"-----END PUBLIC KEY-----"
)


@pytest.fixture
def priv_key2():
return (
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEogIBAAKCAQEAp+8cTxguO6Vg+YO92VfHgNld3Zy8aM3JbZvpJcjTnis+YFJ7\n"
"Zlkcc647yPRRwY9nYBNywahnt5kIeuT1rTvTsMBZWvmUoEVUj1Xg8XXQkBvb9Ozy\n"
"Gqy/G/p8KDDpzMP/U+XCnUeHiXTZrgnqgBIc2cKeCVvWFqDi0GRFGzyaXLaX3PPm\n"
"M7DJ0MIPL1qgmcDq6+7Ze0gJ9SrDYFAeLmbuT1OqDfufXWQl/82JXeiwU2cOpqWq\n"
"7n5fvPOWim7l1tzQ+dSiMRRm0xa6uNexCJww3oJSwvMbAmgzvOhqqhlqv+K7u0u7\n"
"FrFFojESsL36Gq4GBrISnvu2tk7u4GGNTYYQbQIDAQABAoIBAADrqWDQnd5DVZEA\n"
"lR+WINiWuHJAy/KaIC7K4kAMBgbxrz2ZbiY9Ok/zBk5fcnxIZDVtXd1sZicmPlro\n"
"GuWodIxdPZAnWpZ3UtOXUayZK/vCP1YsH1agmEqXuKsCu6Fc+K8VzReOHxLUkmXn\n"
"FYM+tixGahXcjEOi/aNNTWitEB6OemRM1UeLJFzRcfyXiqzHpHCIZwBpTUAsmzcG\n"
"QiVDkMTKubwo/m+PVXburX2CGibUydctgbrYIc7EJvyx/cpRiPZXo1PhHQWdu4Y1\n"
"SOaC66WLsP/wqvtHo58JQ6EN/gjSsbAgGGVkZ1xMo66nR+pLpR27coS7o03xCks6\n"
"DY/0mukCgYEAuLIGgBnqoh7YsOBLd/Bc1UTfDMxJhNseo+hZemtkSXz2Jn51322F\n"
"Zw/FVN4ArXgluH+XsOhvG/MFFpojwZSrb0Qq5b1MRdo9qycq8lGqNtlN1WHqosDQ\n"
"zW29kpL0tlRrSDpww3wRESsN9rH5XIrJ1b3ZXuO7asR+KBVQMy/+NcUCgYEA6MSC\n"
"c+fywltKPgmPl5j0DPoDe5SXE/6JQy7w/vVGrGfWGf/zEJmhzS2R+CcfTTEqaT0T\n"
"Yw8+XbFgKAqsxwtE9MUXLTVLI3sSUyE4g7blCYscOqhZ8ItCUKDXWkSpt++rG0Um\n"
"1+cEJP/0oCazG6MWqvBC4NpQ1nzh46QpjWqMwokCgYAKDLXJ1p8rvx3vUeUJW6zR\n"
"dfPlEGCXuAyMwqHLxXgpf4EtSwhC5gSyPOtx2LqUtcrnpRmt6JfTH4ARYMW9TMef\n"
"QEhNQ+WYj213mKP/l235mg1gJPnNbUxvQR9lkFV8bk+AGJ32JRQQqRUTbU+yN2MQ\n"
"HEptnVqfTp3GtJIultfwOQKBgG+RyYmu8wBP650izg33BXu21raEeYne5oIqXN+I\n"
"R5DZ0JjzwtkBGroTDrVoYyuH1nFNEh7YLqeQHqvyufBKKYo9cid8NQDTu+vWr5UK\n"
"tGvHnwdKrJmM1oN5JOAiq0r7+QMAOWchVy449VNSWWV03aeftB685iR5BXkstbIQ\n"
"EVopAoGAfcGBTAhmceK/4Q83H/FXBWy0PAa1kZGg/q8+Z0KY76AqyxOVl0/CU/rB\n"
"3tO3sKhaMTHPME/MiQjQQGoaK1JgPY6JHYvly2KomrJ8QTugqNGyMzdVJkXAK2AM\n"
"GAwC8ivAkHf8CHrHa1W7l8t2IqBjW1aRt7mOW92nfG88Hck0Mbo=\n"
"-----END RSA PRIVATE KEY-----"
)


@pytest.fixture
def pub_key2():
return (
"-----BEGIN PUBLIC KEY-----\n"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+8cTxguO6Vg+YO92VfH\n"
"gNld3Zy8aM3JbZvpJcjTnis+YFJ7Zlkcc647yPRRwY9nYBNywahnt5kIeuT1rTvT\n"
"sMBZWvmUoEVUj1Xg8XXQkBvb9OzyGqy/G/p8KDDpzMP/U+XCnUeHiXTZrgnqgBIc\n"
"2cKeCVvWFqDi0GRFGzyaXLaX3PPmM7DJ0MIPL1qgmcDq6+7Ze0gJ9SrDYFAeLmbu\n"
"T1OqDfufXWQl/82JXeiwU2cOpqWq7n5fvPOWim7l1tzQ+dSiMRRm0xa6uNexCJww\n"
"3oJSwvMbAmgzvOhqqhlqv+K7u0u7FrFFojESsL36Gq4GBrISnvu2tk7u4GGNTYYQ\n"
"bQIDAQAB\n"
"-----END PUBLIC KEY-----"
)


@pytest.fixture
def msg():
return b"It's me, Mario"


@pytest.fixture
def sig():
return (
b"\x07\xf3\xb1\xe7\xdb\x06\xf4_\xe2\xdc\xcb!F\xfb\xbex{W\x1d\xe4E"
b"\xd3\r\xc5\x90\xca(\x05\x1d\x99\x8b\x1aug\x9f\x95>\x94\x7f\xe3+"
b"\x12\xfa\x9c\xd4\xb8\x02]\x0e\xa5\xa3LL\xc3\xa2\x8f+\x83Z\x1b\x17"
b'\xbfT\xd3\xc7\xfd\x0b\xf4\xd7J\xfe^\x86q"I\xa3x\xbc\xd3$\xe9M<\xe1'
b"\x07\xad\xf2_\x9f\xfa\xf7g(~\xd8\xf5\xe7\xda-\xa3Ko\xfc.\x99\xcf"
b"\x9b\xb9\xc1U\x97\x82'\xcb\xc6\x08\xaa\xa0\xe4\xd0\xc1+\xfc\x86"
b'\r\xe4y\xb1#\xd3\x1dS\x96D28\xc4\xd5\r\xd4\x98\x1a44"\xd7\xc2\xb4'
b"]\xa7\x0f\xa7Db\x85G\x8c\xd6\x94!\x8af1O\xf6g\xd7\x03\xfd\xb3\xbc"
b"\xce\x9f\xe7\x015\xb8\x1d]AHK\xa0\x14m\xda=O\xa7\xde\xf2\xff\x9b"
b"\x8e\x83\xc8j\x11\x1a\x98\x85\xde\xc5\x91\x07\x84!\x12^4\xcb\xa8"
b"\x98\x8a\x8a&#\xb9(#?\x80\x15\x9eW\xb5\x12\xd1\x95S\xf2<G\xeb\xf1"
b"\x14H\xb2\xc4>\xc3A\xed\x86x~\xcfU\xd5Q\xfe~\x10\xd2\x9b"
)


@pytest.fixture
def cryptodome_key_path(tmp_path, pub_key):
key_path = str(tmp_path / "cryptodome-3.4.6.pub")
with salt.utils.files.fopen(key_path, "wb") as fd:
fd.write(pub_key.encode())
return key_path
186 changes: 186 additions & 0 deletions tests/pytests/unit/crypt/test_crypt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
"""
tests.pytests.unit.test_crypt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Unit tests for salt's crypt module
"""

import os

import pytest

import salt.crypt
import salt.master
import salt.utils.files
import salt.utils.stringutils
from tests.pytests.unit.crypt import HAS_M2, HAS_PYCRYPTO_RSA
from tests.support.mock import MagicMock, MockCall, mock_open, patch

if HAS_PYCRYPTO_RSA:
from tests.pytests.unit.crypt import RSA


def test_get_rsa_pub_key_bad_key(tmp_path):
"""
get_rsa_pub_key raises InvalidKeyError when encountering a bad key
"""
key_path = str(tmp_path / "key")
with salt.utils.files.fopen(key_path, "w") as fp:
fp.write("")
Comment on lines +27 to +29
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
key_path = str(tmp_path / "key")
with salt.utils.files.fopen(key_path, "w") as fp:
fp.write("")
key_path = tmp_path / "key"
key_path.touch()

FYI

with pytest.raises(salt.crypt.InvalidKeyError):
salt.crypt.get_rsa_pub_key(key_path)


def test_verify_signature(pub_key, priv_key, tmp_path):
tmp_path.joinpath("foo.pem").write_text(priv_key.strip())
tmp_path.joinpath("foo.pub").write_text(pub_key.strip())
msg = b"foo bar"
sig = salt.crypt.sign_message(str(tmp_path.joinpath("foo.pem")), msg)
assert salt.crypt.verify_signature(str(tmp_path.joinpath("foo.pub")), msg, sig)


def test_verify_signature_bad_sig(pub_key2, priv_key, tmp_path):
tmp_path.joinpath("foo.pem").write_text(priv_key.strip())
tmp_path.joinpath("bar.pub").write_text(pub_key2.strip())
msg = b"foo bar"
sig = salt.crypt.sign_message(str(tmp_path.joinpath("foo.pem")), msg)
assert not salt.crypt.verify_signature(str(tmp_path.joinpath("bar.pub")), msg, sig)


@pytest.mark.skipif(not HAS_PYCRYPTO_RSA, reason="pycrypto >= 2.6 is not available")
@pytest.mark.skipif(HAS_M2, reason="m2crypto is used by salt.crypt if installed")
@pytest.mark.slow_test
def test_gen_keys():
open_priv_wb = MockCall("/keydir{}keyname.pem".format(os.sep), "wb+")
open_pub_wb = MockCall("/keydir{}keyname.pub".format(os.sep), "wb+")

with patch.multiple(
os,
umask=MagicMock(),
chmod=MagicMock(),
access=MagicMock(return_value=True),
):
with patch("salt.utils.files.fopen", mock_open()) as m_open, patch(
"os.path.isfile", return_value=True
):
result = salt.crypt.gen_keys("/keydir", "keyname", 2048)
assert result == "/keydir{}keyname.pem".format(os.sep), result
assert open_priv_wb not in m_open.calls
assert open_pub_wb not in m_open.calls

with patch("salt.utils.files.fopen", mock_open()) as m_open, patch(
"os.path.isfile", return_value=False
):
salt.crypt.gen_keys("/keydir", "keyname", 2048)
assert open_priv_wb in m_open.calls
assert open_pub_wb in m_open.calls


@pytest.mark.skipif(not HAS_PYCRYPTO_RSA, reason="pycrypto >= 2.6 is not available")
@pytest.mark.skipif(HAS_M2, reason="m2crypto is used by salt.crypt if installed")
@pytest.mark.slow_test
def test_gen_keys_with_passphrase():
key_path = os.path.join(os.sep, "keydir")
open_priv_wb = MockCall(os.path.join(key_path, "keyname.pem"), "wb+")
open_pub_wb = MockCall(os.path.join(key_path, "keyname.pub"), "wb+")

with patch.multiple(
os,
umask=MagicMock(),
chmod=MagicMock(),
chown=MagicMock(),
access=MagicMock(return_value=True),
):
with patch("salt.utils.files.fopen", mock_open()) as m_open, patch(
"os.path.isfile", return_value=True
):
assert salt.crypt.gen_keys(
key_path, "keyname", 2048, passphrase="password"
) == os.path.join(key_path, "keyname.pem")
result = salt.crypt.gen_keys(
key_path, "keyname", 2048, passphrase="password"
)
assert result == os.path.join(key_path, "keyname.pem"), result
assert open_priv_wb not in m_open.calls
assert open_pub_wb not in m_open.calls

with patch("salt.utils.files.fopen", mock_open()) as m_open, patch(
"os.path.isfile", return_value=False
):
salt.crypt.gen_keys(key_path, "keyname", 2048)
assert open_priv_wb in m_open.calls
assert open_pub_wb in m_open.calls


@pytest.mark.skipif(not HAS_PYCRYPTO_RSA, reason="pycrypto >= 2.6 is not available")
@pytest.mark.skipif(HAS_M2, reason="m2crypto is used by salt.crypt if installed")
def test_sign_message(priv_key, msg, sig):
key = RSA.importKey(priv_key)
with patch("salt.crypt.get_rsa_key", return_value=key):
assert sig == salt.crypt.sign_message("/keydir/keyname.pem", msg)


@pytest.mark.skipif(not HAS_PYCRYPTO_RSA, reason="pycrypto >= 2.6 is not available")
@pytest.mark.skipif(HAS_M2, reason="m2crypto is used by salt.crypt if installed")
def test_sign_message_with_passphrase(priv_key, msg, sig):
key = RSA.importKey(priv_key)
with patch("salt.crypt.get_rsa_key", return_value=key):
assert sig == salt.crypt.sign_message(
"/keydir/keyname.pem", msg, passphrase="password"
)


@pytest.mark.skipif(
not HAS_M2 and not HAS_PYCRYPTO_RSA,
reason="No crypto library found. Install either M2Crypto or Cryptodome to run this test",
)
def test_pwdata_decrypt():
key_string = """-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAzhBRyyHa7b63RLE71uKMKgrpulcAJjaIaN68ltXcCvy4w9pi
Kj+4I3Qp6RvUaHOEmymqyjOMjQc6iwpe0scCFqh3nUk5YYaLZ3WAW0htQVlnesgB
ZiBg9PBeTQY/LzqtudL6RCng/AX+fbnCsddlIysRxnUoNVMvz0gAmCY2mnTDjcTt
pyxuk2T0AHSHNCKCalm75L1bWDFF+UzFemf536tBfBUGRWR6jWTij85vvCntxHS/
HdknaTJ50E7XGVzwBJpCyV4Y2VXuW/3KrCNTqXw+jTmEw0vlcshfDg/vb3IxsUSK
5KuHalKq/nUIc+F4QCJOl+A10goGdIfYC1/67QIDAQABAoIBAAOP+qoFWtCTZH22
hq9PWVb8u0+yY1lFxhPyDdaZueUiu1r/coUCdv996Z+TEJgBr0AzdzVpsLtbbaKr
ujnwoNOdc/vvISPTfKN8P4zUcrcXgZd4z7VhR+vUH/0652q8m/ZDdHorMy2IOP8Z
cAk9DQ2PmA4TRm+tkX0G5KO8vWLsK921aRMWdsKJyQ0lYxl7M8JWupFsCJFr/U+8
dAVtwnUiS7RnhBABZ1cfNTHYhXVAh4d+a9y/gZ00a66OGqPxiXfhjjDUZ6fGvWKN
FlhKWEg6YqIx/H4aNXkLI5Rzzhdx/c2ukNm7+X2veRcAW7bcTwk8wxJxciEP5pBi
1el9VE0CgYEA/lbzdE2M4yRBvTfYYC6BqZcn+BqtrAUc2h3fEy+p7lwlet0af1id
gWpYpOJyLc0AUfR616/m2y3PwEH/nMKDSTuU7o/qKNtlHW0nQcnhDCjTUydS3+J/
JM3dhfgVqi03rjqNcgHA2eOEwcu/OBZtiaC0wqKbuRZRtfGffyoO3ssCgYEAz2iw
wqu/NkA+MdQIxz/a3Is7gGwoFu6h7O+XU2uN8Y2++jSBw9AzzWj31YCvyjuJPAE+
gxHm6yOnNoLVn423NtibHejhabzHNIK6UImH99bSTKabsxfF2BX6v982BimU1jwc
bYykzws37oN/poPb5FTpEiAUrsd2bAMn/1S43icCgYEAulHkY0z0aumCpyUkA8HO
BvjOtPiGRcAxFLBRXPLL3+vtIQachLHcIJRRf+jLkDXfiCo7W4pm6iWzTbqLkMEG
AD3/qowPFAM1Hct6uL01efzmYsIp+g0o60NMhvnolRQu+Bm4yM30AyqjdHzYBjSX
5fyuru8EeSCal1j8aOHcpuUCgYEAhGhDH6Pg59NPYSQJjpm3MMA59hwV473n5Yh2
xKyO6zwgRT6r8MPDrkhqnwQONT6Yt5PbwnT1Q/t4zhXsJnWkFwFk1U1MSeJYEa+7
HZsPECs2CfT6xPRSO0ac00y+AmUdPT8WruDwfbSdukh8f2MCR9vlBsswKPvxH7dM
G3aMplUCgYEAmMFgB/6Ox4OsQPPC6g4G+Ezytkc4iVkMEcjiVWzEsYATITjq3weO
/XDGBYJoBhYwWPi9oBufFc/2pNtWy1FKKXPuVyXQATdA0mfEPbtsHjMFQNZbeKnm
0na/SysSDCK3P+9ijlbjqLjMmPEmhJxGWTJ7khnTTkfre7/w9ZxJxi8=
-----END RSA PRIVATE KEY-----"""
pwdata = b"""\
V\x80+b\xca\x06M\xb6\x12\xc6\xe8\xf2\xb5\xbb\xd8m\xc0\x97\x9a\xeb\xb9q\x19\xc3\
\xcdi\xb84\x90\xaf\x12kT\xe2@u\xd6\xe8T\x89\xa3\xc7\xb2Y\xd1N\x00\xa9\xc0"\xbe\
\xed\xb1\xc3\xb7^\xbf\xbd\x8b\x13\xd3/L\x1b\xa1`\xe2\xea\x03\x98\x82\xf3uS&|\
\xe5\xd8J\xce\xfc\x97\x8d\x0b\x949\xc0\xbd^\xef\xc6\xfd\xce\xbb\x1e\xd0"(m\xe1\
\x95\xfb\xc8/\x07\x93\xb8\xda\x8f\x99\xfe\xdc\xd5\xcb\xdb\xb2\xf11M\xdbD\xcf\
\x95\x13p\r\xa4\x1c{\xd5\xdb\xc7\xe5\xaf\x95F\x97\xa9\x00p~\xb5\xec\xa4.\xd0\
\xa4\xb4\xf4f\xcds,Y/\xa1:WF\xb8\xc7\x07\xaa\x0b<\'~\x1b$D9\xd4\x8d\xf0x\xc5\
\xee\xa8:\xe6\x00\x10\xc5i\x11\xc7]C8\x05l\x8b\x9b\xc3\x83e\xf7y\xadi:0\xb4R\
\x1a(\x04&yL8\x19s\n\x11\x81\xfd?\xfb2\x80Ll\xa1\xdc\xc9\xb6P\xca\x8d\'\x11\xc1\
\x07\xa5\xa1\x058\xc7\xce\xbeb\x92\xbf\x0bL\xec\xdf\xc3M\x83\xfb$\xec\xd5\xf9\
"""
assert "1234" == salt.crypt.pwdata_decrypt(key_string, pwdata)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
assert "1234" == salt.crypt.pwdata_decrypt(key_string, pwdata)
assert salt.crypt.pwdata_decrypt(key_string, pwdata) == "1234"

https://gist.github.com/s0undt3ch/92d065815f4ce526345f72d40a40074d



@pytest.mark.skipif(HAS_M2, reason="Skip when m2crypto is installed")
def test_crypto_bad_key(cryptodome_key_path):
"""
Load public key with an invalid header and validate it without m2crypto
"""
key = salt.crypt.get_rsa_pub_key(cryptodome_key_path)
assert key.can_encrypt()
49 changes: 49 additions & 0 deletions tests/pytests/unit/crypt/test_crypticle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import uuid

import pytest

import salt.crypt
import salt.master
import salt.utils.files
import salt.utils.stringutils


def test_crypticle_dumps_no_nonce():
master_crypt = salt.crypt.Crypticle({}, salt.crypt.Crypticle.generate_key_string())
data = {"foo": "bar"}
ret = master_crypt.dumps(data)

# Validate message structure
assert isinstance(ret, bytes)
une = master_crypt.decrypt(ret)
une.startswith(master_crypt.PICKLE_PAD)
assert salt.payload.loads(une[len(master_crypt.PICKLE_PAD) :]) == data

# Validate load back to orig data
assert master_crypt.loads(ret) == data


def test_crypticle_dumps_valid_nonce():
nonce = uuid.uuid4().hex
master_crypt = salt.crypt.Crypticle({}, salt.crypt.Crypticle.generate_key_string())
data = {"foo": "bar"}
ret = master_crypt.dumps(data, nonce=nonce)

assert isinstance(ret, bytes)
une = master_crypt.decrypt(ret)
une.startswith(master_crypt.PICKLE_PAD)
nonce_and_data = une[len(master_crypt.PICKLE_PAD) :]
assert nonce_and_data.startswith(nonce.encode())
assert salt.payload.loads(nonce_and_data[len(nonce) :]) == data

assert master_crypt.loads(ret, nonce=nonce) == data


def test_crypticle_dumps_invalid_nonce():
nonce = uuid.uuid4().hex
master_crypt = salt.crypt.Crypticle({}, salt.crypt.Crypticle.generate_key_string())
data = {"foo": "bar"}
ret = master_crypt.dumps(data, nonce=nonce)
assert isinstance(ret, bytes)
with pytest.raises(salt.crypt.SaltClientError, match="Nonce verification error"):
assert master_crypt.loads(ret, nonce="abcde")
Comment on lines +48 to +49
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
with pytest.raises(salt.crypt.SaltClientError, match="Nonce verification error"):
assert master_crypt.loads(ret, nonce="abcde")
with pytest.raises(salt.crypt.SaltClientError, match="Nonce verification error"):
master_crypt.loads(ret, nonce="abcde")

Loading