/* We're essentially using three salts, but we're going to pack it into a single blob for now. Input: $NETNTLMv2$USER_DOMAIN$_SERVER_CHALLENGE_$_NTLMv2_RESP_$_CLIENT_CHALLENGE_ Username: <=20 Domain: <=15 Server Challenge: 8 bytes Client Challenge: ??? Output: Identity length, Identity(UTF16)\0, Challenge Size, Server Challenge + Client Challenge */ static void *get_salt(char *ciphertext) { static unsigned char *binary_salt; int i, identity_length, challenge_size; char *pos = NULL; #if !ARCH_ALLOWS_UNALIGNED static unsigned *bs2; if (!bs2) bs2 = mem_alloc_tiny(SALT_SIZE, MEM_ALIGN_WORD); #endif if (!binary_salt) binary_salt = mem_alloc_tiny(SALT_SIZE, MEM_ALIGN_WORD); /* Calculate identity length */ for (pos = ciphertext + 11; *pos != '$'; pos++); /* Convert identity (username + domain) string to NT unicode */ #if !ARCH_ALLOWS_UNALIGNED identity_length = enc_to_utf16((uint16 *)bs2, 2 * (USERNAME_LENGTH + DOMAIN_LENGTH), (uchar *)ciphertext + 11, pos - (ciphertext + 11)) * sizeof(int16); if (identity_length < 0) // Truncated at Unicode conversion. identity_length = strlen16((UTF16 *)bs2) * sizeof(int16); memcpy(&binary_salt[1], bs2, identity_length); #else identity_length = enc_to_utf16((uint16 *)&binary_salt[1], 2 * (USERNAME_LENGTH + DOMAIN_LENGTH), (uchar *)ciphertext + 11, pos - (ciphertext + 11)) * sizeof(int16); if (identity_length < 0) // Truncated at Unicode conversion. identity_length = strlen16((UTF16 *)&binary_salt[1]) * sizeof(int16); #endif /* Set server and client challenge size */ /* Skip: $NETNTLMv2$USER_DOMAIN$ */ ciphertext = pos + 1; /* SERVER_CHALLENGE$NTLMV2_RESPONSE$CLIENT_CHALLENGE --> SERVER_CHALLENGECLIENT_CHALLENGE */ /* CIPHERTEXT == NTLMV2_RESPONSE (16 bytes / 32 characters) */ challenge_size = (strlen(ciphertext) - CIPHERTEXT_LENGTH - 2) / 2; /* Store identity length */ binary_salt[0] = identity_length; /* Set challenge size in response - 2 bytes */ memset(binary_salt + 1 + identity_length, 0, 1); memset(binary_salt + 1 + identity_length + 1, (challenge_size & 0xFF00) >> 8, 1); memset(binary_salt + 1 + identity_length + 2, challenge_size & 0x00FF, 1); /* Set server challenge */ for (i = 0; i < SERVER_CHALL_LENGTH / 2; i++) binary_salt[identity_length + 1 + 2 + 1 + i] = (atoi16[ARCH_INDEX(ciphertext[i*2])] << 4) + atoi16[ARCH_INDEX(ciphertext[i*2+1])]; /* Set client challenge */ ciphertext += SERVER_CHALL_LENGTH + 1 + CIPHERTEXT_LENGTH + 1; for (i = 0; i < strlen(ciphertext) / 2; ++i) binary_salt[identity_length + 1 + 2 + 1 + SERVER_CHALL_LENGTH / 2 + i] = (atoi16[ARCH_INDEX(ciphertext[i*2])] << 4) + atoi16[ARCH_INDEX(ciphertext[i*2+1])]; /* Return a concatenation of the server and client challenges and the identity value */ return (void*)binary_salt; }
static void DCC(unsigned char *salt, unsigned int username_len, unsigned int *dcc_hash, unsigned int count) { unsigned int id ; unsigned int buffer[64] ; unsigned int nt_hash[69] ; // large enough to handle 128 byte user name (when we expand to that size). int password_len; MD4_CTX ctx; for (id = 0; id < count; id++) { /* Proper Unicode conversion from UTF-8 or codepage */ password_len = enc_to_utf16((UTF16*)buffer, MAX_PLAINTEXT_LENGTH, (UTF8*)key_host[id], strlen((const char*)key_host[id])); /* Handle truncation */ if (password_len < 0) password_len = strlen16((UTF16*)buffer); // generate MD4 hash of the password (NT hash) MD4_Init(&ctx); MD4_Update(&ctx, buffer, password_len<<1); MD4_Final((unsigned char*)nt_hash, &ctx); // concatenate NT hash and the username (salt) memcpy((unsigned char *)nt_hash + 16, salt, username_len << 1) ; MD4_Init(&ctx); MD4_Update(&ctx, nt_hash, (username_len<<1)+16); MD4_Final((unsigned char*)(dcc_hash+4*id), &ctx); } }
static int crypt_all(int *pcount, struct db_salt *salt) { const int count = *pcount; int index = 0; #ifdef _OPENMP #pragma omp parallel for #endif for (index = 0; index < count; index++) { unsigned char passwordBuf[PLAINTEXT_LENGTH*2+2]; int len; len = enc_to_utf16((UTF16*)passwordBuf, PLAINTEXT_LENGTH, (UTF8*)saved_key[index], strlen(saved_key[index])); if (len < 0) len = strlen16((UTF16*)passwordBuf); len <<= 1; if(cur_salt->version == 0) { SHA_CTX ctx; SHA1_Init(&ctx); SHA1_Update(&ctx, cur_salt->esalt, 16); SHA1_Update(&ctx, passwordBuf, len); SHA1_Final((unsigned char*)crypt_out[index], &ctx); } else if(cur_salt->version == 1) { SHA256_CTX ctx; SHA256_Init(&ctx); SHA256_Update(&ctx, cur_salt->esalt, 16); SHA256_Update(&ctx, passwordBuf, len); SHA256_Final((unsigned char*)crypt_out[index], &ctx); } } return count; }
static unsigned char* GeneratePasswordHashUsingSHA1(char *password) { unsigned char hashBuf[20], *inputBuf, *key, *final; /* H(0) = H(salt, password) * hashBuf = SHA1Hash(salt, password); * create input buffer for SHA1 from salt and unicode version of password */ unsigned char passwordBuf[512] = {0}; int passwordBufSize; int i; SHA_CTX ctx; /* convert key to UTF-16LE */ passwordBufSize = enc_to_utf16((UTF16*)passwordBuf, 125, (UTF8*)password, strlen(password)); if (passwordBufSize < 0) passwordBufSize = strlen16((UTF16*)passwordBuf); passwordBufSize <<= 1; inputBuf = (unsigned char *)malloc(salt_struct->saltSize + passwordBufSize); memcpy(inputBuf, salt_struct->osalt, salt_struct->saltSize); memcpy(inputBuf + salt_struct->saltSize, passwordBuf, passwordBufSize); SHA1_Init(&ctx); SHA1_Update(&ctx, inputBuf, salt_struct->saltSize + passwordBufSize); SHA1_Final(hashBuf, &ctx); free(inputBuf); /* Generate each hash in turn * H(n) = H(i, H(n-1)) * hashBuf = SHA1Hash(i, hashBuf); */ // Create an input buffer for the hash. This will be 4 bytes larger than // the hash to accommodate the unsigned int iterator value. inputBuf = (unsigned char *)malloc(0x14 + 0x04); // Create a byte array of the integer and put at the front of the input buffer // 1.3.6 says that little-endian byte ordering is expected memcpy(inputBuf + 4, hashBuf, 20); for (i = 0; i < 50000; i++) { *(int *)inputBuf = i; // XXX: size & endianness // 'append' the previously generated hash to the input buffer SHA1_Init(&ctx); SHA1_Update(&ctx, inputBuf, 0x14 + 0x04); SHA1_Final(inputBuf + 4, &ctx); } // Finally, append "block" (0) to H(n) // hashBuf = SHA1Hash(hashBuf, 0); i = 0; memmove(inputBuf, inputBuf + 4, 20); memcpy(inputBuf + 20, &i, 4); // XXX: size & endianness SHA1_Init(&ctx); SHA1_Update(&ctx, inputBuf, 0x14 + 0x04); SHA1_Final(hashBuf, &ctx); free(inputBuf); key = DeriveKey(hashBuf); // Should handle the case of longer key lengths as shown in 2.3.4.9 // Grab the key length bytes of the final hash as the encrypytion key final = (unsigned char *)malloc(salt_struct->keySize/8);
static void sevenzip_set_key(char *key, int index) { UTF16 c_key[PLAINTEXT_LENGTH + 1]; int length = strlen(key); /* Convert password to utf-16-le format (--encoding aware) */ length = enc_to_utf16(c_key, PLAINTEXT_LENGTH, (UTF8*)key, length); if (length <= 0) length = strlen16(c_key); inbuffer[index].length = length; memcpy(inbuffer[index].v, c_key, 2 * length); }
static char *get_key(int index) { static UTF16 u16[PLAINTEXT_LENGTH + 1]; static UTF8 out[3 * PLAINTEXT_LENGTH + 1]; int i, len = saved_idx[index + 1] - saved_idx[index]; UTF8 *key = (UTF8*)&saved_key[saved_idx[index]]; for (i = 0; i < len; i++) out[i] = *key++; out[i] = 0; /* Ensure we truncate just like the GPU conversion does */ enc_to_utf16(u16, PLAINTEXT_LENGTH, (UTF8*)out, len); return (char*)utf16_to_enc(u16); }
static void set_key(char *key, int index) { int plen; UTF16 buf[PLAINTEXT_LENGTH + 1]; /* UTF-16LE encode the password, encoding aware */ plen = enc_to_utf16(buf, PLAINTEXT_LENGTH, (UTF8*) key, strlen(key)); if (plen < 0) plen = strlen16(buf); memcpy(&saved_key[UNICODE_LENGTH * index], buf, UNICODE_LENGTH); saved_len[index] = plen << 1; #ifdef CL_VERSION_1_0 new_keys = 1; #endif }
static void set_key(char *key, int index) { UTF16 *utfkey = (UTF16*)&saved_key[index * UNICODE_LENGTH]; /* Clean slate */ memset(utfkey, 0, UNICODE_LENGTH); /* convert key to UTF-16LE */ saved_len[index] = enc_to_utf16(utfkey, PLAINTEXT_LENGTH, (UTF8*)key, strlen(key)); if (saved_len[index] < 0) saved_len[index] = strlen16(utfkey); /* Prepare for GPU */ utfkey[saved_len[index]] = 0x80; saved_len[index] <<= 1; new_keys = 1; //dump_stuff_msg("key buffer", &saved_key[index*UNICODE_LENGTH], UNICODE_LENGTH); }
/* We're essentially using three salts, but we're going to pack it into a single blob for now. |Client Challenge (8 Bytes)|Server Challenge (8 Bytes)|Unicode(Username (<=20).Domain (<=15)) */ static void *get_salt(char *ciphertext) { static unsigned char *binary_salt; unsigned char identity[USERNAME_LENGTH + DOMAIN_LENGTH + 1]; UTF16 identity_ucs2[USERNAME_LENGTH + DOMAIN_LENGTH + 1]; int i, identity_length; int identity_ucs2_length; char *pos = NULL; if (!binary_salt) binary_salt = mem_alloc_tiny(SALT_SIZE, MEM_ALIGN_WORD); memset(binary_salt, 0, SALT_SIZE); /* Calculate identity length */ for (pos = ciphertext + 9; *pos != '$'; pos++); identity_length = pos - (ciphertext + 9); /* Convert identity (username + domain) string to NT unicode */ strnzcpy((char *)identity, ciphertext + 9, sizeof(identity)); identity_ucs2_length = enc_to_utf16((UTF16 *)identity_ucs2, USERNAME_LENGTH + DOMAIN_LENGTH, (UTF8 *)identity, identity_length) * sizeof(int16); if (identity_ucs2_length < 0) // Truncated at Unicode conversion. identity_ucs2_length = strlen16((UTF16 *)identity_ucs2) * sizeof(int16); binary_salt[16] = (unsigned char)identity_ucs2_length; memcpy(&binary_salt[17], (char *)identity_ucs2, identity_ucs2_length); /* Set server challenge */ ciphertext += 10 + identity_length; for (i = 0; i < 8; i++) binary_salt[i] = (atoi16[ARCH_INDEX(ciphertext[i*2])] << 4) + atoi16[ARCH_INDEX(ciphertext[i*2+1])]; /* Set client challenge */ ciphertext += 2 + CHALLENGE_LENGTH / 2 + CIPHERTEXT_LENGTH; for (i = 0; i < 8; ++i) binary_salt[i + 8] = (atoi16[ARCH_INDEX(ciphertext[i*2])] << 4) + atoi16[ARCH_INDEX(ciphertext[i*2+1])]; /* Return a concatenation of the server and client challenges and the identity value */ return (void*)binary_salt; }
static int crypt_all(int *pcount, struct db_salt *salt) { const int count = *pcount ; int salt_len; #ifdef _DEBUG struct timeval startc, endc, startg, endg ; gettimeofday(&startc, NULL) ; #endif UTF16 salt_host[MAX_SALT_LENGTH + 1]; memset(salt_host, 0, sizeof(salt_host)); /* Proper Unicode conversion from UTF-8 or codepage */ salt_len = enc_to_utf16(salt_host, MAX_SALT_LENGTH, (UTF8*)currentsalt.username, currentsalt.length); /* Handle truncation */ if (salt_len < 0) salt_len = strlen16(salt_host); DCC((unsigned char*)salt_host, salt_len, dcc_hash_host, count) ; if(salt_len > 22) pbkdf2_iter0(dcc_hash_host,(unsigned char*)salt_host, (salt_len << 1) , count); #ifdef _DEBUG gettimeofday(&startg, NULL) ; #endif ///defined in common_opencl_pbkdf2.c. Details provided in common_opencl_pbkdf2.h pbkdf2_divide_work(dcc_hash_host, (cl_uint*)salt_host, salt_len, currentsalt.iter_cnt, dcc2_hash_host, hmac_sha1_out, count) ; #ifdef _DEBUG gettimeofday(&endg, NULL); gettimeofday(&endc, NULL); fprintf(stderr, "\nGPU:%f ",(endg.tv_sec - startg.tv_sec) + (double)(endg.tv_usec - startg.tv_usec) / 1000000.000) ; fprintf(stderr, "CPU:%f ",(endc.tv_sec - startc.tv_sec) + (double)(endc.tv_usec - startc.tv_usec) / 1000000.000 - ((endg.tv_sec - startg.tv_sec) + (double)(endg.tv_usec - startg.tv_usec) / 1000000.000)) ; #endif return count ; }
void sevenzip_kdf(UTF8 *password, unsigned char *master) { int len; long long rounds = (long long) 1 << cur_salt->NumCyclesPower; long long round; UTF16 buffer[PLAINTEXT_LENGTH + 1]; #if !ARCH_LITTLE_ENDIAN int i; unsigned char temp[8] = { 0,0,0,0,0,0,0,0 }; #endif SHA256_CTX sha; /* Convert password to utf-16-le format (--encoding aware) */ len = enc_to_utf16(buffer, PLAINTEXT_LENGTH, password, strlen((char*)password)); if (len <= 0) { password[-len] = 0; // match truncation len = strlen16(buffer); } len *= 2; /* kdf */ SHA256_Init(&sha); for (round = 0; round < rounds; round++) { //SHA256_Update(&sha, "", cur_salt->SaltSize); SHA256_Update(&sha, (char*)buffer, len); #if ARCH_LITTLE_ENDIAN SHA256_Update(&sha, (char*)&round, 8); #else SHA256_Update(&sha, temp, 8); for (i = 0; i < 8; i++) if (++(temp[i]) != 0) break; #endif } SHA256_Final(master, &sha); }