/******************************************************************************* * Function Name : recv * Description : Receive the data and parse the data into package according to the protocol. * Input : socket - the socket connection rec_size - the size of the receive buffer * Output : pack - the result parsed from data read from socket * Return : If no error occurs, recv returns the number of bytes received * and the buffer pointed to by the buf parameter will contain this data received. * If the connection has been gracefully closed, the return value is zero *******************************************************************************/ int Protocol::recv(SOCKET socket, int rec_size, ProtocolPackage& pack){ //receive the header to package boost::shared_ptr<char> header_buf(new char[ProtocolHeader::SIZE], boost::checked_array_deleter<char>()); int iResult = ::recv(socket, header_buf.get(), ProtocolHeader::SIZE, 0); if(iResult >= ProtocolHeader::SIZE){ //assign the header pack.header.mode = header_buf.get()[0]; pack.header.type = header_buf.get()[1]; pack.header.seq = header_buf.get()[2]; pack.header.reserved = header_buf.get()[3]; pack.header.pin[0] = header_buf.get()[4]; pack.header.pin[1] = header_buf.get()[5]; pack.header.pin[2] = header_buf.get()[6]; pack.header.pin[3] = header_buf.get()[7]; pack.header.pin[4] = header_buf.get()[8]; pack.header.pin[5] = header_buf.get()[9]; pack.header.length[0] = header_buf.get()[10]; pack.header.length[1] = header_buf.get()[11]; //calculate the length of the body unsigned int body_len = (unsigned char)pack.header.length[0] | (unsigned char)pack.header.length[1] << 8; body_len += strlen(ProtocolPackage::EOP); //allocate the memory for receiving body boost::shared_ptr<char> body_buf(new char[body_len], boost::checked_array_deleter<char>()); unsigned int offset = 0; do{ //receive the body to package iResult = ::recv(socket, body_buf.get() + offset, body_len - offset, 0); //In order to receive all the data blocks, //the function "recv" might be invoked for some times if the data is huge. //So here loop to receive the data until the length of received data is equal to the header, //and sleep a short time before the data available. if(iResult > 0){ offset += iResult; if(offset < body_len){ //Sleep(200); } }else{ break; } }while(offset < body_len); if(offset >= body_len){ //allocate the memory for the body pack.body = new char[body_len]; //assign the body for(unsigned int i = 0; i < body_len; i++){ pack.body[i] = body_buf.get()[i]; } } } return iResult; }
void Client::start_read() { std::shared_ptr<uint8_t> header_buf(new uint8_t[4], std::default_delete<uint8_t[]>()); BOOST_LOG_TRIVIAL(info) << "Waiting for packet..."; boost::asio::async_read( socket_, boost::asio::buffer(header_buf.get(), 4), boost::asio::transfer_at_least(4), boost::bind( &Client::header_callback, this, header_buf, _1, _2)); }
// set file offset to beginning before calling int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs::file* f, bool verbose) { u8 header[0xA0] = { 0 }; u8 empty_header[0xA0] = { 0 }; u8 header_hash[0x10] = { 0 }; u8 metadata_hash[0x10] = { 0 }; const u64 file_offset = f->pos(); // Check NPD version and flags. if ((npd->version == 0) || (npd->version == 1)) { if (edat->flags & 0x7EFFFFFE) { LOG_ERROR(LOADER, "EDAT: Bad header flags!"); return 1; } } else if (npd->version == 2) { if (edat->flags & 0x7EFFFFE0) { LOG_ERROR(LOADER, "EDAT: Bad header flags!"); return 1; } } else if ((npd->version == 3) || (npd->version == 4)) { if (edat->flags & 0x7EFFFFC0) { LOG_ERROR(LOADER, "EDAT: Bad header flags!"); return 1; } } else { LOG_ERROR(LOADER, "EDAT: Unknown version!"); return 1; } // Read in the file header. f->read(header, 0xA0); // Read in the header and metadata section hashes. f->seek(file_offset + 0x90); f->read(metadata_hash, 0x10); f->read(header_hash, 0x10); // Setup the hashing mode and the crypto mode used in the file. const int crypto_mode = 0x1; int hash_mode = ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) == 0) ? 0x00000002 : 0x10000002; if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0) { hash_mode |= 0x01000000; if (verbose) LOG_WARNING(LOADER, "EDAT: DEBUG data detected!"); } // Setup header key and iv buffers. unsigned char header_key[0x10] = { 0 }; unsigned char header_iv[0x10] = { 0 }; // Test the header hash (located at offset 0xA0). if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), header, empty_header, 0xA0, header_key, header_iv, key, header_hash)) { if (verbose) LOG_WARNING(LOADER, "EDAT: Header hash is invalid!"); // If the header hash test fails and the data is not DEBUG, then RAP/RIF/KLIC key is invalid. if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != EDAT_DEBUG_DATA_FLAG) { LOG_ERROR(LOADER, "EDAT: RAP/RIF/KLIC key is invalid!"); return 1; } } // Parse the metadata info. const int metadata_section_size = ((edat->flags & EDAT_COMPRESSED_FLAG) != 0 || (edat->flags & EDAT_FLAG_0x20) != 0) ? 0x20 : 0x10; if (((edat->flags & EDAT_COMPRESSED_FLAG) != 0)) { if (verbose) LOG_WARNING(LOADER, "EDAT: COMPRESSED data detected!"); } const int block_num = (int)((edat->file_size + edat->block_size - 1) / edat->block_size); const int metadata_offset = 0x100; const int metadata_size = metadata_section_size * block_num; u64 metadata_section_offset = metadata_offset; long bytes_read = 0; long bytes_to_read = metadata_size; std::unique_ptr<u8> metadata(new u8[metadata_size]); std::unique_ptr<u8> empty_metadata(new u8[metadata_size]); while (bytes_to_read > 0) { // Locate the metadata blocks. f->seek(file_offset + metadata_section_offset); // Read in the metadata. f->read(metadata.get() + bytes_read, metadata_section_size); // Adjust sizes. bytes_read += metadata_section_size; bytes_to_read -= metadata_section_size; if (((edat->flags & EDAT_FLAG_0x20) != 0)) // Metadata block before each data block. metadata_section_offset += (metadata_section_size + edat->block_size); else metadata_section_offset += metadata_section_size; } // Test the metadata section hash (located at offset 0x90). if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), metadata.get(), empty_metadata.get(), metadata_size, header_key, header_iv, key, metadata_hash)) { if (verbose) LOG_WARNING(LOADER, "EDAT: Metadata section hash is invalid!"); } // Checking ECDSA signatures. if ((edat->flags & EDAT_DEBUG_DATA_FLAG) == 0) { // Setup buffers. unsigned char metadata_signature[0x28] = { 0 }; unsigned char header_signature[0x28] = { 0 }; unsigned char signature_hash[20] = { 0 }; unsigned char signature_r[0x15] = { 0 }; unsigned char signature_s[0x15] = { 0 }; unsigned char zero_buf[0x15] = { 0 }; // Setup ECDSA curve and public key. ecdsa_set_curve(VSH_CURVE_P, VSH_CURVE_A, VSH_CURVE_B, VSH_CURVE_N, VSH_CURVE_GX, VSH_CURVE_GY); ecdsa_set_pub(VSH_PUB); // Read in the metadata and header signatures. f->seek(file_offset + 0xB0); f->read(metadata_signature, 0x28); f->read(header_signature, 0x28); // Checking metadata signature. // Setup signature r and s. memcpy(signature_r + 01, metadata_signature, 0x14); memcpy(signature_s + 01, metadata_signature + 0x14, 0x14); if ((!memcmp(signature_r, zero_buf, 0x15)) || (!memcmp(signature_s, zero_buf, 0x15))) LOG_WARNING(LOADER, "EDAT: Metadata signature is invalid!"); else { // Setup signature hash. if ((edat->flags & EDAT_FLAG_0x20) != 0) //Sony failed again, they used buffer from 0x100 with half size of real metadata. { int metadata_buf_size = block_num * 0x10; std::unique_ptr<u8> metadata_buf(new u8[metadata_buf_size]); f->seek(file_offset + metadata_offset); f->read(metadata_buf.get(), metadata_buf_size); sha1(metadata_buf.get(), metadata_buf_size, signature_hash); } else sha1(metadata.get(), metadata_size, signature_hash); if (!ecdsa_verify(signature_hash, signature_r, signature_s)) { LOG_WARNING(LOADER, "EDAT: Metadata signature is invalid!"); if (((unsigned long long)edat->block_size * block_num) > 0x100000000) LOG_WARNING(LOADER, "EDAT: *Due to large file size, metadata signature status may be incorrect!"); } } // Checking header signature. // Setup header signature r and s. memset(signature_r, 0, 0x15); memset(signature_s, 0, 0x15); memcpy(signature_r + 01, header_signature, 0x14); memcpy(signature_s + 01, header_signature + 0x14, 0x14); if ((!memcmp(signature_r, zero_buf, 0x15)) || (!memcmp(signature_s, zero_buf, 0x15))) LOG_WARNING(LOADER, "EDAT: Header signature is invalid!"); else { // Setup header signature hash. memset(signature_hash, 0, 20); std::unique_ptr<u8> header_buf(new u8[0xD8]); f->seek(file_offset); f->read(header_buf.get(), 0xD8); sha1(header_buf.get(), 0xD8, signature_hash ); if (!ecdsa_verify(signature_hash, signature_r, signature_s)) LOG_WARNING(LOADER, "EDAT: Header signature is invalid!"); } } return 0; }