int Decrypt(rFile& pkg_f, rFile& dec_pkg_f, PKGHeader* m_header) { if (!LoadHeader(pkg_f, m_header)) return -1; aes_context c; u8 iv[HASH_LEN]; u8 buf[BUF_SIZE]; u8 ctr[BUF_SIZE]; // Debug key u8 key[0x40]; memset(key, 0, 0x40); memcpy(key+0x00, &m_header->qa_digest[0], 8); // &data[0x60] memcpy(key+0x08, &m_header->qa_digest[0], 8); // &data[0x60] memcpy(key+0x10, &m_header->qa_digest[8], 8); // &data[0x68] memcpy(key+0x18, &m_header->qa_digest[8], 8); // &data[0x68] pkg_f.Seek(m_header->data_offset); u32 parts = (m_header->data_size + BUF_SIZE - 1) / BUF_SIZE; wxProgressDialog pdlg("PKG Decrypter / Installer", "Please wait, decrypting...", parts, 0, wxPD_AUTO_HIDE | wxPD_APP_MODAL); memcpy(iv, m_header->klicensee, sizeof(iv)); aes_setkey_enc(&c, PKG_AES_KEY, 128); for (u32 i=0; i<parts; i++) { memset(buf, 0, sizeof(buf)); u32 length = pkg_f.Read(buf, BUF_SIZE); u32 bits = (length + HASH_LEN - 1) / HASH_LEN; if (m_header->pkg_type == PKG_RELEASE_TYPE_DEBUG) { for (u32 j=0; j<bits; j++) { u8 hash[0x14]; sha1(key, 0x40, hash); *(u64*)&buf[j*HASH_LEN + 0] ^= *(u64*)&hash[0]; *(u64*)&buf[j*HASH_LEN + 8] ^= *(u64*)&hash[8]; *(be_t<u64>*)&key[0x38] += 1; } } if (m_header->pkg_type == PKG_RELEASE_TYPE_RELEASE) { for (u32 j=0; j<bits; j++) { aes_crypt_ecb(&c, AES_ENCRYPT, iv, ctr+j*HASH_LEN); be_t<u64> hi = *(be_t<u64>*)&iv[0]; be_t<u64> lo = *(be_t<u64>*)&iv[8] + 1; if (lo == 0) hi += 1; *(be_t<u64>*)&iv[0] = hi; *(be_t<u64>*)&iv[8] = lo; } for (u32 j=0; j<length; j++) { buf[j] ^= ctr[j]; } } dec_pkg_f.Write(buf, length); pdlg.Update(i); } pdlg.Update(parts); return 0; }
void mschap(Ticketreq *tr) { char *secret, *hkey; char sbuf[SECRETLEN], hbuf[DESKEYLEN]; uchar chal[CHALLEN]; uchar hash[MShashlen]; uchar hash2[MShashlen]; uchar resp[MSresplen]; OMSchapreply reply; int dupe, lmok, ntok; DigestState *s; uchar digest[SHA1dlen]; /* * Create a challenge and send it. */ randombytes((uchar*)chal, sizeof(chal)); write(1, chal, sizeof(chal)); /* * get chap reply */ if(readn(0, &reply, sizeof(reply)) < 0) exits(0); safecpy(tr->uid, reply.uid, sizeof(tr->uid)); /* * lookup */ secret = findsecret(KEYDB, tr->uid, sbuf); hkey = findkey(KEYDB, tr->hostid, hbuf); if(hkey == 0 || secret == 0){ replyerror("mschap-fail bad response %s/%s(%s)", tr->uid, tr->hostid, raddr); logfail(tr->uid); exits(0); } lmhash(hash, secret); mschalresp(resp, hash, chal); lmok = memcmp(resp, reply.LMresp, MSresplen) == 0; nthash(hash, secret); mschalresp(resp, hash, chal); ntok = memcmp(resp, reply.NTresp, MSresplen) == 0; dupe = memcmp(reply.LMresp, reply.NTresp, MSresplen) == 0; /* * It is valid to send the same response in both the LM and NTLM * fields provided one of them is correct, if neither matches, * or the two fields are different and either fails to match, * the whole sha-bang fails. * * This is an improvement in security as it allows clients who * wish to do NTLM auth (which is insecure) not to send * LM tokens (which is very insecure). * * Windows servers supports clients doing this also though * windows clients don't seem to use the feature. */ if((!ntok && !lmok) || ((!ntok || !lmok) && !dupe)){ replyerror("mschap-fail bad response %s/%s(%s) %d,%d,%d", tr->uid, tr->hostid, raddr, dupe, lmok, ntok); logfail(tr->uid); exits(0); } succeed(tr->uid); /* * reply with ticket & authenticator */ if(tickauthreply(tr, hkey) < 0) exits(0); if(debug) replyerror("mschap-ok %s/%s(%s) %ux", tr->uid, tr->hostid, raddr); nthash(hash, secret); md4(hash, 16, hash2, 0); s = sha1(hash2, 16, 0, 0); sha1(hash2, 16, 0, s); sha1(chal, 8, digest, s); if(write(1, digest, 16) < 0) exits(0); }