Password Algorithms: Skype (Windows)

Introduction

There’s a fantastic article by Fabrice Desclaux and Kostya Kortchinsky which describes the encryption and structures used but doesn’t provide any code.

The article indicates it isn’t possible to decrypt the password which probably explains the lack of code by other people.

Taken from the article…

If told to, Skype will save in the config.xml file

  • The login MD5 hash (username\nskyper\password)
  • The generated RSA private key
  • The Skype encrypted corresponding RSA public key

Everything is heavily encrypted, but in a symmetric way :)
The following algorithms are used

  • CryptProtectData(), CryptUnprotectData()
  • SHA-1
  • AES-256
  • “FastTrack Cipher”
  • 1024+ bit RSA

Only an MD5 hash of password is stored in the user’s profile and it’s encrypted with AES-256
Once hash is decrypted, the only recovery methods available are dictionary attack or variation of brute force.

The information here applies to version 5.10.0.116 but should also work without hitch on some older versions (4.2 was also tested)

Storage

There are 2 things required in order to dump the MD5 hash.

  1. DPAPI blob :
    HKEY_CURRENT_USER\Software\Skype\ProtectedStorage

  2. Credentials ciphertext :
    %APPDATA%\Skype\<login id>\config.xml

The DPAPI blob is just stored as binary and can be passed straight to CryptUnprotectData()

C:\>reg query HKCU\Software\Skype\ProtectedStorage

HKEY_CURRENT_USER\Software\Skype\ProtectedStorage
    0    REG_BINARY    01000000D08C9DDF0115D1118C7A00C04FC297EB01000

The Credentials are hexadecimal string stored in XML file

<?xml version="1.0"?>
<config version="1.0" serial="66" timestamp="1344481520.27">
  <Lib>
    <Account>
      <Credentials3>322EBDF6D922E91F7EB68

As a result of the XML file I ended up using the following libraries from here:

  • libxml2-2.7.8.win32.zip
  • iconv-1.9.2.win32.zip
  • openssl-0.9.8a.win32.zip
  • zlib-1.2.5.win32.zip

Generation

The following demonstrates creation of the MD5 hash using OpenSSL

void GenHash(const char *id, const char *pwd) {
    MD5_CTX ctx;
    const char *skype = "\nskyper\n";
    u_int8_t dgst[32];
    
    MD5_Init(&ctx);
    MD5_Update(&ctx, id, strlen(id));
    MD5_Update(&ctx, skype, strlen(skype));
    MD5_Update(&ctx, pwd, strlen(pwd));
    MD5_Final(dgst, &ctx);

    printf("\n  Login ID = %s"
           "\n  Password = %s"
           "\n  MD5 hash = ", id, pwd);
    
    for (int i = 0;i < 16;i++) {
      printf("%02x", dgst[i]);
    }
    printf("\n");
}
.....
C:\>skype_dump username password
  ...
  Login ID = username
  Password = password
  MD5 hash = 27f6a9d892475e6ce0391de8d2d893f7

Recovery

To extract the Credentials ciphertext, you could read the contents of config.xml and scan for <Credentials3> and </Credentials3>
Here, I’m using LibXML :P

bool GetCredentials(BYTE ciphertext[], std::string config_xml) {    
    bool bFound = false;
    
    // try open config.xml
    xmlTextReaderPtr reader;
    reader = xmlReaderForFile(config_xml.c_str(), NULL, 0);
    
    // tested with Credentials2 or Credentials3
    const xmlChar *credentials; 
    credentials = (const xmlChar*)"Credentials";

    if (reader != NULL) {
    
      // while nodes are available
      while (xmlTextReaderRead(reader) == 1) {
        // get name
        const xmlChar *name;
        name = xmlTextReaderConstName(reader);
        if (name == NULL) continue;

        // equal to credentials we're searching for?
        if (xmlStrncmp(credentials, name, xmlStrlen(credentials)) == 0) {

          // read the next value
          if (xmlTextReaderRead(reader) == 1) {
            const xmlChar *value;
            value = xmlTextReaderConstValue(reader);
            
            for (int i = 0;i < 16;i++) {
              sscanf((const char*)&value[i * 2], "%02x", &ciphertext[i]);
            }
            bFound = true;
            break;
          }
        }
      }
      xmlFreeTextReader(reader);
    }
    xmlCleanupParser();
    return bFound;
}

Obtain the salt which is passed to SHA-1 before being used to create AES key.

PBYTE GetSalt(DWORD &cbSalt) {
    BYTE aBlob[2048];
    DWORD cbSize = sizeof(aBlob);
    const char skype_path[] = "Software\\Skype\\ProtectedStorage";
    
    LSTATUS lStatus = SHGetValue(HKEY_CURRENT_USER, skype_path, 
        "0", 0, aBlob, &cbSize);
      
    if (lStatus != ERROR_SUCCESS) {
      printf("  Unable to open skype key : %08x", lStatus);
      return NULL;
    }

    DATA_BLOB in, out;
    
    in.pbData = aBlob;
    in.cbData = cbSize;
    
    if (CryptUnprotectData(&in, NULL, NULL, NULL, 
        NULL, 0, &out)) {
      cbSalt = out.cbData;
      return out.pbData;
    } else {
      printf("  Unable to decrypt skype entry.");
    }
    return NULL;
}

Then with both the ciphertext and salt, we can decrypt MD5 hash…

void DecryptHash(PBYTE pbCipherText, PBYTE pbSalt, DWORD cbSalt) {
    
    SHA_CTX ctx;
    AES_KEY key;
    
    u_int8_t dgst[40], buffer[AES_BLOCK_SIZE];
    
    memset(&buffer, 0, sizeof(buffer));
    
    // use counter mode + SHA-1 to generate key
    for (ULONG i = 0;i < 2;i++) {
      ULONG ulIndex = _byteswap_ulong(i);
        
      SHA1_Init(&ctx);
      SHA1_Update(&ctx, &ulIndex, sizeof(ulIndex));
      SHA1_Update(&ctx, pbSalt, cbSalt);
      SHA1_Final(&dgst[i*20], &ctx);
    }
    
    AES_set_encrypt_key(dgst, 256, &key);
    AES_encrypt(buffer, buffer, &key);
    
    printf("\n  MD5 hash = ");
    
    // decrypt MD5 hash with XOR
    for (int i = 0;i < 16;i++) {
      printf("%02x", pbCipherText[i] ^ buffer[i]);
    }
    printf("\n");
}

Conclusion

If you want to know more about the internals of Skype, I’d strongly recommend the “Vanilla Skype” papers 1 and 2

It’s safe to say MD5 isn’t a good choice of algorithms for protecting passwords.
Maybe as more recovery tools become available, Microsoft will revise the code to use something stronger.
source code

15 thoughts on “Password Algorithms: Skype (Windows)

  1. Could you give example what the output will be for some define values as you did for GenHash():
    C:\>skype_dump username password

    Login ID = username
    Password = password
    MD5 hash = 27f6a9d892475e6ce0391de8d2d893f7

    I have an error, but I don’t understand in what part of program I should find it. The result MD5 Hash doesn’t coincide with the real.

    • The program I wrote called skype_dump.cpp allows you to generate hash with username and password. Without parameters, it just looks in local user profile.

      I’ll post source code to all articles in next couple of weeks.

    • 20 bytes is the size of SHA-1 hash but 32-bytes are required for AES-256 key so we’re just concatenating 2 SHA-1 hashes, the last 8 bytes don’t matter.

      I suppose SHA-256 or something similar in size would seem like a more appropriate choice but SHA-1 was used instead, I have no idea why.

      By the way, Linux version doesn’t encrypt hash at all.

  2. Hi there,
    I have written a sample program by your article, but I don’t quite understand the result. Unfortunately, I haven’t got enough time to read the specs. It would be nice if you could help me to write an application which reverse the md5 hash of the stored password.

    I attached the source code of the sample program :
    http://codepad.org/811wtQAt

    So this code give me a wrong md5 hash, and I don’t know why.

    Thank you in advance.

    • Hi, sorry for late reply, didn’t see your post.
      I’ll be releasing source code for this later today.

      Although there’s a hash dumper, I haven’t written a cracker but you should be able to write something.

      Regards,

  3. Hello.

    You say that the Linux version does not provide encryption.
    Here is the beginning of my config.xml file, and I can’t find any credentials.
    A heavy grep of everything in my ~/.Skype/ folder of my password or “Credential” gives me nothing.

    Do you know how the password is stored on Linux ?
    $ skype –version
    Skype 4.0.0.8
    Copyright (c) 2004-2012, Skype

    $ head config.xml

    300
    1800
    63
    1

    Best regards, happy new year and thank you.

    • Hmm, at the time of writing, my own version was 2.2.0.35 but it looks like it received a major update since then.

      Mine was located in the following file.
      /home/dietrich/.Skype/dietrich/config.xml

      Check with your version and let me know how you get on.

      cheers

      • I changed my password and then check differences between old and new config.xml file

        The only affected line (timestamp excepted) is in the section “table_insert_history”
        the name of the xml value is a 64 hexa characters, and the values are not very cool.

        It seems that the password isn’t in the config.xml anymore.

        • I installed 4.1.0.20 and for me the password hash is still stored in config.xml
          ‘Sign me in when Skype starts’ box is checked and I recreated profile.

  4. Hi there,
    I would like to transfer a working account (autologin with forgotten password) from one PC to another. I copy whole HKEY_CURRENT_USER\Software\Skype\ and %APPDATA%\Skype\ and %APPDATA%\SkypePM\ but login fails. Do you have any idea what happens?
    Thank you in advance.

  5. Do this still work or have skype updated their way of encrypting the password? I’m getting “Unable to obtain encrypted hash from config.xml”.

    Using skype 6.5

  6. Hey,
    thank you for a very informative article. My question maybe a little bit dumb, but there is a thing that is confusing me a little bit. You mention that the MD5 hash consists of hash(username\nskyper\password).
    Does that mean that the output of your code(which again, Im very thankful for), is not hashed password but rather a combination of all these? Does it mean that if I run oclHashcat on this, it will not generate the password but rather the whole sequence?(username\nskyper\password).

    Again, sorry for this dumb question, but I dont really understand cryptography that much.

    Thank you in advance for your response.

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>