Question: I have he following R functions that use the sodium R package to encrypt and decrypt an access key with a password: encrypt_access_key <- function(access_key, password) { key <- sha256(charToRaw(password)) nonce <- random(24) # Generate a random nonce encrypted <- data_encrypt(charToRaw(access_key), key, nonce) list( encrypted_access_key = base64encode(encrypted), nonce = base64encode(nonce) ) } decrypt_access_key <- function(encrypted_access_key, nonce, password) { key <- sha256(charToRaw(password)) encrypted_raw <- base64decode(encrypted_access_key) nonce_raw <- base64decode(nonce) rawToChar(data_decrypt(encrypted_raw, key, nonce_raw)) }  I want to create a python function that mimics the functionality of the decrypt_access_key function, but I have not been able to do so... In case it is useful, here is the documentation for the data_encrypt and data_decrypt functions from the sodium package: link Edit: Here is a reproducible example encripted_message <- encrypt_access_key("This is a hidden message", "Example123") decrypt_access_key(encripted_message$encrypted_access_key, encripted_message$nonce, "Example123")  There is no need to replicate the functionality of encrypt_access_key, all I need is a python function that can get the string stored as encripted_message$encrypted_access_key and decrypt the message Edit 2: Here is the reproductible example with the explicit value of the nonce and the encrypted message decrypt_access_key(encrypted_access_key = "QG42J4fSVcY9luHaXiEhQcR85isjgUlmFc97pMHIIwuxQyZzDNpz2w==", nonce = "LpO7fBaCs1iobxDxVmOPFycTe/BCifqh", password = "Example123")  And here is one of the failed attempts to decrypt the message using python: import base64 from Crypto.Cipher import ChaCha20_Poly1305 from Crypto.Protocol.KDF import PBKDF2 import hashlib def decrypt_access_key(encrypted_access_key, nonce, password): # Decode the base64 encoded components encrypted_access_key_bytes = base64.b64decode(encrypted_access_key) nonce_bytes = base64.b64decode(nonce) # Derive the key using PBKDF2 key = hashlib.pbkdf2_hmac('sha256', password.encode(), b'', 100000) # Decrypt the access key using ChaCha20-Poly1305 cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce_bytes) decrypted = cipher.decrypt(encrypted_access_key_bytes) return decrypted.decode('utf-8') # Example usage encrypted_access_key = 'QG42J4fSVcY9luHaXiEhQcR85isjgUlmFc97pMHIIwuxQyZzDNpz2w==' nonce = 'LpO7fBaCs1iobxDxVmOPFycTe/BCifqh' password = 'Example123' decrypted_access_key = decrypt_access_key(encrypted_access_key, nonce, password) print(decrypted_access_key) 

Answer: The R code for encryption derives the key from a password using SHA256 and performs authenticated encryption with SecretBox, which uses XSalsa20 and Poly1305 under the hood, see here. The result returns the (24 bytes) nonce and the concatenation of ciphertext and (16 bytes) tag separately. The posted Python code is not compatible with SecretBox. A possible NaCl/Libsodium Python port that supports SecretBox is PyNaCl. In contrast to the R library, PyNaCl returns the concatenation of nonce, ciphertext and tag as the result of the encryption, and requires the concatenation of nonce, ciphertext and tag during decryption: import nacl.secret import hashlib import base64 key = hashlib.sha256(b'Example123').digest() box = nacl.secret.SecretBox(key) nonceB64 = 'LpO7fBaCs1iobxDxVmOPFycTe/BCifqh' ciphertextTagB64 = 'QG42J4fSVcY9luHaXiEhQcR85isjgUlmFc97pMHIIwuxQyZzDNpz2w==' nonceCiphertextTag = base64.b64decode(nonceB64) + base64.b64decode(ciphertextTagB64) decrypted = box.decrypt(nonceCiphertextTag) print(decrypted.decode('utf-8')) # This is a hidden message   Note that the use of a fast digest such as SHA256 is a vulnerability. It is more secure to use a reliable key derivation function, at least PBKDF2, or even better the more modern algorithms mentioned in the Libsodium documentation (Argon2, Scrypt), see here.