Beispiel #1
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)
Beispiel #2
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
    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])
Beispiel #4
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"")
Beispiel #5
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
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'=')
Beispiel #7
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)
Beispiel #8
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
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()
Beispiel #10
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))
 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)
Beispiel #12
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)
Beispiel #13
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
Beispiel #14
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
Beispiel #15
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
Beispiel #16
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'))
Beispiel #17
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)
Beispiel #18
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': ''}
Beispiel #19
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'))
    def test_out_of_order_nonce(self):
        # an inbound out-of-order nonce should be rejected
        t, c, owner = self.make_connection()

        inbound_records = []
        c.recordReceived = inbound_records.append

        RECORD = b"record"
        send_box = SecretBox(owner._receiver_record_key())
        nonce_buf = unhexlify("%048x" % 1) # first nonce must be 0
        encrypted = send_box.encrypt(RECORD, nonce_buf)
        length = unhexlify("%08x" % len(encrypted)) # always 4 bytes long
        c.dataReceived(length)
        c.dataReceived(encrypted[:-2])
        self.assertEqual(inbound_records, [])
        self.assertRaises(transit.BadNonce, c.dataReceived, encrypted[-2:])
        self.assertEqual(inbound_records, [])
        # and the connection should have been dropped
        self.assertEqual(t._connected, False)
Beispiel #21
0
def test_secret_box_bad_decryption():
    box = SecretBox(b"\x11" * 32)
    ciphertext = box.encrypt(b"hello")

    with pytest.raises(CryptoError):
        # changes the nonce
        box.decrypt(flip_byte(ciphertext, 0))
    with pytest.raises(CryptoError):
        # changes ciphertext
        box.decrypt(flip_byte(ciphertext, 24))
    with pytest.raises(CryptoError):
        # changes MAC tag
        box.decrypt(flip_byte(ciphertext, len(ciphertext) - 1))

    with pytest.raises(CryptoError):
        # completely changes ciphertext and tag
        box.decrypt(ciphertext + b"\x00")
    with pytest.raises(CryptoError):
        # completely changes everything
        box.decrypt(b"\x00" + ciphertext)
class EncryptingPickleSerializer(object):
    """Encrypt pickled session state using PyNaCl.

    :type secret: bytes
    :param secret: a 32-byte random secret for encrypting/decrypting the
                   pickled session state.
    """
    def __init__(self, secret):
        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)

    def loads(self, encrypted_state):
        """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`.
        """
        payload = self.box.decrypt(urlsafe_b64decode(encrypted_state))
        return pickle.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
        """
        pickled = pickle.dumps(session_state)
        nonce = random(SecretBox.NONCE_SIZE)
        return urlsafe_b64encode(self.box.encrypt(pickled, nonce))
Beispiel #23
0
    def generate(cls, email: str, name: str, passphrase: str) -> typing.Tuple['Key', 'Key']:
        """
        Generate a new public/private key pair.

        This handles encipherment of the private keys.

        :param email: The email for the initial User ID.
        :param name: The name for the initial User ID.
        :param passphrase: The passphrase to encrypt the private key with.
        :return: A tuple containing a public and a private key.
        """
        privatekey = public.PrivateKey.generate()
        publickey = privatekey.public_key
        assert isinstance(privatekey, public.PrivateKey)
        assert isinstance(publickey, public.PublicKey)

        pub, priv = publickey.encode(), privatekey.encode()

        # Generate the signing key seed.
        seed = random(32)
        # Create the signing private key, temporary usage to extract the verify key.
        s_privatekey = signing.SigningKey(seed)
        s_publickey = s_privatekey.verify_key

        s_pub = s_publickey.encode()

        # Encrypt both private keys.
        key = derive_passphrase(passphrase.encode())
        # Use a random nonce, for now.
        nonce1 = random(SecretBox.NONCE_SIZE)
        nonce2 = random(SecretBox.NONCE_SIZE)

        # Encrypt both.
        sbox1 = SecretBox(key)
        sbox2 = SecretBox(key)

        priv = sbox1.encrypt(priv, nonce1)
        # Don't encrypt the s_privatekey; encrypt the seed.
        s_priv = sbox2.encrypt(seed, nonce2)

        # Create a pair of Keys.
        public_key = Key(public_key=pub, public_signing_key=s_pub)
        private_key = Key(private_key=priv.ciphertext, private_signing_seed=s_priv.ciphertext,
                          private_nonce=priv.nonce, private_signing_nonce=s_priv.nonce)

        del privatekey, priv, s_privatekey, s_priv
        # Force a GC collect.
        gc.collect()

        # Create the requested User ID.
        u = UserID(0, email, name)
        # We only add the user ID to the public key.
        public_key.userid = u

        # Generate the self-signature.
        to_hash = u.get_hash()
        # Sign the message using the private key.
        signature = private_key.sign_raw(passphrase, to_hash)
        public_key.self_signature = signature

        verified = public_key.verify_self_signature()
        if not verified:
            raise exc.BadSignature("The self-signature was invalid.")

        return public_key, private_key
 def encrypt(self, signature, field_data):
     encrypt_key = truncate_or_pad(signature)
     box = SecretBox(key=encrypt_key)
     encrypted = box.encrypt(convert_to_bytes(field_data), nonce=self.nonce)
     return self._signifier + standard_b64encode(encrypted)
Beispiel #25
0
def secret_box_encrypt(key_material: bytes, salt: bytes,
                       plaintext: bytes) -> bytes:
    wrapping_key = derive_wrapping_key_from_key_material(key_material, salt)
    secret_box = SecretBox(wrapping_key)
    ciphertext = secret_box.encrypt(plaintext)
    return ciphertext
def encrypt(secret_box: SecretBox, data: bytes):
    encrypted = secret_box.encrypt(data)
    assert len(
        encrypted) == len(data) + secret_box.NONCE_SIZE + secret_box.MACBYTES
    return encrypted
Beispiel #27
0
class Connection(protocol.Protocol, policies.TimeoutMixin):
    def __init__(self, owner, relay_handshake, start, description):
        self.state = "too-early"
        self.buf = b""
        self.owner = owner
        self.relay_handshake = relay_handshake
        self.start = start
        self._description = description
        self._negotiation_d = defer.Deferred(self._cancel)
        self._error = None
        self._consumer = None
        self._consumer_bytes_written = 0
        self._consumer_bytes_expected = None
        self._consumer_deferred = None
        self._inbound_records = deque()
        self._waiting_reads = deque()

    def connectionMade(self):
        self.setTimeout(TIMEOUT) # does timeoutConnection() when it expires
        self.factory.connectionWasMade(self)

    def startNegotiation(self):
        if self.relay_handshake is not None:
            self.transport.write(self.relay_handshake)
            self.state = "relay"
        else:
            self.state = "start"
        self.dataReceived(b"") # cycle the state machine
        return self._negotiation_d

    def _cancel(self, d):
        self.state = "hung up" # stop reacting to anything further
        self._error = defer.CancelledError()
        self.transport.loseConnection()
        # if connectionLost isn't called synchronously, then our
        # self._negotiation_d will have been errbacked by Deferred.cancel
        # (which is our caller). So if it's still around, clobber it
        if self._negotiation_d:
            self._negotiation_d = None


    def dataReceived(self, data):
        try:
            self._dataReceived(data)
        except Exception as e:
            self.setTimeout(None)
            self._error = e
            self.transport.loseConnection()
            self.state = "hung up"
            if not isinstance(e, BadHandshake):
                raise

    def _check_and_remove(self, expected):
        # any divergence is a handshake error
        if not self.buf.startswith(expected[:len(self.buf)]):
            raise BadHandshake("got %r want %r" % (self.buf, expected))
        if len(self.buf) < len(expected):
            return False # keep waiting
        self.buf = self.buf[len(expected):]
        return True

    def _dataReceived(self, data):
        # protocol is:
        #  (maybe: send relay handshake, wait for ok)
        #  send (send|receive)_handshake
        #  wait for (receive|send)_handshake
        #  sender: decide, send "go" or hang up
        #  receiver: wait for "go"
        self.buf += data

        assert self.state != "too-early"
        if self.state == "relay":
            if not self._check_and_remove(b"ok\n"):
                return
            self.state = "start"
        if self.state == "start":
            self.transport.write(self.owner._send_this())
            self.state = "handshake"
        if self.state == "handshake":
            if not self._check_and_remove(self.owner._expect_this()):
                return
            self.state = self.owner.connection_ready(self)
            # If we're the receiver, we'll be moved to state
            # "wait-for-decision", which means we're waiting for the other
            # side (the sender) to make a decision. If we're the sender,
            # we'll either be moved to state "go" (send GO and move directly
            # to state "records") or state "nevermind" (send NEVERMIND and
            # hang up).

        if self.state == "wait-for-decision":
            if not self._check_and_remove(b"go\n"):
                return
            self._negotiationSuccessful()
        if self.state == "go":
            GO = b"go\n"
            self.transport.write(GO)
            self._negotiationSuccessful()
        if self.state == "nevermind":
            self.transport.write(b"nevermind\n")
            raise BadHandshake("abandoned")
        if self.state == "records":
            return self.dataReceivedRECORDS()
        if self.state == "hung up":
            return
        if isinstance(self.state, Exception): # for tests
            raise self.state
        raise ValueError("internal error: unknown state %s" % (self.state,))

    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)

    def dataReceivedRECORDS(self):
        while True:
            if len(self.buf) < 4:
                return
            length = int(hexlify(self.buf[:4]), 16)
            if len(self.buf) < 4+length:
                return
            encrypted, self.buf = self.buf[4:4+length], self.buf[4+length:]

            record = self._decrypt_record(encrypted)
            self.recordReceived(record)

    def _decrypt_record(self, encrypted):
        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: got %d, expected %d"
                           % (nonce, self.next_receive_nonce))
        self.next_receive_nonce += 1
        record = self.receive_box.decrypt(encrypted)
        return record

    def describe(self):
        return self._description

    def send_record(self, record):
        if not isinstance(record, type(b"")): raise InternalError
        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
        self.transport.write(length)
        self.transport.write(encrypted)

    def recordReceived(self, record):
        if self._consumer:
            self._writeToConsumer(record)
            return
        self._inbound_records.append(record)
        self._deliverRecords()

    def receive_record(self):
        d = defer.Deferred()
        self._waiting_reads.append(d)
        self._deliverRecords()
        return d

    def _deliverRecords(self):
        while self._inbound_records and self._waiting_reads:
            r = self._inbound_records.popleft()
            d = self._waiting_reads.popleft()
            d.callback(r)

    def close(self):
        self.transport.loseConnection()
        while self._waiting_reads:
            d = self._waiting_reads.popleft()
            d.errback(error.ConnectionClosed())

    def timeoutConnection(self):
        self._error = BadHandshake("timeout")
        self.transport.loseConnection()

    def connectionLost(self, reason=None):
        self.setTimeout(None)
        d, self._negotiation_d = self._negotiation_d, None
        # the Deferred is only relevant until negotiation finishes, so skip
        # this if it's alredy been fired
        if d:
            # Each call to loseConnection() sets self._error first, so we can
            # deliver useful information to the Factory that's waiting on
            # this (although they'll generally ignore the specific error,
            # except for logging unexpected ones). The possible cases are:
            #
            # cancel: defer.CancelledError
            # far-end disconnect: BadHandshake("connection lost")
            # handshake error (something we didn't like): BadHandshake(what)
            # other error: some other Exception
            # timeout: BadHandshake("timeout")

            d.errback(self._error or BadHandshake("connection lost"))
        if self._consumer_deferred:
            self._consumer_deferred.errback(error.ConnectionClosed())

    # IConsumer methods, for outbound flow-control. We pass these through to
    # the transport. The 'producer' is something like a t.p.basic.FileSender
    def registerProducer(self, producer, streaming):
        assert interfaces.IConsumer.providedBy(self.transport)
        self.transport.registerProducer(producer, streaming)
    def unregisterProducer(self):
        self.transport.unregisterProducer()
    def write(self, data):
        self.send_record(data)

    # IProducer methods, for inbound flow-control. We pass these through to
    # the transport.
    def stopProducing(self):
        self.transport.stopProducing()
    def pauseProducing(self):
        self.transport.pauseProducing()
    def resumeProducing(self):
        self.transport.resumeProducing()

    # Helper methods

    def connectConsumer(self, consumer, expected=None):
        """Helper method to glue an instance of e.g. t.p.ftp.FileConsumer to
        us. Inbound records will be written as bytes to the consumer.

        Set 'expected' to an integer to automatically disconnect when at
        least that number of bytes have been written. This function will then
        return a Deferred (that fires with the number of bytes actually
        received). If the connection is lost while this Deferred is
        outstanding, it will errback. If 'expected' is 0, the Deferred will
        fire right away.

        If 'expected' is None, then this function returns None instead of a
        Deferred, and you must call disconnectConsumer() when you are done."""

        if self._consumer:
            raise RuntimeError("A consumer is already attached: %r" %
                               self._consumer)

        # be aware of an ordering hazard: when we call the consumer's
        # .registerProducer method, they are likely to immediately call
        # self.resumeProducing, which we'll deliver to self.transport, which
        # might call our .dataReceived, which may cause more records to be
        # available. By waiting to set self._consumer until *after* we drain
        # any pending records, we avoid delivering records out of order,
        # which would be bad.
        consumer.registerProducer(self, True)
        # There might be enough data queued to exceed 'expected' before we
        # leave this function. We must be sure to register the producer
        # before it gets unregistered.

        self._consumer = consumer
        self._consumer_bytes_written = 0
        self._consumer_bytes_expected = expected
        d = None
        if expected is not None:
            d = defer.Deferred()
        self._consumer_deferred = d
        if expected == 0:
            # write empty record to kick consumer into shutdown
            self._writeToConsumer(b"")
        # drain any pending records
        while self._consumer and self._inbound_records:
            r = self._inbound_records.popleft()
            self._writeToConsumer(r)
        return d

    def _writeToConsumer(self, record):
        self._consumer.write(record)
        self._consumer_bytes_written += len(record)
        if self._consumer_bytes_expected is not None:
            if self._consumer_bytes_written >= self._consumer_bytes_expected:
                d = self._consumer_deferred
                self.disconnectConsumer()
                d.callback(self._consumer_bytes_written)

    def disconnectConsumer(self):
        self._consumer.unregisterProducer()
        self._consumer = None
        self._consumer_bytes_expected = None
        self._consumer_deferred = None

    # Helper method to write a known number of bytes to a file. This has no
    # flow control: the filehandle cannot push back. 'progress' is an
    # optional callable which will be called on each write (with the number
    # of bytes written). Returns a Deferred that fires (with the number of
    # bytes written) when the count is reached or the RecordPipe is closed.

    def writeToFile(self, f, expected, progress=None, hasher=None):
        fc = FileConsumer(f, progress, hasher)
        return self.connectConsumer(fc, expected)
Beispiel #28
0
 def _encrypt(self, bin_data, key):
     key_data = self._get_key(key)
     public_box = SecretBox(key_data[1])
     return str(key_data[0]) + ':::' + str(public_box.encrypt(bin_data, self._get_nonce()))
Beispiel #29
0
 def encrypt_bytes(self, data: bytes, encoder=RawEncoder) -> bytes:
     box = SecretBox(self.key)
     return box.encrypt(data, None, encoder)
def secret_encrypt_content(cleartext):
    box = SecretBox(
        base64.b64decode(settings.PDK_EXTERNAL_CONTENT_SYMETRIC_KEY))

    return base64.b64encode(box.encrypt(cleartext))
Beispiel #31
0
class CurveCPServerDispatcher(DatagramProtocol):
    def __init__(self, reactor, serverKey, factory):
        self.reactor = reactor
        self.serverKey = serverKey
        self.factory = factory
        self.transports = {}
        self._secretBox = SecretBox(os.urandom(SecretBox.KEY_SIZE))

    def _replyWithCookie(self, data, host_port):
        if len(data) != _helloStruct.size:
            return
        serverExtension, clientExtension, clientShortPubkey, nonce, encrypted = _helloStruct.unpack(data)
        serverLongClientShort = Box(self.serverKey.key, PublicKey(clientShortPubkey))
        try:
            serverLongClientShort.decrypt(encrypted, 'CurveCP-client-H' + nonce)
        except CryptoError:
            return
        serverShortKey = PrivateKey.generate()
        unencryptedCookie = clientShortPubkey + str(serverShortKey)
        cookieNonce = self.serverKey.nonce(longterm=True)
        cookie = cookieNonce + self._secretBox.encrypt(unencryptedCookie, 'c' * 8 + cookieNonce).ciphertext
        boxData = str(serverShortKey.public_key) + cookie
        cookiePacket = (
            'RL3aNMXK'
            + clientExtension
            + serverExtension
            + cookieNonce
            + serverLongClientShort.encrypt(boxData, 'CurveCPK' + cookieNonce).ciphertext)
        self.transport.write(cookiePacket, host_port)

    def _checkInitiate(self, clientID, data, host_port):
        cookieNonce, encryptedCookie, nonce = _initiateStruct.unpack_from(data)
        try:
            decryptedCookie = self._secretBox.decrypt(encryptedCookie, 'c' * 8 + cookieNonce)
        except CryptoError:
            return
        clientShortPubkey = PublicKey(decryptedCookie[:32])
        serverShortKey = PrivateKey(decryptedCookie[32:])
        serverShortClientShort = Box(serverShortKey, clientShortPubkey)
        try:
            decrypted = serverShortClientShort.decrypt(data[176:], 'CurveCP-client-I' + nonce)
        except CryptoError:
            return
        clientPubkeyString, vouchNonce, encryptedVouch, serverDomain = _initiateInnerStruct.unpack_from(decrypted)
        clientPubkey = PublicKey(clientPubkeyString)
        serverLongClientLong = Box(self.serverKey.key, clientPubkey)
        try:
            vouchKey = serverLongClientLong.decrypt(encryptedVouch, 'CurveCPV' + vouchNonce)
        except CryptoError:
            return
        if vouchKey != str(clientShortPubkey):
            return
        transport = CurveCPServerTransport(
            self.reactor, self.serverKey, self.factory, clientID,
            clientPubkey, host_port, serverShortClientShort, dnsToName(serverDomain))
        return transport, decrypted[352:]

    def datagramReceived(self, data, host_port):
        l = len(data)
        if l < 80 or l > 1184 or l & 0xf:
            return

        if data[:8] == 'QvnQ5XlH':
            self._replyWithCookie(data, host_port)
            return

        clientID = data[8:72]
        if clientID in self.transports:
            self.transports[clientID].datagramReceived(data, host_port)
            return

        if data[:8] != 'QvnQ5XlI':
            return
        result = self._checkInitiate(clientID, data, host_port)
        if result is None:
            return
        log.msg('new client: %s' % clientID.encode('hex'), category='success')
        transport, message = result
        self.transports[clientID] = transport
        transport.transport = self.transport
        transport.startProtocol()
        transport._parseMessage(transport._now(), message)
        transport.notifyFinish().addCallback(self._clientFinished, clientID)

    def _clientFinished(self, ign, clientID):
        del self.transports[clientID]
    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
        send_box = SecretBox(owner._receiver_record_key())

        RECORD3 = b"record3"
        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"
        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])

        # receiving two records at the same time: deliver both
        inbound_records[:] = []
        RECORD5 = b"record5"
        nonce_buf = unhexlify("%048x" % 2)  # nonces increment
        encrypted = send_box.encrypt(RECORD5, nonce_buf)
        length = unhexlify("%08x" % len(encrypted))  # always 4 bytes long
        r5 = length + encrypted
        RECORD6 = b"record6"
        nonce_buf = unhexlify("%048x" % 3)  # nonces increment
        encrypted = send_box.encrypt(RECORD6, nonce_buf)
        length = unhexlify("%08x" % len(encrypted))  # always 4 bytes long
        r6 = length + encrypted
        c.dataReceived(r5 + r6)
        self.assertEqual(inbound_records, [RECORD5, RECORD6])
Beispiel #33
0
def init(server, username, keydir, action, message, recipients):
    """ SHSM CLI client. """

    global serverurl
    serverurl = server

    if action == "register":
        master_signing_key = SigningKey.generate()
        device_signing_key = SigningKey.generate()
        device_private_key = PrivateKey.generate()

        enc_master_verify_key = master_signing_key.verify_key.encode(encoder=HexEncoder)
        register(username, enc_master_verify_key)

        # TODO: make sure keydir exists

        save_key(master_signing_key.encode(encoder=HexEncoder), keydir + "/master_signing_key")
        save_key(device_signing_key.encode(encoder=HexEncoder), keydir + "/device_signing_key")
        save_key(device_private_key.encode(encoder=HexEncoder), keydir + "/device_private_key")

    else:
        try:
            master_signing_key = SigningKey(load_key(keydir + "/master_signing_key"), encoder=HexEncoder)
            device_signing_key = SigningKey(load_key(keydir + "/device_signing_key"), encoder=HexEncoder)
            device_private_key = PrivateKey(load_key(keydir + "/device_private_key"), encoder=HexEncoder)
        except TypeError:
            print "bad key, exiting."
            exit()

        if action == "add-device":

            enc_device_verify_key = device_signing_key.verify_key.encode(encoder=HexEncoder)
            enc_signed_device_verify_key = b64encode(master_signing_key.sign(enc_device_verify_key))

            enc_device_public_key = device_private_key.public_key.encode(encoder=HexEncoder)
            enc_signed_device_public_key = b64encode(master_signing_key.sign(enc_device_public_key))

            add_device(username, enc_signed_device_verify_key, enc_signed_device_public_key)

        if action == "send-message":

            ephemeral_key = PrivateKey.generate()
            enc_ephemeral_public_key = b64encode(
                device_signing_key.sign(ephemeral_key.public_key.encode(encoder=HexEncoder))
            )

            # TODO:: should sign binary text, no? b"bob"
            destination_usernames = recipients.split(",")
            enc_dest_usernames = b64encode(
                device_signing_key.sign(json.dumps({"destination_usernames": destination_usernames}))
            )
            symmetric_key = random(SecretBox.KEY_SIZE)
            symmetric_box = SecretBox(symmetric_key)
            nonce = random(SecretBox.NONCE_SIZE)
            msg_manifest = {}
            msg_manifest["recipients"] = {}
            msg_manifest["msg"] = b64encode(symmetric_box.encrypt(str(message), nonce))

            for dest_user in destination_usernames:
                msg_manifest["recipients"][dest_user] = {}

                for recipient_key in get_recipient_keys(
                    device_signing_key.verify_key.encode(encoder=HexEncoder),
                    b64encode(device_signing_key.sign(str(dest_user))),
                ):

                    # TODO:: should sign binary text, no?
                    crypt_box = Box(ephemeral_key, recipient_key)
                    nonce = random(Box.NONCE_SIZE)
                    crypt_key = b64encode(crypt_box.encrypt(symmetric_key, nonce))
                    dest_key = recipient_key.encode(encoder=HexEncoder)
                    msg_manifest["recipients"][dest_user][dest_key] = crypt_key

            enc_signed_crypt_msg = b64encode(device_signing_key.sign(json.dumps(msg_manifest)))

            send_message(
                device_signing_key.verify_key.encode(encoder=HexEncoder),
                enc_dest_usernames,
                enc_signed_crypt_msg,
                enc_ephemeral_public_key,
            )

        if action == "get-messages":

            enc_device_verify_key = device_signing_key.verify_key.encode(encoder=HexEncoder)
            enc_signed_device_verify_key = b64encode(device_signing_key.sign(enc_device_verify_key))
            messages = get_messages(enc_device_verify_key, enc_signed_device_verify_key)

            for message_public_key in messages["messages"].keys():
                try:
                    crypto_box = Box(device_private_key, PublicKey(b64decode(message_public_key), encoder=HexEncoder))
                except TypeError:
                    print "not a valid public key"
                    exit()
                packed_msg = json.loads(messages["messages"][message_public_key])
                msg_manifest = json.loads(b64decode(packed_msg["message_manifest"]))
                dest_pub_key = device_private_key.public_key.encode(encoder=HexEncoder)
                symmetric_key = crypto_box.decrypt(b64decode(msg_manifest["recipients"][username][dest_pub_key]))
                symmetric_box = SecretBox(symmetric_key)
                print ("From: %s\nMessage: %s") % (
                    packed_msg["reply_to"],
                    symmetric_box.decrypt(b64decode(msg_manifest["msg"])),
                )
Beispiel #34
0
class _StreamingEncryptionObject(object):
    def __init__(self, mode, user_key, filepath):
        self.mode = mode
        self.user_key = user_key
        self.filepath = filepath
        self.key = None
        self.EOF = False

        self.index = 0

        if self.mode == 'ENCRYPT':
            self.fd = open(filepath, 'wb')
            self.key = nacl_random(32)
            self.partial_nonce = nacl_random(16)
            key = _GCE.asymmetric_encrypt(self.user_key, self.key)
            self.fd.write(key)
            self.fd.write(self.partial_nonce)
        else:
            self.fd = open(filepath, 'rb')
            x = self.fd.read(80)
            self.key = _GCE.asymmetric_decrypt(self.user_key, x)
            self.partial_nonce = self.fd.read(16)

        self.box = SecretBox(self.key)

    def fullNonce(self, i):
        return self.partial_nonce + struct.pack('<Q', i)

    def lastFullNonce(self):
        return self.partial_nonce + struct.pack('>Q', 1)

    def getNextNonce(self, last):
        if last:
            chunkNonce = self.lastFullNonce()
        else:
            chunkNonce = self.fullNonce(self.index)

        self.index += 1

        return chunkNonce

    def encrypt_chunk(self, chunk, last=0):
        chunkNonce = self.getNextNonce(last)
        self.fd.write(struct.pack('>B', last))
        self.fd.write(struct.pack('>I', len(chunk)))
        self.fd.write(self.box.encrypt(chunk, chunkNonce)[24:])

    def decrypt_chunk(self):
        last = struct.unpack('>B', self.fd.read(1))[0]
        if last:
            self.EOF = True

        chunkNonce = self.getNextNonce(last)
        chunkLen = struct.unpack('>I', self.fd.read(4))[0]
        chunk = self.fd.read(chunkLen + 16)
        return last, self.box.decrypt(chunk, chunkNonce)

    def read(self, a):
        if not self.EOF:
            return self.decrypt_chunk()[1]

    def close(self):
        if self.fd is not None:
            self.fd.close()
            self.fd = None

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()

    def __del__(self):
        self.close()
Beispiel #35
0
 def _encrypt_data(self, key, data):
     assert len(key) == SecretBox.KEY_SIZE
     box = SecretBox(key)
     nonce = utils.random(SecretBox.NONCE_SIZE)
     return box.encrypt(data, nonce)
Beispiel #36
0
 def _encrypt_data(self, key, data):
     assert len(key) == SecretBox.KEY_SIZE
     box = SecretBox(key)
     nonce = utils.random(SecretBox.NONCE_SIZE)
     return box.encrypt(data, nonce)
Beispiel #37
0
    def persist(self):
        serialized_data = serialize(self.data)
        box = SecretBox(bytes.fromhex(self.key))
        encrypted_data = box.encrypt(serialized_data)

        return self.persist_as_blocks(encrypted_data)
Beispiel #38
0
class Connection(protocol.Protocol, policies.TimeoutMixin):
    def __init__(self, owner, relay_handshake, start, description):
        self.state = "too-early"
        self.buf = b""
        self.owner = owner
        self.relay_handshake = relay_handshake
        self.start = start
        self._description = description
        self._negotiation_d = defer.Deferred(self._cancel)
        self._error = None
        self._consumer = None
        self._consumer_bytes_written = 0
        self._consumer_bytes_expected = None
        self._consumer_deferred = None
        self._inbound_records = deque()
        self._waiting_reads = deque()

    def connectionMade(self):
        debug("handle %r" % (self.transport, ))
        self.setTimeout(TIMEOUT)  # does timeoutConnection() when it expires
        self.factory.connectionWasMade(self)

    def startNegotiation(self):
        if self.relay_handshake is not None:
            self.transport.write(self.relay_handshake)
            self.state = "relay"
        else:
            self.state = "start"
        self.dataReceived(b"")  # cycle the state machine
        return self._negotiation_d

    def _cancel(self, d):
        self.state = "hung up"  # stop reacting to anything further
        self._error = defer.CancelledError()
        self.transport.loseConnection()
        # if connectionLost isn't called synchronously, then our
        # self._negotiation_d will have been errbacked by Deferred.cancel
        # (which is our caller). So if it's still around, clobber it
        if self._negotiation_d:
            self._negotiation_d = None

    def dataReceived(self, data):
        try:
            self._dataReceived(data)
        except Exception as e:
            self.setTimeout(None)
            self._error = e
            self.transport.loseConnection()
            self.state = "hung up"
            if not isinstance(e, BadHandshake):
                raise

    def _check_and_remove(self, expected):
        # any divergence is a handshake error
        if not self.buf.startswith(expected[:len(self.buf)]):
            raise BadHandshake("got %r want %r" % (self.buf, expected))
        if len(self.buf) < len(expected):
            return False  # keep waiting
        self.buf = self.buf[len(expected):]
        return True

    def _dataReceived(self, data):
        # protocol is:
        #  (maybe: send relay handshake, wait for ok)
        #  send (send|receive)_handshake
        #  wait for (receive|send)_handshake
        #  sender: decide, send "go" or hang up
        #  receiver: wait for "go"
        self.buf += data

        assert self.state != "too-early"
        if self.state == "relay":
            if not self._check_and_remove(b"ok\n"):
                return
            self.state = "start"
        if self.state == "start":
            self.transport.write(self.owner._send_this())
            self.state = "handshake"
        if self.state == "handshake":
            if not self._check_and_remove(self.owner._expect_this()):
                return
            self.state = self.owner.connection_ready(self)
            # If we're the receiver, we'll be moved to state
            # "wait-for-decision", which means we're waiting for the other
            # side (the sender) to make a decision. If we're the sender,
            # we'll either be moved to state "go" (send GO and move directly
            # to state "records") or state "nevermind" (send NEVERMIND and
            # hang up).

        if self.state == "wait-for-decision":
            if not self._check_and_remove(b"go\n"):
                return
            self._negotiationSuccessful()
        if self.state == "go":
            GO = b"go\n"
            self.transport.write(GO)
            self._negotiationSuccessful()
        if self.state == "nevermind":
            self.transport.write(b"nevermind\n")
            raise BadHandshake("abandoned")
        if self.state == "records":
            return self.dataReceivedRECORDS()
        if isinstance(self.state, Exception):  # for tests
            raise self.state

    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)

    def dataReceivedRECORDS(self):
        while True:
            if len(self.buf) < 4:
                return
            length = int(hexlify(self.buf[:4]), 16)
            if len(self.buf) < 4 + length:
                return
            encrypted, self.buf = self.buf[4:4 + length], self.buf[4 + length:]

            record = self._decrypt_record(encrypted)
            self.recordReceived(record)

    def _decrypt_record(self, encrypted):
        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: got %d, expected %d" %
                (nonce, self.next_receive_nonce))
        self.next_receive_nonce += 1
        record = self.receive_box.decrypt(encrypted)
        return record

    def describe(self):
        return self._description

    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
        self.transport.write(length)
        self.transport.write(encrypted)

    def recordReceived(self, record):
        if self._consumer:
            self._writeToConsumer(record)
            return
        self._inbound_records.append(record)
        self._deliverRecords()

    def receive_record(self):
        d = defer.Deferred()
        self._waiting_reads.append(d)
        self._deliverRecords()
        return d

    def _deliverRecords(self):
        while self._inbound_records and self._waiting_reads:
            r = self._inbound_records.popleft()
            d = self._waiting_reads.popleft()
            d.callback(r)

    def close(self):
        self.transport.loseConnection()
        while self._waiting_reads:
            d = self._waiting_reads.popleft()
            d.errback(error.ConnectionClosed())

    def timeoutConnection(self):
        self._error = BadHandshake("timeout")
        self.transport.loseConnection()

    def connectionLost(self, reason=None):
        self.setTimeout(None)
        d, self._negotiation_d = self._negotiation_d, None
        # the Deferred is only relevant until negotiation finishes, so skip
        # this if it's alredy been fired
        if d:
            # Each call to loseConnection() sets self._error first, so we can
            # deliver useful information to the Factory that's waiting on
            # this (although they'll generally ignore the specific error,
            # except for logging unexpected ones). The possible cases are:
            #
            # cancel: defer.CancelledError
            # far-end disconnect: BadHandshake("connection lost")
            # handshake error (something we didn't like): BadHandshake(what)
            # other error: some other Exception
            # timeout: BadHandshake("timeout")

            d.errback(self._error or BadHandshake("connection lost"))
        if self._consumer_deferred:
            self._consumer_deferred.errback(error.ConnectionClosed())

    # IConsumer methods, for outbound flow-control. We pass these through to
    # the transport. The 'producer' is something like a t.p.basic.FileSender
    def registerProducer(self, producer, streaming):
        assert interfaces.IConsumer.providedBy(self.transport)
        self.transport.registerProducer(producer, streaming)

    def unregisterProducer(self):
        self.transport.unregisterProducer()

    def write(self, data):
        self.send_record(data)

    # IProducer methods, for inbound flow-control. We pass these through to
    # the transport.
    def stopProducing(self):
        self.transport.stopProducing()

    def pauseProducing(self):
        self.transport.pauseProducing()

    def resumeProducing(self):
        self.transport.resumeProducing()

    # Helper methods

    def connectConsumer(self, consumer, expected=None):
        """Helper method to glue an instance of e.g. t.p.ftp.FileConsumer to
        us. Inbound records will be written as bytes to the consumer.

        Set 'expected' to an integer to automatically disconnect when at
        least that number of bytes have been written. This function will then
        return a Deferred (that fires with the number of bytes actually
        received). If the connection is lost while this Deferred is
        outstanding, it will errback.

        If 'expected' is None, then this function returns None instead of a
        Deferred, and you must call disconnectConsumer() when you are done."""

        if self._consumer:
            raise RuntimeError("A consumer is already attached: %r" %
                               self._consumer)

        # be aware of an ordering hazard: when we call the consumer's
        # .registerProducer method, they are likely to immediately call
        # self.resumeProducing, which we'll deliver to self.transport, which
        # might call our .dataReceived, which may cause more records to be
        # available. By waiting to set self._consumer until *after* we drain
        # any pending records, we avoid delivering records out of order,
        # which would be bad.
        consumer.registerProducer(self, True)
        # There might be enough data queued to exceed 'expected' before we
        # leave this function. We must be sure to register the producer
        # before it gets unregistered.

        self._consumer = consumer
        self._consumer_bytes_written = 0
        self._consumer_bytes_expected = expected
        d = None
        if expected is not None:
            d = defer.Deferred()
        self._consumer_deferred = d
        # drain any pending records
        while self._consumer and self._inbound_records:
            r = self._inbound_records.popleft()
            self._writeToConsumer(r)
        return d

    def _writeToConsumer(self, record):
        self._consumer.write(record)
        self._consumer_bytes_written += len(record)
        if self._consumer_bytes_expected is not None:
            if self._consumer_bytes_written >= self._consumer_bytes_expected:
                d = self._consumer_deferred
                self.disconnectConsumer()
                d.callback(self._consumer_bytes_written)

    def disconnectConsumer(self):
        self._consumer.unregisterProducer()
        self._consumer = None
        self._consumer_bytes_expected = None
        self._consumer_deferred = None

    # Helper method to write a known number of bytes to a file. This has no
    # flow control: the filehandle cannot push back. 'progress' is an
    # optional callable which will be called on each write (with the number
    # of bytes written). Returns a Deferred that fires (with the number of
    # bytes written) when the count is reached or the RecordPipe is closed.
    def writeToFile(self, f, expected, progress=None, hasher=None):
        fc = FileConsumer(f, progress, hasher)
        return self.connectConsumer(fc, expected)
def encrypt_message(message, secret):
    message_bytes = message.encode('utf-8', 'ignore')
    secret_box = SecretBox(secret)
    nonce = random(SecretBox.NONCE_SIZE)
    return secret_box.encrypt(nonce=nonce, plaintext=message_bytes)
Beispiel #40
0
def block_encrypt(block, nextid):
    key = sha512(block.secret, encoder=RawEncoder)
    nonce = calc_nonce(key, block.N, block.offset)
    box = SecretBox(key[:SecretBox.KEY_SIZE])
    data_padded = pack("<I", nextid) + pad_inner(block.data)
    return nonce, box.encrypt(data_padded, nonce).ciphertext
Beispiel #41
0
class NACL:
    KEY_SIZE = 32

    def __init__(self, private_key=None, symmetric_key=None):
        """Constructor for nacl object

        Args:
            private_key (bytes, optional): The private key used to sign and encrypt the data. Generated randomly if not given.
            symmetric_key (bytes, optional): The key used for symmetric encryption. Generated randomly if not given.
        """
        self.private_key = PrivateKey.generate(
        ) if private_key is None else PrivateKey(private_key)
        private_key = self.get_private_key()
        self.public_key = self.private_key.public_key
        self.symmetric_key = nacl.utils.random(
            NACL.KEY_SIZE) if symmetric_key is None else symmetric_key
        self.signing_key = SigningKey(private_key)
        self.symmetric_box = SecretBox(self.symmetric_key)

    def encrypt(self, message, reciever_public_key):
        """Encrypt the message to send to a receiver. (public key encryption)

        Args:
            message (bytes): The message to be encrypted.
            reciever_public_key (bytes): The receiver's public key.

        Returns:
            bytes: The encrypted message
        """
        return Box(self.private_key,
                   PublicKey(reciever_public_key)).encrypt(message)

    def decrypt(self, message, sender_public_key):
        """Decrypt a received message. (public key encryption)

        Args:
            message (bytes): The encrypted message.
            sender_public_key (bytes): The public key of the sender.

        Returns:
            bytes: The decrypted message
        """
        return Box(self.private_key,
                   PublicKey(sender_public_key)).decrypt(message)

    def encrypt_symmetric(self, message):
        """Encrypt the message to send to a receiver. (secret key encryption)

        Args:
            message (bytes): The message to be encrypted.

        Returns:
            bytes: The encrypted message
        """
        return self.symmetric_box.encrypt(message)

    def decrypt_symmetric(self, message, symmetric_key):
        """Decrypt the receiver message. (secret key encryption)

        Args:
            message (bytes): The message to be decrypted.

        Returns:
            bytes: The decrypted message
        """
        return SecretBox(symmetric_key).decrypt(message)

    def sign(self, message):
        """Sign the message and return the messsage and the signature.

        Args:
            message (bytes): The message to be signed

        Returns:
            bytes, bytes: The message and the signature.
        """
        signed = self.signing_key.sign(message)
        return message, signed.signature

    def verify(self, message, signature, verification_key):
        """Verify that the signature using the verification key

        Args:
            message (bytes): The received message.
            signature (bytes): The recieved signature.
            verification_key (bytes): The verification key.

        Returns:
            bool: True if the verification succeeds.
        """
        try:
            VerifyKey(verification_key).verify(message, signature)
            return True
        except BadSignatureError:
            return False

    def get_signing_seed(self):
        """Returns the signing seed (same as the private key).

        Returns:
            bytes: The 32-bit signing key.
        """
        return bytes(self.signing_key._seed)

    def get_verification_key(self):
        """Returns the verification key.

        Returns:
            bytes: The verification key.
        """
        return bytes(self.signing_key.verify_key)

    def get_public_key(self):
        """Getter for the public key.

        Returns:
            bytes: The public key.
        """
        return bytes(self.public_key)

    def get_private_key(self):
        """Getter for the private key.

        Returns:
            bytes: The private key.
        """
        return bytes(self.private_key)

    def get_symmetric_key(self):
        """Getter for the symmetric key.

        Returns:
            bytes: The symmetric key.
        """
        return bytes(self.symmetric_key)
Beispiel #42
0
class Connection(protocol.Protocol, policies.TimeoutMixin):
    def __init__(self, owner, relay_handshake, start):
        self.state = "too-early"
        self.buf = b""
        self.owner = owner
        self.relay_handshake = relay_handshake
        self.start = start
        self._negotiation_d = defer.Deferred(self._cancel)
        self._error = None
        self._consumer = None
        self._inbound_records = collections.deque()
        self._waiting_reads = collections.deque()

    def connectionMade(self):
        debug("handle %r" %  (self.transport,))
        self.setTimeout(TIMEOUT) # does timeoutConnection() when it expires
        self.factory.connectionWasMade(self, self.transport.getPeer())

    def startNegotiation(self, description):
        self.description = description
        if self.relay_handshake is not None:
            self.transport.write(self.relay_handshake)
            self.state = "relay"
        else:
            self.state = "start"
        self.dataReceived(b"") # cycle the state machine
        return self._negotiation_d

    def _cancel(self, d):
        self.state = "hung up" # stop reacting to anything further
        self._error = defer.CancelledError()
        self.transport.loseConnection()
        # if connectionLost isn't called synchronously, then our
        # self._negotiation_d will have been errbacked by Deferred.cancel
        # (which is our caller). So if it's still around, clobber it
        if self._negotiation_d:
            self._negotiation_d = None


    def dataReceived(self, data):
        try:
            self._dataReceived(data)
        except Exception as e:
            self.setTimeout(None)
            self._error = e
            self.transport.loseConnection()
            self.state = "hung up"
            if not isinstance(e, BadHandshake):
                raise

    def _check_and_remove(self, expected):
        # any divergence is a handshake error
        if not self.buf.startswith(expected[:len(self.buf)]):
            raise BadHandshake("got %r want %r" % (self.buf, expected))
        if len(self.buf) < len(expected):
            return False # keep waiting
        self.buf = self.buf[len(expected):]
        return True

    def _dataReceived(self, data):
        # protocol is:
        #  (maybe: send relay handshake, wait for ok)
        #  send (send|receive)_handshake
        #  wait for (receive|send)_handshake
        #  sender: decide, send "go" or hang up
        #  receiver: wait for "go"
        self.buf += data

        assert self.state != "too-early"
        if self.state == "relay":
            if not self._check_and_remove(b"ok\n"):
                return
            self.state = "start"
        if self.state == "start":
            self.transport.write(self.owner._send_this())
            self.state = "handshake"
        if self.state == "handshake":
            if not self._check_and_remove(self.owner._expect_this()):
                return
            self.state = self.owner.connection_ready(self, self.description)
            # If we're the receiver, we'll be moved to state
            # "wait-for-decision", which means we're waiting for the other
            # side (the sender) to make a decision. If we're the sender,
            # we'll either be moved to state "go" (send GO and move directly
            # to state "records") or state "nevermind" (send NEVERMIND and
            # hang up).

        if self.state == "wait-for-decision":
            if not self._check_and_remove(b"go\n"):
                return
            self._negotiationSuccessful()
        if self.state == "go":
            GO = b"go\n"
            self.transport.write(GO)
            self._negotiationSuccessful()
        if self.state == "nevermind":
            self.transport.write(b"nevermind\n")
            raise BadHandshake("abandoned")
        if self.state == "records":
            return self.dataReceivedRECORDS()
        if isinstance(self.state, Exception): # for tests
            raise self.state

    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)

    def dataReceivedRECORDS(self):
        if len(self.buf) < 4:
            return
        length = int(hexlify(self.buf[:4]), 16)
        if len(self.buf) < 4+length:
            return
        encrypted, self.buf = self.buf[4:4+length], self.buf[4+length:]

        record = self._decrypt_record(encrypted)
        self.recordReceived(record)

    def _decrypt_record(self, encrypted):
        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: got %d, expected %d"
                           % (nonce, self.next_receive_nonce))
        self.next_receive_nonce += 1
        record = self.receive_box.decrypt(encrypted)
        return record

    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
        self.transport.write(length)
        self.transport.write(encrypted)

    def recordReceived(self, record):
        if self._consumer:
            self._consumer.write(record)
            return
        self._inbound_records.append(record)
        self._deliverRecords()

    def receive_record(self):
        d = defer.Deferred()
        self._waiting_reads.append(d)
        self._deliverRecords()
        return d

    def _deliverRecords(self):
        while self._inbound_records and self._waiting_reads:
            r = self._inbound_records.popleft()
            d = self._waiting_reads.popleft()
            d.callback(r)

    def close(self):
        self.transport.loseConnection()
        while self._waiting_reads:
            d = self._waiting_reads.popleft()
            d.errback(error.ConnectionClosed())

    def timeoutConnection(self):
        self._error = BadHandshake("timeout")
        self.transport.loseConnection()

    def connectionLost(self, reason=None):
        self.setTimeout(None)
        d, self._negotiation_d = self._negotiation_d, None
        # the Deferred is only relevant until negotiation finishes, so skip
        # this if it's alredy been fired
        if d:
            # Each call to loseConnection() sets self._error first, so we can
            # deliver useful information to the Factory that's waiting on
            # this (although they'll generally ignore the specific error,
            # except for logging unexpected ones). The possible cases are:
            #
            # cancel: defer.CancelledError
            # far-end disconnect: BadHandshake("connection lost")
            # handshake error (something we didn't like): BadHandshake(what)
            # other error: some other Exception
            # timeout: BadHandshake("timeout")

            d.errback(self._error or BadHandshake("connection lost"))

    # IConsumer methods, for outbound flow-control. We pass these through to
    # the transport. The 'producer' is something like a t.p.basic.FileSender
    def registerProducer(self, producer, streaming):
        assert interfaces.IConsumer.providedBy(self.transport)
        self.transport.registerProducer(producer, streaming)
    def unregisterProducer(self):
        self.transport.unregisterProducer()
    def write(self, data):
        self.send_record(data)

    # IProducer methods, for inbound flow-control. We pass these through to
    # the transport.
    def stopProducing(self):
        self.transport.stopProducing()
    def pauseProducing(self):
        self.transport.pauseProducing()
    def resumeProducing(self):
        self.transport.resumeProducing()

    # Helper method to glue an instance of e.g. t.p.ftp.FileConsumer to us.
    # Inbound records will be written as bytes to the consumer.
    def connectConsumer(self, consumer):
        if self._consumer:
            raise RuntimeError("A consumer is already attached: %r" %
                               self._consumer)
        self._consumer = consumer
        # drain any pending records
        while self._inbound_records:
            r = self._inbound_records.popleft()
            consumer.write(r)
        consumer.registerProducer(self, True)

    def disconnectConsumer(self):
        self._consumer.unregisterProducer()
        self._consumer = None
Beispiel #43
0
 def encrypt(self, signature, field_data):
     encrypt_key = truncate_or_pad(signature)
     box = SecretBox(key=encrypt_key)
     encrypted = box.encrypt(convert_to_bytes(field_data), nonce=self.nonce)
     return self._signifier + standard_b64encode(encrypted)
Beispiel #44
0
    def handle(self, *args, **options):  # pylint: disable=too-many-locals, too-many-statements, too-many-branches
        here_tz = pytz.timezone(settings.TIME_ZONE)

        parameters = {}

        if options['start_date'] is not None:
            components = options['start_date'].split('-')

            start_date = datetime.datetime(int(components[0]),
                                           int(components[1]),
                                           int(components[2]), 0, 0, 0, 0,
                                           here_tz)

            parameters['start_date'] = start_date

        if options['end_date'] is not None:
            components = options['end_date'].split('-')

            end_date = datetime.datetime(int(components[0]), int(
                components[1]), int(components[2]), 0, 0, 0, 0,
                                         here_tz) + datetime.timedelta(days=1)

            parameters['end_date'] = end_date

        parameters['clear_archived'] = options['clear_archived']

        key = None

        try:
            key = base64.b64decode(settings.PDK_BACKUP_KEY)
        except AttributeError:
            print 'Please define PDK_BACKUP_KEY in the settings.'

            sys.exit(1)

        destinations = None

        try:
            destinations = settings.PDK_BACKUP_DESTINATIONS
        except AttributeError:
            print 'Please define PDK_BACKUP_DESTINATIONS in the settings.'

            sys.exit(1)

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

                to_transmit, to_clear = pdk_api.incremental_backup(parameters)

                for destination in destinations:
                    destination_url = urlparse.urlparse(destination)

                    if destination_url.scheme == 'file':
                        dest_path = destination_url.path

                        final_folder = self.folder_for_options(options)

                        if final_folder is not None:
                            dest_path = os.path.join(dest_path, final_folder)

                        if os.path.exists(dest_path) is False:
                            print 'Creating folder for archive storage: ' + dest_path
                            os.makedirs(dest_path)

                        for path in to_transmit:
                            box = SecretBox(key)

                            with open(path, 'rb') as backup_file:
                                encrypted_str = box.encrypt(backup_file.read())

                                filename = os.path.basename(
                                    path) + '.encrypted'

                                encrypted_path = os.path.join(
                                    dest_path, filename)

                                print 'Writing to filesystem: ' + encrypted_path

                                with open(encrypted_path,
                                          'wb') as encrypted_file:
                                    encrypted_file.write(encrypted_str)

                            os.remove(path)
                    elif destination_url.scheme == 'dropbox':
                        access_token = destination_url.netloc

                        client = dropbox.Dropbox(access_token)

                        for path in to_transmit:
                            box = SecretBox(key)

                            with open(path, 'rb') as backup_file:
                                encrypted_io = StringIO.StringIO()
                                encrypted_io.write(backup_file.read())
                                encrypted_io.seek(0)

                                filename = os.path.basename(
                                    path) + '.encrypted'

                                final_folder = self.folder_for_options(options)

                                dropbox_path = os.path.join(
                                    destination_url.path,
                                    final_folder + '/' + filename)

                                print 'Uploading to Dropbox: ' + dropbox_path

                                client.files_upload(encrypted_io.read(),
                                                    dropbox_path)

                            os.remove(path)
                    else:
                        print 'Unknown desitination: ' + destination

                pdk_api.clear_points(to_clear)

            except ImportError:
                pass
            except AttributeError:
                pass