Authenticated encryption class Encryption algorithm: AES-CBC Signing algorithm: HMAC-SHA256
| 1947 | |
| 1948 | |
| 1949 | class Crypticle: |
| 1950 | """ |
| 1951 | Authenticated encryption class |
| 1952 | |
| 1953 | Encryption algorithm: AES-CBC |
| 1954 | Signing algorithm: HMAC-SHA256 |
| 1955 | """ |
| 1956 | |
| 1957 | PICKLE_PAD = b"pickle::" |
| 1958 | AES_BLOCK_SIZE = 16 |
| 1959 | SIG_SIZE = hashlib.sha256().digest_size |
| 1960 | |
| 1961 | def __init__(self, opts, key_string, key_size=192, serial=0): |
| 1962 | self.key_string = key_string |
| 1963 | self.keys = self.extract_keys(self.key_string, key_size) |
| 1964 | self.key_size = key_size |
| 1965 | self.serial = serial |
| 1966 | |
| 1967 | @classmethod |
| 1968 | def generate_key_string(cls, key_size=192, **kwargs): |
| 1969 | key = os.urandom(key_size // 8 + cls.SIG_SIZE) |
| 1970 | b64key = base64.b64encode(key) |
| 1971 | b64key = b64key.decode("utf-8") |
| 1972 | # Return data must be a base64-encoded string, not a unicode type |
| 1973 | return b64key.replace("\n", "") |
| 1974 | |
| 1975 | @classmethod |
| 1976 | def write_key(cls, path, key_size=192): |
| 1977 | directory = pathlib.Path(path).parent |
| 1978 | with salt.utils.files.set_umask(0o177): |
| 1979 | fd, tmp = tempfile.mkstemp(dir=directory, prefix="aes") |
| 1980 | os.close(fd) |
| 1981 | with salt.utils.files.fopen(tmp, "w") as fp: |
| 1982 | fp.write(cls.generate_key_string(key_size)) |
| 1983 | os.rename(tmp, path) |
| 1984 | |
| 1985 | @classmethod |
| 1986 | def read_key(cls, path): |
| 1987 | try: |
| 1988 | with salt.utils.files.fopen(path, "r") as fp: |
| 1989 | return fp.read() |
| 1990 | except FileNotFoundError: |
| 1991 | pass |
| 1992 | |
| 1993 | @classmethod |
| 1994 | def extract_keys(cls, key_string, key_size): |
| 1995 | key = salt.utils.stringutils.to_bytes(base64.b64decode(key_string)) |
| 1996 | assert len(key) == key_size / 8 + cls.SIG_SIZE, "invalid key" |
| 1997 | return key[: -cls.SIG_SIZE], key[-cls.SIG_SIZE :] |
| 1998 | |
| 1999 | def encrypt(self, data): |
| 2000 | """ |
| 2001 | encrypt data with AES-CBC and sign it with HMAC-SHA256 |
| 2002 | """ |
| 2003 | aes_key, hmac_key = self.keys |
| 2004 | pad = self.AES_BLOCK_SIZE - len(data) % self.AES_BLOCK_SIZE |
| 2005 | data = data + salt.utils.stringutils.to_bytes(pad * chr(pad)) |
| 2006 | iv_bytes = os.urandom(self.AES_BLOCK_SIZE) |
no outgoing calls
no test coverage detected