Software Engineering Institute Carnegie Mellon

Into the Black Box: A Case Study in Obtaining Visibility into Commercial Software

4 Key Database

Decoding the key database was significantly more difficult than was the case for the certificate database. This difficulty was mainly due to the lack of documentation available, and the fact the private key record in the data are encrypted with a password. Unlike the certificate database, the Netscape NSS does not provide any information describing the format of this database or the encryption used.

In trying to decode this database, we first dumped all of the records in the database. We discovered that there are only four different types of records in the key database and only two records contained the common header mentioned in Section 3. Records that use the common header have the record types shown in Figure 7.


//Record Types

#define PRIVATEKEY 8

#define PASSWORDCHECK 16


Figure 7: Key Record Types






The other two records which do not contain the common header are the Version record and the Global Salt1 record. These records can be easily identified by their access keys, "Version" and "global-salt" respectively. The key database can be identified by the existence of the version record. Additionally, if the key database contains any private key records it will also contain a password check record, which can be accessed using "password-check" for the database access key.

As in the certificate database, records in the key database are in big endian format. The key database record formats shown in Figure 8 were actually easy to determine. However, determining how to use this information to decrypt a private key was a different story. Determining the role of each record in the decryption of a private key was going to be a challenge.

We started this task by first dumping a private key record header and data (ASN.1 encoded) as shown in Figure 9. The software used to decode the ASN.1 encoded information was written by Peter Gutmann and may be download from his Web site at

http://www.cs.auckland.ac.nz/~pgut001/

 

Decoding the ASN.1 key data revealed the object identifier (OID)2 of (06 0B 2A 86 48 86 F7 0D 01 0C 05 01 03) that has description string of

pkcs-12-PBEWithSha1AndTripleDESCBC

indicating the specific encryption technique used to encrypt the private key. This OID description specifies password-based encryption (PBE) with secure hash version one (SHA1) and the Triple Data Encryption Standard (DES) in cipher block chaining mode (CBC). The OCTET String and the integer contained in the sequence following the OID are the salt and iterator value for the PBE scheme. Finally, the last OCTET STRING is the encrypted private key.



typedef struct

  {

unsigned char GlobalSalt[16];

}GlobalSaltHeader;


typedef struct

{

  // Contains just the common header

} KeyVersionHeader;


#define KEYPASSCHKFIXEDSIZE 18

typedef struct

{ 

  unsigned char Salt[16];

  unsigned short CryptAlgLength;

  unsigned char *AlgInfo;

  unsigned char *EncryptedAccessKey; // "password-check" Encrypted 16 bytes

} PasswordCheckHeader;


#define KEYHEADERFIXEDSIZE 8

typedef struct


{

  unsigned char Salt[8];

  char * NickName;

  unsigned char * KeyInfoDER;

}KeyHeader;


Figure 8: Private Key Database Record Formats








Record:

Size: 436 bytes

Version: 3

Type: Private Key

Flags: 0x23

Initial Vector: 47 EB A8 CE FC 4B C0 6B

Key Name:Scott A Hissam's VeriSign, Inc. ID

Name Length:34

Encrypted ASN.1 Private Key

0 30 386: SEQUENCE {

4 30 28 : SEQUENCE {

6 06 11 : OBJECT IDENTIFIER

: pkcs-12-PBEWithSha1AndTripleDESCBC (1 2 840 113549 1
12 5 1 3)

: (PKCS #12 OID PBEID (1 2 840 113549 1 12 5 1).
Deprecated, use the incompatible but similar (1 2 840 113549 1 12 1 3) or (1 2 840
113549 1 12 1 4) instead)

19 30 13: SEQUENCE {

21 04 8: OCTET STRING

: 47 EB A8 CE FC 4B C0 6B

31 02 1: INTEGER 1

: }

: }

34 04 352: OCTET STRING

: BF 3E 52 71 3E 07 94 73 25 F2 28 8D 06 D6 1E F8

: B3 EC FA 59 17 06 EC F9 8F 92 19 FE 4C FF C3 81

: F8 BE F0 12 A2 DD 6A D3 17 DA 56 5A B4 65 8B E8

: 5D 6F 4B AE 6F 5F 39 DC 1F EF BF 56 6E 79 D5 B4

: 2B 9A 6E 20 98 4D 66 98 79 4C 85 98 31 1D 4B E3

: DE EF C3 07 54 76 86 50 A8 22 9E 94 C8 CB F9 F4

: 46 9E 52 26 F8 20 8C 51 E8 52 6E 95 16 CA 9D 4D

: E6 7E 90 69 96 1E 1E DF CC 67 FE AB 96 5A D7 88

: 26 1A A9 CC 52 F6 97 0F 28 FC 52 96 DE FB FD F7

: 87 01 AE 71 E0 88 1B C6 7D 01 C8 83 27 40 36 A3

: 46 23 DD 64 86 64 F7 64 73 46 04 30 3A 96 71 33

: 7E 98 F1 BE 18 B9 8B 10 DA FF FA 32 AC 03 18 37

: DA 87 32 5F EB F7 ED 0D 37 B2 1B 97 35 D6 38 F2

: F8 CC 4E 2D 00 E2 43 F1 6F 02 B2 FD 94 53 9D 7B

: 78 00 4D FB 4D 47 63 6E B9 65 92 4C 03 C2 A6 9F

: 20 59 80 D5 A0 D4 B2 79 51 6E 31 B6 20 D4 A9 43

: 80 31 CE C6 93 0C B0 1E 2F 13 3F C3 C0 E0 7B 16

: 89 76 88 DD 38 D6 8F 2B 5F 6F 50 1D F7 48 D9 2E

: 89 C2 04 1F 78 6B AC 85 97 55 0F 71 BE 5D D2 C7

: C8 22 41 B6 C9 A0 C9 81 CD 93 55 83 D2 9D E3 00

: 63 72 4F 79 D4 E9 AD 1D 1E CD 79 3F 89 9A 66 E4

: F6 A2 1D EC A0 3E 61 35 81 CC B8 83 5C DF 87 24

: }


Figure 9: Private Key Record Header And Key






We needed to find a document that described the PBEWithSha1AndTripleDESCBC password-based encryption technique. An initial search of the Web did not reveal any additional information about the OID. However, we located documentation that described the password-based encryption technique for a similar OID called PBEWithSha1And3-KeyTripleDESCBC in the RSA laboratories PKCS#12 Personal Information Exchange Standard [RSA 97]. We thought there was a good chance that both object identifiers used the same password-based encryption technique.

We performed a Web search for an encryption package that supported the hashing function SHA1 and Triple DES CBC encryption. This resulted in the discovery of a package called SSLEAY that contains cryptographic libraries and certificate support software. Additionally, we located a software package that enhanced the certificate support software in SSLEAY by adding support for the PKCS12 standard [RSA 97]. This was fantastic because we found all of the software needed to decrypt a Netscape private key record on the Web.

We examined the source code from the downloaded software and incorporated into our browsing tool the portions that were needed to decrypt a private key. We then attempted to decrypt a private key using the code extracted from the implementation of the PKCS12 standard. This attempt ended in failure.

Because of our failed attempt, we decided to take a closer look at the Netscape NSS software. Upon examination, we noticed the function call SECKEY_ChangeKeyDBPasswordAlg. This API call appeared to change the password-based encryption algorithm used to encrypt the database. This was a guess because the NSS documentation only describes the higher level API calls necessary for using SSL and NSPR, it does not include (other than undocumented C header files) any documentation describing the lower level APIs. Examination of the header files yielded two password-based encryption algorithm identifiers that were of particular interest:

  1. SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC
  2. SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC

The first algorithm identifier appeared to be the same as the OID that we were unable to find any information about, while the second algorithm appeared to be the same as the OID that we had obtained documentation as well was an implementation. Possibly, our assumption that both OID’s were compatible was incorrect.

We then proceeded to write a program to change the database encryption algorithm to SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC. After much trial and error in trying to figure out the semantics of Netscape's undocumented interface, we were successful using code shown in Figure 10. This exercise turned out to be very informative. We learned that the global salt record was used in combination with the password (exact details were not known at this time) and that, contrary to what we had thought, the two OID’s were not compatible.

Next, we tried to decrypt a private key record in the converted base database. Initially we were unsuccessful, but after some trial and error, with different password formats (unicode or non-unicode), we discovered that we could decrypt a private key. The output from the NSS API call SECKEY_HashPassword needed to be the input password to the PBE PKCS12 decryption software that we obtained from the Web. After further trial and error (really a wild guess), we determined that the SECKEY_HashPassword actually performs the hashing function shown in Figure 11. This was determined by first noticing that all password were always 20 bytes long, indicating that the user input password and salt were most likely being used as input to SHA-1 (since SHA1 is a hashing function that always returns a twenty-byte digest).

On our first attempt, we used the SHA1_Update call in the hash function shown in Figure 11 to concatenate salt onto the password; this failed, however. Next we changed the order (salt then password); this worked.3

Almost incidentally, we also determined that key databases do not always contain a "Global Salt" record, which is reason for the HaveGlobalSalt flag in the password hashing function, which explains the "if" statement in the hash function. The hashed password, however, is always 20 bytes in length.



#include <stdio.h>

#include <string.h>

#include <secitem.h>

#include <key.h>

int main (int argc, char **argv)

{

SECKEYKeyDBHandle *Handle;

SECItem *st;

char passwd[512];

if (argc!=2) {

printf("usage: changedb <database file>\n");

return -1;

}

if ((Handle=SECKEY_OpenKeyDBFilename(argv[1],0))==NULL) {

printf("database open error\n");

return -1;

}

printf("Enter Password:");

fgets(passwd,sizeof(passwd),stdin);

if (strlen(passwd)) passwd[strlen(passwd)-1]='\0';

st=SECKEY_HashPassword(passwd,Handle->global_salt );

if (SECKEY_CheckKeyDBPassword(Handle,st)!=SECSuccess) {

printf("Incorrect Password\n");

SECKEY_CloseKeyDB(Handle);

return -1;

}

// Original Database format was SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC

if (SECKEY_ChangeKeyDBPasswordAlg(Handle,st, st,

SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC)==SECSuccess)

printf("Database Format Change Success\n");

else printf("Database Format Change Falied\n");

SECKEY_CloseKeyDB(Handle);

return 0;

}


Figure 10: Code to Change the DB Encryption Algorithm








Unsigned char HashPassword[20];

void __fastcall TForm1::SetHashPassword(char *Password)

{

SHA_CTX c;

SHA1_Init(&c);

if (HaveGlobalSalt) SHA1_Update(&c,GlobalSalt, 16);

SHA1_Update(&c, (unsigned char *)Password,strlen(Password));

SHA1_Final(HashPasswd,&c);

}


Figure 11: Password and Global Salt Hash Function






At this point, our tool could decrypt all of the records in private key database that had been converted to use the SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC encryption algorithm. However, requiring a database conversion was unsatisfactory to us—we were too close to stop here. So we needed to determine the details of the PBEWithSha1AndTripleDESCBC encryption algorithm. An exhaustive search of the Web was performed and the following information was discovered about this uncommon OID (note again the overseas addresses in one of the sources):

Using the above resources and still more trial and error, this time to figure out the semantics of the above terse documentation, we finally were able to decrypt the private key information in the database without using NSS to change to the database password encryption algorithms. The private keys were decrypted as follows:

  1. The user input password and global salt (if present) are used to generate a hash password using the SetHashPassword method shown in Figure 11.
  2. The "Key" and the "Initial Value" for Triple Des Cipher are generated by calling the BEPGetKeyIV method shown in Figure 12 using the HashPassword for the password value, salt and iterator from the ASN.1 object. A 24-byte key and 16-byte initial value are returned.
  3. Next, the decrypt function shown in Figure 13 is called using the initial value and key generated in step 2 and the encrypted data portion of ASN.1 object. If decryption is successful, a pointer to decrypted data as well as its length is returned.

This software was then incorporated into our browsing tool. This tool now had the capability to examine and decrypt all the records in Netscape’s certificate and key databases.

Next, we investigated Netscape’s password check record. After some trial and error, we determined that this record contained a sixteen-byte salt, an encryption algorithm OID, and sixteen bytes of encrypted data. When the encrypted data is decrypted correctly, the plain text turns out to be the string "password-check." This is how Netscape determines if a password is correct without decrypting a private key record.

Now our database-browsing tool was robust enough to allow us to easily examine the Netscape databases. We investigated how Netscape uses database keys to link certificates in the certificate database to the private key database. We studied a certificate and private key record that was known to match and noticed that Netscape included an octet string (see Figure 14), the certificate record which was the database access key to obtain the private key record from the private database (see Figure 15). Additional information about Netscape’s use of database access keys can be determined through studying database records using the browsing tool. Such information is beyond the scope of this report.



void __fastcall TForm1::PBEGetKeyIV(unsigned char *Password,

unsigned char *Salt,

int SaltLength,

int Iterator,

unsigned char *Key,

unsigned char *IV)

{

unsigned char Digest[20],

SecondDigest[20],

DK[40];

SHA_CTX c;

HMAC_SHA1_CTX hmac_ctx;

memset (SecondDigest, 0, 20);

memcpy (SecondDigest, Salt, SaltLength);

SHA1_Init(&c);

SHA1_Update(&c, Password,20);

SHA1_Update(&c, Salt,SaltLength);

SHA1_Final(Digest,&c);

for (int i = 1; i < Iterator; i++)

{

SHA1_Init(&c);

SHA1_Update(&c,Digest, 20);

SHA1_Final(Digest,&c);

}

for (int i = 0; i < 2; i++)

{

HMAC_SHA1_Init(&hmac_ctx, Digest,20);

HMAC_SHA1_Update(&hmac_ctx, SecondDigest, 20);

HMAC_SHA1_Update(&hmac_ctx, Salt, SaltLength);

HMAC_SHA1_Final(&hmac_ctx, &DK[i*20], NULL);

HMAC_SHA1_Init(&hmac_ctx, Digest,20);

HMAC_SHA1_Update(&hmac_ctx, SecondDigest, 20);

HMAC_SHA1_Final(&hmac_ctx, SecondDigest, NULL);

}

memcpy (Key, DK,24);

memcpy (IV, DK + 32, 8);

}


Figure 12: Key and IV Generation








unsigned char * __fastcall TForm1::TrippleDESDecrypt(unsigned char *CryptData,

int CryptDataLen,

unsigned char *Key,

unsigned char *IV,

int *DecryptDataLen)

{

DES_EDE3_CBC_Type cipher_ctx;

unsigned char *DecryptData;

int tmp;

if ((DecryptData = (unsigned char *)malloc (CryptDataLen + 8))==NULL)

{

*DecryptDataLen=0;

return(NULL);

}

DES_EDE_3_CBC_Init(&cipher_ctx, Key, IV,DECRYPT);

DES_EDE_3_CBC_Update(&cipher_ctx,DecryptData,DecryptDataLen,CryptData,

CryptDataLen);

if (!DES_EDE_3_CBC_Final(&cipher_ctx, DecryptData+*DecryptDataLen,&tmp))

{

free(DecryptData);

*DecryptDataLen=0;

return(NULL);

}

(*DecryptDataLen)+=tmp;

return(DecryptData);

}


Figure 13: Triple DES Decrypt Function








470 03 75: BIT STRING 0 unused bits, encapsulates {

473 30 72: SEQUENCE {

475 02 65: INTEGER

: 00 B1 E0 AD 39 E7 09 41 B9 D3 21 90 9B 0F 95 78

: E6 FD EF D3 62 34 51 4D 79 02 83 17 9F 4F 09 68

: 5C 81 A2 E6 2D B1 F7 BB E6 69 BA 39 A5 F4 17 0B

: A9 A9 EA B0 4C 7F FF 55 A5 46 A7 67 10 3A 1F E1

: 7B

542 02 3: INTEGER 65537

: }

: }


Figure 14: Certificate Fragment of Database Access Key







Key Data:

Size is :65 bytes

0 00B1 E0AD 39E7 0941 B9D3 2190 9B0F 9578 E6FD EFD3 ....9..A..!....x....

20 6234 514D 7902 8317 9F4F 0968 5C81 A2E6 2DB1 F7BB b4QMy....O.h\...-...

40 E669 BA39 A5F4 170B A9A9 EAB0 4C7F FF55 A546 A767 .i.9........L..U.F.g

60 103A 1FE1 7B


Figure 15: Private Key Record Access Key






[abstract] [chapter 1] [chapter 2] [chapter 3] [chapter 4] [chapter 5] [references] [DTIC] [PDF]


1. A string of random bits concatenated with a key or password to foil pre-computation attacks.
2. A concept defined by the ASN.1 specification.
3. Sometimes, good clean living pays off.