def decrypt(iv, key, ciphertext_bytes): """ Takes strings in and is expected to give strings out. All binary string conversion is internal only. """ assert type(iv) == bytes assert type(key) == bytes assert type(ciphertext_bytes) == bytes codec = AES.new(bytestring(key), AES.MODE_CFB, bytestring(iv)) return stdstring(codec.decrypt(ciphertext_bytes))
def encode_prop(iv_bytes, key_salt_bytes, ciphertext_bytes): assert type(iv_bytes) == bytes assert len(iv_bytes) == IV_BLOCK_SIZE assert type(key_salt_bytes) == bytes assert len(key_salt_bytes) == SALT_BLOCK_SIZE assert type(ciphertext_bytes) == bytes tmp = iv_bytes + key_salt_bytes + ciphertext_bytes payload = base64.b64encode(bytestring(tmp)) return "{" + stdstring(payload) + "}"
def decrypt(iv, key, ciphertext_bytes): """ Takes strings in and is expected to give strings out. All binary string conversion is internal only. """ assert type(iv) == bytes assert type(key) == bytes assert type(ciphertext_bytes) == bytes codec = crypto.AES.new(bytestring(key), crypto.AES.MODE_CFB, bytestring(iv)) msg = stdstring(codec.decrypt(ciphertext_bytes)) if msg[0] != '[' or msg[-1] != ']': return None, "Passphrase incorrect" return msg[1:-1], None
def encrypt_config(server_name, filename): """ Encrypt given server password. """ if not acmd.util.crypto.is_supported(): error( "Crypto functions are not supported on this system. Install pycrypto or pycryptodome" ) return USER_ERROR config = read_config(filename) section_name = 'server {}'.format(server_name) if not config.has_section(section_name): error("No section {} in config {}".format(server_name, filename)) return USER_ERROR plaintext_password = stdstring(config.get(section_name, PASSWORD_PROP)) assert type(plaintext_password) == str if is_encrypted(plaintext_password): error( "Password for server {} is already encrypted".format(server_name)) return USER_ERROR iv_bytes = acmd.util.crypto.random_bytes(IV_BLOCK_SIZE) assert type( iv_bytes ) == bytes # get_iv() is sometimes mocked and should be checked in tests key_salt = acmd.util.crypto.random_bytes(SALT_BLOCK_SIZE) key_bytes = get_key(key_salt, "Set passphrase: ") ciphertext_bytes = encrypt_str(iv_bytes, key_bytes, plaintext_password) prop = encode_prop(iv_bytes, key_salt, ciphertext_bytes) config.set(section_name, PASSWORD_PROP, prop) with open(filename, 'w') as f: config.write(f) return OK
def encrypt_config(server_name, filename): """ Encrypt given server password. """ config = read_config(filename) section_name = 'server {}'.format(server_name) if not config.has_section(section_name): error("No section {} in config {}".format(server_name, filename)) return USER_ERROR plaintext_password = stdstring(config.get(section_name, PASSWORD_PROP)) assert type(plaintext_password) == str if is_encrypted(plaintext_password): error( "Password for server {} is already encrypted".format(server_name)) return USER_ERROR # Put fixes on string to be able to recognize successful decryption formatted_password = "******" + plaintext_password + "]" iv_bytes = acmd.util.crypto.random_bytes(IV_BLOCK_SIZE) assert type( iv_bytes ) == bytes # get_iv() is sometimes mocked and should be checked in tests key_salt = acmd.util.crypto.random_bytes(SALT_BLOCK_SIZE) key_bytes = get_key(key_salt, "Set passphrase: ") ciphertext_bytes = encrypt_str(iv_bytes, key_bytes, formatted_password) prop = encode_prop(iv_bytes, key_salt, ciphertext_bytes) config.set(section_name, PASSWORD_PROP, prop) with open(filename, 'w') as f: config.write(f) return OK