Esempio n. 1
0
def encrypt_data(key, plaintext):
    assert isinstance(key, type(b"")), type(key)
    assert isinstance(plaintext, type(b"")), type(plaintext)
    assert len(key) == SecretBox.KEY_SIZE, len(key)
    box = SecretBox(key)
    nonce = utils.random(SecretBox.NONCE_SIZE)
    return box.encrypt(plaintext, nonce)
Esempio n. 2
0
    def decrypt(self, data, password, salt):
        salt = self._fix_salt(salt)
        key = hash_password_raw(password, hash_len=32, salt=salt)
        box = SecretBox(key)
        data = box.decrypt(data, encoder=nacl.encoding.Base64Encoder)

        return data
Esempio n. 3
0
 def __init__(self, skt, send_key, receive_key):
     self.skt = skt
     self.send_box = SecretBox(send_key)
     self.send_nonce = 0
     self.receive_buf = ReceiveBuffer(self.skt)
     self.receive_box = SecretBox(receive_key)
     self.next_receive_nonce = 0
 def _encrypt_data(self, key, data):
     assert isinstance(key, type(b"")), type(key)
     assert isinstance(data, type(b"")), type(data)
     if len(key) != SecretBox.KEY_SIZE: raise UsageError
     box = SecretBox(key)
     nonce = utils.random(SecretBox.NONCE_SIZE)
     return box.encrypt(data, nonce)
Esempio n. 5
0
 def _decrypt_data(self, key, encrypted):
     assert isinstance(key, type(b"")), type(key)
     assert isinstance(encrypted, type(b"")), type(encrypted)
     if len(key) != SecretBox.KEY_SIZE: raise UsageError
     box = SecretBox(key)
     data = box.decrypt(encrypted)
     return data
Esempio n. 6
0
 def _encrypt_data(self, key, data):
     assert isinstance(key, type(b"")), type(key)
     assert isinstance(data, type(b"")), type(data)
     if len(key) != SecretBox.KEY_SIZE: raise UsageError
     box = SecretBox(key)
     nonce = utils.random(SecretBox.NONCE_SIZE)
     return box.encrypt(data, nonce)
Esempio n. 7
0
    def unpack_packet(self, data: bytes) -> Tuple[int, int, int, bytes]:
        """
        Unpacks a voice packet received from Discord.

        :param data: The data to unpack.
        :return: A tuple of (ssrc, sequence, timestamp, data).
        """
        header = data[:12]
        encrypted_data = data[12:]

        # unpack header data
        type_ = header[0]
        version = header[1]
        sequence = struct.unpack(">H", header[2:4])[0]
        timestamp = struct.unpack(">I", header[4:8])[0]
        ssrc = struct.unpack(">I", header[8:12])[0]

        # okay, for some reason discord sends malformed packets
        # 0x90 as type means we need to chop off the first 8 bytes from the decrypted data
        # because it's invalid opus
        # first, decrypt the data

        nonce = bytearray(24)
        nonce[:12] = header

        encryptor = SecretBox(bytes(self.vs_ws.secret_key))
        decrypted = encryptor.decrypt(encrypted_data, nonce=bytes(nonce))

        if type_ == 0x90:
            decrypted = decrypted[8:]

        pcm_frames = self.decoder.decode(decrypted, 960)

        return ssrc, sequence, timestamp, pcm_frames
Esempio n. 8
0
def encrypt_for_node(identity: Identity, public_key: str,
                     payload: Union[str, bytes]) -> str:
    """
    encrypt payload using a nacl.SecretBox with a shared key derived from the public key of the node and private key of the user

    Args:
      identity(Identity): the identity object that contains the key pair of the user
      public_key(str): public key of the node, hex-encoded
      payload(Union[str, bytes]): any data you want to encrypt

    Returns:
      str: hex-encoded encrypted data. you can use this safely into your reservation data

    """
    user_private = identity.nacl.signing_key.to_curve25519_private_key(
    ).encode()

    node_verify_bin = binascii.unhexlify(public_key)
    node_public = VerifyKey(node_verify_bin).to_curve25519_public_key()
    node_public = node_public.encode()

    shared_secret = crypto_scalarmult(user_private, node_public)
    h = blake2b(shared_secret, digest_size=32)
    key = h.digest()

    if isinstance(payload, str):
        payload = payload.encode()

    box = SecretBox(key)
    encrypted = box.encrypt(payload)
    return binascii.hexlify(encrypted)
Esempio n. 9
0
def step4_api2():
    hkdf_salt = random(32)
    nodeid = do_priv("get_nodeid")
    to_server_key = get_subkey("to_server", hkdf_salt)
    ciphertext = SecretBox(to_server_key).encrypt(nodeid.encode())

    try:
        with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as s:
            s.settimeout(5)
            s.connect((bootstrap_ipv6, 1337))

            assert(len(hkdf_salt) < 256)
            s.sendall(len(hkdf_salt).to_bytes(1, byteorder='big') + hkdf_salt)
            assert(len(ciphertext) < 256)
            s.sendall(len(ciphertext).to_bytes(1, byteorder='big') + ciphertext)

            num_bytes = int.from_bytes(s.recv(1), byteorder='big')
            resp=b''
            while len(resp) < num_bytes:
                resp += s.recv(num_bytes - len(resp))
    except (OSError, socket.timeout):
        abort(404, "Not found")

    from_server_key = get_subkey("from_server", hkdf_salt)
    global network_id
    network_id = SecretBox(from_server_key).decrypt(resp).decode()

    #XXX Do we need to leave networks with overlapping IP space? Better to warn?
    do_priv("leaveall private")
    do_priv("join %s" % network_id)

    return "ok"
Esempio n. 10
0
class RecordPipe:
    def __init__(self, skt, send_key, receive_key):
        self.skt = skt
        self.send_box = SecretBox(send_key)
        self.send_nonce = 0
        self.receive_buf = ReceiveBuffer(self.skt)
        self.receive_box = SecretBox(receive_key)
        self.next_receive_nonce = 0

    def send_record(self, record):
        if not isinstance(record, type(b"")): raise UsageError
        assert SecretBox.NONCE_SIZE == 24
        assert self.send_nonce < 2**(8*24)
        assert len(record) < 2**(8*4)
        nonce = unhexlify("%048x" % self.send_nonce) # big-endian
        self.send_nonce += 1
        encrypted = self.send_box.encrypt(record, nonce)
        length = unhexlify("%08x" % len(encrypted)) # always 4 bytes long
        send_to(self.skt, length)
        send_to(self.skt, encrypted)

    def receive_record(self):
        length_buf = self.receive_buf.read(4)
        length = int(hexlify(length_buf), 16)
        encrypted = self.receive_buf.read(length)
        nonce_buf = encrypted[:SecretBox.NONCE_SIZE] # assume it's prepended
        nonce = int(hexlify(nonce_buf), 16)
        if nonce != self.next_receive_nonce:
            raise BadNonce("received out-of-order record")
        self.next_receive_nonce += 1
        record = self.receive_box.decrypt(encrypted)
        return record

    def close(self):
        self.skt.close()
Esempio n. 11
0
 def _encrypt_data(self, key, data):
     assert isinstance(key, type(b"")), type(key)
     assert isinstance(data, type(b"")), type(data)
     assert len(key) == SecretBox.KEY_SIZE, len(key)
     box = SecretBox(key)
     nonce = utils.random(SecretBox.NONCE_SIZE)
     return box.encrypt(data, nonce)
Esempio n. 12
0
def encrypt_message(secret, topic, message):
    """Encrypt message."""

    keylen = SecretBox.KEY_SIZE

    if isinstance(secret, dict):
        key = secret.get(topic)
    else:
        key = secret

    if key is None:
        _LOGGER.warning(
            "Unable to encrypt payload because no decryption key known "
            "for topic %s",
            topic,
        )
        return None

    key = key.encode("utf-8")
    key = key[:keylen]
    key = key.ljust(keylen, b"\0")

    try:
        message = message.encode("utf-8")
        payload = SecretBox(key).encrypt(message, encoder=Base64Encoder)
        _LOGGER.debug("Encrypted message: %s to %s", message, payload)
        return payload.decode("utf-8")
    except ValueError:
        _LOGGER.warning("Unable to encrypt message for topic %s", topic)
        return None
Esempio n. 13
0
def encrypt(message, keyPath):
    """
    Encrypts a message given a path to a local file containing a key.

    :param message: The message to be encrypted.
    :param keyPath: A path to a file containing a 256-bit key (and nothing else).
    :type message: str
    :type keyPath: str
    :rtype: str

    A constant overhead is added to every encrypted message (for the nonce and MAC).
    >>> import tempfile
    >>> k = tempfile.mktemp()
    >>> with open(k, 'w') as f:
    ...     f.write(nacl.utils.random(SecretBox.KEY_SIZE))
    >>> message = 'test'
    >>> len(encrypt(message, k)) == overhead + len(message)
    True
    """
    with open(keyPath) as f:
        key = f.read()
    if len(key) != SecretBox.KEY_SIZE:
        raise ValueError("Key is %d bytes, but must be exactly %d bytes" %
                         (len(key), SecretBox.KEY_SIZE))
    sb = SecretBox(key)
    # We generate the nonce using secure random bits. For long enough
    # nonce size, the chance of a random nonce collision becomes
    # *much* smaller than the chance of a subtle coding error causing
    # a nonce reuse. Currently the nonce size is 192 bits--the chance
    # of a collision is astronomically low. (This approach is
    # recommended in the libsodium documentation.)
    nonce = nacl.utils.random(SecretBox.NONCE_SIZE)
    assert len(nonce) == SecretBox.NONCE_SIZE
    return str(sb.encrypt(message, nonce))
Esempio n. 14
0
 def add_third_party_caveat(self,
                            macaroon,
                            location,
                            key,
                            key_id,
                            nonce=None,
                            **kwargs):
     derived_key = truncate_or_pad(
         generate_derived_key(convert_to_bytes(key))
     )
     old_key = truncate_or_pad(binascii.unhexlify(macaroon.signature_bytes))
     box = SecretBox(key=old_key)
     nonce = nonce or nacl.utils.random(box.NONCE_SIZE)
     verification_key_id = box.encrypt(
         derived_key, nonce=nonce
     )
     caveat = Caveat(
         caveat_id=key_id,
         location=location,
         verification_key_id=verification_key_id
     )
     macaroon.caveats.append(caveat)
     encode_key = binascii.unhexlify(macaroon.signature_bytes)
     macaroon.signature = sign_third_party_caveat(
         encode_key,
         caveat._verification_key_id,
         caveat._caveat_id
     )
     return macaroon
Esempio n. 15
0
    def decryptFile(self, inpPath, outPath, hexKey, chunkSize=65536):
        """Decrypt the data in the input file store the result in the output file.

        Args:
            inpPath ([type]): input file path (encrypted)
            outPath ([type]): output file path
            hexKey ([type]): encryption key
            chunkSize (int, optional): the size of incremental copy operations. Defaults to 65536.

        Returns:
            (bool): True for success or False otherwise
        """
        try:
            box = SecretBox(hexKey.encode("utf-8"), encoder=HexEncoder)
            tL = []
            with open(inpPath, "rb") as ifh:
                while True:
                    chunk = ifh.read(chunkSize)
                    if not chunk:
                        break
                    tL.append(chunk)
            #
            enctxt = b"".join(tL)
            #
            txt = box.decrypt(enctxt)
            tL = [txt[i:i + chunkSize] for i in range(0, len(txt), chunkSize)]
            logger.debug("Chunks %d size %d", len(tL), len(txt))
            #
            with open(outPath, "wb") as ofh:
                for tV in tL:
                    ofh.write(tV)
            return True
        except Exception as e:
            logger.exception("Failing with %r", str(e))
        return False
Esempio n. 16
0
    async def read(self):
        if self.closed:
            return None
        try:
            data = await self.reader.readexactly(HEADER_LENGTH)
        except IncompleteReadError:
            self.closed = True
            return None

        box = SecretBox(self.key)

        header = box.decrypt(data, self.nonce)

        if header == TERMINATION_HEADER:
            self.closed = True
            return None

        length = struct.unpack('>H', header[:2])[0]
        mac = header[2:]

        data = await self.reader.readexactly(length)

        body = box.decrypt(mac + data, inc_nonce(self.nonce))

        self.nonce = inc_nonce(inc_nonce(self.nonce))
        return body
Esempio n. 17
0
    def read_data(self, escrowed_data, sign_key, layer_count=None):
        self.log.info('reading data from %d escrowed bytes', len(escrowed_data))

        # TODO: check that we're logged in

        post_data = {
            'escrow_data': escrowed_data,
            'sign_key': serial.dumps(sign_key)
        }
        if layer_count is not None:
            post_data['layer_count'] = layer_count

        self.log.debug('requesting read_data')
        r = requests.post(
            self.url + 'data', params=self.get_auth_params(), data=post_data)
        boxed_data = r.content
        self.log.debug('got %d byte response from read_data', len(boxed_data))

        self.log.debug('unboxing response')
        key = bcrypt.kdf(
            self.password.encode('utf-8'),
            self.challenge,
            SecretBox.KEY_SIZE, ITERATIONS
        )
        box = SecretBox(key)
        data = box.decrypt(boxed_data)
        self.log.debug('unboxed response, got %d bytes', len(data))

        return data
Esempio n. 18
0
class EncryptedSerializer(object):
    """Encrypt session state using PyNaCl.

    :type secret: bytes
    :param secret: a 32-byte random secret for encrypting/decrypting the
                   pickled session state.
    :param serializer:
        An object with two methods: ``loads`` and ``dumps``. The ``loads``
        method should accept bytes and return a Python object. The ``dumps``
        method should accept a Python object and return bytes. A ``ValueError``
        should be raised for malformed inputs. Default: ``None``, which will
        use :class:`pyramid.session.PickleSerializer`.
    """
    def __init__(self, secret, serializer=None):
        if len(secret) != SecretBox.KEY_SIZE:
            raise ValueError(
                "Secret should be a random bytes string of length %d" %
                SecretBox.KEY_SIZE)
        self.box = SecretBox(secret)

        if serializer is None:
            serializer = PickleSerializer()

        self.serializer = serializer

    def loads(self, bstruct):
        """Decrypt session state.

        :type encrypted_state: bytes
        :param encrypted_state: the encrypted session state.

        :rtype: :class:`dict` / picklable mapping
        :returns: the decrypted, unpickled session state, as passed as
                  ``session_state`` to :meth:`dumps`.
        """
        try:
            b64padding = b'=' * (-len(bstruct) % 4)
            fstruct = urlsafe_b64decode(bstruct + b64padding)
        except (binascii.Error, TypeError) as e:
            raise ValueError('Badly formed base64 data: %s' % e)

        try:
            payload = self.box.decrypt(fstruct)
        except CryptoError as e:
            raise ValueError('Possible tampering: %s' % e)
        return self.serializer.loads(payload)

    def dumps(self, session_state):
        """Encrypt session state.

        :type session_state: :class:`dict` / picklable mapping
        :param session_state: the session state to be encrypted.

        :rtype: bytes
        :returns: the encrypted session state
        """
        cstruct = self.serializer.dumps(session_state)
        nonce = random(SecretBox.NONCE_SIZE)
        fstruct = self.box.encrypt(cstruct, nonce)
        return urlsafe_b64encode(fstruct).rstrip(b'=')
Esempio n. 19
0
def decrypt(ciphertext, keyPath):
    """
    Decrypts a given message that was encrypted with the encrypt() method.

    :param ciphertext: The encrypted message (as a string).
    :param keyPath: A path to a file containing a 256-bit key (and nothing else).
    :type keyPath: str
    :rtype: str

    Raises an error if ciphertext was modified
    >>> import tempfile
    >>> k = tempfile.mktemp()
    >>> with open(k, 'w') as f:
    ...     f.write(nacl.utils.random(SecretBox.KEY_SIZE))
    >>> ciphertext = encrypt("testMessage", k)
    >>> ciphertext = chr(ord(ciphertext[0]) ^ 1) + ciphertext[1:]
    >>> decrypt(ciphertext, k)
    Traceback (most recent call last):
    ...
    CryptoError: Decryption failed. Ciphertext failed verification

    Otherwise works correctly
    >>> decrypt(encrypt("testMessage", k), k)
    'testMessage'
    """
    with open(keyPath) as f:
        key = f.read()
    if len(key) != SecretBox.KEY_SIZE:
        raise ValueError("Key is %d bytes, but must be exactly %d bytes" %
                         (len(key), SecretBox.KEY_SIZE))
    sb = SecretBox(key)
    # The nonce is kept with the message.
    return sb.decrypt(ciphertext)
    def handle(self, *args, **options):
        key = base64.b64decode(settings.PDK_BACKUP_KEY)

        for app in settings.INSTALLED_APPS:
            try:
                pdk_api = importlib.import_module(app + '.pdk_api')

                for encrypted_file in options['file']:
                    if os.path.exists(encrypted_file):
                        filename = os.path.basename(encrypted_file)

                        box = SecretBox(key)

                        with open(encrypted_file, 'rb') as backup_file:
                            content = box.decrypt(backup_file.read())

                            decompressed = bz2.decompress(content)

                            pdk_api.load_backup(filename, decompressed)
                    else:
                        raise RuntimeError(file + ' does not exist.')

            except ImportError:
                pass
            except AttributeError:
                pass
Esempio n. 21
0
    def __enter__(self) -> typing.Tuple[PrivateKey, PrivateKey]:
        """
        Provides a pair of private keys.
        """
        # Derive the key from the passphrase.
        derived = util.derive_passphrase(self.passphrase)

        sign_box = SecretBox(derived)
        enc_box = SecretBox(derived)

        # Decrypt, using the two nonces.
        s_d = sign_box.decrypt(self.key._private_signing_seed, self.key._private_signing_nonce)
        e_d = enc_box.decrypt(self.key._private_key_raw, self.key._private_nonce)

        # Generate a SigningKey out of the seed.
        self.sign = SigningKey(s_d)
        self.encrypt = PrivateKey(e_d)

        # Update the key's public keys.
        if self.key._public_key is None:
            self.key._public_key = self.encrypt.public_key

        if self.key._public_signing_key is None:
            self.key._public_signing_key = self.sign.verify_key

        return self.encrypt, self.sign
Esempio n. 22
0
    def __exit__(self, exc_type, exc_val, exc_tb):
        """
        Re-encrypt.
        """
        # Derive the key from the passphrase.
        derived = util.derive_passphrase(self.passphrase)

        # Generate two random nonces.
        nonce1 = random(SecretBox.NONCE_SIZE)
        nonce2 = random(SecretBox.NONCE_SIZE)

        sign_box = SecretBox(derived)
        enc_box = SecretBox(derived)

        s_p = self.sign.encode()
        e_p = self.encrypt.encode()

        s_e = sign_box.encrypt(s_p, nonce1)
        e_e = enc_box.encrypt(e_p, nonce2)

        # Update `self.key`.
        self.key._private_key_raw = e_e.ciphertext
        self.key._private_signing_key_raw = s_e.ciphertext

        # Bit of a mixed up name.
        self.key._private_nonce = e_e.nonce
        self.key._private_signing_nonce = s_e.nonce

        if exc_type is not None:
            raise exc_type(exc_val)
Esempio n. 23
0
def retrieve(sid, key):
    # Try to rename this sid's directory. This is an atomic operation on
    # POSIX file systems, meaning two concurrent requests cannot rename
    # the same directory -- for one of them, it will look like the
    # source directory does not exist. This also implicitly covers the
    # case where we try to retrieve an invalid sid.
    locked_sid = sid + '_locked'
    try:
        rename(join(DATA, sid), join(DATA, locked_sid))
    except OSError:
        return None, ALREADY_REVEALED

    # Now that we have "locked" this sid, we can safely read it and then
    # destroy it.
    with open(join(DATA, locked_sid, 'secret'), 'rb') as fp:
        secret_bytes = fp.read()
    run(['/usr/bin/shred', join(DATA, locked_sid, 'secret')])
    rmtree(join(DATA, locked_sid))

    # Restore padding. (No point in using something like a while loop
    # here, we checked for an explicit length earlier.)
    key += '='
    key = key.replace('_', '/')
    key_bytes = b64decode(key.encode('ASCII'))
    try:
        box = SecretBox(key_bytes)
        decrypted_bytes = box.decrypt(secret_bytes)
    except:
        return None, WRONG_KEY
    return decrypted_bytes.decode('UTF-8'), OK
Esempio n. 24
0
def store(secret):
    while True:
        try:
            # Again, mkdir is an atomic operation on POSIX file systems.
            # Two concurrent requests cannot store data into the same
            # directory.
            sid = generate_sid()
            mkdir(join(DATA, sid))
            break
        except FileExistsError:
            continue

    key_bytes = random(SecretBox.KEY_SIZE)
    box = SecretBox(key_bytes)

    with open(join(DATA, sid, 'secret'), 'wb') as fp:
        fp.write(box.encrypt(secret.encode('UTF-8')))

    # Turn key into base64 and remove padding, because it has the
    # potential of confusing users. ("Is this part of the URL?")
    key = str(b64encode(key_bytes), 'ASCII')
    key = key.replace('/', '_')
    key = key.rstrip('=')

    return sid, key
Esempio n. 25
0
def decrypt_data(key, encrypted):
    assert isinstance(key, type(b"")), type(key)
    assert isinstance(encrypted, type(b"")), type(encrypted)
    assert len(key) == SecretBox.KEY_SIZE, len(key)
    box = SecretBox(key)
    data = box.decrypt(encrypted)
    return data
Esempio n. 26
0
    def decrypt(self,
                edata: Tuple[bytes, bytes],
                privkey: bytes = None) -> bytes:
        """
        Decrypt data encrypted by ECIES
        edata = (ekey, edata)
            ekey is needed to reconstruct a DH secret
            edata encrypted by the block cipher
            privkey is optional private key if we want to use something else
            than what keypair uses
        """
        if isinstance(edata[0], tuple) and isinstance(edata[1], tuple):
            # In case it was re-encrypted data
            return self.decrypt_reencrypted(edata)

        ekey, edata = edata
        # When it comes to decrypt(), ekey[1] is always None
        # we could use that and save 2 bytes,
        # but it makes the code less readable
        ekey = umbral.EncryptedKey(ekey=ec.deserialize(API.PRE.ecgroup,
                                                       ekey[0]),
                                   re_id=ekey[1])
        if privkey is None:
            privkey = self._priv_key
        else:
            privkey = ec.deserialize(API.PRE.ecgroup, privkey)

        key = self.pre.decapsulate(privkey, ekey)
        cipher = SecretBox(key)
        return cipher.decrypt(edata)
 def encryptCredential(self, key, data):
     """Credential will be only encrypted here. Decryption is done via
     Javascript later at client browser."""
     assert type(key) == bytes and len(key) == 32
     assert type(data) == bytes
     box = SecretBox(key)
     return base64.b64encode(box.encrypt(data)).decode("ascii")
Esempio n. 28
0
def encrypt(message, key, output):
    message_bytes = message.encode('ascii')
    with open(key, mode="rb") as key_file:
        key = key_file.read()
    with open(output, "wb") as output_file:
        secret_box = SecretBox(key)
        output_file.write(secret_box.encrypt(message_bytes))
Esempio n. 29
0
 def _decrypt_data(self, key, encrypted):
     assert isinstance(key, type(b"")), type(key)
     assert isinstance(encrypted, type(b"")), type(encrypted)
     assert len(key) == SecretBox.KEY_SIZE, len(key)
     box = SecretBox(key)
     data = box.decrypt(encrypted)
     return data
Esempio n. 30
0
 def _decrypt_data(self, key, encrypted):
     assert isinstance(key, type(b"")), type(key)
     assert isinstance(encrypted, type(b"")), type(encrypted)
     if len(key) != SecretBox.KEY_SIZE: raise UsageError
     box = SecretBox(key)
     data = box.decrypt(encrypted)
     return data
Esempio n. 31
0
    def recv_msg(self, user, packet):
        '''
		INPUT
			* user		: user message is from 
			* packet	: encrypted message received
		OUTPUT
			* Decrypted message with appropriate 
		'''
        try:
            dec_packet = encoder.decode(packet)
            self.send_ratc[user] = PublicKey(dec_packet[:32])
            mac_packet = dec_packet[32:64]
            enc_msg = dec_packet[64:]
            dh_sec = get_DH_secret(self.recv_ratc[user], self.send_ratc[user])
            salt = hashlib.md5(dh_sec).digest()
            self.root_keys[user] = kdf(self.root_keys[user], slt=salt)
            box = SecretBox(self.root_keys[user])
            msg = box.decrypt(enc_msg)
            mac = hashlib.pbkdf2_hmac('sha256', msg, self.ad_number[user],
                                      1414)
            if mac == mac_packet:
                return msg
            else:
                raise Exception('VERIFICATION FAILED: Connection to [' + user +
                                '] aborted.')
        except Exception as e:
            print '[SALSAJAR: recv_msg] ' + str(e)
Esempio n. 32
0
 def add_third_party_caveat(self,
                            macaroon,
                            location,
                            key,
                            key_id,
                            **kwargs):
     derived_key = truncate_or_pad(
         generate_derived_key(convert_to_bytes(key))
     )
     old_key = truncate_or_pad(binascii.unhexlify(macaroon.signature_bytes))
     box = SecretBox(key=old_key)
     verification_key_id = box.encrypt(
         derived_key, nonce=kwargs.get('nonce')
     )
     caveat = Caveat(
         caveat_id=key_id,
         location=location,
         verification_key_id=verification_key_id,
         version=macaroon.version
     )
     macaroon.caveats.append(caveat)
     encode_key = binascii.unhexlify(macaroon.signature_bytes)
     macaroon.signature = sign_third_party_caveat(
         encode_key,
         caveat._verification_key_id,
         caveat._caveat_id
     )
     return macaroon
Esempio n. 33
0
def encrypt_data(key, plaintext):
    assert isinstance(key, type(b"")), type(key)
    assert isinstance(plaintext, type(b"")), type(plaintext)
    assert len(key) == SecretBox.KEY_SIZE, len(key)
    box = SecretBox(key)
    nonce = utils.random(SecretBox.NONCE_SIZE)
    return box.encrypt(plaintext, nonce)
Esempio n. 34
0
def encrypt_blocks(datablocks, debug):
    blockid_to_chunk = {}
    for V, block in enumerate(
        [datablocks[N] for N in range(0, len(datablocks))]):
        key = "%08x%08x" % (block.fileno, block.N)
        blockid_to_chunk[key] = V
    output = []
    phys_offs = 0
    for P, block in enumerate(datablocks):
        next_chunkid = blockid_to_chunk.get(
            "%08x%08x" % (block[0], block[1] + 1), 0xFFFFFFFF)
        nonce, encrypted_data = block_encrypt(block, nextid=next_chunkid)
        assert len(encrypted_data) == MAX_OUTER_LEN
        output.append(encrypted_data)
        if debug:
            key = sha512(block.secret, encoder=RawEncoder)
            box = SecretBox(key[:SecretBox.KEY_SIZE])
            data = box.decrypt(encrypted_data, nonce)
            assert len(data) == FRAME_LEN
            eprint("%4X %8X %s %4X %s %s %8X %s" %
                   (P, phys_offs, hexlify(encrypted_data[:4]), block.N,
                    sha512(block.secret)[:8], hexlify(
                        nonce[:4]), block.offset, sha512(data)[:8]))
        phys_offs += len(encrypted_data)
    return output
Esempio n. 35
0
class BoxStream(object):
    """
    i am a helper class for boxing datagrams in a unidirectional stream
    """
    key = attr.ib(validator=is_32bytes)
    initial_nonce = attr.ib(validator=is_24bytes)

    nonce = attr.ib(init=False, default=None)

    MAX_LEN = 4096

    def __attrs_post_init__(self):
        self.nonce = NonceCounter(self.initial_nonce,
                                  int(SecretBox.NONCE_SIZE))
        self.box = SecretBox(self.key)

    def encrypt(self, datagram):
        """
        SecretBox-encrypt the datagram and return ciphertext
        """
        assert len(datagram) < self.MAX_LEN
        encrypted_body = self.box.encrypt(datagram, nonce=self.nonce())
        return encrypted_body.ciphertext

    def decrypt(self, datagram):
        """
        given SecretBox`ed ciphertext, decrypt and return plaintext
        """
        assert len(datagram) < self.MAX_LEN
        payload = self.box.decrypt(datagram, nonce=self.nonce())
        return payload
Esempio n. 36
0
 def encrypt(self, data: bytes) -> bytes:
     """
     Raises:
         CryptoError: if key is invalid.
     """
     box = SecretBox(self)
     return box.encrypt(data)
Esempio n. 37
0
def encrypt(message, keyPath):
    """
    Encrypts a message given a path to a local file containing a key.

    :param message: The message to be encrypted.
    :param keyPath: A path to a file containing a 256-bit key (and nothing else).
    :type message: str
    :type keyPath: str
    :rtype: str

    A constant overhead is added to every encrypted message (for the nonce and MAC).
    >>> import tempfile
    >>> k = tempfile.mktemp()
    >>> with open(k, 'w') as f:
    ...     f.write(nacl.utils.random(SecretBox.KEY_SIZE))
    >>> message = 'test'
    >>> len(encrypt(message, k)) == encryptionOverhead + len(message)
    True
    """
    with open(keyPath) as f:
        key = f.read()
    if len(key) != SecretBox.KEY_SIZE:
        raise ValueError("Key is %d bytes, but must be exactly %d bytes" % (len(key),
                                                                            SecretBox.KEY_SIZE))
    sb = SecretBox(key)
    # We generate the nonce using secure random bits. For long enough
    # nonce size, the chance of a random nonce collision becomes
    # *much* smaller than the chance of a subtle coding error causing
    # a nonce reuse. Currently the nonce size is 192 bits--the chance
    # of a collision is astronomically low. (This approach is
    # recommended in the libsodium documentation.)
    nonce = nacl.utils.random(SecretBox.NONCE_SIZE)
    assert len(nonce) == SecretBox.NONCE_SIZE
    return str(sb.encrypt(message, nonce))
Esempio n. 38
0
def decrypt(ciphertext, keyPath):
    """
    Decrypts a given message that was encrypted with the encrypt() method.

    :param ciphertext: The encrypted message (as a string).
    :param keyPath: A path to a file containing a 256-bit key (and nothing else).
    :type keyPath: str
    :rtype: str

    Raises an error if ciphertext was modified
    >>> import tempfile
    >>> k = tempfile.mktemp()
    >>> with open(k, 'w') as f:
    ...     f.write(nacl.utils.random(SecretBox.KEY_SIZE))
    >>> ciphertext = encrypt("testMessage", k)
    >>> ciphertext = chr(ord(ciphertext[0]) ^ 1) + ciphertext[1:]
    >>> decrypt(ciphertext, k)
    Traceback (most recent call last):
    ...
    CryptoError: Decryption failed. Ciphertext failed verification

    Otherwise works correctly
    >>> decrypt(encrypt("testMessage", k), k)
    'testMessage'
    """
    with open(keyPath) as f:
        key = f.read()
    if len(key) != SecretBox.KEY_SIZE:
        raise ValueError("Key is %d bytes, but must be exactly %d bytes" % (len(key),
                                                                            SecretBox.KEY_SIZE))
    sb = SecretBox(key)
    # The nonce is kept with the message.
    return sb.decrypt(ciphertext)
Esempio n. 39
0
def test_secret_box_decryption_combined(key, nonce, plaintext, ciphertext):
    box = SecretBox(key, encoder=HexEncoder)

    combined = binascii.hexlify(binascii.unhexlify(nonce) + binascii.unhexlify(ciphertext))
    decrypted = binascii.hexlify(box.decrypt(combined, encoder=HexEncoder))

    assert decrypted == plaintext
Esempio n. 40
0
class RecordPipe:
    def __init__(self, skt, send_key, receive_key):
        self.skt = skt
        self.send_box = SecretBox(send_key)
        self.send_nonce = 0
        self.receive_buf = ReceiveBuffer(self.skt)
        self.receive_box = SecretBox(receive_key)
        self.next_receive_nonce = 0

    def send_record(self, record):
        if not isinstance(record, type(b"")): raise UsageError
        assert SecretBox.NONCE_SIZE == 24
        assert self.send_nonce < 2**(8 * 24)
        assert len(record) < 2**(8 * 4)
        nonce = unhexlify("%048x" % self.send_nonce)  # big-endian
        self.send_nonce += 1
        encrypted = self.send_box.encrypt(record, nonce)
        length = unhexlify("%08x" % len(encrypted))  # always 4 bytes long
        send_to(self.skt, length)
        send_to(self.skt, encrypted)

    def receive_record(self):
        length_buf = self.receive_buf.read(4)
        length = int(hexlify(length_buf), 16)
        encrypted = self.receive_buf.read(length)
        nonce_buf = encrypted[:SecretBox.NONCE_SIZE]  # assume it's prepended
        nonce = int(hexlify(nonce_buf), 16)
        if nonce != self.next_receive_nonce:
            raise BadNonce("received out-of-order record")
        self.next_receive_nonce += 1
        record = self.receive_box.decrypt(encrypted)
        return record

    def close(self):
        self.skt.close()
Esempio n. 41
0
 def _encrypt_data(self, key, data):
     assert isinstance(key, type(b"")), type(key)
     assert isinstance(data, type(b"")), type(data)
     assert len(key) == SecretBox.KEY_SIZE, len(key)
     box = SecretBox(key)
     nonce = utils.random(SecretBox.NONCE_SIZE)
     return box.encrypt(data, nonce)
def run_exchange(transport, key, nonce):
    box = SecretBox(key)
    line = transport.receive_line()
    decrypted = box.decrypt(util.hexstr_to_bytes(line))
    transport.send_line(decrypted.decode('utf-8'))
    encrypted = util.bytes_to_hexstr(box.encrypt(decrypted, nonce))
    transport.send_line(encrypted)
Esempio n. 43
0
 def __init__(self, skt, send_key, receive_key):
     self.skt = skt
     self.send_box = SecretBox(send_key)
     self.send_nonce = 0
     self.receive_buf = ReceiveBuffer(self.skt)
     self.receive_box = SecretBox(receive_key)
     self.next_receive_nonce = 0
Esempio n. 44
0
 def decrypt(self, ciphered: bytes) -> bytes:
     """
     Raises:
         CryptoError: if key is invalid.
     """
     box = SecretBox(self)
     return box.decrypt(ciphered)
Esempio n. 45
0
def encrypt(file, privkey, recipients):
    # ignores privkey and recipients for now
    key = random(SecretBox.KEY_SIZE)
    box = SecretBox(key)
    enc = box.encrypt(file.encode("utf-8"))
    jsondata = json.dumps({"version":"0.1","key":base64.b64encode(key).decode("utf-8")})
    return jsondata.encode("utf-8")+_separator+enc
Esempio n. 46
0
def test_secret_box_encryption_generates_different_nonces(key, nonce, plaintext, ciphertext):
    box = SecretBox(key, encoder=HexEncoder)

    nonce_0 = box.encrypt(binascii.unhexlify(plaintext), encoder=HexEncoder).nonce

    nonce_1 = box.encrypt(binascii.unhexlify(plaintext), encoder=HexEncoder).nonce

    assert nonce_0 != nonce_1
Esempio n. 47
0
def test_secret_box_optional_nonce(key, nonce, plaintext, ciphertext):
    box = SecretBox(key, encoder=HexEncoder)

    encrypted = box.encrypt(binascii.unhexlify(plaintext), encoder=HexEncoder)

    decrypted = binascii.hexlify(box.decrypt(encrypted, encoder=HexEncoder))

    assert decrypted == plaintext
Esempio n. 48
0
def handshake_initiate(private_key, redis_client):
    try:
        request = expect_json_request(bottle.request, INITIATE_SCHEMA)

        symmetric_key = redis_get_cookie(
            redis_client, request[INITIATE_COOKIE_FIELD])
        cookie_sbox = SecretBox(symmetric_key)
        cookie = cookie_sbox.decrypt(
            str(request[INITIATE_COOKIE_FIELD]), encoder=Base64Encoder)

        if len(cookie) != 2 * CURVE25519_KEY_BYTES:
            bottle.response.status = HTTP_INTERNAL_SERVER_ERROR
            return {'error': 'An invalid cookie was sent to the client.'}
        client_transient_pkey = PublicKey(cookie[0:CURVE25519_KEY_BYTES])
        transient_skey = PrivateKey(cookie[CURVE25519_KEY_BYTES:])

        if request[INITIATE_CLIENT_TRANSIENT_PKEY_FIELD] != \
           client_transient_pkey.encode(Base64Encoder):
            raise InvalidClientRequest(
                'Initiate: non matching transient public keys.')

        vouch_json = open_box(request[INITIATE_VOUCH_FIELD],
                              transient_skey, client_transient_pkey)
        vouch = parse_and_verify_json(vouch_json, VOUCH_SCHEMA)

        client_pkey = PublicKey(
            str(vouch[VOUCH_CLIENT_PKEY_FIELD]), encoder=Base64Encoder)
        vouch_for_transient_pkey = open_box(
            vouch[VOUCH_TRANSIENT_KEY_BOX_FIELD], private_key, client_pkey)
        if vouch_for_transient_pkey != client_transient_pkey.encode():
            raise InvalidClientRequest(
                'Initiate: non matching transient public keys.')

        resp = 'I believe you are {} and you want {}'.format(
            client_pkey.encode(Base64Encoder), vouch[VOUCH_MESSAGE_FIELD])
        print(resp)
        response_nonce = nacl.utils.random(Box.NONCE_SIZE)
        response_box = Box(transient_skey, client_transient_pkey)
        response_box_cipher = response_box.encrypt(
            resp, response_nonce, encoder=Base64Encoder)
        return {'response': response_box_cipher}
    except jsonschema.ValidationError as e:
        log.exception(e)
        bottle.response.status = HTTP_BAD_REQUEST
        return {'error': str(e)}
    except InvalidClientRequest as e:
        log.exception(e)
        bottle.response.status = HTTP_BAD_REQUEST
        return {'error': str(e)}
    except MissingCookie as e:
        log.exception(e)
        bottle.response.status = HTTP_BAD_REQUEST
        return {'error': str(e)}
    except CryptoError as e:
        log.exception(e)
        bottle.response.status = HTTP_BAD_REQUEST
        return {'error': 'Bad encryption in handshake.'}
    return {'error': ''}
Esempio n. 49
0
def test_secret_box_wrong_lengths():
    with pytest.raises(ValueError):
        SecretBox(b"")

    box = SecretBox(b"ec2bee2d5be613ca82e377c96a0bf2220d823ce980cdff6279473edc52862798", encoder=HexEncoder)
    with pytest.raises(ValueError):
        box.encrypt(b"", b"")
    with pytest.raises(ValueError):
        box.decrypt(b"", b"")
Esempio n. 50
0
def decrypt_list_entry(boxed, symkey, tmppub):
    sbox = SecretBox(symkey)
    msg = remove_prefix(sbox.decrypt(boxed),
                        "list:", NotListResponseError)
    (got_tmppub, fetch_token, delete_token,
     length) = struct.unpack(">32s32s32sQ", msg)
    if not equal(got_tmppub, tmppub):
        raise WrongPubkeyError
    return fetch_token, delete_token, length
Esempio n. 51
0
def test_secret_box_encryption(key, nonce, plaintext, ciphertext):
    box = SecretBox(key, encoder=HexEncoder)
    encrypted = box.encrypt(binascii.unhexlify(plaintext), binascii.unhexlify(nonce), encoder=HexEncoder)

    expected = binascii.hexlify(binascii.unhexlify(nonce) + binascii.unhexlify(ciphertext))

    assert encrypted == expected
    assert encrypted.nonce == nonce
    assert encrypted.ciphertext == ciphertext
Esempio n. 52
0
def test_secret_box_decryption(key, nonce, plaintext, ciphertext):
    box = SecretBox(key, encoder=HexEncoder)

    nonce = binascii.unhexlify(nonce)
    decrypted = binascii.hexlify(
        box.decrypt(ciphertext, nonce, encoder=HexEncoder),
    )

    assert decrypted == plaintext
Esempio n. 53
0
def create_list_entry(symkey, tmppub, length,
                      nonce=None, fetch_token=None, delete_token=None):
    assert len(tmppub) == 32
    fetch_token = fetch_token or os.urandom(32)
    delete_token = delete_token or os.urandom(32)
    msg = "list:" + struct.pack(">32s32s32sQ",
                                tmppub, fetch_token, delete_token, length)
    nonce = nonce or os.urandom(24)
    sbox = SecretBox(symkey)
    return sbox.encrypt(msg, nonce), fetch_token, delete_token
Esempio n. 54
0
class PassphraseBox(object):

    ITERATIONS = 90000

    # Given passphrase and plaintext as strings, returns a dict
    # containing the ciphertext and other values needed for later
    # decryption.  Binary values are encoded as hexadecimal strings.
    @classmethod
    def encrypt(cls, passphrase, plaintext):
        box = cls(passphrase)
        return box._encrypt(plaintext)

    # encrypted = dict(salt=salt, nonce=nonce, ciphertext=ciphertext)
    # PassphraseBox.decrypt("my great password", encrypted)
    @classmethod
    def decrypt(cls, passphrase, encrypted):
        salt = encrypted['salt']
        iterations = encrypted['iterations']

        return cls(passphrase, salt, iterations)._decrypt(
            encrypted['ciphertext'], encrypted['nonce'])

    # Initialize with an existing salt and iterations to allow
    # decryption.  Otherwise, creates new values for these, meaning
    # it creates an entirely new secret box.
    def __init__(self, passphrase, salt=None, iterations=None):
        passphrase = passphrase.encode('utf-8')
        self.salt = salt.decode('hex') if salt else urandom(16)
        if iterations:
            self.iterations = iterations
        else:
            # per OWASP, use a random number of iterations between 90k and 110k
            self.iterations = self.ITERATIONS + randint(0,20000)

        key = pbkdf2_bin(passphrase,
                         salt=self.salt,
                         iterations=self.iterations,
                         keylen=32)

        self.box = SecretBox(key)


    def _encrypt(self, plaintext):
        plaintext = plaintext.encode('utf-8')
        nonce = urandom(SecretBox.NONCE_SIZE)
        encrypted = self.box.encrypt(plaintext, nonce)
        ciphertext = encrypted.ciphertext
        return dict(
            salt=self.salt.encode('hex'), iterations=self.iterations,
            nonce=nonce.encode('hex'), ciphertext=ciphertext.encode('hex')
        )

    def _decrypt(self, ciphertext, nonce):
        return self.box.decrypt(ciphertext.decode('hex'), nonce.decode('hex'))
Esempio n. 55
0
 def _negotiationSuccessful(self):
     self.state = "records"
     self.setTimeout(None)
     send_key = self.owner._sender_record_key()
     self.send_box = SecretBox(send_key)
     self.send_nonce = 0
     receive_key = self.owner._receiver_record_key()
     self.receive_box = SecretBox(receive_key)
     self.next_receive_nonce = 0
     d, self._negotiation_d = self._negotiation_d, None
     d.callback(self)
Esempio n. 56
0
 def _encrypt_data(self, key, data):
     # Without predefined roles, we can't derive predictably unique keys
     # for each side, so we use the same key for both. We use random
     # nonces to keep the messages distinct, and we automatically ignore
     # reflections.
     # TODO: HKDF(side, nonce, key) ?? include 'side' to prevent
     # reflections, since we no longer compare messages
     assert isinstance(key, type(b"")), type(key)
     assert isinstance(data, type(b"")), type(data)
     assert len(key) == SecretBox.KEY_SIZE, len(key)
     box = SecretBox(key)
     nonce = utils.random(SecretBox.NONCE_SIZE)
     return box.encrypt(data, nonce)
    def test_records_good(self):
        # now make sure that outbound records are encrypted properly
        t, c, owner = self.make_connection()

        RECORD1 = b"record"
        c.send_record(RECORD1)
        buf = t.read_buf()
        expected = ("%08x" % (24+len(RECORD1)+16)).encode("ascii")
        self.assertEqual(hexlify(buf[:4]), expected)
        encrypted = buf[4:]
        receive_box = SecretBox(owner._sender_record_key())
        nonce_buf = encrypted[:SecretBox.NONCE_SIZE] # assume it's prepended
        nonce = int(hexlify(nonce_buf), 16)
        self.assertEqual(nonce, 0) # first message gets nonce 0
        decrypted = receive_box.decrypt(encrypted)
        self.assertEqual(decrypted, RECORD1)

        # second message gets nonce 1
        RECORD2 = b"record2"
        c.send_record(RECORD2)
        buf = t.read_buf()
        expected = ("%08x" % (24+len(RECORD2)+16)).encode("ascii")
        self.assertEqual(hexlify(buf[:4]), expected)
        encrypted = buf[4:]
        receive_box = SecretBox(owner._sender_record_key())
        nonce_buf = encrypted[:SecretBox.NONCE_SIZE] # assume it's prepended
        nonce = int(hexlify(nonce_buf), 16)
        self.assertEqual(nonce, 1)
        decrypted = receive_box.decrypt(encrypted)
        self.assertEqual(decrypted, RECORD2)

        # and that we can receive records properly
        inbound_records = []
        c.recordReceived = inbound_records.append

        RECORD3 = b"record3"
        send_box = SecretBox(owner._receiver_record_key())
        nonce_buf = unhexlify("%048x" % 0) # first nonce must be 0
        encrypted = send_box.encrypt(RECORD3, nonce_buf)
        length = unhexlify("%08x" % len(encrypted)) # always 4 bytes long
        c.dataReceived(length[:2])
        c.dataReceived(length[2:])
        c.dataReceived(encrypted[:-2])
        self.assertEqual(inbound_records, [])
        c.dataReceived(encrypted[-2:])
        self.assertEqual(inbound_records, [RECORD3])

        RECORD4 = b"record4"
        send_box = SecretBox(owner._receiver_record_key())
        nonce_buf = unhexlify("%048x" % 1) # nonces increment
        encrypted = send_box.encrypt(RECORD4, nonce_buf)
        length = unhexlify("%08x" % len(encrypted)) # always 4 bytes long
        c.dataReceived(length[:2])
        c.dataReceived(length[2:])
        c.dataReceived(encrypted[:-2])
        self.assertEqual(inbound_records, [RECORD3])
        c.dataReceived(encrypted[-2:])
        self.assertEqual(inbound_records, [RECORD3, RECORD4])
Esempio n. 58
0
def handshake_hello(private_key, redis_client):
    try:
        request = expect_json_request(bottle.request, HELLO_SCHEMA)
        client_transient_pkey = PublicKey(
            str(request[HELLO_CLIENT_TRANSIENT_PKEY_FIELD]), Base64Encoder)

        zeros = open_box(request[HELLO_ZEROS_BOX_FIELD],
                         private_key, client_transient_pkey)
        if len(zeros) != HELLO_PADDING_BYTES:
            raise InvalidClientRequest(
                'zeros_box should contain exactly %d bytes of padding' %
                HELLO_PADDING_BYTES)

        transient_skey = PrivateKey.generate()
        cookie_plain = client_transient_pkey.encode() + \
                       transient_skey.encode()
        cookie_nonce = nacl.utils.random(SecretBox.NONCE_SIZE)
        symmetric_key = nacl.utils.random(SecretBox.KEY_SIZE)
        cookie_sbox = SecretBox(symmetric_key)
        cookie = cookie_sbox.encrypt(
            cookie_plain, cookie_nonce, encoder=Base64Encoder)
        redis_set_cookie(redis_client, cookie, symmetric_key)

        cookie_box = Box(private_key, client_transient_pkey)
        cookie_box_nonce = nacl.utils.random(Box.NONCE_SIZE)
        server_tpkey = transient_skey.public_key.encode(Base64Encoder)
        cookie_box_cipher = cookie_box.encrypt(json.dumps({
            COOKIE_SERVER_TRANSIENT_PKEY_FIELD: server_tpkey,
            COOKIE_COOKIE_FIELD: cookie
        }), cookie_box_nonce, encoder=Base64Encoder)

        response = {COOKIE_COOKIE_BOX_FIELD: cookie_box_cipher}
        jsonschema.validate(response, COOKIE_SCHEMA)
        return response
    except jsonschema.ValidationError:
        log.exception(e)
        bottle.response.status = HTTP_INTERNAL_SERVER_ERROR
        return {'error': 'A packet with an invalid JSON schema was generated.'}
    except InvalidClientRequest as e:
        log.exception(e)
        bottle.response.status = HTTP_BAD_REQUEST
        return {'error': str(e)}
    except CryptoError as e:
        log.exception(e)
        bottle.response.status = HTTP_BAD_REQUEST
        return {'error': 'bad encryption'}
    return {'error': ''}
Esempio n. 59
0
class PassphraseBox:

    ITERATIONS = 10000

    @classmethod
    def encrypt(cls, passphrase, plaintext):
        box = cls(passphrase)
        return box._encrypt(plaintext)

    @classmethod
    def decrypt(cls, passphrase, encrypted):
        salt = encrypted['salt']
        iterations = encrypted['iterations']

        ppbox = cls(passphrase, salt, iterations)
        return ppbox._decrypt(encrypted['ciphertext'], encrypted['nonce'])

    def __init__(self, passphrase, salt=None, iterations=None):
        passphrase = passphrase.encode('utf-8')
        if salt is None:
            salt = random(16)
            iterations = self.ITERATIONS
        else:
            salt = salt.decode('hex')

        key = PBKDF2(passphrase, salt, 32, iterations)

        self.salt = salt
        self.iterations = iterations
        self.box = SecretBox(key)


    def _encrypt(self, plaintext):
        plaintext = plaintext.encode('utf-8')
        nonce = random(SecretBox.NONCE_SIZE)
        encrypted = self.box.encrypt(plaintext, nonce)
        ciphertext = encrypted.ciphertext
        return dict(
            salt=self.salt.encode('hex'), iterations=self.iterations,
            nonce=nonce.encode('hex'), ciphertext=ciphertext.encode('hex')
        )

    def _decrypt(self, ciphertext, nonce):
        return self.box.decrypt(ciphertext.decode('hex'), nonce.decode('hex'))
Esempio n. 60
0
async def test_webhook_handle_decryption(webhook_client,  # noqa: F811
                                         create_registrations):  # noqa: F401, F811, E501
    """Test that we can encrypt/decrypt properly."""
    try:
        # pylint: disable=unused-import
        from nacl.secret import SecretBox  # noqa: F401
        from nacl.encoding import Base64Encoder  # noqa: F401
    except (ImportError, OSError):
        pytest.skip("libnacl/libsodium is not installed")
        return

    import json

    keylen = SecretBox.KEY_SIZE
    key = create_registrations[0]['secret'].encode("utf-8")
    key = key[:keylen]
    key = key.ljust(keylen, b'\0')

    payload = json.dumps(RENDER_TEMPLATE['data']).encode("utf-8")

    data = SecretBox(key).encrypt(payload,
                                  encoder=Base64Encoder).decode("utf-8")

    container = {
        'type': 'render_template',
        'encrypted': True,
        'encrypted_data': data,
    }

    resp = await webhook_client.post(
        '/api/webhook/{}'.format(create_registrations[0]['webhook_id']),
        json=container
    )

    assert resp.status == 200

    webhook_json = await resp.json()
    assert 'encrypted_data' in webhook_json

    decrypted_data = SecretBox(key).decrypt(webhook_json['encrypted_data'],
                                            encoder=Base64Encoder)
    decrypted_data = decrypted_data.decode("utf-8")

    assert json.loads(decrypted_data) == {'one': 'Hello world'}