
How I did the web version of KeePass
Somehow I needed to add a list of passwords to the admin panel. The database was stored on the server in the KeePass format (kdbx v2), the server was on the node - without thinking twice, I took the first package that I got and did it. And then it took the same thing, but right at the user’s browser, without a server. Nothing was found. The first desire was to fork the lib and replace the use of node api, but from the first view of the code, the desire disappeared, I decided to do it myself.

Under the cat, I’ll talk about the problems that I encountered and how to solve them
I had to study the kdbx format, which was not described, unfortunately, nowhere except for the source code and this short article. But then it is quite simple. To read kdbx, you need to:
Of the algorithms, AES for symmetric encryption and SHA256 for hashing are used there. The fastest implementation for web that I found is asmCrypto , it is written in asm.js, it works faster than other browser alternatives, and, importantly, it can be assembled in pieces, including only the necessary modules with algorithms. Having patched it so that all key transformation cycles take place inside asm.js, without additional data copying, I managed to achieve a speed of 4..7 times lower than that of the native implementation (if you put a delay of 1 second in KeePass, the seconds file will open for 6). With default settings, the file open time on average is about 200ms. WebAssembly will save us all, but for now, like this.
UPD: in the comments they suggested WebCrypto, now the opening time in browsers with its support is almost the same as KeePass.
For work with gzip I took pako - it is small, fast and MIT. Compared to encryption, I did not notice significant decompression costs.
The result is kdbxweb , which works in node.js and modern browsers. Due to the need to work with the binary format, there are no old versions in the list of supported browsers. Library + dependencies turned out to be 150kb.
So, there is. Why not write a web interface for her now? A good password manager for the web should:
Most of this has been achieved.
The application was written in backbone + zepto (at first I wanted to try Angular2, but somehow it didn’t work, the generated code of the framework itself is still more than 1MB in size, it’s probably too beta and then it will be better).
The browser versions that support the reader of the format are not so far from the latter, so there are practically no cross-browser crutches.
When you enter text into any input, all entered values even with the input history can be stored in the browser memory indefinitely. And if you can clean the memory in a desktop application, then in the browser you have no control over the memory occupied by the strings: when the GC wants it, then it will clean it, while it may nullify the memory, or maybe not:

Some applications think that memory can do not clean even after closing the file, although for applications this, of course, is not as critical as for the web:

It won’t work, if the application didn’t go anywhere else, then I wouldn’t enter the master password in such an input in the browser, so I had to make a bicycle: when I enter the characters, XOR characters come with a random sequence that is selected so that the output contains characters some unused unicode block. The input shows them, thinking that this value (anyway there are asterisks), the value itself is stored symbolically in the buffer. Of course, you can add the value with the key, having full access to the memory, but this is another level of complexity:

To save the file generated in the browser is not so simple, but it is necessary:

There is FileSaver.js, but it has an ambush in Safari, here is a thread with interesting comments , where the author asks to buy him a macbook. Almost all browsers now support
It’s inconvenient to work by downloading the file each time; I collected applications on electron . It works smartly, the API is well described and intuitive, I did not notice any problems with it at all:

Auto-updater is only for poppy, but in the future it will most likely be added for other wasps. As for node-webkit, electron-builder and electron-packager have already appeared for the electron, which I used to build the application and installer.
The config for building the installer, which makes dmg for mac os x and exe installer for windows (deb build for linux so far they do not support):
Electron adds a nice opportunity to get the path of the opened files. When a file is dragged into an application or opened from an input, the path property is added to the File, which contains the full path to the file. You can save the file later as usual in the node, fs.writeFile.

KeePass has many icons with strange names in enum. But firstly, they are a bit outdated for 2015, and secondly, I did not want to use bitmap graphics to keep the application small. I had to make a correspondence manually, fortunately, absolutely everything was found in font awesome:

The format allows you to set the recording color and background color, which KeePass uses, but I think the ability to choose an arbitrary color for text and background from the color picker itself is not the best solution. The color of the record is needed to assign the record to any logical group (for example, green - money) and quickly search for them - so that the marked ones are striking and quickly available.

Therefore, in the application, color is used as an asterisk, but instead of a yellow star, you can select a star of any color:

In the case when there are colors in the imported file, the algorithm calculates the tone closest in similarity, Hue. Back to KeePass, colors are exported as the light background of the selected hue.
I was pleasantly surprised that to connect to the dropbox from SPA via dropbox-js, you no longer need to embed the “encrypted” secret key in the application, as it was before. He didn’t learn how to track tab closure in popup authorization, but it’s easy to learn (but you need to patch the lib).
The copy API started working in browsers not so long ago: in chrome it appeared in the summer, in firefox in the fall of this year, in IE it was earlier, but with a question to the user. In safari it still is not there, but I want to copy the text somehow. Especially in mobile safari. But if you can’t copy there, then you can show the Copy bubble to the user by making a transparent input. You’ll have to poke the screen again, but still it’s not as painful as the selection and copying:

If a person opened several files, most likely he wants the search to be all of them. Therefore, the search, filters, sorting and basket are made common. Filters are arranged in order of demand by the user. First, All Items (it’s even available by shortcuts Ctrl / Cmd-A, because most often I want to show everything and just find what I need in the search), then the colors are favorites, followed by tags, structure and the trash at the very bottom:

Search can work around: fields, tags, attachments. In the list of records, when sorting by different fields, the second line shows the field by which they were sorted:

The format supports files without a basket, however, the UI has a basket all the time. This is done then to show it separately from the list of groups, one for all files. In the list of ordinary groups, the basket has nothing to do, it should be special.
When I talked about the application on sourceforge in the KeePass forum, Dominik Reichl (the KeePass developer) wrote to me by mail, which turned out well, suggested adding the application to the unofficial clients page , and asked me to change the name, which I did.
In the application, there are still bugs that I gradually catch. Use at your own risk and make backups. In extreme cases, there is an export to XML, where you can see what went wrong. Much has not been done yet , but in general I liked the idea of the application, I am going to develop and support it.
All application components, like itself, are available under MIT.
keeweb - web application
releases - desktop release
github - code
keeweb.info - site with features on one page in the form of pictures
kdbxweb - kdbx reader for browsers and node.js
kee_web - twitter project

Under the cat, I’ll talk about the problems that I encountered and how to solve them
Reading kdbx format in browser
I had to study the kdbx format, which was not described, unfortunately, nowhere except for the source code and this short article. But then it is quite simple. To read kdbx, you need to:
- read the binary header ( what's in it? )
- initialize encryption algorithm and random value generator (salsa-20)
- calculate password and key hash, get credentials hash
- Encrypt the hash N times (the value from the header), having received the master key - this is the most computationally time-consuming operation
- decrypt data
- verify decryption by comparing the data block with the block from the header
- GZIP upload data
- parse xml
- generate salt for protected fields
- on demand, when you need them, you can now expand the protected fields
- read xml metadata ( what's in them? )
- read groups and notes
Of the algorithms, AES for symmetric encryption and SHA256 for hashing are used there. The fastest implementation for web that I found is asmCrypto , it is written in asm.js, it works faster than other browser alternatives, and, importantly, it can be assembled in pieces, including only the necessary modules with algorithms. Having patched it so that all key transformation cycles take place inside asm.js, without additional data copying, I managed to achieve a speed of 4..7 times lower than that of the native implementation (if you put a delay of 1 second in KeePass, the seconds file will open for 6). With default settings, the file open time on average is about 200ms. WebAssembly will save us all, but for now, like this.
UPD: in the comments they suggested WebCrypto, now the opening time in browsers with its support is almost the same as KeePass.
For work with gzip I took pako - it is small, fast and MIT. Compared to encryption, I did not notice significant decompression costs.
The result is kdbxweb , which works in node.js and modern browsers. Due to the need to work with the binary format, there are no old versions in the list of supported browsers. Library + dependencies turned out to be 150kb.
application
So, there is. Why not write a web interface for her now? A good password manager for the web should:
- be a single file so that you can take and, say, put yourself in a dropbox, on a hosting or even on a disk
- do not require absolutely no server, do not forward anything anywhere, work in the browser
- occupy less than 1MB (conditionally; the order is really important)
- be able to work from a file and offline
- load fast
- work in all browsers
- do not store passwords in clear text
- mess with dropbox
- use the existing format, do not reinvent the wheel
- somehow support all the features of the format
- work with multiple files / databases at the same time
- be backward compatible with the original application
- be open-sorts
Most of this has been achieved.
The application was written in backbone + zepto (at first I wanted to try Angular2, but somehow it didn’t work, the generated code of the framework itself is still more than 1MB in size, it’s probably too beta and then it will be better).
The browser versions that support the reader of the format are not so far from the latter, so there are practically no cross-browser crutches.
input type = password
When you enter text into any input, all entered values even with the input history can be stored in the browser memory indefinitely. And if you can clean the memory in a desktop application, then in the browser you have no control over the memory occupied by the strings: when the GC wants it, then it will clean it, while it may nullify the memory, or maybe not:

Some applications think that memory can do not clean even after closing the file, although for applications this, of course, is not as critical as for the web:

It won’t work, if the application didn’t go anywhere else, then I wouldn’t enter the master password in such an input in the browser, so I had to make a bicycle: when I enter the characters, XOR characters come with a random sequence that is selected so that the output contains characters some unused unicode block. The input shows them, thinking that this value (anyway there are asterisks), the value itself is stored symbolically in the buffer. Of course, you can add the value with the key, having full access to the memory, but this is another level of complexity:

Saving Files
To save the file generated in the browser is not so simple, but it is necessary:

There is FileSaver.js, but it has an ambush in Safari, here is a thread with interesting comments , where the author asks to buy him a macbook. Almost all browsers now support
But not Safari. Safari stubbornly neither wants to understand the download attribute ( feelings about this can be poured out on webkit.org ), nor to download Blob, complaining that this is supposedly unsafe. But if you convert the file to base64, you can still download it. I sent a patch to the author, now FileSaver works in safari, but the file name is still Unknown. If someone knows a way to do better, please tell us.Desktop
It’s inconvenient to work by downloading the file each time; I collected applications on electron . It works smartly, the API is well described and intuitive, I did not notice any problems with it at all:

Auto-updater is only for poppy, but in the future it will most likely be added for other wasps. As for node-webkit, electron-builder and electron-packager have already appeared for the electron, which I used to build the application and installer.
The config for building the installer, which makes dmg for mac os x and exe installer for windows (deb build for linux so far they do not support):
{
"osx" : {
"title": "KeeWeb",
"background": "../graphics/dmg-bg.png",
"icon": "../graphics/app.icns",
"icon-size": 80,
"contents": [
{ "x": 438, "y": 344, "type": "link", "path": "/Applications" },
{ "x": 192, "y": 344, "type": "file" }
]
},
"win" : {
"title": "KeeWeb",
"icon": "graphics/app.ico"
}
}
Electron adds a nice opportunity to get the path of the opened files. When a file is dragged into an application or opened from an input, the path property is added to the File, which contains the full path to the file. You can save the file later as usual in the node, fs.writeFile.

Icons
KeePass has many icons with strange names in enum. But firstly, they are a bit outdated for 2015, and secondly, I did not want to use bitmap graphics to keep the application small. I had to make a correspondence manually, fortunately, absolutely everything was found in font awesome:

Colors
The format allows you to set the recording color and background color, which KeePass uses, but I think the ability to choose an arbitrary color for text and background from the color picker itself is not the best solution. The color of the record is needed to assign the record to any logical group (for example, green - money) and quickly search for them - so that the marked ones are striking and quickly available.

Therefore, in the application, color is used as an asterisk, but instead of a yellow star, you can select a star of any color:

In the case when there are colors in the imported file, the algorithm calculates the tone closest in similarity, Hue. Back to KeePass, colors are exported as the light background of the selected hue.
Dropbox
I was pleasantly surprised that to connect to the dropbox from SPA via dropbox-js, you no longer need to embed the “encrypted” secret key in the application, as it was before. He didn’t learn how to track tab closure in popup authorization, but it’s easy to learn (but you need to patch the lib).
Copy
The copy API started working in browsers not so long ago: in chrome it appeared in the summer, in firefox in the fall of this year, in IE it was earlier, but with a question to the user. In safari it still is not there, but I want to copy the text somehow. Especially in mobile safari. But if you can’t copy there, then you can show the Copy bubble to the user by making a transparent input. You’ll have to poke the screen again, but still it’s not as painful as the selection and copying:

Search and Cart
If a person opened several files, most likely he wants the search to be all of them. Therefore, the search, filters, sorting and basket are made common. Filters are arranged in order of demand by the user. First, All Items (it’s even available by shortcuts Ctrl / Cmd-A, because most often I want to show everything and just find what I need in the search), then the colors are favorites, followed by tags, structure and the trash at the very bottom:

Search can work around: fields, tags, attachments. In the list of records, when sorting by different fields, the second line shows the field by which they were sorted:

The format supports files without a basket, however, the UI has a basket all the time. This is done then to show it separately from the list of groups, one for all files. In the list of ordinary groups, the basket has nothing to do, it should be special.
Title
When I talked about the application on sourceforge in the KeePass forum, Dominik Reichl (the KeePass developer) wrote to me by mail, which turned out well, suggested adding the application to the unofficial clients page , and asked me to change the name, which I did.
Oh boring
In the application, there are still bugs that I gradually catch. Use at your own risk and make backups. In extreme cases, there is an export to XML, where you can see what went wrong. Much has not been done yet , but in general I liked the idea of the application, I am going to develop and support it.
All application components, like itself, are available under MIT.
References
keeweb - web application
releases - desktop release
github - code
keeweb.info - site with features on one page in the form of pictures
kdbxweb - kdbx reader for browsers and node.js
kee_web - twitter project