Files
libaaruformat/tests/ps3_encryption_map.cpp

265 lines
7.3 KiB
C++

/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2026 Natalia Portillo.
*
* PS3 encryption map parsing, serialization, and sector lookup tests.
*/
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include "gtest/gtest.h"
extern "C"
{
#include "../src/ps3/ps3_encryption_map.h"
}
/*
* Build a synthetic sector 0 in big-endian format:
* offset 0x00: region_count = 2 (BE)
* offset 0x04: unknown = 0 (BE)
* offset 0x08: region[0].start = 0 (BE)
* offset 0x0C: region[0].end = 31 (BE)
* offset 0x10: region[1].start = 256 (BE)
* offset 0x14: region[1].end = 511 (BE)
*/
static void build_synthetic_sector0(uint8_t *buf, uint32_t size)
{
memset(buf, 0, size);
/* region_count = 2, big-endian */
buf[0] = 0;
buf[1] = 0;
buf[2] = 0;
buf[3] = 2;
/* unknown field */
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
/* region[0]: start=0, end=31 */
buf[8] = 0;
buf[9] = 0;
buf[10] = 0;
buf[11] = 0; /* start=0 */
buf[12] = 0;
buf[13] = 0;
buf[14] = 0;
buf[15] = 31; /* end=31 */
/* region[1]: start=256, end=511 */
buf[16] = 0;
buf[17] = 0;
buf[18] = 1;
buf[19] = 0; /* start=256 */
buf[20] = 0;
buf[21] = 0;
buf[22] = 1;
buf[23] = 0xFF; /* end=511 */
}
/* Test: parse valid sector 0 */
TEST(PS3EncMap, ParseValid)
{
uint8_t sector0[2048];
build_synthetic_sector0(sector0, 2048);
Ps3PlaintextRegion *regions = NULL;
uint32_t count = 0;
int32_t ret = ps3_parse_encryption_map(sector0, 2048, &regions, &count);
ASSERT_EQ(0, ret);
ASSERT_EQ(2u, count);
ASSERT_NE(nullptr, regions);
EXPECT_EQ(0u, regions[0].start_sector);
EXPECT_EQ(31u, regions[0].end_sector);
EXPECT_EQ(256u, regions[1].start_sector);
EXPECT_EQ(511u, regions[1].end_sector);
free(regions);
}
/* Test: parse zero regions */
TEST(PS3EncMap, ParseZeroRegions)
{
uint8_t sector0[2048];
memset(sector0, 0, 2048); /* region_count = 0 */
Ps3PlaintextRegion *regions = NULL;
uint32_t count = 99;
int32_t ret = ps3_parse_encryption_map(sector0, 2048, &regions, &count);
ASSERT_EQ(0, ret);
EXPECT_EQ(0u, count);
EXPECT_EQ(nullptr, regions);
}
/* Test: parse rejects too many regions */
TEST(PS3EncMap, ParseTooManyRegions)
{
uint8_t sector0[2048];
memset(sector0, 0, 2048);
/* region_count = 33 (> max 32) */
sector0[3] = 33;
Ps3PlaintextRegion *regions = NULL;
uint32_t count = 0;
int32_t ret = ps3_parse_encryption_map(sector0, 2048, &regions, &count);
EXPECT_LT(ret, 0);
}
/* Test: parse rejects invalid region (start > end) */
TEST(PS3EncMap, ParseInvalidRegion)
{
uint8_t sector0[2048];
memset(sector0, 0, 2048);
sector0[3] = 1; /* 1 region */
/* start=100, end=50 (invalid) */
sector0[11] = 100;
sector0[15] = 50;
Ps3PlaintextRegion *regions = NULL;
uint32_t count = 0;
int32_t ret = ps3_parse_encryption_map(sector0, 2048, &regions, &count);
EXPECT_LT(ret, 0);
}
/* Test: parse rejects too-short buffer */
TEST(PS3EncMap, ParseBufferTooShort)
{
uint8_t sector0[8];
memset(sector0, 0, 8);
sector0[3] = 1; /* 1 region, but buffer is only 8 bytes (need 16) */
Ps3PlaintextRegion *regions = NULL;
uint32_t count = 0;
int32_t ret = ps3_parse_encryption_map(sector0, 8, &regions, &count);
EXPECT_LT(ret, 0);
}
/* Test: serialize and deserialize round-trip */
TEST(PS3EncMap, SerializeDeserializeRoundTrip)
{
Ps3PlaintextRegion input[3] = {{0, 31}, {256, 511}, {1024, 2047}};
uint8_t *data = NULL;
uint32_t length = 0;
int32_t ret = ps3_serialize_encryption_map(input, 3, &data, &length);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, data);
ASSERT_EQ(4u + 3u * 8u, length); /* 4 + 24 = 28 */
Ps3PlaintextRegion *output = NULL;
uint32_t count = 0;
ret = ps3_deserialize_encryption_map(data, length, &output, &count);
ASSERT_EQ(0, ret);
ASSERT_EQ(3u, count);
ASSERT_NE(nullptr, output);
for(uint32_t i = 0; i < 3; i++)
{
EXPECT_EQ(input[i].start_sector, output[i].start_sector);
EXPECT_EQ(input[i].end_sector, output[i].end_sector);
}
free(data);
free(output);
}
/* Test: serialize zero regions */
TEST(PS3EncMap, SerializeZeroRegions)
{
uint8_t *data = NULL;
uint32_t length = 0;
int32_t ret = ps3_serialize_encryption_map(NULL, 0, &data, &length);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, data);
ASSERT_EQ(4u, length);
/* First 4 bytes should be 0 (LE) */
EXPECT_EQ(0, data[0]);
EXPECT_EQ(0, data[1]);
EXPECT_EQ(0, data[2]);
EXPECT_EQ(0, data[3]);
free(data);
}
/* Test: sector encrypted — outside plaintext regions */
TEST(PS3EncMap, SectorEncryptedOutside)
{
Ps3PlaintextRegion regions[2] = {{0, 31}, {256, 511}};
/* Sector 32: between regions → encrypted */
EXPECT_TRUE(ps3_is_sector_encrypted(regions, 2, 32));
/* Sector 100: between regions → encrypted */
EXPECT_TRUE(ps3_is_sector_encrypted(regions, 2, 100));
/* Sector 255: just before second region → encrypted */
EXPECT_TRUE(ps3_is_sector_encrypted(regions, 2, 255));
/* Sector 512: just after second region → encrypted */
EXPECT_TRUE(ps3_is_sector_encrypted(regions, 2, 512));
/* Sector 10000: way past all regions → encrypted */
EXPECT_TRUE(ps3_is_sector_encrypted(regions, 2, 10000));
}
/* Test: sector not encrypted — inside plaintext regions */
TEST(PS3EncMap, SectorPlaintextInside)
{
Ps3PlaintextRegion regions[2] = {{0, 31}, {256, 511}};
/* Sector 0: first sector of first region → plaintext */
EXPECT_FALSE(ps3_is_sector_encrypted(regions, 2, 0));
/* Sector 15: middle of first region → plaintext */
EXPECT_FALSE(ps3_is_sector_encrypted(regions, 2, 15));
/* Sector 31: last sector of first region → plaintext */
EXPECT_FALSE(ps3_is_sector_encrypted(regions, 2, 31));
/* Sector 256: first sector of second region → plaintext */
EXPECT_FALSE(ps3_is_sector_encrypted(regions, 2, 256));
/* Sector 400: middle of second region → plaintext */
EXPECT_FALSE(ps3_is_sector_encrypted(regions, 2, 400));
/* Sector 511: last sector of second region → plaintext */
EXPECT_FALSE(ps3_is_sector_encrypted(regions, 2, 511));
}
/* Test: sector encrypted when no regions defined */
TEST(PS3EncMap, SectorEncryptedNoRegions)
{
EXPECT_TRUE(ps3_is_sector_encrypted(NULL, 0, 0));
EXPECT_TRUE(ps3_is_sector_encrypted(NULL, 0, 100));
}
/* Test: parse then use for sector lookup */
TEST(PS3EncMap, ParseThenLookup)
{
uint8_t sector0[2048];
build_synthetic_sector0(sector0, 2048);
Ps3PlaintextRegion *regions = NULL;
uint32_t count = 0;
int32_t ret = ps3_parse_encryption_map(sector0, 2048, &regions, &count);
ASSERT_EQ(0, ret);
/* Sector 0: in first plaintext region */
EXPECT_FALSE(ps3_is_sector_encrypted(regions, count, 0));
/* Sector 50: between regions → encrypted */
EXPECT_TRUE(ps3_is_sector_encrypted(regions, count, 50));
/* Sector 300: in second plaintext region */
EXPECT_FALSE(ps3_is_sector_encrypted(regions, count, 300));
/* Sector 600: past all regions → encrypted */
EXPECT_TRUE(ps3_is_sector_encrypted(regions, count, 600));
free(regions);
}