static void hash_plugin_parse_hash(char *filename) { int fd; char buf8[8]; int64_t cno = 0; int64_t data_size = 0; int64_t count = 0; unsigned char *chunk1 = NULL; unsigned char chunk2[4096]; char path[LARGE_ENOUGH]; char *name = NULL; headerver = 0; fd = open(filename, O_RDONLY); if (fd < 0) { fprintf(stderr, "Can't open file: %s\n", filename); return; } if (read(fd, buf8, 8) <= 0) { fprintf(stderr, "%s is not a DMG file!\n", filename); close(fd); return; } if (strncmp(buf8, "encrcdsa", 8) == 0) { headerver = 2; } else { if (lseek(fd, -8, SEEK_END) < 0) { fprintf(stderr, "Unable to seek in %s\n", filename); close(fd); return; } if (read(fd, buf8, 8) <= 0) { fprintf(stderr, "%s is not a DMG file!\n", filename); close(fd); return; } if (strncmp(buf8, "cdsaencr", 8) == 0) { headerver = 1; } } if (headerver == 0) { fprintf(stderr, "%s is not an encrypted DMG file!\n", filename); return; } // fprintf(stderr, "Header version %d detected\n", headerver); if (headerver == 1) { strnzcpyn(path, filename, LARGE_ENOUGH); if (lseek(fd, -sizeof(cencrypted_v1_header), SEEK_END) < 0) { fprintf(stderr, "Unable to seek in %s\n", filename); return; } if (read(fd, &header, sizeof(cencrypted_v1_header)) < 1) { fprintf(stderr, "%s is not a DMG file!\n", filename); return; } header_byteorder_fix(&header); if (!(name = basename(path))) name = path; fprintf(stderr, "%s (DMG v%d) successfully parsed, iterations " "count %u\n", name, headerver, header.kdf_iteration_count); printf("%s:$dmg$%d*%d*", name, headerver, header.kdf_salt_len); print_hex(header.kdf_salt, header.kdf_salt_len); printf("*%d*", header.len_wrapped_aes_key); print_hex(header.wrapped_aes_key, header.len_wrapped_aes_key); printf("*%d*", header.len_hmac_sha1_key); print_hex(header.wrapped_hmac_sha1_key, header.len_hmac_sha1_key); printf("*%u::::%s\n", header.kdf_iteration_count, filename); } else { strnzcpyn(path, filename, LARGE_ENOUGH); if (lseek(fd, 0, SEEK_SET) < 0) { fprintf(stderr, "Unable to seek in %s\n", filename); return; } if (read(fd, &header2, sizeof(cencrypted_v2_pwheader)) < 1) { fprintf(stderr, "%s is not a DMG file!\n", filename); return; } header2_byteorder_fix(&header2); chunk_size = header2.blocksize; if (lseek(fd, header2.dataoffset, SEEK_SET) < 0) { fprintf(stderr, "Unable to seek in %s\n", filename); return; } cno = ((header2.datasize + 4095ULL) / 4096) - 2; data_size = header2.datasize - cno * 4096ULL; if (data_size < 0) { fprintf(stderr, "%s is not a valid DMG file!\n", filename); return; } if (header2.kdf_salt_len > 32) { fprintf(stderr, "%s is not a valid DMG file, salt length is too long!\n", filename); return; } if (!(name = basename(path))) name = path; fprintf(stderr, "%s (DMG v%d) successfully parsed, iterations " "count %u\n", name, headerver, header2.kdf_iteration_count); /* read starting chunk(s) */ chunk1 = (unsigned char *) malloc(data_size); if (lseek(fd, header2.dataoffset + cno * 4096LL, SEEK_SET) < 0) { fprintf(stderr, "Unable to seek in %s\n", filename); free(chunk1); return; } count = read(fd, chunk1, data_size); if (count < 1 || count != data_size) { fprintf(stderr, "Unable to read required data from %s\n", filename); free(chunk1); return; } /* read last chunk */ if (lseek(fd, header2.dataoffset, SEEK_SET) < 0) { fprintf(stderr, "Unable to seek in %s\n", filename); free(chunk1); return; } count = read(fd, chunk2, 4096); if (count < 1 || count != 4096) { fprintf(stderr, "Unable to read required data from %s\n", filename); free(chunk1); return; } /* output hash */ printf("%s:$dmg$%d*%d*", name, headerver, header2.kdf_salt_len); print_hex(header2.kdf_salt, header2.kdf_salt_len); printf("*32*"); print_hex(header2.blob_enc_iv, 32); printf("*%d*", header2.encrypted_keyblob_size); print_hex(header2.encrypted_keyblob, header2.encrypted_keyblob_size); printf("*%d*%d*", (int)cno, (int)data_size); print_hex(chunk1, data_size); printf("*1*"); print_hex(chunk2, 4096); printf("*%u::::%s\n", header2.kdf_iteration_count, filename); free(chunk1); } close(fd); }
static void hash_plugin_parse_hash(char *in_filepath) { int fd; char buf8[8]; uint32_t i = 0; int64_t cno = 0; int64_t data_size = 0; int64_t count = 0; unsigned char *chunk1 = NULL; unsigned char chunk2[4096]; char filepath[LARGE_ENOUGH]; char name[LARGE_ENOUGH]; char *filename; int is_sparsebundle = 0; int filepath_length = strnzcpyn(filepath, in_filepath, LARGE_ENOUGH); strnzcpyn(name, in_filepath, LARGE_ENOUGH); if (!(filename = basename(name))) { filename = filepath; } if(strstr(filepath, ".sparsebundle")) { // The filepath given indicates this is a sparsebundle // A sparsebundle is simply a directory with contents. // Let's check to see if that is the case. struct stat file_stat; char *token_path; if (stat(filepath, &file_stat) != 0) { fprintf(stderr, "Can't stat file: %s\n", filename); return; } // Determine if the filepath given is a directory. if (!(file_stat.st_mode & S_IFDIR)) { fprintf(stderr, "%s claims to be a sparsebundle but isn't a directory\n", filename); return; } // Let's look to see if the token file exists. fprintf(stderr, "filepath = %s path_length = %d\n", filepath, filepath_length); if (filepath_length + 6 + 1 >= LARGE_ENOUGH) { fprintf(stderr, "Can't create token path. Path too long.\n"); return; } is_sparsebundle = 1; token_path = strnzcat(filepath, "/token", LARGE_ENOUGH); strnzcpyn(filepath, token_path, LARGE_ENOUGH); strnzcpyn(name, filepath, LARGE_ENOUGH); if (!(filename = basename(name))) { filename = filepath; } } headerver = 0; fd = open(filepath, O_RDONLY); if (fd < 0) { fprintf(stderr, "Can't open file: %s\n", filename); return; } if (read(fd, buf8, 8) <= 0) { fprintf(stderr, "%s is not a DMG file!\n", filename); close(fd); return; } if (strncmp(buf8, "encrcdsa", 8) == 0) { headerver = 2; } else { if (lseek(fd, -8, SEEK_END) < 0) { fprintf(stderr, "Unable to seek in %s\n", filename); close(fd); return; } if (read(fd, buf8, 8) <= 0) { fprintf(stderr, "%s is not a DMG file!\n", filename); close(fd); return; } if (strncmp(buf8, "cdsaencr", 8) == 0) { headerver = 1; } } if (headerver == 0) { fprintf(stderr, "%s is not an encrypted DMG file!\n", filename); return; } // fprintf(stderr, "Header version %d detected\n", headerver); if (headerver == 1) { if (lseek(fd, -sizeof(cencrypted_v1_header), SEEK_END) < 0) { fprintf(stderr, "Unable to seek in %s\n", filename); return; } if (read(fd, &header, sizeof(cencrypted_v1_header)) < 1) { fprintf(stderr, "%s is not a DMG file!\n", filename); return; } header_byteorder_fix(&header); fprintf(stderr, "%s (DMG v%d) successfully parsed, iterations " "count %u\n", name, headerver, header.kdf_iteration_count); printf("%s:$dmg$%d*%d*", name, headerver, header.kdf_salt_len); print_hex(header.kdf_salt, header.kdf_salt_len); printf("*%d*", header.len_wrapped_aes_key); print_hex(header.wrapped_aes_key, header.len_wrapped_aes_key); printf("*%d*", header.len_hmac_sha1_key); print_hex(header.wrapped_hmac_sha1_key, header.len_hmac_sha1_key); printf("*%u::::%s\n", header.kdf_iteration_count, filename); } else { cencrypted_v2_key_header_pointer header_pointer; int password_header_found = 0; if (lseek(fd, 0, SEEK_SET) < 0) { fprintf(stderr, "Unable to seek in %s\n", filename); return; } if (read(fd, &header2, sizeof(cencrypted_v2_header)) < 1) { fprintf(stderr, "%s is not a DMG file!\n", filename); return; } header2_byteorder_fix(&header2); chunk_size = header2.blocksize; // If this is a sparsebundle then there is no data to seek // to in this file so we skip over this particular check. if (!is_sparsebundle) { if (lseek(fd, header2.dataoffset, SEEK_SET) < 0) { fprintf(stderr, "Unable to seek in %s\n", filename); return; } } if(strstr(name, ".sparseimage") || is_sparsebundle) { // If this file is a sparseimage then we want one of the first chunks as the other chunks could be empty. cno = 1; data_size = 8192; } else { cno = ((header2.datasize + 4095ULL) / 4096) - 2; data_size = header2.datasize - cno * 4096ULL; } if (data_size < 0) { fprintf(stderr, "%s is not a valid DMG file!\n", filename); return; } for (i = 0; i < header2.keycount; i++) { // Seek to the start of the key header pointers offset by the current key which start immediately after the v2 header. if (lseek(fd, (sizeof(cencrypted_v2_header) + (sizeof(cencrypted_v2_key_header_pointer)*i)), SEEK_SET) < 0) { fprintf(stderr, "Unable to seek to header pointers in %s\n", filename); return; } // Read in the key header pointer count = read(fd, &header_pointer, sizeof(cencrypted_v2_key_header_pointer)); if (count < 1 || count != sizeof(cencrypted_v2_key_header_pointer)) { fprintf(stderr, "Unable to read required data from %s\n", filename); return; } v2_key_header_pointer_byteorder_fix(&header_pointer); // We, currently, only care about the password key header. If it's not the password header type skip over it. if (header_pointer.header_type != 1) { continue; } // Seek to where the password key header is in the file. if (lseek(fd, header_pointer.header_offset, SEEK_SET) < 0) { fprintf(stderr, "Unable to seek to password header in %s\n", filename); return; } // Read in the password key header but avoid reading anything into the keyblob. count = read(fd, &v2_password_header, sizeof(cencrypted_v2_password_header) - sizeof(unsigned char *)); if (count < 1 || count != (sizeof(cencrypted_v2_password_header) - sizeof(unsigned char *))) { fprintf(stderr, "Unable to read required data from %s\n", filename); return; } v2_password_header_byteorder_fix(&v2_password_header); // Allocate the keyblob memory v2_password_header.keyblob = mem_alloc(v2_password_header.keyblobsize); // Seek to the keyblob in the header if (lseek(fd, header_pointer.header_offset + sizeof(cencrypted_v2_password_header) - sizeof(unsigned char *), SEEK_SET) < 0) { fprintf(stderr, "Unable to seek to password header in %s\n", filename); free(v2_password_header.keyblob); return; } // Read in the keyblob count = read(fd, v2_password_header.keyblob, v2_password_header.keyblobsize); if (count < 1 || count != (v2_password_header.keyblobsize)) { fprintf(stderr, "Unable to read required data from %s\n", filename); free(v2_password_header.keyblob); return; } password_header_found = 1; // We only need one password header. Don't search any longer. break; } if (!password_header_found) { fprintf(stderr, "Password header not found in %s\n", filename); free(v2_password_header.keyblob); return; } if (v2_password_header.salt_size > 32) { fprintf(stderr, "%s is not a valid DMG file, salt length is too long!\n", filename); free(v2_password_header.keyblob); return; } fprintf(stderr, "%s (DMG v%d) successfully parsed, iterations " "count %u\n", name, headerver, v2_password_header.itercount); if (is_sparsebundle) { // If this is a sparsebundle then we need to get the chunks // of data out of 0 from the bands directory. Close the // previous file and open bands/0 char *bands_path; if (close(fd) != 0) { fprintf(stderr, "Failed closing file %s\n", filename); free(v2_password_header.keyblob); return; } filepath_length = strnzcpyn(filepath, in_filepath, LARGE_ENOUGH); strnzcpyn(name, in_filepath, LARGE_ENOUGH); // See if we have enough room to append 'bands/0' to the path. if (filepath_length + 8 + 1 >= LARGE_ENOUGH) { fprintf(stderr, "Can't create bands path. Path too long.\n"); free(v2_password_header.keyblob); return; } bands_path = strnzcat(filepath, "/bands/0", LARGE_ENOUGH); strnzcpyn(filepath, bands_path, LARGE_ENOUGH); strnzcpyn(name, filepath, LARGE_ENOUGH); if (!(filename = basename(name))) { filename = filepath; } // Open the file for reading. fd = open(filepath, O_RDONLY); if (fd < 0) { fprintf(stderr, "Can't open file: %s\n", filename); return; } // Since we are in a different file the we can ignore the dataoffset header2.dataoffset = 0; } /* read starting chunk(s) */ chunk1 = (unsigned char *) mem_alloc(data_size); if (lseek(fd, header2.dataoffset + cno * 4096LL, SEEK_SET) < 0) { fprintf(stderr, "Unable to seek in %s\n", filename); free(chunk1); free(v2_password_header.keyblob); return; } count = read(fd, chunk1, data_size); if (count < 1 || count != data_size) { fprintf(stderr, "Unable to read required data from %s\n", filename); free(chunk1); free(v2_password_header.keyblob); return; } /* read last chunk */ if (lseek(fd, header2.dataoffset, SEEK_SET) < 0) { fprintf(stderr, "Unable to seek in %s\n", filename); free(chunk1); free(v2_password_header.keyblob); return; } count = read(fd, chunk2, 4096); if (count < 1 || count != 4096) { fprintf(stderr, "Unable to read required data from %s\n", filename); free(chunk1); free(v2_password_header.keyblob); return; } /* output hash */ printf("%s:$dmg$%d*%d*", name, headerver, v2_password_header.salt_size); print_hex(v2_password_header.salt, v2_password_header.salt_size); printf("*32*"); print_hex(v2_password_header.iv, 32); printf("*%d*", v2_password_header.keyblobsize); print_hex(v2_password_header.keyblob, v2_password_header.keyblobsize); printf("*%d*%d*", (int)cno, (int)data_size); print_hex(chunk1, data_size); printf("*1*"); print_hex(chunk2, 4096); printf("*%u::::%s\n", v2_password_header.itercount, filename); free(chunk1); free(v2_password_header.keyblob); } close(fd); }
hash_stat hash_plugin_parse_hash(char *hashline, char *filename) { int fd; char buf8[8]; size_t fsize; size_t fromsize; fd = open(filename, O_RDONLY); if (fd<0) { if (!hashline) elog("Can't open file: %s\n", filename); return hash_err; } if (read(fd,buf8,8)<=0) { if (!hashline) elog("File %s is not a DMG file!\n", filename); return hash_err; } if (strncmp(buf8,"encrcdsa",8)==0) { //return hash_err; headerver=2; } else { lseek(fd,-8,SEEK_END); if (read(fd,buf8,8)<=0) { if (!hashline) elog("File %s is not a DMG file!\n", filename); return hash_err; } if (strncmp(buf8,"cdsaencr",8)==0) { headerver=1; } } if (headerver==0) { if (!hashline) elog("File %s is not a DMG file!\n", filename); return hash_err; } if (!hashline) hlog("Header version %d detected\n",headerver); if (headerver==1) { lseek(fd,-sizeof(cencrypted_v1_header), SEEK_END); if (read(fd,&header, sizeof(cencrypted_v1_header)) < 1) { if (!hashline) elog("File %s is not a DMG file!\n", filename); return hash_err; } header_byteorder_fix(&header); } else { lseek(fd,0, SEEK_SET); if (read(fd,&header2, sizeof(cencrypted_v2_pwheader)) < 1) { if (!hashline) elog("File %s is not a DMG file!\n", filename); return hash_err; } header2_byteorder_fix(&header2); //printf("AES key len=%d\n",header2.blob_enc_key_bits); chunk_size = header2.blocksize; lseek(fd,header2.dataoffset,SEEK_SET); read(fd,chunk,/*4096*/chunk_size); fsize = header2.dataoffset+header2.datasize; fromsize=fsize-header2.dataoffset; while ((fromsize%4096!=0)||(fromsize==fsize-header2.dataoffset)) fromsize--; chunk_no = ((fromsize+1) / chunk_size); chunkoffset=0; if ((fsize-(fromsize+header2.dataoffset))<(4095-678)) { chunkoffset+=(fsize-(fromsize+header2.dataoffset)); fromsize-=4096; chunk_no--; } //printf("fsize=%ld fromsize=%ld dataoffset=%ld at=%ld chunk_no=%d\n",fsize,header2.dataoffset,fromsize,fromsize+header2.dataoffset,chunk_no); lseek(fd,fromsize+header2.dataoffset,SEEK_SET); read(fd,chunk2,/*4096*/chunk_size); } close(fd); (void)hash_add_username(filename); (void)hash_add_hash("DMG file ",0); (void)hash_add_salt("123"); (void)hash_add_salt2(" "); return hash_ok; }