void sha1_final(SHA1_CONTEXT *hd) { u32 t, msb, lsb; unsigned char *p; sha1_write(hd, NULL, 0); /* flush */; t = hd->nblocks; /* multiply by 64 to make a byte count */ lsb = t << 6; msb = t >> 26; /* add the count */ t = lsb; if( (lsb += hd->count) < t ) msb++; /* multiply by 8 to make a bit count */ t = lsb; lsb <<= 3; msb <<= 3; msb |= t >> 29; if( hd->count < 56 ) { /* enough room */ hd->buf[hd->count++] = 0x80; /* pad */ while( hd->count < 56 ) hd->buf[hd->count++] = 0; /* pad */ } else { /* need one extra block */ hd->buf[hd->count++] = 0x80; /* pad character */ while( hd->count < 64 ) hd->buf[hd->count++] = 0; sha1_write(hd, NULL, 0); /* flush */; memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ } /* append the 64 bit count */ hd->buf[56] = msb >> 24; hd->buf[57] = msb >> 16; hd->buf[58] = msb >> 8; hd->buf[59] = msb ; hd->buf[60] = lsb >> 24; hd->buf[61] = lsb >> 16; hd->buf[62] = lsb >> 8; hd->buf[63] = lsb ; transform( hd, hd->buf ); p = hd->buf; #ifdef BIG_ENDIAN_HOST #define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0) #else /* little endian */ #define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \ *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while(0) #endif X(0); X(1); X(2); X(3); X(4); #undef X }
/* API */ char *oauth_sign_hmac_sha1_raw (const char *m, const size_t ml, const char *k, const size_t kl) { sha1nfo s; sha1_initHmac(&s, (const uint8_t*) k, kl); sha1_write(&s, m, ml); unsigned char *digest = sha1_resultHmac(&s); return oauth_encode_base64(HASH_LENGTH, digest); }
/** Get the Node ID */ long getId(char *str){ sha1nfo i; char ipPort[30], tmp[30]; if (strcmp(str, "\0") == 0){ //connect ip and port strcpy (ipPort, current->ip); strcat (ipPort,": "); sprintf(tmp, "%d", current->port); strcat (ipPort, tmp); } else strcpy(ipPort, str); sha1_init(&i); sha1_write(&i, ipPort, strlen(ipPort)); uint8_t* hash = sha1_result(&i); uint32_t b0 = hash[0] | hash[1] << 8 | hash[2] << 16 | hash[3] << 24; uint32_t b1 = hash[4] | hash[5] << 8 | hash[6] << 16 | hash[7] << 24; uint32_t b2 = hash[8] | hash[9] << 8 | hash[10] << 16 | hash[11] << 24; uint32_t b3 = hash[12] | hash[13] << 8 | hash[14] << 16 | hash[15] << 24; uint32_t b4 = hash[16] | hash[17] << 8 | hash[18] << 16 | hash[19] << 24; long id; id = b0 ^ b1 ^ b2 ^ b3 ^ b4; return id; }
/* Update the message digest with the contents * of INBUF with length INLEN. */ void sha1_write( SHA1_CONTEXT *hd, unsigned char *inbuf, size_t inlen) { if( hd->count == 64 ) { /* flush the buffer */ transform( hd, hd->buf ); hd->count = 0; hd->nblocks++; } if( !inbuf ) return; if( hd->count ) { for( ; inlen && hd->count < 64; inlen-- ) hd->buf[hd->count++] = *inbuf++; sha1_write( hd, NULL, 0 ); if( !inlen ) return; } while( inlen >= 64 ) { transform( hd, inbuf ); hd->count = 0; hd->nblocks++; inlen -= 64; inbuf += 64; } for( ; inlen && hd->count < 64; inlen-- ) hd->buf[hd->count++] = *inbuf++; }
int cconf_write(int fd, struct cconf *c) { int i; SHA_CTX ctx; struct cconf_header hdr; hdr.signature = htonl(CCONF_SIGNATURE); hdr.version = htonl(1); SHA1_Init(&ctx); SHA1_Update(&ctx, &hdr, offsetof(struct cconf_header, crc)); /* leave room for the header to be written later as CRC will be calculated as we write the rest of the data */ lseek(fd, sizeof(hdr), SEEK_SET); /* put number of targets */ sha1_write_int(&ctx, fd, c->nr); for(i = 0; i < c->nr; i++) { int j; struct target *target = c->target + i; if (!target->src) return -1; sha1_write(&ctx, fd, target->src, strsize(target->src)); /* write number of filters */ sha1_write_int(&ctx, fd, target->nr); for(j=0; j < target->nr; j++) { struct filter *f = &target->filter[j]; sha1_write(&ctx, fd, f->pattern, strsize(f->pattern)); sha1_write(&ctx, fd, f->dest, strsize(f->dest)); } } SHA1_Final(hdr.crc, &ctx); /* write header */ lseek(fd, 0, SEEK_SET); sha1_write(&ctx, fd, &hdr, sizeof(hdr)); return 0; }
static void rand_refill() { void*rh; int i,r; byte*b; if(pool==NULL)init_seth_rand(); ppos=0; /*we assume each rand() call will give us 8 random bits (it probably has more, but you can't have too much random).*/ rh=sha1_new(); /*make the period longer by making the next block dependend on the current one*/ sha1_write(rh,pool,20); /*add the random to the soup*/ for(i=0;i<20;i++){ r=rand(); sha1_write(rh,(void*)&r,sizeof(r)); } /*fill the pool*/ b=sha1_get(rh); memcpy(pool,b,20); sha1_close(rh); }
static int ICACHE_FLASH_ATTR createWsAcceptKey(const char *key, char *buffer, int bufferSize) { sha1nfo s; char concatenatedBuffer[512]; concatenatedBuffer[0] = '\0'; //concatenate the key and the GUID os_strcat(concatenatedBuffer, key); os_strcat(concatenatedBuffer, WS_GUID); //build the sha1 hash sha1_init(&s); sha1_write(&s, concatenatedBuffer, strlen(concatenatedBuffer)); uint8_t *hash = sha1_result(&s); return base64_encode(20, hash, bufferSize, buffer); }
char *oauth_body_hash_file(char *filename) { FILE *F= fopen(filename, "r"); if (!F) return NULL; size_t len=0; char fb[BUFSIZ]; sha1nfo s; sha1_init(&s); while (!feof(F) && (len=fread(fb,sizeof(char),BUFSIZ, F))>0) { sha1_write(&s, fb, len); } fclose(F); unsigned char *dgst = xmalloc(HASH_LENGTH*sizeof(char)); // oauth_body_hash_encode frees the digest.. memcpy(dgst, sha1_result(&s), HASH_LENGTH); return oauth_body_hash_encode(HASH_LENGTH, dgst); }
int crack_password_permutations(uint8_t* hash_ptr, int current_len, char* solution, int ends_with) { sha1nfo current_hash; uint8_t *current_hash_ptr; char current_pw[100]; uint8_t current_idxs[100]; // index into charset int i; // initialize for (i = 0; i < 100; i++) { current_pw[i] = 0; current_idxs[i] = 0; } for (i = 0; i < current_len; i++) { current_pw[0] = charset[0]; } current_pw[current_len-1] = charset[ends_with]; //if (my_id == id) // printf("start: %s\n", current_pw); do { // loops over password space for given password length //printf("%s\n", current_pw); // hash current password attempt sha1_init(¤t_hash); sha1_write(¤t_hash, current_pw, strlen(current_pw)); current_hash_ptr = sha1_result(¤t_hash); // check if equal to hash we are cracking if (strncmp((char *)hash_ptr, (char *)current_hash_ptr, HASH_LENGTH) == 0) { strncpy(solution, current_pw, current_len); printf("found a password with a matching hash!\n"); printHash(current_hash_ptr); printf("password is: %s\n", current_pw); return 1; } } while (next_password(current_pw, current_idxs, current_len - 1)); return 0; }
/* Update the message digest with the contents * of INBUF with length INLEN. */ static void sha1_write( void *context, const void *inbuf_arg, size_t inlen) { const unsigned char *inbuf = inbuf_arg; SHA1_CONTEXT *hd = context; size_t nblocks; if (hd->count == 64) /* Flush the buffer. */ { TRANSFORM( hd, hd->buf, 1 ); _gcry_burn_stack (88+4*sizeof(void*)); hd->count = 0; hd->nblocks++; } if (!inbuf) return; if (hd->count) { for (; inlen && hd->count < 64; inlen--) hd->buf[hd->count++] = *inbuf++; sha1_write (hd, NULL, 0); if (!inlen) return; } nblocks = inlen / 64; if (nblocks) { TRANSFORM (hd, inbuf, nblocks); hd->count = 0; hd->nblocks += nblocks; inlen -= nblocks * 64; inbuf += nblocks * 64; } _gcry_burn_stack (88+4*sizeof(void*)); /* Save remaining bytes. */ for (; inlen && hd->count < 64; inlen--) hd->buf[hd->count++] = *inbuf++; }
void run_master(int me, int nprocs, int argc, char** argv) { sha1nfo hash; uint8_t *hash_ptr; const char *pw = "h678a"; int i; int num_workers = nprocs - 1; // compute hash sha1_init(&hash); sha1_write(&hash, pw, strlen(pw)); hash_ptr = sha1_result(&hash); //printHash(hash_ptr); // send hash for (i = 0; i < num_workers; i++) { MPI_Send((void *)(hash_ptr), HASH_LENGTH, MPI_UNSIGNED_CHAR, i + 1, 0, MPI_COMM_WORLD); } // send work for (i = 0; i < strlen(charset); i++) { } }
// The rest is added for LibFuzzer void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out) { sha1nfo s; sha1_init(&s); sha1_write(&s, (const char*)Data, Len); memcpy(Out, sha1_result(&s), HASH_LENGTH); }
/* * Generate a #PKCS1.5 padded message * The output string buffer should have enough memory to incorporate the padding. */ int pkcs1_v1_5_generate(unsigned char *output, const unsigned char *msg, const size_t msg_len, const size_t block_len, enum pkcs1_v1_5_msg_type msg_type, const enum pkcs1_v1_5_sign_hash_method h_method) { size_t pad_len, hash_len; uint8_t sha256_buf[SHA256_HASH_SIZE]; struct sha256nfo sha256_h; struct sha1nfo sha1_h; char *hash_name; memset(output, 0, block_len); /* * Hash type */ switch(h_method) { case SHA1: hash_len = SHA1_HASH_LENGTH; hash_name = PKCS1_SIGN_HASH_METHOD_SHA_1; break; case SHA256: hash_len = SHA256_HASH_SIZE; hash_name = PKCS1_SIGN_HASH_METHOD_SHA_256; break; default: return -1; } if (3 + strlen(hash_name) + hash_len > block_len) return 0x01; /* Padding */ output[0] = 0x00; switch (msg_type) { case pkcs1_signature: output[1] = PKCS1_BT_01; pad_len = block_len - strlen(hash_name) - hash_len - (3); memset(output + 2, 0xff, pad_len); break; case pkcs1_msg: output[1] = PKCS1_BT_02; pad_len = block_len - msg_len - (3); pkcs1_v1_5_gen_rpadding(output + 2, pad_len); break; } output[2 + pad_len] = 0x00; /* * Hash value */ switch (msg_type) { case pkcs1_signature: memcpy(output + 3 + pad_len, hash_name, strlen(hash_name)); switch(h_method) { case SHA1: sha1_init(&sha1_h); sha1_write(&sha1_h, (char*) msg, msg_len); memcpy(output + 3 + pad_len + strlen(hash_name), sha1_result(&sha1_h), SHA1_HASH_LENGTH); break; case SHA256: sha256_init(&sha256_h); sha256_write(&sha256_h, (uint8_t*) msg, msg_len); sha256_result(&sha256_h, sha256_buf); memcpy(output + 3 + pad_len + strlen(hash_name), sha256_buf, SHA256_HASH_SIZE); break; default: return -1; } break; case pkcs1_msg: memcpy(output + 3 + pad_len, msg, msg_len); break; } return 0x00; }
/* * The liboauth sha1 is too intelligent : it detect the platform's endianess and * return a coherent result, independant from endian. However it's much more simple * to work in bitstream (i.e. big endian) when it's come to padding. Of course on a * real platform you don't have access to the endianess, therefore you have to test * both cases. */ int main (int argc, char **argv) { uint8_t basic_hash[SHA1_HASH_LENGTH], pad_basic_oauth[2*SHA1_BLOCK_LENGTH]; size_t i,padlen, basic_oauthlen = strlen(basic_oauth) + strlen(secret), // Supposedly known by the attacker. padded_basic_oauthlen; uint8_t *padded_basic_oauth; // SHA pad test sha1_utils_test_pad(); // Break SHA-1 printf("Exercice : break keyed SHA-1\n"); // Create basic token sha1_utils_keyed_mac(basic_hash, (uint8_t*) secret, strlen(secret), (uint8_t*) basic_oauth, strlen(basic_oauth)); printf("Basic auth hash :"); sha1_utils_printHash(basic_hash); // Compute pad sha1_utils_md_pad(pad_basic_oauth, &padlen, (uint8_t*) basic_oauth, basic_oauthlen); padded_basic_oauthlen = strlen(basic_oauth) + padlen + strlen(admin_key); padded_basic_oauth = malloc(padded_basic_oauthlen*sizeof(uint8_t)); if (NULL == padded_basic_oauth) return 0x01; sha1_utils_concat(padded_basic_oauth, (uint8_t*) basic_oauth, strlen(basic_oauth), pad_basic_oauth, padlen); // check if padding works struct sha1nfo padded_basic_s; sha1_init(&padded_basic_s); sha1_write(&padded_basic_s, secret, strlen(secret)); sha1_write(&padded_basic_s, (char*) padded_basic_oauth, strlen(basic_oauth) + padlen); printf("Basic padded auth hash :"); sha1_utils_print_array((uint8_t*) padded_basic_s.state, SHA1_HASH_LENGTH, SWAP_ENDIAN ); //SHA-1 "fixation" struct sha1nfo s; s.state[0] = htonl(((uint32_t*) basic_hash)[0]); s.state[1] = htonl(((uint32_t*) basic_hash)[1]); s.state[2] = htonl(((uint32_t*) basic_hash)[2]); s.state[3] = htonl(((uint32_t*) basic_hash)[3]); s.state[4] = htonl(((uint32_t*) basic_hash)[4]); s.byteCount = strlen(secret) + strlen(basic_oauth) + padlen; s.bufferOffset = 0; // Add new data sha1_write(&s, admin_key, strlen(admin_key)); uint8_t *result = sha1_result(&s); for (i = 0; i < strlen(admin_key); i++) padded_basic_oauth[i + strlen(basic_oauth) + padlen] = admin_key[i]; // Check signature if (test_sha1_sig(padded_basic_oauth, padded_basic_oauthlen, result)) { printf("Valid command : "); write(1, padded_basic_oauth, padded_basic_oauthlen); printf("\n"); } free(padded_basic_oauth); return 0; }
static int load_split_rom_parts(struct archive *archive, int *chip_list, struct rom_info *rom_info, uint8_t **bufferp, size_t *sizep) { uint8_t *buffer; uint8_t *ptr; size_t size; off_t offsets[MAX_ROMS]; int file_list[MAX_ROMS]; int num_chips; int status; int i; size = 0; num_chips = rom_info->prg_size_count + rom_info->chr_size_count; for (i = 0; i < MAX_ROMS; i++) file_list[i] = -1; status = 0; for (i = 0; i < num_chips; i++) { int j; for (j = 0; j < archive->file_list->count; j++) { if (chip_list[j] == i) { offsets[i] = size; size += archive->file_list->entries[j].size; break; } } } buffer = malloc(INES_HEADER_SIZE + size); if (!buffer) { return -1; } ptr = buffer + INES_HEADER_SIZE; for (i = 0; i < num_chips; i++) { int j; for (j = 0; j < archive->file_list->count; j++) { if (chip_list[j] == i) { sha1nfo sha1; uint8_t *result; file_list[i] = j; status = archive_read_file_by_index(archive, file_list[i], ptr); if (status) { free(buffer); return -1; } /* Validate each chip's SHA1, if present. If it doesn't match, then move on to the next match for that chip in the archive. */ if ((i < rom_info->prg_size_count) && rom_info->prg_sha1_count) { sha1_init(&sha1); sha1_write(&sha1, (char *)ptr, archive->file_list->entries[file_list[i]].size); result = sha1_result(&sha1); if (memcmp(result, rom_info->prg_sha1[i], 20) != 0) { continue; } } else if (rom_info->chr_sha1_count) { sha1_init(&sha1); sha1_write(&sha1, (char *)ptr, archive->file_list->entries[file_list[i]].size); result = sha1_result(&sha1); if (memcmp(result, rom_info->chr_sha1[i - rom_info->prg_size_count], 20) != 0) { continue; } } ptr += archive->file_list->entries[file_list[i]].size; break; } } if (j == archive->file_list->count) { status = -1; break; } } if (status < 0) { if (bufferp) *bufferp = NULL; return 0; } status = -1; for (i = 0; (i < MAX_ROMS) && (file_list[i] >= 0); i++) { uint8_t *ptr; ptr = buffer + INES_HEADER_SIZE + offsets[i]; status = archive_read_file_by_index(archive, file_list[i], ptr); if (status) break; } if (status) { free(buffer); if (bufferp) *bufferp = NULL; return 0; } if (sizep) { *sizep = size + INES_HEADER_SIZE; } *bufferp = buffer; return 0; }
int main (int argc, char **argv) { uint32_t a; sha1nfo s; printf("sizeof(sha1nfo)=%d\n\n", sizeof(sha1nfo)); // SHA tests printf("Test: FIPS 180-2 C.1 and RFC3174 7.3 TEST1\n"); printf("Expect:a9993e364706816aba3e25717850c26c9cd0d89d\n"); printf("Result:"); sha1_init(&s); sha1_write(&s, "abc", 3); printHash(sha1_result(&s)); printf("\n\n"); printf("Test: FIPS 180-2 C.2 and RFC3174 7.3 TEST2\n"); printf("Expect:84983e441c3bd26ebaae4aa1f95129e5e54670f1\n"); printf("Result:"); sha1_init(&s); sha1_write(&s, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56); printHash(sha1_result(&s)); printf("\n\n"); printf("Test: RFC3174 7.3 TEST4\n"); printf("Expect:dea356a2cddd90c7a7ecedc5ebb563934f460452\n"); printf("Result:"); sha1_init(&s); for (a=0; a<80; a++) sha1_write(&s, "01234567", 8); printHash(sha1_result(&s)); printf("\n\n"); // HMAC tests printf("Test: FIPS 198a A.1\n"); printf("Expect:4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a\n"); printf("Result:"); sha1_initHmac(&s, hmacKey1, 64); sha1_write(&s, "Sample #1",9); printHash(sha1_resultHmac(&s)); printf("\n\n"); printf("Test: FIPS 198a A.2\n"); printf("Expect:0922d3405faa3d194f82a45830737d5cc6c75d24\n"); printf("Result:"); sha1_initHmac(&s, hmacKey2, 20); sha1_write(&s, "Sample #2", 9); printHash(sha1_resultHmac(&s)); printf("\n\n"); printf("Test: FIPS 198a A.3\n"); printf("Expect:bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa\n"); printf("Result:"); sha1_initHmac(&s, hmacKey3,100); sha1_write(&s, "Sample #3", 9); printHash(sha1_resultHmac(&s)); printf("\n\n"); printf("Test: FIPS 198a A.4\n"); printf("Expect:9ea886efe268dbecce420c7524df32e0751a2a26\n"); printf("Result:"); sha1_initHmac(&s, hmacKey4,49); sha1_write(&s, "Sample #4", 9); printHash(sha1_resultHmac(&s)); printf("\n\n"); // Long tests printf("Test: FIPS 180-2 C.3 and RFC3174 7.3 TEST3\n"); printf("Expect:34aa973cd4c4daa4f61eeb2bdbad27316534016f\n"); printf("Result:"); sha1_init(&s); for (a=0; a<1000000; a++) sha1_writebyte(&s, 'a'); printHash(sha1_result(&s)); // liang: 65536 zeros printf("\n\n"); printf("Test: 65536 zeros\n"); printf("Expect:1adc95bebe9eea8c112d40cd04ab7a8d75c4f961\n"); printf("Result:"); sha1_init(&s); for (a=0; a<65536; a++) sha1_writebyte(&s, 0); printHash(sha1_result(&s)); // test liang_zhash printf("\n\n"); printf("Test: 65536 zeros\n"); printf("Expect:1adc95bebe9eea8c112d40cd04ab7a8d75c4f961\n"); printf("Result:"); uint8_t hash[20]; char buf[65536]; for(a=0; a<65536; a++) buf[a]=0; liang_zhash((const uint8_t *)buf, 65536, hash); printHash(hash); return 0; }
static void sha1_final(void *context) { SHA1_CONTEXT *hd = context; u32 t, msb, lsb; unsigned char *p; sha1_write(hd, NULL, 0); /* flush */; t = hd->nblocks; /* multiply by 64 to make a byte count */ lsb = t << 6; msb = t >> 26; /* add the count */ t = lsb; if( (lsb += hd->count) < t ) msb++; /* multiply by 8 to make a bit count */ t = lsb; lsb <<= 3; msb <<= 3; msb |= t >> 29; if( hd->count < 56 ) /* enough room */ { hd->buf[hd->count++] = 0x80; /* pad */ while( hd->count < 56 ) hd->buf[hd->count++] = 0; /* pad */ } else /* need one extra block */ { hd->buf[hd->count++] = 0x80; /* pad character */ while( hd->count < 64 ) hd->buf[hd->count++] = 0; sha1_write(hd, NULL, 0); /* flush */; memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ } /* append the 64 bit count */ hd->buf[56] = msb >> 24; hd->buf[57] = msb >> 16; hd->buf[58] = msb >> 8; hd->buf[59] = msb ; hd->buf[60] = lsb >> 24; hd->buf[61] = lsb >> 16; hd->buf[62] = lsb >> 8; hd->buf[63] = lsb ; TRANSFORM( hd, hd->buf, 1 ); _gcry_burn_stack (88+4*sizeof(void*)); p = hd->buf; #ifdef WORDS_BIGENDIAN #define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0) #else /* little endian */ #define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \ *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while(0) #endif X(0); X(1); X(2); X(3); X(4); #undef X }
uint64_t buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn, const SystemChar* apploaderIn, const SystemChar* partHeadIn) { /* Read head and validate key members */ std::unique_ptr<IFileIO> ph = NewFileIO(partHeadIn); uint8_t tkey[16]; { if (ph->beginReadStream(0x1BF)->read(tkey, 16) != 16) LogModule.report(logvisor::Fatal, _S("unable to read title key from %s"), partHeadIn); } uint8_t tkeyiv[16] = {}; { if (ph->beginReadStream(0x1DC)->read(tkeyiv, 8) != 8) LogModule.report(logvisor::Fatal, _S("unable to read title key IV from %s"), partHeadIn); } uint8_t ccIdx; { if (ph->beginReadStream(0x1F1)->read(&ccIdx, 1) != 1) LogModule.report(logvisor::Fatal, _S("unable to read common key index from %s"), partHeadIn); if (ccIdx > 1) LogModule.report(logvisor::Fatal, _S("common key index may only be 0 or 1")); } uint32_t tmdSz; { if (ph->beginReadStream(0x2A4)->read(&tmdSz, 4) != 4) LogModule.report(logvisor::Fatal, _S("unable to read TMD size from %s"), partHeadIn); tmdSz = SBig(tmdSz); } uint64_t h3Off; { uint32_t h3Ptr; if (ph->beginReadStream(0x2B4)->read(&h3Ptr, 4) != 4) LogModule.report(logvisor::Fatal, _S("unable to read H3 pointer from %s"), partHeadIn); h3Off = uint64_t(SBig(h3Ptr)) << 2; } uint64_t dataOff; { uint32_t dataPtr; if (ph->beginReadStream(0x2B8)->read(&dataPtr, 4) != 4) LogModule.report(logvisor::Fatal, _S("unable to read data pointer from %s"), partHeadIn); dataOff = uint64_t(SBig(dataPtr)) << 2; } m_userOffset = dataOff; std::unique_ptr<uint8_t[]> tmdData(new uint8_t[tmdSz]); if (ph->beginReadStream(0x2C0)->read(tmdData.get(), tmdSz) != tmdSz) LogModule.report(logvisor::Fatal, _S("unable to read TMD from %s"), partHeadIn); /* Copy partition head up to H3 table */ std::unique_ptr<IFileIO::IWriteStream> ws = m_parent.getFileIO().beginWriteStream(m_baseOffset); { uint64_t remCopy = h3Off; uint8_t copyBuf[8192]; std::unique_ptr<IFileIO::IReadStream> rs = ph->beginReadStream(); while (remCopy) { size_t rdBytes = rs->read(copyBuf, std::min(size_t(8192), size_t(remCopy))); if (rdBytes) { ws->write(copyBuf, rdBytes); remCopy -= rdBytes; continue; } for (size_t i=0 ; i<remCopy ; ++i) ws->write("", 1); break; } } /* Prepare crypto pass */ m_aes->setKey(COMMON_KEYS[ccIdx]); m_aes->decrypt(tkeyiv, tkey, tkey, 16); m_aes->setKey(tkey); { /* Assemble partition data */ std::unique_ptr<IPartWriteStream> cws = beginWriteStream(0x1F0000); bool result = DiscBuilderBase::PartitionBuilderBase::buildFromDirectory(*cws, dirIn, dolIn, apploaderIn); if (!result) return 0; /* Pad out user area to nearest cleartext sector */ m_curUser = cws->position(); uint64_t curUserRem = m_curUser % 0x1F0000; if (curUserRem) { curUserRem = 0x1F0000 - curUserRem; for (size_t i=0 ; i<curUserRem ; ++i) cws->write("\xff", 1); m_curUser += curUserRem; } /* Begin crypto write and add content header */ cws = beginWriteStream(0); Header header(m_gameID, m_gameTitle.c_str(), true, 0, 0, 0); header.write(*cws); /* Get Apploader Size */ Sstat theStat; if (Stat(apploaderIn, &theStat)) LogModule.report(logvisor::Fatal, _S("unable to stat %s"), apploaderIn); /* Compute boot table members and write */ size_t fstOff = 0x2440 + ROUND_UP_32(theStat.st_size); size_t fstSz = sizeof(FSTNode) * m_buildNodes.size(); fstSz += m_buildNameOff; fstSz = ROUND_UP_32(fstSz); if (fstOff + fstSz >= 0x1F0000) LogModule.report(logvisor::Fatal, "FST flows into user area (one or the other is too big)"); cws->write(nullptr, 0x420 - sizeof(Header)); uint32_t vals[4]; vals[0] = SBig(uint32_t(m_dolOffset >> uint64_t(2))); vals[1] = SBig(uint32_t(fstOff >> uint64_t(2))); vals[2] = SBig(uint32_t(fstSz)); vals[3] = SBig(uint32_t(fstSz)); cws->write(vals, 16); /* Write Apploader */ cws->write(nullptr, 0x2440 - 0x430); std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(apploaderIn)->beginReadStream(); char buf[8192]; size_t xferSz = 0; SystemString apploaderName(apploaderIn); ++m_parent.m_progressIdx; while (true) { size_t rdSz = rs->read(buf, 8192); if (!rdSz) break; cws->write(buf, rdSz); xferSz += rdSz; if (0x2440 + xferSz >= 0x1F0000) LogModule.report(logvisor::Fatal, "apploader flows into user area (one or the other is too big)"); m_parent.m_progressCB(m_parent.m_progressIdx, apploaderName, xferSz); } size_t fstOffRel = fstOff - 0x2440; if (xferSz > fstOffRel) LogModule.report(logvisor::Fatal, "apploader unexpectedly flows into FST"); for (size_t i=0 ; i<fstOffRel-xferSz ; ++i) cws->write("\xff", 1); /* Write FST */ cws->write(m_buildNodes.data(), m_buildNodes.size() * sizeof(FSTNode)); for (const std::string& str : m_buildNames) cws->write(str.data(), str.size()+1); } /* Write new crypto content size */ uint64_t groupCount = m_curUser / 0x1F0000; uint64_t cryptContentSize = (groupCount * 0x200000) >> uint64_t(2); uint32_t cryptContentSizeBig = SBig(uint32_t(cryptContentSize)); ws = m_parent.getFileIO().beginWriteStream(m_baseOffset + 0x2BC); ws->write(&cryptContentSizeBig, 0x4); /* Write new H3 */ ws = m_parent.getFileIO().beginWriteStream(m_baseOffset + h3Off); ws->write(m_h3, 0x18000); /* Compute content hash and replace in TMD */ sha1nfo sha; sha1_init(&sha); sha1_write(&sha, (char*)m_h3, 0x18000); memcpy(tmdData.get() + 0x1F4, sha1_result(&sha), 20); /* Same for content size */ uint64_t contentSize = groupCount * 0x1F0000; uint64_t contentSizeBig = SBig(contentSize); memcpy(tmdData.get() + 0x1EC, &contentSizeBig, 8); /* Zero-out TMD signature to simplify brute-force */ memset(tmdData.get() + 0x4, 0, 0x100); /* Brute-force zero-starting hash */ size_t tmdCheckSz = tmdSz - 0x140; struct BFWindow { uint64_t word[7]; }* bfWindow = (BFWindow*)(tmdData.get() + 0x19A); bool good = false; uint64_t attempts = 0; SystemString bfName(_S("Brute force attempts")); ++m_parent.m_progressIdx; for (int w=0 ; w<7 ; ++w) { for (uint64_t i=0 ; i<UINT64_MAX ; ++i) { bfWindow->word[w] = i; sha1_init(&sha); sha1_write(&sha, (char*)(tmdData.get() + 0x140), tmdCheckSz); uint8_t* hash = sha1_result(&sha); ++attempts; if (hash[0] == 0) { good = true; break; } m_parent.m_progressCB(m_parent.m_progressIdx, bfName, attempts); } if (good) break; } m_parent.m_progressCB(m_parent.m_progressIdx, bfName, attempts); ws = m_parent.getFileIO().beginWriteStream(m_baseOffset + 0x2C0); ws->write(tmdData.get(), tmdSz); return m_baseOffset + dataOff + groupCount * 0x200000; }