Example #1
0
//TODO: The fwrite/fread error checking was broken.
//Maybe the MS runtime is returning the number of bytes written instead of the element count?
BOOL __stdcall np_sign_file(s8 *fname)
{
	u8 padding_data[0x10] = 
	{
		0xbc, 0x3f, 0x7a, 0x48, 0xaf, 0x45, 0xef, 0x28, 0x3a, 0x05, 0x98, 0x10, 0xbc, 0x3f, 0x7a, 0x48
	};

	keyset_t *ks;
	FILE *fp = NULL;
	u8 *buffer = NULL;
	u32 length;
	u32 padding;
	u8 hash[0x14], R[0x15], S[0x15];

	//Try to find keyset.
	if((ks = keyset_find_by_name(CONFIG_NP_SIG_KNAME)) == NULL)
		return FALSE;

	if((fp = fopen(fname, "r+b")) == NULL)
		return FALSE;

	fseek(fp, 0, SEEK_END);
	length = ftell(fp);

	padding = length % 0x10;
	if(padding > 0)
	{
		fwrite(padding_data, sizeof(u8), padding, fp);
		length += padding;
	}

	fseek(fp, 0, SEEK_SET);
	if((buffer = (u8 *)calloc(length, sizeof(char))) == NULL)
	{
		fclose(fp);
		return FALSE;
	}
	fread(buffer, sizeof(u8), length, fp);

	//Generate header hash.
	sha1(buffer, length, hash);

	//Generate signature.
	/* TODO: Set the right curve and private key */
	ecdsa_set_curve(ks->ctype | USE_VSH_CURVE);
	ecdsa_set_pub(ks->pub);
	ecdsa_set_priv(ks->priv);
	ecdsa_sign(hash, R, S);
	fseek(fp, 0, SEEK_END);
	fwrite(R + 1, 0x14, 1, fp);
	fwrite(S + 1, 0x14, 1, fp);
	/* Let's be as stupid as sony here... */
	fwrite(hash + 0xC, 8, 1, fp);

	free(buffer);
	fclose(fp);

	return TRUE;
}
Example #2
0
int add_npdrm_footer_sig(const char *filename) {
  FILE *fp; 

  uint8_t s[21]; 
  uint8_t r[21]; 
  uint8_t hash[20]; 

  static char padding[] = {
	0x8b, 0x3f, 0x7a,0x48,
	0xaf, 0x45, 0xef, 0x28,
	0x3a, 0x05, 0x98, 0x10,
	0xbc, 0x3f, 0x7a, 0x48
  };
  
  keyset_t *keyset = find_keyset_by_name("NP_sig");
  
  if ( !keyset)
	return 0;
	
  fp = fopen(filename, "r+b");
  if (!fp)
    return 0;
	
  fseek(fp, 0, SEEK_END);
  size_t size = ftell (fp);
  // Error ? SCETool takes left_not_aligned as (size & 0xF)
  size_t left_not_aligned = (0x10 - (size & 0xF)) & 0x0F;
  if (left_not_aligned) {
    fwrite(padding, 1, left_not_aligned, fp);
    size += left_not_aligned;
  }
  fseek(fp, 0, SEEK_SET);
  uint8_t *buffer = malloc(size);
  if (!buffer)  {
    fclose(fp);
    return 0;
  }

  if(fread(buffer, 1, size, fp) != size)
    return 0;
    
  
  sha1(buffer, size, hash);
  
  ecdsa_set_curve(keyset->ctype | 0x40);
  ecdsa_set_pub(keyset->pub_key);
  ecdsa_set_priv(keyset->priv_key);
  ecdsa_sign(r, s, hash);
  
  fseek(fp, 0, SEEK_END); 
  fwrite(&r[1], 20, 1, fp);
  fwrite(&s[1], 20, 1, fp);
  fwrite(&hash[12], 8, 1, fp);
  
  free(buffer);
  fclose(fp);  
  return 1;
}
Example #3
0
static void get_keys(const char *suffix)
{
	if (key_get(type, suffix, &ks) < 0)
		fail("key_get failed");

	if (ks.pub_avail < 0)
		fail("no public key available");

	if (ks.priv_avail < 0)
		fail("no private key available");

	if (ecdsa_set_curve(ks.ctype) < 0)
		fail("ecdsa_set_curve failed");

	ecdsa_set_pub(ks.pub);
	ecdsa_set_priv(ks.priv);
}
Example #4
0
int edata_check_ecdsa(u8 *edata_buf)
{
	u8 sha1_hash[20];
	int retv;

	printf("EDATA ID: %s\n", (char*)(edata_buf+0x10));

	ecdsa_set_curve(&ecdsa_app);
	ecdsa_set_pub(pubkey_edat_x, pubkey_edat_y);

	SHA1(edata_buf, 0x58, sha1_hash);
	retv = ecdsa_verify(sha1_hash, edata_buf+0x58, edata_buf+0x6c);
	if(retv==0){
		//printf("ECDSA verify passed!\n");
	}else{
		printf("edata_check_ecdsa: ECDSA verify failed!\n");
	}

	return retv;
}
Example #5
0
static void decrypt(u8* ptr)
{
	if (keyid < 0)
		keyid = sce_decrypt_header(ptr, klist);
	else if (keyid != sce_decrypt_header(ptr, klist))
		fail("Both files must have the same key id");

	if (keyid < 0)
		fail("sce_decrypt_header failed");

	if (sce_decrypt_data(ptr) < 0)
		fail("sce_decrypt_data failed");

	if (klist->keys[keyid].pub_avail < 0)
		fail("no public key available");

	if (ecdsa_set_curve(klist->keys[keyid].ctype) < 0)
		fail("ecdsa_set_curve failed");

	ecdsa_set_pub(klist->keys[keyid].pub);
}
Example #6
0
static void decrypt(void)
{
	int keyid;
       
	sce_remove_npdrm(ptr, klist);
	keyid = sce_decrypt_header(ptr, klist);

	if (keyid < 0)
		fail("sce_decrypt_header failed");

	if (sce_decrypt_data(ptr) < 0)
		fail("sce_decrypt_data failed");

	if (klist->keys[keyid].pub_avail < 0)
		fail("no public key available");

	if (ecdsa_set_curve(klist->keys[keyid].ctype) < 0)
		fail("ecdsa_set_curve failed");

	ecdsa_set_pub(klist->keys[keyid].pub);
}
Example #7
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;
}