Notes: the Android .apk is unsigned, so it asks for your permission to install an unknown application and warns that the application is not checked. The browser version executes JavaScript to generate your password 'on the fly', nothing it stored in your browser and nothing is submitted to the server.
CombiPass is an Android and web app to generate passwords based on user-provided input. You enter an app name (a name you give the application or website you want to access) and a password, CombiPass then generates a password using a simple algorithm based on a hashing mechanism (SHA-256). This way, all you have to do is remember the name for the app and a single password - there's no need to store the generated password anywhere, and none of the data you provide is stored either in the app or web storage, nor on any server.
The generated passwords have a high entropy ('randomness') and consist of 4 lower-case characters, 4 upper-case characters, 4 digits and 4 punctuation characters, so they should satisfy even the most demading password checks.
For those interested: the algorithm is quite simple: create an HMAC with the password as key and the app name as data, then walk through the result in pairs, using the first char of the pair to determine what set of characters is used (lowercase, uppercase, digit or punctuation), then the second char is used to determine the character of that set. Below is a fully working implementation in Python (used because it's easy to read, but the mechanism should work in all languages that have an HMAC/SHA-256 library - the app, for instance, uses JavaScript):
import hmac import hashlib import string import getpass appname = input('App name: ') base_pw = getpass.getpass('Base password: ') h = hmac.new( base_pw.encode('utf-8'), appname.encode('utf-8'), digestmod=hashlib.sha256) hmac_result = h.digest() charlists = [ string.ascii_uppercase, string.ascii_lowercase, string.digits, string.punctuation] passwordchars = [] charlists = None for i in range(16): if not charlists: charlists = [ string.ascii_uppercase, string.ascii_lowercase, string.digits, string.punctuation] # we could use charlists.pop(0) if i % 8 == 0, but now we have less code charlist = charlists.pop(hmac_result[i * 2] % len(charlists)) char = charlist[hmac_result[i * 2 + 1] % len(charlist)] passwordchars.append(char) print('Generated password:', ''.join(passwordchars))
Note that this Python script generates exactly the same results as the app or the browser version, since the same algorithms are used to generate the password.
Using this application has a number of advantages compared to other solutions:
However, it is important to understand that every solution has its downsides! If your base password is known to anyone, either because you tell them, or because they guessed it correctly, that person has access to all your apps at once. Therefore make sure your base password is not easy to guess (it should not be in a dictionary for instance) and do not write it down anywhere. Also, of course, malware that logs keystrokes or grabs information from the operating system's copy/paste buffer may capture your base or the generated passwords. If security is of a very high importance to you, make sure every step of the process is protected well - remember, any system is only as strong as its weakest link!