/*******************************************************************************
* 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;
}
Example #2
0
	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));
	}
Example #3
0
// 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;
}