Example #1
0
 def test_pseudo_bytes(self):
     with self.assertRaises(MemoryError):
         Rand.rand_pseudo_bytes(-1)
     self.assertEqual(Rand.rand_pseudo_bytes(0), ('', 1))
     a, b = Rand.rand_pseudo_bytes(1)
     self.assertEqual(len(a), 1)
     self.assertEqual(b, 1)
Example #2
0
 def test_pseudo_bytes(self):
     with self.assertRaises(MemoryError):
         Rand.rand_pseudo_bytes(-1)
     self.assertEqual(Rand.rand_pseudo_bytes(0), (b'', 1))
     a, b = Rand.rand_pseudo_bytes(1)
     self.assertEqual(len(a), 1)
     self.assertEqual(b, 1)
Example #3
0
 def test_pseudo_bytes(self):
     with warnings.catch_warnings():
         warnings.simplefilter('ignore', DeprecationWarning)
         with self.assertRaises(MemoryError):
             Rand.rand_pseudo_bytes(-1)
         self.assertEqual(Rand.rand_pseudo_bytes(0), (b'', 1))
         a, b = Rand.rand_pseudo_bytes(1)
         self.assertEqual(len(a), 1)
         self.assertEqual(b, 1)
Example #4
0
 def test_pseudo_bytes(self):
     with warnings.catch_warnings():
         warnings.simplefilter('ignore', DeprecationWarning)
         with self.assertRaises(MemoryError):
             Rand.rand_pseudo_bytes(-1)
         self.assertEqual(Rand.rand_pseudo_bytes(0), (b'', 1))
         a, b = Rand.rand_pseudo_bytes(1)
         self.assertEqual(len(a), 1)
         self.assertEqual(b, 1)
Example #5
0
    def __init__(self, source, destination, private_key, pub_key_cache):
        self.private_key = private_key

        self.cipher = rdfvalue.CipherProperties(
            name=self.cipher_name,
            key=Rand.rand_pseudo_bytes(self.key_size / 8)[0],
            iv=Rand.rand_pseudo_bytes(self.iv_size / 8)[0],
            hmac_key=Rand.rand_pseudo_bytes(self.key_size / 8)[0],
        )

        self.pub_key_cache = pub_key_cache
        serialized_cipher = self.cipher.SerializeToString()

        self.cipher_metadata = rdfvalue.CipherMetadata()
        # Old clients interpret this as a string so we have to omit the "aff4:/"
        # prefix on the wire. Can be removed after all clients have been updated.
        self.cipher_metadata.SetWireFormat("source",
                                           utils.SmartStr(source.Basename()))

        # Sign this cipher.
        digest = self.hash_function(serialized_cipher).digest()

        # We never want to have a password dialog
        private_key = self.private_key.GetPrivateKey()

        self.cipher_metadata.signature = private_key.sign(
            digest, self.hash_function_name)

        # Now encrypt the cipher with our key
        rsa_key = pub_key_cache.GetRSAPublicKey(destination)

        stats.STATS.IncrementCounter("grr_rsa_operations")
        # M2Crypto verifies the key on each public_encrypt call which is horribly
        # slow therefore we just call the swig wrapped method directly.
        self.encrypted_cipher = m2.rsa_public_encrypt(rsa_key.rsa,
                                                      serialized_cipher,
                                                      self.e_padding)

        # Encrypt the metadata block symmetrically.
        _, self.encrypted_cipher_metadata = self.Encrypt(
            self.cipher_metadata.SerializeToString(), self.cipher.iv)

        self.signature_verified = True
Example #6
0
  def __init__(self, source, destination, private_key, pub_key_cache):
    self.private_key = private_key

    self.cipher = rdfvalue.CipherProperties(
        name=self.cipher_name,
        key=Rand.rand_pseudo_bytes(self.key_size / 8)[0],
        iv=Rand.rand_pseudo_bytes(self.iv_size / 8)[0],
        hmac_key=Rand.rand_pseudo_bytes(self.key_size / 8)[0],
        )

    self.pub_key_cache = pub_key_cache
    serialized_cipher = self.cipher.SerializeToString()

    self.cipher_metadata = rdfvalue.CipherMetadata()
    # Old clients interpret this as a string so we have to omit the "aff4:/"
    # prefix on the wire. Can be removed after all clients have been updated.
    self.cipher_metadata.SetWireFormat("source",
                                       utils.SmartStr(source.Basename()))

    # Sign this cipher.
    digest = self.hash_function(serialized_cipher).digest()

    # We never want to have a password dialog
    private_key = self.private_key.GetPrivateKey()

    self.cipher_metadata.signature = private_key.sign(
        digest, self.hash_function_name)

    # Now encrypt the cipher with our key
    rsa_key = pub_key_cache.GetRSAPublicKey(destination)

    stats.STATS.IncrementCounter("grr_rsa_operations")
    # M2Crypto verifies the key on each public_encrypt call which is horribly
    # slow therefore we just call the swig wrapped method directly.
    self.encrypted_cipher = m2.rsa_public_encrypt(
        rsa_key.rsa, serialized_cipher, self.e_padding)

    # Encrypt the metadata block symmetrically.
    _, self.encrypted_cipher_metadata = self.Encrypt(
        self.cipher_metadata.SerializeToString(), self.cipher.iv)

    self.signature_verified = True
Example #7
0
  def Encrypt(self, data, iv=None):
    """Symmetrically encrypt the data using the optional iv."""
    if iv is None:
      iv = Rand.rand_pseudo_bytes(self.iv_size / 8)[0]

    evp_cipher = EVP.Cipher(alg=self.cipher_name, key=self.cipher.key,
                            iv=iv, op=ENCRYPT)

    ctext = evp_cipher.update(data)
    ctext += evp_cipher.final()

    return iv, ctext
Example #8
0
    def Encrypt(self, data, iv=None):
        """Symmetrically encrypt the data using the optional iv."""
        if iv is None:
            iv = Rand.rand_pseudo_bytes(self.iv_size / 8)[0]

        evp_cipher = EVP.Cipher(alg=self.cipher_name,
                                key=self.cipher.key,
                                iv=iv,
                                op=ENCRYPT)

        ctext = evp_cipher.update(data)
        ctext += evp_cipher.final()

        return iv, ctext
Example #9
0
 def test_pseudo_bytes(self):
     self.assertRaises(MemoryError, Rand.rand_pseudo_bytes, -1)
     assert Rand.rand_pseudo_bytes(0) == ("", 1)
     a, b = Rand.rand_pseudo_bytes(1)
     assert len(a) == 1
     assert b == 1
Example #10
0
 def test_pseudo_bytes(self):
     self.assertRaises(MemoryError, Rand.rand_pseudo_bytes, -1)
     assert Rand.rand_pseudo_bytes(0) == ('', 1)
     a, b = Rand.rand_pseudo_bytes(1)
     assert len(a) == 1
     assert b == 1
Example #11
0
def main():

    q = LockboxOrderedDict()
    observer = Observer()
    observer.schedule(CleartextEventHandler(q, cleartext_dir, ciphertext_dir), path=cleartext_dir, recursive=True)
    observer.schedule(CiphertextEventHandler(q, cleartext_dir, ciphertext_dir), path=ciphertext_dir, recursive=True)
    observer.start()

    try:
        while True:
            time.sleep(1)
            try:
                while True:
                    (stem, deets) = q.first()  #just read, don't pop here because we need it to stay in the OrderedDict in case another event comes in on this file before we're done
                    logger.debug('%s %s', stem, deets)
                    if not deets['collided']:
                        check_for_collided_after_operation = False
                        if deets['action'] == 'encrypt':
                            logger.debug('encrypting from %s to %s', deets['cleartext_full_path'], deets['ciphertext_full_path'])
                            check_for_collided_after_operation = True
                            target_path = deets['ciphertext_full_path']
                            (tmp_fd, tmp_path) = tempfile.mkstemp()
                            os.close(tmp_fd)


                            rio = BIO.openfile(deets['cleartext_full_path'], 'rb')
                            rio.write_close()
                            wrio = BIO.openfile(tmp_path, 'wb')

                            cf = BIO.CipherStream(wrio)

                            salt = Rand.rand_pseudo_bytes(8)[0]
                            logger.debug("salt=%s",ByteToHex(salt))

                            passphrase_f = open(os.path.join(deets['config_dir_path'], 'key.txt'), 'r')  ## TODO cache this
                            passphrase = passphrase_f.readline().rstrip()
                            passphrase_f.close()

                            (key, iv) = m2.bytes_to_key(m2.aes_256_cbc(), m2.md5(), passphrase, salt, 1)
                            logger.debug("key=%s", ByteToHex(key))
                            logger.debug("iv=%s", ByteToHex(iv))

                            cf.set_cipher('aes_256_cbc', key, iv, 1)
                            wrio.write('Salted__')  # magic - see openssl's enc.c
                            wrio.write(salt)

                            while True:
                                out = rio.read(4096)
                                if not out:
                                    break
                                cf.write(out)

                            cf.flush()
                            cf.write_close()
                            cf.close()
                            wrio.flush()
                            wrio.write_close()
                            wrio.close()

                        elif deets['action'] == 'decrypt':
                            logger.debug('decrypting from %s to %s', deets['ciphertext_full_path'], deets['cleartext_full_path'])
                            check_for_collided_after_operation = True
                            target_path = deets['cleartext_full_path']
                            (tmp_fd, tmp_path) = tempfile.mkstemp()
                            os.close(tmp_fd)
                            ## TODO: handle failure of decryption

                            rio = BIO.openfile(deets['ciphertext_full_path'], 'rb')
                            rio.write_close()
                            wrio = BIO.openfile(deets['cleartext_full_path'], 'wb')

                            cf = BIO.CipherStream(wrio)

                            header = rio.read(size=len('Salted__'))
                            if header != 'Salted__':
                                print "uh, this doesn't look like an encrypted file"
                                exit()
                            salt = rio.read(size=8)
                            logger.debug("salt=%s",ByteToHex(salt))

                            passphrase_f = open(os.path.join(deets['config_dir_path'], 'key.txt'), 'r')  ## TODO cache this
                            passphrase = passphrase_f.readline().rstrip()
                            passphrase_f.close()

                            (key, iv) = m2.bytes_to_key(m2.aes_256_cbc(), m2.md5(), passphrase, salt, 1)
                            logger.debug("key=%s", ByteToHex(key))
                            logger.debug("iv=%s", ByteToHex(iv))

                            cf.set_cipher('aes_256_cbc', key, iv, 0)

                            while True:
                                out = rio.read(4096)
                                if not out:
                                    break
                                cf.write(out)

                            cf.flush()
                            cf.write_close()
                            cf.close()
                            wrio.flush()
                            wrio.write_close()
                            wrio.close()


                        elif deets['action'] == 'delete-cipher':
                            logger.debug('deleting %s', deets['ciphertext_full_path'])
                            if os.path.exists(deets['ciphertext_full_path']):
                                os.unlink(deets['ciphertext_full_path'])

                        elif deets['action'] == 'delete-clear':
                            logger.debug('deleting %s', deets['cleartext_full_path'])
                            if os.path.exists(deets['cleartext_full_path']):
                                os.unlink(deets['cleartext_full_path'])

                        else:
                            logger.error('Unknown action %s on %s', deets['action'], deets)

                        time.sleep(0)  ## http://stackoverflow.com/questions/787803/how-does-a-threading-thread-yield-the-rest-of-its-quantum-in-python
                        (stem, deets) = q.popitem(False)

                        if check_for_collided_after_operation:
                            ## now, if it got marked as collided in the interim while we were encrypting/decrypting then we don't want to overwrite 
                            if not deets['collided']:
                                ## move from temp location to real location
                                if platform.system() == 'Windows':
                                    ## TODO: this can throw an exception on windows if the target_place is locked.  need to think about how to deal with this
                                    if os.path.exists(target_path):
                                        logger.debug('windows only: unlink %s', target_path)
                                        os.unlink(target_path)
                                logger.debug('rename %s to %s', tmp_path, target_path)
                                mkdir_p(os.path.dirname(target_path))
                                os.rename(tmp_path, target_path)
                            else:
                                ## TODO: if it was a decrypt, move the newly decrypted file to stem-from-dropbox-collision
                                ##       if it was an encrypt, immediately decrypt ciphertext version to stem-from-dropbox-collision
                                ## TODO: delete tmp_path in the case that we're no longer using it (it was an encrypt that we no longer can copy to the ciphertext location)
                                pass
                    else:
                        (stem, deets) = q.popitem(False)
                        if deets['action'] in ('delete-clear','delete-cipher'):
                            logger.error('should not get a collided delete because they should be removed from the queue in our OrderedDict subclass')
                        else:
                            ## TODO: immediately decrypt and put it into stem-from-dropbox-collision
                            pass

            except StopIteration:
                #print "nada"
                pass
    except KeyboardInterrupt:
        pass
    observer.stop()
    observer.join()
    hexStr = ''.join( hexStr.split(" ") )

    for i in range(0, len(hexStr), 2):
        bytes.append( chr( int (hexStr[i:i+2], 16 ) ) )

    return ''.join( bytes )


rio = BIO.openfile(os.path.expanduser('~/Lockbox/foobar/firsttest.txt'), 'rb')
rio.write_close()
wrio = BIO.openfile(os.path.expanduser('~/Dropbox/LOCKBOX-foobar/firsttest.txt'), 'wb')

cf = BIO.CipherStream(wrio)

salt = Rand.rand_pseudo_bytes(8)[0]
#salt = '\x00\x00\x00\x00\x00\x00\x00\x00'
print "salt=%s" % ByteToHex(salt)

passphrase = 'foo bar'

(key, iv) = m2.bytes_to_key(m2.aes_256_cbc(), m2.md5(), passphrase, salt, 1)
print "key=%s" % ByteToHex(key)
print "iv=%s" % ByteToHex(iv)

cf.set_cipher('aes_256_cbc', key, iv, 1)


wrio.write('Salted__')  # magic - see openssl's enc.c
wrio.write(salt)