Password safe support, even for Windows OS

The Pidgin’s master password branch, which engaged me for the last two months is now ready to show to the public eye. Moreover, it depended on the other security-related task: taking care of Windows build – this one is also mostly done now. Today, I would like to present the current results of my work.

When I was just before start of work on master password branch, it was described as almost ready to merge, or even ready. In fact, it worked fine only for a small part of cases, where user sets up everything correctly and never mistakes while typing in a password for the configured keyring. The funny thing is, that the feature mentioned in the name of the branch, was never implemented (storing passwords internally, encrypted with a master password).

I must admit, that some part of the work done by GSoC’08 student was fine. I would say, it was a good proof-of-concept implementation. I just done the final one and made it close to be ready to ship. Handling all possible use cases (not only the ideal one) required almost twice more code than produced during SoC, also the small part of the code was left as-is (because of its good enough quality). The chart below presents some estimations about it, made only on newly added source files (keyring.c and specific keyring implementations).

Code refactored for master password branch

Doing things right required also a lot of fixes in the main development branch: ciphers reworking, fixing win32 build (there is also a special keyring for this OS), fixing UI components like request API and some minor 3.0.0 bugs. Some of them wasn’t too absorbing (preparing ciphers API for my needs taken just few days), and some were big enough to entitle them as separate task (win32 build taken about 1/4 of the total time spent).

Windows build

The 3.0.0 win32 build was broken for a year or two, so I had to fix it to be able to implement a keyring for this OS. Although, it was a separate security issue, because runtime dependencies, shipped with Windows version of Pidgin, were collected from sources that weren’t eager to update them.

I have managed to switch almost all win32 dependencies to pretty reliable openSUSE Build Service. I guess, some of them (like these related to WebKitGTK) would be hard to obtain from elsewhere than OBS. This service proved high responsibility for their releases, by fixing security issues in few hours after my requests (updating some libraries or applying patches with security fixes). Non security issues also were fixed in reasonable time. I would make a special thanks to Fridrich Strba, who assisted me with preparing OBS repository for Pidgin’s needs. Without his help, doing a pretty stable 3.0.0 build would be twice as hard.

Supported keyrings

Keyring is a safe, which holds passwords for accounts configured in Pidgin (or other libpurple client). There are few of them implemented, so the user may choose the one, which best fits his needs. If none of them are suitable, he could provide his own implementation.

Internal keyring in cleartext mode provides backward compatibility, where passwords are stored without any encryption, just as-is. This doesn’t need to be insecure, as long as the access to accounts.xml file is restricted.

Internal keyring in master password mode also stores them in accounts.xml file, but encrypted. The encryption key is derived from a master password, which have to be entered once per every client startup.

GNOME Keyring and KWallet moves this responsibility to a service started by operating system. Passwords are stored here encrypted using a master password, entered once (depending on configuration) per OS startup.

Secret Service (implemented by libsecret) is another OS keyring. Unfortunately, its plugin serves a lot of issues at the moment, so it’s not enabled yet.

Windows credential manager encrypts passwords using Windows user account data. Its security depends on system configuration – encryption does nothing, if user’s account isn’t even protected with password.

KeePass is a cross-platform keyring, which could be a good choice for people using the same Pidgin configuration files for multiple operating systems. Unfortunately, it doesn’t seems that KeePass could work with Pidgin out-of-the-box – it requires installing a plugin for KeePass to operate with various applications. At this moment, there is no implementation for it.

Encryption scheme for internal keyring

Password encryption implementation for internal keyring is really sensitive spot, so it had to be done very carefully. It’s important not to try doing own, fancy schemes, but to use approved methods. Even then, it’s really easy to screw things up.

Choosing a good blocks to build this feature is crucial, but if they turn out, to be weak, there have to be an option to change them. So, I made a possibility to choose encryption method, but I’ve implemented only one for now. I have chosen two algorithms: AES-256 for encryption and PBKDF2-SHA256 for deriving a key from the master password.

PBKDF2 algorithm have configurable amount of iterations (default is 10000), so user may to raise it, if he needs paranoid level of security, or decrease (but not below 1000) if his machine is too slow for the default value.

It’s important to use AES correctly, to eliminate various classes of potential attacks. I’ve implemented the following scheme:
ciphertext := [IV] ++ AES( [plaintext] ++ [min length padding] ++ [control string] ++ [pkcs7 padding] )
where:

  • ciphertext is base64 encoded, so it’s possible to store it in xml file.
  • IV is a random, 128bit vector, which makes every ciphertext different, even for the equal plaintexts. It’s stored with the AES output, to make it easier to maintain.
  • AES is used with 256bit keys in CBC mode.
  • plaintext is stored without NUL terminator – its length is determined by one of the paddings, depending of its length.
  • min length padding extends plaintext length to be not shorter than 50 characters, by appending NUL bytes to its end. This hides an information about a password being short or long.
  • control string is a constant string – allows verifying, if decryption was successful.
  • pkcs7 padding determines the length of the [plaintext] ++ [min length padding] ++ [control string] sequence.

Builds ready for testing

The source code is available directly from the hg repository, but I’ve prepared some packages for these of you, who just want to take a quick look:

I’m waiting for any feedback, bug reports and comments. I would also appreciate any linguistic corrections – you may review all of them by searching in pidgin.pot file for /keyring.c and /keyrings/ phrases.

Leave a Reply

Your email address will not be published. Required fields are marked *