3 Commits 92b37f6be7 ... 266f3fc76d

Author SHA1 Message Date
  Nichlas Severinsen 266f3fc76d Release 0.0.9 2 years ago
  Nichlas Severinsen fef4eee23a Fix #11 - read_regions bug which caused incorrect encryption/decryption 2 years ago
  Nichlas Severinsen 79f303be57 Update requirement versions and allow compatible versions to be used 2 years ago
4 changed files with 48 additions and 29 deletions
  1. 7 0
      CHANGELOG.md
  2. 30 20
      libray/iso.py
  3. 5 4
      requirements.txt
  4. 6 5
      setup.py

+ 7 - 0
CHANGELOG.md

@@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file.
 
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
+## [0.0.9] - 2022-02-19
+### Fixed
+- Issue #11: fix read_regions bug which caused incorrect encryption/decryption
+
+### Changed
+- A little more lenient requirements using ~=
+
 ## [0.0.8] - 2021-11-27
 ### Fixed
 - Issue #7: fix manually supplied .ird files not being used.

+ 30 - 20
libray/iso.py

@@ -53,28 +53,38 @@ class ISO:
   NUM_INFO_BYTES = 4
 
 
-  def read_regions(self, input_iso, filename):
+  def read_regions(self, input_iso):
     """List with info dict (start, end, whether it's encrypted) for every region.
 
     Basically, every other (odd numbered) region is encrypted.
     """
-    regions = []
+
+    # The first region is always unencrypted
 
     encrypted = False
-    for _ in range(0, self.number_of_regions):
 
-      regions.append({
-        'start': core.to_int(input_iso.read(self.NUM_INFO_BYTES)) * core.SECTOR,
-        'end': core.to_int(input_iso.read(self.NUM_INFO_BYTES)) * core.SECTOR,
-        'enc': encrypted
-      })
+    regions = [{
+      'start': core.to_int(input_iso.read(self.NUM_INFO_BYTES)) * core.SECTOR, # Should always be 0?
+      'end': core.to_int(input_iso.read(self.NUM_INFO_BYTES)) * core.SECTOR + core.SECTOR,
+      'enc': encrypted
+    }]
+
+    # We'll read 4 bytes until we hit a non-size (<=0)
 
-      input_iso.seek(input_iso.tell() - self.NUM_INFO_BYTES)
+    while True:
 
       encrypted = not encrypted
 
-    # Last region might not actually be 2048 bytes, so we'll just cheat
-    regions[-1]['end'] = self.size
+      end = core.to_int(input_iso.read(self.NUM_INFO_BYTES)) * core.SECTOR
+
+      if not end:
+        break
+
+      regions.append({
+        'start': regions[-1]['end'],
+        'end': end + core.SECTOR - (core.SECTOR if encrypted else 0),
+        'enc': encrypted
+      })
 
     return regions
 
@@ -88,13 +98,13 @@ class ISO:
       core.error('looks like ISO file/mount is empty?')
 
     with open(args.iso, 'rb') as input_iso:
-      # Get number of regions (times two as the number represents both encrypted and decrypted regions  )
-      self.number_of_regions = core.to_int(input_iso.read(self.NUM_INFO_BYTES)) * 2
+      # Get number of unencrypted regions
+      self.number_of_unencrypted_regions = core.to_int(input_iso.read(self.NUM_INFO_BYTES))
 
       # Skip unused bytes
       input_iso.seek(input_iso.tell() + self.NUM_INFO_BYTES)
 
-      self.regions = self.read_regions(input_iso, args.iso)
+      self.regions = self.read_regions(input_iso)
 
       # Seek to the start of sector 2, '+ 16' skips a section containing some 'playstation'
       input_iso.seek(core.SECTOR + 16)
@@ -228,8 +238,8 @@ class ISO:
 
           self.ird = ird.IRD(args.ird)
 
-          if self.ird.region_count != len(self.regions)-1:
-            core.error('Corrupt ISO or error in IRD. Expected %s regions, found %s regions' % (self.ird.region_count, len(self.regions)-1))
+          if self.ird.region_count != len(self.regions):
+            core.error('Corrupt ISO or error in IRD. Expected %s regions, found %s regions' % (self.ird.region_count, len(self.regions)))
 
           if self.regions[-1]['start'] > self.size:
             core.error('Corrupt ISO or error in IRD. Expected filesize larger than %.2f GiB, actual size is %.2f GiB' % (self.regions[-1]['start'] / 1024**3, self.size / 1024**3 ) )
@@ -242,8 +252,8 @@ class ISO:
 
         self.ird = ird.IRD(args.ird)
 
-        if self.ird.region_count != len(self.regions)-1:
-          core.error('Corrupt ISO or error in IRD. Expected %s regions, found %s regions' % (self.ird.region_count, len(self.regions)-1))
+        if self.ird.region_count != len(self.regions):
+          core.error('Corrupt ISO or error in IRD. Expected %s regions, found %s regions' % (self.ird.region_count, len(self.regions)))
 
         if self.regions[-1]['start'] > self.size:
           core.error('Corrupt ISO or error in IRD. Expected filesize larger than %.2f GiB, actual size is %.2f GiB' % (self.regions[-1]['start'] / 1024**3, self.size / 1024**3 ) )
@@ -387,7 +397,7 @@ class ISO:
     print('Game ID: %s' % self.game_id)
     print('Key: %s' % self.disc_key.hex())
     print('Info from ISO:')
-    print('Regions: %s' % self.number_of_regions)
+    print('Unencrypted regions: %s' % self.number_of_unencrypted_regions)
     for i, region in enumerate(self.regions):
-      print(i, region)
+      print(i, region, region['start'] // core.SECTOR, region['end'] // core.SECTOR)
 

+ 5 - 4
requirements.txt

@@ -1,4 +1,5 @@
-tqdm==4.32.2
-pycryptodome==3.9.8
-requests==2.22.0
-beautifulsoup4==4.7.1
+tqdm~=4.62.3
+pycryptodome~=3.14.1
+requests~=2.27.1
+beautifulsoup4~=4.10.0
+html5lib~=1.1

+ 6 - 5
setup.py

@@ -11,7 +11,7 @@ with open('README.md') as f:
 
 setup(
   name="libray",
-  version="0.0.8",
+  version="0.0.9",
   description='A Libre (FLOSS) Python application for unencrypting, extracting, repackaging, and encrypting PS3 ISOs',
   long_description=long_description,
   long_description_content_type='text/markdown',
@@ -21,10 +21,11 @@ setup(
   packages=['libray'],
   scripts=['libray/libray'],
   install_requires=[
-    'tqdm==4.32.2',
-    'pycryptodome==3.9.8',
-    'requests==2.22.0',
-    'beautifulsoup4==4.7.1',
+    'tqdm~=4.62.3',
+    'pycryptodome~=3.14.1',
+    'requests~=2.27.1',
+    'beautifulsoup4~=4.10.0',
+    'html5lib~=1.1'
   ],
   include_package_data=True,
   package_data={'': ['data/keys.db']},