owncloud-archive / apps

Repo for ownCloud apps. Code here is work in progress and not intended for endusers
373 stars 337 forks source link

Password Manager App #356

Closed 4bendo closed 10 years ago

4bendo commented 11 years ago

Use app to add/manage passwords. Similar function to "last pass" or "SafeWallet". Further functionality to add iOS and Android Apps to manage passwords when not logged into web interface.

Feature request was suggested in the OC forums: http://forum.owncloud.org/viewtopic.php?f=4&t=7014

Sagdiyev commented 11 years ago

To add to this RFE:

godfuture commented 11 years ago

That sounds too good to be true! I would like such app.

Well, I am using Last Pass and I am very content with their service quality. But I would like to sync my passwords on my own server. I think it makes sense to focus on the following key features to provide sustainable alternative:

many greetings

Nonobis commented 11 years ago

+1 It would be a great feature !

strigona commented 11 years ago

I just started using LastPass and while I do trust them, it would be really nice to be able to sync to ownCloud.

godfuture commented 11 years ago

I think this is pretty nice feature. In time of insufficient internet securiety, strong passwords seem to be a small light in the dark.

BUT

Owncloud needs a vision. What I am talking about? There already exists a solution to sync passwords...at least for Firefox (Firefox Sync app). But it does not reach the functionality of the LastPass addon and for sure, its just available for Firefox..uuuf.

I would prefer a build-in password manager with more functions than e.g. standard Firefox and a compatibilty for more than one browser. Actually it is the same idea with bookmarks sync.

What you think?

flipflopsimsommer commented 11 years ago

+1

shieldsit commented 11 years ago

I keep checking for this functionality but it doesn't seem to be a pressing issue. I'm going to start checking in to what it takes to develop apps for owncloud and try to make my own (ha) I guess.

imhoffd commented 10 years ago

I began developing this a few months ago, but my life got a bit busy and I am just now looking back into this. It is definitely needed for ownCloud!

Here is the repo: https://github.com/dwieeb/ownCloud-pwmanager

4bendo commented 10 years ago

I don't know much about coding, but would be very interested to be a tester to help develop this further.

On Mon, Nov 4, 2013 at 4:06 PM, Daniel Imhoff notifications@github.comwrote:

I began developing this a few months ago, but my life got a bit busy and I am just now looking back into this. It is definitely needed for ownCloud!

Here is the repo: https://github.com/dwieeb/ownCloud-pwmanager

— Reply to this email directly or view it on GitHubhttps://github.com/owncloud/apps/issues/356#issuecomment-27735971 .

flipflopsimsommer commented 10 years ago

how did you consider storing the access keys and how will you transfair them to the client?

imhoffd commented 10 years ago

It's still being considered, but the preliminary idea is we will use the user's ownCloud password as the access key, and they will need to "confirm their password" when they go to their password "vault" so we can get the plain text version of it. Then, the entire list of passwords will be sent once to the client. HTTPS will be strongly recommended so that plain text transfer of passwords is encrypted.

I'm open to ideas, though.

flipflopsimsommer commented 10 years ago

the only alternative i thought throw would be combining it with a browser addon that stores your key and you later kann encrypt in on the client. but again then the passwordsafe is only usefull on your pc and the cloud spirit gets lost :( i woudn't fill comfortable sending all my passwds (and a passwordsafe only makes sence if you can store all your passwd) over https unenctrypted at least it shoudn't show any passwords by default so users can add new passwords from unsave locations.

strigona commented 10 years ago

I think that trying to duplicate Last Pass would be a great way to go. Since OwnCloud is self hosted, the decrypting of the passwords doesn't have to happen client side. Features I'd want:

Mobile support is tricky.. at least on Android you have Firefox which supports addons, but WP's are trickier. You essentially need to create an app with a WebBrowser element and inject JS to do all the scanning & filling. An alternative solution would be an app that simply lets you pull up the list of usernames and passwords so you can copy them into whatever App you want to use.

imhoffd commented 10 years ago

@flipflopsimsommer "over https unencrypted" makes no sense. HTTPS is an encrypted connection.

@strigona Yes, LastPass is what I'm basing this on. The "Secure communication between browser & server" is HTTPS, otherwise everything is sent as plain text.

The first release of this will not have any browser extension, but will use the ownCloud UI to show a user's passwords.

strigona commented 10 years ago

One interpretation of "over https unencrypted" could be that the data itself is not encrypted, but the communication method (HTTPS) is. In the case of LastPass, the data that retrieved from their server is encrypted and is decrypted on the client side/browser using javascript and the users password.

In theory, this means that LastPass cannot see our passwords if they wanted to. Unfortunately, we trust that Last Pass doesn't change the JS to something that sends the master password back to their servers so they can then decrypt the passwords. Lavabit (the secure email servers that shut down a few months ago) was in the same situation.

This is the value in having a self hosted solution - we can trust both ends and still have the same level of functionality.

imhoffd commented 10 years ago

Decrypting with JS is probably the best solution (using crypto-js). It's not perfect, but this is two-way encryption and it will never be perfect unless they use HTTPS.

strigona commented 10 years ago

Agreed. HTTPS will prevent man in the middle attacks for altering JS.

I haven't done any OwnCloud development, but I'm decent at PHP. Let me know if you want a hand.

flipflopsimsommer commented 10 years ago

@strigona yes thats how i mean over https unencrypted. mybe ssl is secure enogth to transfai all my passwords :lock: but if we love owncloud and it's user we shoudn't allow this over http by the way i can help in php and javascript let me know otherwise i will try to help but i have no github comunities expirince yet so letzt try this out :+1:

imhoffd commented 10 years ago

We can allow it, as the passwords will still be sent encrypted (however the algorithm and user password will not), but as I mentioned earlier, strongly recommend HTTPS.

xmgz commented 10 years ago

Interesting project, keep your passwords encrypted on your own server and available browser-wide using a plugin

godfuture commented 10 years ago

Just want to add...

...I even have use for a password manager for my desktop. Why should we limit the manager on browsers?

Maybe the developer can consider that when coding the manager. If the API to access that password store is generic enough, desktop use should't be a problem, right?

strigona commented 10 years ago

I would say that developing a desktop password manager would be more work than a browser plugin. That being said, I think you're right about making the API generic enough to support both use cases.

msquared-au commented 10 years ago

Have a look at https://github.com/clipperz/password-manager for a neat approach to web-based password managers.

Basically, it's just a single-page JavaScript app with a simple PHP back-end for storage, but the crypto is handled client-side; this has the advantage that the server never sees the cleartext data.

Since all the crypto is done in the browser, it doesn't even matter whether the connection to the server is secure (other than to guard against MitM attacks, of course).

vgezer commented 10 years ago

Good news! We now have a PassMan app: http://apps.owncloud.com/content/show.php/Passman?content=166285

ghost commented 9 years ago

For anyone who still wants this app, use ownCloud Passwords (for ownCloud 8 and later and still provides updates). Primarily intended as a safe solution for storing passwords on your own server: https://github.com/fcturner/passwords https://apps.owncloud.com/content/show.php/Passwords?content=170480

Passman 1.3.30 only works on old versions and stopped developing. Clipperz isn't made for ownCloud.

screenshot1

morriswinkler commented 8 years ago

well i hate to break it, but passsword managers without sharing to other user is only usefull to individuals, and there are tons of this single user password managers, realy create a multi user version of that

ghost commented 8 years ago

@morriswinkler Will be available in my next version: v18, ETA this April/May.

morriswinkler commented 8 years ago

great, tell me more, love to hear about it, how do you get around that whole encryption thing ? Are you planning on browser plugin implementation later ?

ghost commented 8 years ago

Browser plugin will be available in next release too! For Firefox only, that is. Project page: https://github.com/eglia/ff-oc-passwords (and the addin page: https://addons.mozilla.org/en-US/firefox/addon/firefox-owncloud-passwords/).

As for encryption, here is what I tell my users :

And my whole encryption class:

class Encryption {
/**
 * A class to handle secure encryption and decryption of arbitrary data
 *
 *  Note that this is not just straight encryption. It also has a few other
 *  features in it to make the encrypted data far more secure.  Note that any
 *  other implementations used to decrypt data will have to do the same exact
 *  operations.  
 *
 * Security Benefits:
 *
 * - Uses Key stretching
 * - Hides the Initialization Vector
 * - Does HMAC verification of source data
 *
 */
    public static function makeKey($userKey, $serverKey, $userSuppliedKey) {
        $key = hash_hmac('sha512', $userKey, $serverKey);
        $key = hash_hmac('sha512', $key, $userSuppliedKey);
        return $key;
    } 
    /**
     * @var string $cipher The mcrypt cipher to use for this instance
     */
    protected $cipher = '';

    /**
     * @var int $mode The mcrypt cipher mode to use
     */
    protected $mode = '';
    /**
     * @var int $rounds The number of rounds to feed into PBKDF2 for key generation
     */
    protected $rounds = 100;
    /**
     * Constructor!
     *
     * @param string $cipher The MCRYPT_* cypher to use for this instance
     * @param int    $mode   The MCRYPT_MODE_* mode to use for this instance
     * @param int    $rounds The number of PBKDF2 rounds to do on the key
     */
    public function __construct($cipher, $mode, $rounds = 100) {
        $this->cipher = $cipher;
        $this->mode = $mode;
        $this->rounds = (int) $rounds;
    }
    /**
     * Decrypt the data with the provided key
     *
     * @param string $data The encrypted datat to decrypt
     * @param string $key  The key to use for decryption
     * 
     * @returns string|false The returned string if decryption is successful
     *                           false if it is not
     */
    public function decrypt($data_hex, $key) {
        if ( !function_exists( 'hex2bin' ) ) {
            function hex2bin( $str ) {
                $sbin = "";
                $len = strlen( $str );
                for ( $i = 0; $i < $len; $i += 2 ) {
                    $sbin .= pack( "H*", substr( $str, $i, 2 ) );
                }
                return $sbin;
            }
        }
        $data = hex2bin($data_hex);
        $salt = substr($data, 0, 128);
        $enc = substr($data, 128, -64);
        $mac = substr($data, -64);
        list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);
        //if (!hash_equals(hash_hmac('sha512', $enc, $macKey, true), $mac)) {
        if (!Encryption::hash_equals(hash_hmac('sha512', $enc, $macKey, true), $mac)) {
             return false;
        }
        $dec = mcrypt_decrypt($this->cipher, $cipherKey, $enc, $this->mode, $iv);
        $data = $this->unpad($dec);
        return $data;
    }
    /**
     * Encrypt the supplied data using the supplied key
     * 
     * @param string $data The data to encrypt
     * @param string $key  The key to encrypt with
     *
     * @returns string The encrypted data
     */
    public function encrypt($data, $key) {
        $salt = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
        //list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);
        list ($cipherKey, $macKey, $iv) = Encryption::getKeys($salt, $key);
        //$data = $this->pad($data);
        $data = Encryption::pad($data);
        $enc = mcrypt_encrypt($this->cipher, $cipherKey, $data, $this->mode, $iv);
        $mac = hash_hmac('sha512', $enc, $macKey, true);
        $data = $salt . $enc . $mac;
        $data = bin2hex($salt . $enc . $mac);
        //$data = pack("H*" , $data);
        return $data;

        return $salt . $enc . $mac;
    }
    /**
     * Generates a set of keys given a random salt and a master key
     *
     * @param string $salt A random string to change the keys each encryption
     * @param string $key  The supplied key to encrypt with
     *
     * @returns array An array of keys (a cipher key, a mac key, and a IV)
     */
    protected function getKeys($salt, $key) {
        $ivSize = mcrypt_get_iv_size($this->cipher, $this->mode);
        $keySize = mcrypt_get_key_size($this->cipher, $this->mode);
        $length = 2 * $keySize + $ivSize;
        //$key = $this->pbkdf2('sha512', $key, $salt, $this->rounds, $length);
        $key = Encryption::pbkdf2('sha512', $key, $salt, $this->rounds, $length);
        $cipherKey = substr($key, 0, $keySize);
        $macKey = substr($key, $keySize, $keySize);
        $iv = substr($key, 2 * $keySize);
        return array($cipherKey, $macKey, $iv);
    }
    function hash_equals($a, $b) {
        $key = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
        return hash_hmac('sha512', $a, $key) === hash_hmac('sha512', $b, $key);
    }
    /**
     * Stretch the key using the PBKDF2 algorithm
     *
     * @see http://en.wikipedia.org/wiki/PBKDF2
     *
     * @param string $algo   The algorithm to use
     * @param string $key    The key to stretch
     * @param string $salt   A random salt
     * @param int    $rounds The number of rounds to derive
     * @param int    $length The length of the output key
     *
     * @returns string The derived key.
     */
    protected function pbkdf2($algo, $key, $salt, $rounds, $length) {
        $size   = strlen(hash($algo, '', true));
        $len    = ceil($length / $size);
        $result = '';
        for ($i = 1; $i <= $len; $i++) {
            $tmp = hash_hmac($algo, $salt . pack('N', $i), $key, true);
            $res = $tmp;
            for ($j = 1; $j < $rounds; $j++) {
                 $tmp  = hash_hmac($algo, $tmp, $key, true);
                 $res ^= $tmp;
            }
            $result .= $res;
        }
        return substr($result, 0, $length);
    }
    protected function pad($data) {
        $length = mcrypt_get_block_size($this->cipher, $this->mode);
        $padAmount = $length - strlen($data) % $length;
        if ($padAmount == 0) {
            $padAmount = $length;
        }
        return $data . str_repeat(chr($padAmount), $padAmount);
    }
    protected function unpad($data) {
        $length = mcrypt_get_block_size($this->cipher, $this->mode);
        $last = ord($data[strlen($data) - 1]);
        if ($last > $length) return false;
        if (substr($data, -1 * $last) !== str_repeat(chr($last), $last)) {
            return false;
        }
        return substr($data, 0, -1 * $last);
    }
}

So to encrypt:

$pass = // password that users choose when adding a new entry in my app i.e. their own database
$userKey = // something gave in by user;
$serverKey = \OC_Config::getValue('passwordsalt', '');
$userSuppliedKey = $website;
$key = Encryption::makeKey($userKey, $serverKey, $userSuppliedKey);
$e = new Encryption(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
$encryptedPass = $e->encrypt($pass, $key);

And reverse for decrypt, you get the point :wink:

morriswinkler commented 8 years ago

so if $userKey is given by user, how do you share a password than, wouldn't you need than something from the user the password is shared with ?

ghost commented 8 years ago

True. So, when sharing, it must be replaced by something else. So sharing will be less secure than unshared passwords. But still safe enough; very few encryption systems use this method of three variables building a key. I could replace it by a key that's only known to the user and the one he is sharing it with. Only then nobody can decrypt it.

morriswinkler commented 8 years ago

I would like to forward you to the following stackexchange post,

https://security.stackexchange.com/questions/8245/gpg-file-size-with-multiple-recipients

it explains quiet nicely how multiple-user is implemented in GPG, maybe something to consider, it would certainly keep things safer.

since the website and the salt are known on the server i don't really see how adding three factors makes it more secure if two factors are known on the server side ( salt is in the config file ( ??? ) and website is cleartext in the database as is the bytechunk that holds the encrypted information) i mean if someone steals it, he will steal everything

than what do you use the "properties" field for in the database and what is the field "loginname" used for

ghost commented 8 years ago

No, you don't get it. If you hack a server, you don't necessarily have direct access to the database. When you hack the database, you don't necessarily have direct access to ownCloud users credentials. When you hack ownCloud, you don't necessarily have direct access to everything on the server. The website is sent by Ajax, the password salt is from a local server file. They only meet when a user is logged in into ownCloud.

The properties field is an encrypted value of password properties like loginname, strength, length and so forth. Loginname itself is obsolete and for backwards compatibility.

Thanks for the link! If you would like to propose enhancements, please create a new issue on my GitHub project page. Thanks!

morriswinkler commented 8 years ago

I did not intend to do harsh critic, it is rather some feedback, and maybe i am wrong, but my wild guess is that more than 90% of owncloud installations share filestorage and database on the same server. And yes you are right if you don't necessary get access to the database if you break into owncloud, or access to the database or files that are stored on the server. I also understand that there is still a user credential in place that makes all the stolen data unusable unless you got the user crediantials necessary tun decrypt the password.

My suggestion was rather towards the multi user implementation, since you sad it would make thinks less safe, i guesed that there would be no factor that would hold an attacker from decrypting passwords once he has access to the server that hosts the file and database server. I was suggesting an option that allows to encrypt a password information with a users public key and that would work for all users residing on the system, decryption would than only be possible by a users private key or guessing the encryption key.

And yes you are right i should ask for enhancements on the projects github, sorry somehow this conversation ended up in this issue thread.

So i will continue over there.

ghost commented 8 years ago

No problem, I appreciate the feedback!