string base64decode(const string& buf) { unsigned len; char *plain = (char*)mir_base64_decode(buf.data(), &len); return (plain == NULL) ? string() : string(plain, len); }
// decrypt string using KeyX, return decoded string as ASCII or NULL LPSTR __cdecl cpp_decrypt(pCNTX ptr, LPCSTR szEncMsg) { ptrA ciphered; try { ptr->error = ERROR_SEH; pSIMDATA p = (pSIMDATA)ptr->pdata; unsigned clen = (unsigned)strlen(szEncMsg); if (ptr->features & FEATURES_BASE64) ciphered = (LPSTR)mir_base64_decode(szEncMsg, &clen); else ciphered = base16decode(szEncMsg, &clen); LPSTR bciphered = ciphered; BYTE dataflag = 0; if (ptr->features & FEATURES_GZIP) { dataflag = *ciphered; bciphered++; clen--; // cut GZIP flag } if (ptr->features & FEATURES_CRC32) { int len = *(WORD*)bciphered; bciphered += 2; clen -= 2; // cut CRC32 length if ((int)clen - CRC32::DIGESTSIZE < len) { // mesage not full #if defined(_DEBUG) || defined(NETLIB_LOG) Sent_NetLog("cpp_decrypt: error bad_len"); #endif ptr->error = ERROR_BAD_LEN; return NULL; } BYTE crc32[CRC32::DIGESTSIZE]; memset(crc32, 0, sizeof(crc32)); CRC32().CalculateDigest(crc32, (PBYTE)(bciphered + CRC32::DIGESTSIZE), len); if (memcmp(crc32, bciphered, CRC32::DIGESTSIZE)) { // message is bad crc #if defined(_DEBUG) || defined(NETLIB_LOG) Sent_NetLog("cpp_decrypt: error bad_crc"); #endif ptr->error = ERROR_BAD_CRC; return NULL; } bciphered += CRC32::DIGESTSIZE; // cut CRC32 digest clen = len; } string unciphered; CBC_Mode<AES>::Decryption dec(p->KeyX, Tiger::DIGESTSIZE, IV); StreamTransformationFilter cbcDecryptor(dec, new StringSink(unciphered)); cbcDecryptor.Put((PBYTE)bciphered, clen); cbcDecryptor.MessageEnd(); if (dataflag & DATA_GZIP) { size_t clen2 = clen; LPSTR res = (LPSTR)cpp_gunzip((PBYTE)unciphered.data(), unciphered.length(), clen2); replaceStr(ptr->tmp, mir_strndup(res, clen2)); free(res); } else replaceStr(ptr->tmp, mir_strdup(unciphered.c_str())); ptr->error = ERROR_NONE; return ptr->tmp; } catch (...) { #if defined(_DEBUG) || defined(NETLIB_LOG) Sent_NetLog("cpp_decrypt: error seh"); #endif mir_free(ptr->tmp); ptr->tmp = 0; return NULL; } }
bool TScramAuth::validateLogin(const TCHAR *challenge) { unsigned chlLen; ptrA chl((char*)mir_base64_decode(_T2A(challenge), &chlLen)); return chl && strncmp((char*)chl + 2, serverSignature, chlLen - 2) == 0; }
char* TScramAuth::getChallenge(const TCHAR *challenge) { unsigned chlLen, saltLen = 0; ptrA snonce, salt; int ind = -1; ptrA chl((char*)mir_base64_decode(_T2A(challenge), &chlLen)); for (char *p = strtok(NEWSTR_ALLOCA(chl), ","); p != NULL; p = strtok(NULL, ",")) { if (*p == 'r' && p[1] == '=') { // snonce if (strncmp(cnonce, p + 2, mir_strlen(cnonce))) return NULL; snonce = mir_strdup(p + 2); } else if (*p == 's' && p[1] == '=') // salt salt = (char*)mir_base64_decode(p + 2, &saltLen); else if (*p == 'i' && p[1] == '=') ind = atoi(p + 2); } if (snonce == NULL || salt == NULL || ind == -1) return NULL; ptrA passw(mir_utf8encodeT(info->conn.password)); size_t passwLen = mir_strlen(passw); BYTE saltedPassw[MIR_SHA1_HASH_SIZE]; Hi(saltedPassw, passw, passwLen, salt, saltLen, ind); BYTE clientKey[MIR_SHA1_HASH_SIZE]; mir_hmac_sha1(clientKey, saltedPassw, sizeof(saltedPassw), (BYTE*)"Client Key", 10); BYTE storedKey[MIR_SHA1_HASH_SIZE]; mir_sha1_ctx ctx; mir_sha1_init(&ctx); mir_sha1_append(&ctx, clientKey, MIR_SHA1_HASH_SIZE); mir_sha1_finish(&ctx, storedKey); char authmsg[4096]; int authmsgLen = mir_snprintf(authmsg, _countof(authmsg), "%s,%s,c=biws,r=%s", msg1, chl, snonce); BYTE clientSig[MIR_SHA1_HASH_SIZE]; mir_hmac_sha1(clientSig, storedKey, sizeof(storedKey), (BYTE*)authmsg, authmsgLen); BYTE clientProof[MIR_SHA1_HASH_SIZE]; for (unsigned j = 0; j < sizeof(clientKey); j++) clientProof[j] = clientKey[j] ^ clientSig[j]; /* Calculate the server signature */ BYTE serverKey[MIR_SHA1_HASH_SIZE]; mir_hmac_sha1(serverKey, saltedPassw, sizeof(saltedPassw), (BYTE*)"Server Key", 10); BYTE srvSig[MIR_SHA1_HASH_SIZE]; mir_hmac_sha1(srvSig, serverKey, sizeof(serverKey), (BYTE*)authmsg, authmsgLen); serverSignature = mir_base64_encode((PBYTE)srvSig, sizeof(srvSig)); char buf[4096]; ptrA encproof(mir_base64_encode((PBYTE)clientProof, sizeof(clientProof))); int cbLen = mir_snprintf(buf, "c=biws,r=%s,p=%s", snonce, encproof); return mir_base64_encode((PBYTE)buf, cbLen); }
char* TMD5Auth::getChallenge(const TCHAR *challenge) { if (iCallCount > 0) return NULL; iCallCount++; unsigned resultLen; ptrA text((char*)mir_base64_decode( _T2A(challenge), &resultLen)); TStringPairs pairs(text); const char *realm = pairs["realm"], *nonce = pairs["nonce"]; char cnonce[40], tmpBuf[40]; DWORD digest[4], hash1[4], hash2[4]; mir_md5_state_t ctx; Utils_GetRandom(digest, sizeof(digest)); mir_snprintf(cnonce, _countof(cnonce), "%08x%08x%08x%08x", htonl(digest[0]), htonl(digest[1]), htonl(digest[2]), htonl(digest[3])); T2Utf uname(info->conn.username), passw(info->conn.password); ptrA serv(mir_utf8encode(info->conn.server)); mir_md5_init(&ctx); mir_md5_append(&ctx, (BYTE*)(char*)uname, (int)mir_strlen(uname)); mir_md5_append(&ctx, (BYTE*)":", 1); mir_md5_append(&ctx, (BYTE*)realm, (int)mir_strlen(realm)); mir_md5_append(&ctx, (BYTE*)":", 1); mir_md5_append(&ctx, (BYTE*)(char*)passw, (int)mir_strlen(passw)); mir_md5_finish(&ctx, (BYTE*)hash1); mir_md5_init(&ctx); mir_md5_append(&ctx, (BYTE*)hash1, 16); mir_md5_append(&ctx, (BYTE*)":", 1); mir_md5_append(&ctx, (BYTE*)nonce, (int)mir_strlen(nonce)); mir_md5_append(&ctx, (BYTE*)":", 1); mir_md5_append(&ctx, (BYTE*)cnonce, (int)mir_strlen(cnonce)); mir_md5_finish(&ctx, (BYTE*)hash1); mir_md5_init(&ctx); mir_md5_append(&ctx, (BYTE*)"AUTHENTICATE:xmpp/", 18); mir_md5_append(&ctx, (BYTE*)(char*)serv, (int)mir_strlen(serv)); mir_md5_finish(&ctx, (BYTE*)hash2); mir_md5_init(&ctx); mir_snprintf(tmpBuf, _countof(tmpBuf), "%08x%08x%08x%08x", htonl(hash1[0]), htonl(hash1[1]), htonl(hash1[2]), htonl(hash1[3])); mir_md5_append(&ctx, (BYTE*)tmpBuf, (int)mir_strlen(tmpBuf)); mir_md5_append(&ctx, (BYTE*)":", 1); mir_md5_append(&ctx, (BYTE*)nonce, (int)mir_strlen(nonce)); mir_snprintf(tmpBuf, _countof(tmpBuf), ":%08d:", iCallCount); mir_md5_append(&ctx, (BYTE*)tmpBuf, (int)mir_strlen(tmpBuf)); mir_md5_append(&ctx, (BYTE*)cnonce, (int)mir_strlen(cnonce)); mir_md5_append(&ctx, (BYTE*)":auth:", 6); mir_snprintf(tmpBuf, _countof(tmpBuf), "%08x%08x%08x%08x", htonl(hash2[0]), htonl(hash2[1]), htonl(hash2[2]), htonl(hash2[3])); mir_md5_append(&ctx, (BYTE*)tmpBuf, (int)mir_strlen(tmpBuf)); mir_md5_finish(&ctx, (BYTE*)digest); char *buf = (char*)alloca(8000); int cbLen = mir_snprintf(buf, 8000, "username=\"%s\",realm=\"%s\",nonce=\"%s\",cnonce=\"%s\",nc=%08d," "qop=auth,digest-uri=\"xmpp/%s\",charset=utf-8,response=%08x%08x%08x%08x", uname, realm, nonce, cnonce, iCallCount, serv, htonl(digest[0]), htonl(digest[1]), htonl(digest[2]), htonl(digest[3])); return mir_base64_encode((PBYTE)buf, cbLen); }
char* NtlmCreateResponseFromChallenge(HANDLE hSecurity, const char *szChallenge, const TCHAR* login, const TCHAR* psw, bool http, unsigned& complete) { if (hSecurity == NULL || ntlmCnt == 0) return NULL; SecBufferDesc outputBufferDescriptor, inputBufferDescriptor; SecBuffer outputSecurityToken, inputSecurityToken; TimeStamp tokenExpiration; ULONG contextAttributes; char *szOutputToken; NtlmHandleType* hNtlm = (NtlmHandleType*)hSecurity; if (mir_tstrcmpi(hNtlm->szProvider, _T("Basic"))) { bool isGSSAPI = mir_tstrcmpi(hNtlm->szProvider, _T("GSSAPI")) == 0; TCHAR *szProvider = isGSSAPI ? (TCHAR*)_T("Kerberos") : hNtlm->szProvider; bool hasChallenge = szChallenge != NULL && szChallenge[0] != '\0'; if (hasChallenge) { unsigned tokenLen; BYTE *token = (BYTE*)mir_base64_decode(szChallenge, &tokenLen); if (token == NULL) return NULL; if (isGSSAPI && complete) return CompleteGssapi(hSecurity, token, tokenLen); inputBufferDescriptor.cBuffers = 1; inputBufferDescriptor.pBuffers = &inputSecurityToken; inputBufferDescriptor.ulVersion = SECBUFFER_VERSION; inputSecurityToken.BufferType = SECBUFFER_TOKEN; inputSecurityToken.cbBuffer = tokenLen; inputSecurityToken.pvBuffer = token; // try to decode the domain name from the NTLM challenge if (login != NULL && login[0] != '\0' && !hNtlm->hasDomain) { NtlmType2packet* pkt = (NtlmType2packet*)token; if (!strncmp(pkt->sign, "NTLMSSP", 8) && pkt->type == 2) { wchar_t* domainName = (wchar_t*)&token[pkt->targetName.offset]; int domainLen = pkt->targetName.len; // Negotiate ANSI? if yes, convert the ANSI name to unicode if ((pkt->flags & 1) == 0) { int bufsz = MultiByteToWideChar(CP_ACP, 0, (char*)domainName, domainLen, NULL, 0); wchar_t* buf = (wchar_t*)alloca(bufsz * sizeof(wchar_t)); domainLen = MultiByteToWideChar(CP_ACP, 0, (char*)domainName, domainLen, buf, bufsz) - 1; domainName = buf; } else domainLen /= sizeof(wchar_t); if (domainLen) { size_t newLoginLen = mir_tstrlen(login) + domainLen + 1; TCHAR *newLogin = (TCHAR*)alloca(newLoginLen * sizeof(TCHAR)); _tcsncpy(newLogin, domainName, domainLen); newLogin[domainLen] = '\\'; mir_tstrcpy(newLogin + domainLen + 1, login); char* szChl = NtlmCreateResponseFromChallenge(hSecurity, NULL, newLogin, psw, http, complete); mir_free(szChl); } } } } else { if (SecIsValidHandle(&hNtlm->hClientContext)) DeleteSecurityContext(&hNtlm->hClientContext); if (SecIsValidHandle(&hNtlm->hClientCredential)) FreeCredentialsHandle(&hNtlm->hClientCredential); SEC_WINNT_AUTH_IDENTITY auth; if (login != NULL && login[0] != '\0') { memset(&auth, 0, sizeof(auth)); NetlibLogf(NULL, "Security login requested, user: %S pssw: %s", login, psw ? "(exist)" : "(no psw)"); const TCHAR* loginName = login; const TCHAR* domainName = _tcschr(login, '\\'); size_t domainLen = 0; size_t loginLen = mir_tstrlen(loginName); if (domainName != NULL) { loginName = domainName + 1; loginLen = mir_tstrlen(loginName); domainLen = domainName - login; domainName = login; } else if ((domainName = _tcschr(login, '@')) != NULL) { loginName = login; loginLen = domainName - login; domainLen = mir_tstrlen(++domainName); } auth.User = (PWORD)loginName; auth.UserLength = (ULONG)loginLen; auth.Password = (PWORD)psw; auth.PasswordLength = (ULONG)mir_tstrlen(psw); auth.Domain = (PWORD)domainName; auth.DomainLength = (ULONG)domainLen; auth.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; hNtlm->hasDomain = domainLen != 0; } SECURITY_STATUS sc = AcquireCredentialsHandle(NULL, szProvider, SECPKG_CRED_OUTBOUND, NULL, hNtlm->hasDomain ? &auth : NULL, NULL, NULL, &hNtlm->hClientCredential, &tokenExpiration); if (sc != SEC_E_OK) { ReportSecError(sc, __LINE__); return NULL; } } outputBufferDescriptor.cBuffers = 1; outputBufferDescriptor.pBuffers = &outputSecurityToken; outputBufferDescriptor.ulVersion = SECBUFFER_VERSION; outputSecurityToken.BufferType = SECBUFFER_TOKEN; outputSecurityToken.cbBuffer = hNtlm->cbMaxToken; outputSecurityToken.pvBuffer = alloca(outputSecurityToken.cbBuffer); SECURITY_STATUS sc = InitializeSecurityContext(&hNtlm->hClientCredential, hasChallenge ? &hNtlm->hClientContext : NULL, hNtlm->szPrincipal, isGSSAPI ? ISC_REQ_MUTUAL_AUTH | ISC_REQ_STREAM : 0, 0, SECURITY_NATIVE_DREP, hasChallenge ? &inputBufferDescriptor : NULL, 0, &hNtlm->hClientContext, &outputBufferDescriptor, &contextAttributes, &tokenExpiration); complete = (sc != SEC_I_COMPLETE_AND_CONTINUE && sc != SEC_I_CONTINUE_NEEDED); if (sc == SEC_I_COMPLETE_NEEDED || sc == SEC_I_COMPLETE_AND_CONTINUE) sc = CompleteAuthToken(&hNtlm->hClientContext, &outputBufferDescriptor); if (sc != SEC_E_OK && sc != SEC_I_CONTINUE_NEEDED) { ReportSecError(sc, __LINE__); return NULL; } szOutputToken = mir_base64_encode((PBYTE)outputSecurityToken.pvBuffer, outputSecurityToken.cbBuffer); } else { if (!login || !psw) return NULL; char *szLogin = mir_t2a(login); char *szPassw = mir_t2a(psw); size_t authLen = mir_strlen(szLogin) + mir_strlen(szPassw) + 5; char *szAuth = (char*)alloca(authLen); int len = mir_snprintf(szAuth, authLen, "%s:%s", szLogin, szPassw); szOutputToken = mir_base64_encode((BYTE*)szAuth, len); complete = true; mir_free(szPassw); mir_free(szLogin); } if (szOutputToken == NULL) return NULL; if (!http) return szOutputToken; ptrA szProvider(mir_t2a(hNtlm->szProvider)); size_t resLen = mir_strlen(szOutputToken) + mir_strlen(szProvider) + 10; char *result = (char*)mir_alloc(resLen); mir_snprintf(result, resLen, "%s %s", szProvider, szOutputToken); mir_free(szOutputToken); return result; }