From: pgut01@cs.auckland.ac.nz (Peter Gutmann)
Newsgroups: alt.security,comp.security.misc,sci.crypt
Subject: How Windows encrypts .PWL files
Date: 28 Nov 1995 13:13:36 GMT
Organization: University of Auckland
Sender: pgut01@cs.auckland.ac.nz (Peter Gutmann)
Message-ID: <49f1u0$6ai@net.auckland.ac.nz>
NNTP-Posting-Host: cs26.cs.auckland.ac.nz

Windows for Workgroups can assign passwords to shared resources such as shared
directories, printer queues, and network DDE shares.  To save having to enter a
password for each resource each time you log on, it keeps encrypted copies of
the passwords in password (.PWL) files and decrypts them with the password you
use initially to log on.  The details of this are mostly undocumented "for
security reasons".  They're about to become documented...
 
When you log on for the first time or when you delete your .PWL file, Windows
will ask you whether you want it to create a password file for you.  This
contains the encrypted passwords.  You add passwords to the file using the
semi-documented WNetCachePassword() function and retrieve them using the
equally semi-documented WNetGetCachedPassword() function.  Anything running on
the machine at any time a user is logged on can use WNgetGetCachedPassword() to
retrieve any of the passwords in the .PWL file.  When you add a password, you
supply the name of the resource it pertains to (eg "\\NTSERVER\PRINTER1"), the
password itself, and a number from 1 to 254 for the resource type (more about 0
and 255 later). Windows reserves resource types 1, 2, and 3 for its own use for
network resources.  The .PWL file is not protected from modification.  To use a
new password to access the network, simply delete the .PWL file and Windows
will ask you if you want to create a new one the next time you log on.
 
There can be no more than 255 passwords with types 1 to 127.  If more than 256
are added, Windows starts throwing existing ones away to make room.  You can
avoid this by giving the resource a type from 128 to 254, but once you've used
up this range all further attempts to add passwords will fail.  By adding too
many passwords of either type, you can either cause all existing passwords to
be discarded by Windows or saturate the password file so no new passwords can
be added.  Most users (if they can figure out what's going wrong) will respond
by deleting the password file and starting again with a new file, giving you a
chance to recover from any "mistakes" you may have made with their .PWL file.
 
The .PWL file contains a small header, two blocks of 256 byte-fields, and then
the encrypted password resources.  The header consists of a 4-byte magic ID
"\xB0MFN", a 4-byte count of the number of password resources, 256 fields
containing resource numbers or 0 if this resource is unused (which is why
resource type 0 isn't allowed), and 256 fields containing a resource key or
0xFF is this field is unused (which is why resource type 255 isn't allowed).
When you add a new password resource, Windows scans through the second array
looking for the first 0xFF entry and then uses this to store the password
information.
 
Following this data come the encrypted password resources.  Windows stores the
logon password in memory at all times, performing a simple transformation on a
copy of it whenever it's needed to encrypt or decrypt resources.  The password
is copied around to other memory locations as needed.  Since the original
password location isn't in a VxD (Windows virtual device driver), it can be
swapped to disk at any point, and given that it's in memory for the whole time
Windows is in use but is only rarely used, it probably does end up in the
swapfile on numerous occasions.
 
The transformation performed on the in-memory password, which reduces a
variable-length password to 32 bits, is as follows:
 
    unsigned long result = 0L;
 
    for( i = 0; i < passwordLen + 1; i++ )
        {
        int tmp = ( int ) ( result >> 25 );
 
        result += toupper( password[ i ] );
        result = ( result << 7 ) | tmp;
        }
 
Note the use of passwordLen + 1, which includes the null terminator at the end
of the string as part of the password.  The effect is simply to rotate the
final result by 7 bits as toupper( password[ i ] ) == 0.  Here's the output
from the password "blem":
 
           After     After 
            add     rotate
 
    i = 0 00000042 00002100
    i = 1 0000214C 0010A600
    i = 2 0010A645 08532280
    i = 3 085322CD 29916684
    i = 4 29916684 C8B34214
 
This 32-bit key is then passed to RC4 which is used to encrypt or decrypt the
resources.  The above key would be passed to RC4 as { 0x14, 0x42, 0xB3, 0xC8 }.
The RC4 implementation was licensed by MS in object form and probably comes
from the BSAFE toolkit.  I assume everyone has seen RC4 so I won't include it
here (in any case the implementation used in Windows is fairly grotty, I'd
recommend using the asm version I posted to sci.crypt a few weeks ago).
 
The RC4 key usually doesn't contain anywhere near 32 bits of entropy, although
as a whole it's not spectacularly ugly (you just keep rotating the 32-bit
value, adding in one letter of the password each time).  It's probably easier
to brute-force the 32-bit key than to try anything clever based on the fact
that the password will generally consist entirely of uppercase letters.
 
There have been numerous posts in the past on the insecurity of Windows
networking.  This one shows that even the very basic access control mechanisms
are highly insecure, and what's more can't really be made secure: You can patch
Windows to use the whole logon password instead of the mangled 32-bit version
as the RC4 key, but then you need to contend with the fact that any program can
get a password with WNetGetCachedPassword() at any time (think of the
possibilities with a machine running arbitrary apps and a live internet
connection to send the results over) and that the original password is sitting
in memory (and in the swapfile) most of the time.
 
In conclusion: The Windows password/.PWL encryption is quite weak and should
not be relied upon to keep any information secure, or to secure access to
sensitive resources.
 
Peter.