From fbec24550175cb1f8930a08af97862f1b41d6335 Mon Sep 17 00:00:00 2001 From: Nichlas Severinsen Date: Sat, 7 Jul 2018 00:38:10 +0200 Subject: [PATCH] Major refactor. Release 0.0.1 - Now possible to give .iso and .ird and get a decrypted output.iso --- .gitignore | 84 ++++++++++++++++++++--- LibRay-PS3/core.py | 139 -------------------------------------- LibRay-PS3/libray-ps3.py | 141 --------------------------------------- README.md | 20 +++++- libray/__init__.py | 0 libray/core.py | 82 +++++++++++++++++++++++ libray/ird.py | 136 +++++++++++++++++++++++++++++++++++++ libray/iso.py | 106 +++++++++++++++++++++++++++++ libray/libray | 1 + libray/libray.py | 44 ++++++++++++ requirements.txt | 2 +- setup.py | 16 +++++ 12 files changed, 480 insertions(+), 291 deletions(-) delete mode 100644 LibRay-PS3/core.py delete mode 100644 LibRay-PS3/libray-ps3.py create mode 100644 libray/__init__.py create mode 100644 libray/core.py create mode 100644 libray/ird.py create mode 100644 libray/iso.py create mode 120000 libray/libray create mode 100755 libray/libray.py create mode 100755 setup.py diff --git a/.gitignore b/.gitignore index 37bf246..33a1a67 100644 --- a/.gitignore +++ b/.gitignore @@ -1,19 +1,14 @@ -# Custom *.iso *.ird -*.txt -ird -region_* -*.bin -*.BIN -*.ini -*.INI # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class +# C extensions +*.so + # Distribution / packaging .Python build/ @@ -33,7 +28,80 @@ wheels/ *.egg MANIFEST +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + # Installer logs pip-log.txt pip-delete-this-directory.txt +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ \ No newline at end of file diff --git a/LibRay-PS3/core.py b/LibRay-PS3/core.py deleted file mode 100644 index 18a0fc1..0000000 --- a/LibRay-PS3/core.py +++ /dev/null @@ -1,139 +0,0 @@ -# -*- coding: utf8 -*- - -# LibRay-PS3 - Libre Blu-Ray PS3 ISO Tool -# Copyright (C) 2018 Nichlas Severinsen -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import os -import sys -import gzip - -ORDER = 'big' -IRD_ORDER = 'little' -SECTOR = 2048 - -def bytes_to_int(byte): - return int.from_bytes(byte, ORDER) - -def ird_bytes_to_int(byte): - return int.from_bytes(byte, IRD_ORDER) - -def read_seven_bit_encoded_int(fileobj): - # Read out an Int32 7 bits at a time. The high bit - # of the byte when on means to continue reading more bytes - count = 0 - shift = 0 - byte = -1 - while (byte & 0x80) != 0 or byte == -1: - # Check for a corrupted stream. Read a max of 5 bytes. - if shift == (5 * 7): - raise ValueError - byte = ird_bytes_to_int(fileobj.read(1)) - count |= (byte & 0x7F) << shift - shift += 7 - print(byte, count, shift) - return count - - -class IRD: - - def is_compressed(self, fileobj): - fileobj.seek(0) - return fileobj.read(4) != b"3IRD" - - def uncompress(self, filename): - with gzip.open(filename, 'rb') as gzfile: - with open('ird', 'wb') as outfile: - outfile.write(gzfile.read()) - - def __init__(self, filename): - - with open(filename, 'rb') as fileobj: - if self.is_compressed(fileobj): - self.uncompress(filename) - - self.size = os.stat('ird').st_size - with open('ird', 'rb') as ird: - self.magic_string = ird.read(4) - self.version = ird_bytes_to_int(ird.read(1)) - self.game_id = ird.read(9) - length = read_seven_bit_encoded_int(ird) - self.game_name = ird.read(length) - self.update_version = ird.read(4) - self.game_version = ird.read(5) - self.app_version = ird.read(5) - if self.version == 7: - self.identifier = ird.read(4) - if self.version < 9: - back = ird.tell() - length = read_seven_bit_encoded_int(ird) - if length: - self.header = ird.read(length) - else: - ird.seek(back) - back = ird.tell() - length = read_seven_bit_encoded_int(ird) - if length: - self.footer = ird.read(length) - else: - ird.seek(back) - self.region_count = ird_bytes_to_int(ird.read(1)) - self.region_hash = [] - for i in range(0, self.region_count): - self.region_hash.append(ird.read(16)) - self.file_count = ird_bytes_to_int(ird.read(4)) - print(vars(self) ) - - - return - sys.exit() - back = ird.tell() - prefix = bytes_to_int(ird.read(1)) - length = prefix >> 1 - if prefix & 0b00000001: - ird.seek(back) - - - - - self.header = ird.read(length) - back = ird.tell() - prefix = bytes_to_int(ird.read(1)) - length = prefix >> 1 - ird.seek(back) - self.footer = ird.read(length) - self.region_count - - print(self.game_name, self.update_version, self.game_version, self.region_count) - - ird.seek(self.size - (2 + 115 + 16 + 16)) - if self.version >= 9: - self.pic = ird.read(115) - self.data_one = ird.read(16) - print(self.data_one.hex()) - self.data_two = ird.read(16) - if self.version < 9: - self.pic = ird.read(115) - self.uid = ird.read(2) - - print(self.pic) - print(self.uid) - print(self.game_id) - - if filename != 'ird': - os.remove('ird') - - - diff --git a/LibRay-PS3/libray-ps3.py b/LibRay-PS3/libray-ps3.py deleted file mode 100644 index 53bf52a..0000000 --- a/LibRay-PS3/libray-ps3.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf8 -*- - -# LibRay-PS3 - Libre Blu-Ray PS3 ISO Tool -# Copyright (C) 2018 Nichlas Severinsen -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -import os -import sys -import core -import base64 -import struct -import shutil -import binascii -from Crypto.Cipher import AES - -def bytes_to_int(byte): - return int.from_bytes(byte, core.ORDER) - -def int_to_hexstr(integer): - return '{:02x}'.format(integer) - -def int_to_bytes(integer): - return bytes(bytearray.fromhex(int_to_hexstr(integer))) - -def hexstr_to_bytes(hexstr): - return bytes(bytearray.fromhex(hexstr)) - -def bprint(byte): - byteint = bytes_to_int(byte) - print(byte, '\t->', byteint, '\t->', byteint*8, '\t->', byteint*2048 ) - -def decode(self, text): - ''' - Remove the PKCS#7 padding from a text string - ''' - nl = len(text) - val = int(binascii.hexlify(text[-1]), 16) - if val > self.k: - raise ValueError('Input is not padded or padding is corrupt') - - l = nl - val - return text[:l] - - -BS = 32 -pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS) -unpad = lambda s : s[:-ord(s[len(s)-1:])] - -if __name__ == '__main__': - - #core.IRD('BCAS20001-CA107E13820801F29488EBEB7D82A2C4.ird') - #core.IRD('BLES00048-1AA29AD85F7770BDCED0B7030067D59A.ird') - #sys.exit() - - bprint(b'\x00\x00\x00\x00') - bprint(b'\x00\x00\x0c\xbf') - bprint(b'\x00\x00\x00q\xc2') - bprint(b'\x00\x00s\xc2\x7f') - bprint(b'\x00\x00s\xc2\x80') - - data = hexstr_to_bytes("11089487d46ec9c1ec71205c2a6e8adc") # bles00048 - #data = hexstr_to_bytes("18c871628e0c3bbbd20b8a4cfb40b750") # bles000681 - key = hexstr_to_bytes("380bcf0b53455b3c7817ab4fa3ba90ed") - iv = hexstr_to_bytes("69474772af6fdab342743aefaa186287") - - cipher = AES.new(key, AES.MODE_CBC, iv) - disc_key = cipher.encrypt(data) - #print(disc_key) - #print(disc_key.hex()) - #disc_key = hexstr_to_bytes("01AD4F9DFED22E37998BDDC57E135935") - #print(disc_key.hex()) - #print(unpad(disc_key.hex())) - #disc_key = hexstr_to_bytes("DCD55A55B033905C58E7FE2A7F969F27") - - regions = [ - {'start': 0, 'end': 6682624, 'enc': False}, - {'start': 6682624, 'end': 59641856, 'enc': True}, - {'start': 59641856, 'end': 15537010688, 'enc': False}, - {'start': 15537010688, 'end': 15537012736, 'enc': True } - # There's also a last sector between 15537010688 and 15537012736, but seems like it's not used - ] - - files = [] - test = hexstr_to_bytes("533570a1") - with open(sys.argv[1], 'rb') as iso: - for i, region in enumerate(regions): - files.append('region_' + str(i)) - with open('region_' + str(i), 'wb') as output: - iso.seek(region['start']) - - if not region['enc']: - while iso.tell() < region['end']: - data = iso.read(core.SECTOR) - output.write(data) - continue - else: - while iso.tell() < region['end']: - num = iso.tell() // 2048 - backupnum = num - iv = bytearray([0 for i in range(0,16)]) - for j in range(0,16): - iv[16 - j - 1] = (num & 0xFF) - num >>= 8 - - data = iso.read(core.SECTOR) - - cipher = AES.new(disc_key, AES.MODE_CBC, bytes(iv)) - decrypted = cipher.decrypt(data) - - if test in decrypted: - print('nyees') - print(backupnum) - print(iv.hex()) - print(data.hex()) - print(decrypted.hex()) - - output.write(decrypted) - print(iso.tell()) - - - with open('output.iso', 'wb') as iso: - for f in files: - with open(f, 'rb') as fd: - shutil.copyfileobj(fd, iso, 1024*1024*10) - - sys.exit() - \ No newline at end of file diff --git a/README.md b/README.md index efd3ad5..0fe6d4a 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,32 @@ -# LibRay-PS3 +# LibRay LibRay: A portmanteau of Libre and Blu-Ray -LibRay-PS3 aims to be a Libre (FLOSS) Python application for unencrypting, +LibRay aims to be a Libre (FLOSS) Python application for unencrypting, extracting, repackaging, and encrypting PS3 ISOs. A hackable, crossplatform, alternative to ISOTools and ISO-Rebuilder. + [see also](http://www.psdevwiki.com/ps3/Bluray_disc#Encryption) ([archive.fo](https://archive.fo/hN1E6)) [7bit encoded int / RLE / CLP](https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/io/binaryreader.cs#L582-L600) clp = compressed length prefix + + +## Todo + +- Automatically download .ird file if not given +- Docstrings +- Extract ISO (currently doable with `7z x output.iso` +- Test .irds with version < 9 +- Custom command to backup all irds available + +## Advanced + +Figure out the SCSI commands to get data1, if at all possible. + + diff --git a/libray/__init__.py b/libray/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/libray/core.py b/libray/core.py new file mode 100644 index 0000000..4e08801 --- /dev/null +++ b/libray/core.py @@ -0,0 +1,82 @@ +# -*- coding: utf8 -*- + +# libray - Libre Blu-Ray PS3 ISO Tool +# Copyright (C) 2018 Nichlas Severinsen +# +# This file is part of libray. +# +# libray is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# libray is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with libray. If not, see . + +import os +import sys + +try: + from libray import iso +except ImportError: + import iso + +# Magic numbers / Constant variables + +SECTOR = 2048 + +# Utility functions + +def to_int(data, order='big'): + if isinstance(data, bytes): + return int.from_bytes(data, order) + + +def to_bytes(data): + if isinstance(data, str): + return bytes(bytearray.fromhex(data)) + + +ISO_SECRET = to_bytes("380bcf0b53455b3c7817ab4fa3ba90ed") +ISO_IV = to_bytes("69474772af6fdab342743aefaa186287") + + +def filesize(filename): + return os.stat(filename).st_size + + +def read_seven_bit_encoded_int(fileobj, order): + # Read out an Int32 7 bits at a time. The high bit + # of the byte when on means to continue reading more bytes + count = 0 + shift = 0 + byte = -1 + while (byte & 0x80) != 0 or byte == -1: + # Check for a corrupted stream. Read a max of 5 bytes. + if shift == (5 * 7): + raise ValueError + byte = to_int(fileobj.read(1), order) + count |= (byte & 0x7F) << shift + shift += 7 + return count + + +def error(msg): + print('ERROR: %s' % msg) + sys.exit(1) + +# Main functions + +def decrypt(args): + + input_iso = iso.ISO(args) + + input_iso.decrypt(args) + + + diff --git a/libray/ird.py b/libray/ird.py new file mode 100644 index 0000000..b64103c --- /dev/null +++ b/libray/ird.py @@ -0,0 +1,136 @@ +# -*- coding: utf8 -*- + +# libray - Libre Blu-Ray PS3 ISO Tool +# Copyright (C) 2018 Nichlas Severinsen +# +# This file is part of libray. +# +# libray is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# libray is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with libray. If not, see . + +import os +import sys +import gzip +import shutil + +try: + from libray import core +except ImportError: + import core + + +class IRD: + + + ORDER = 'little' + TEMP_FILE = 'ird' + MAGIC_STRING = b"3IRD" + + + def __init__(self, args): + + self.uncompress(args.ird) # TODO: Try/Except + + self.size = core.filesize(self.TEMP_FILE) + with open(self.TEMP_FILE, 'rb') as input_ird: + if input_ird.read(4) != self.MAGIC_STRING: + core.error("Either not an IRD file, corruped IRD file, or unknown IRD format") + + self.version = core.to_int(input_ird.read(1), self.ORDER) + self.game_id = input_ird.read(9) + name_length = core.read_seven_bit_encoded_int(input_ird, self.ORDER) + self.game_name = input_ird.read(name_length).decode('utf8') + self.update_version = input_ird.read(4) + self.game_version = input_ird.read(5) + self.app_version = input_ird.read(5) + + if self.version == 7: + self.identifier = input_ird.read(4) + + header_length = (core.to_int(input_ird.read(4), self.ORDER)) + self.header = input_ird.read(header_length) + footer_length = (core.to_int(input_ird.read(4), self.ORDER)) + self.footer = input_ird.read(footer_length) + + self.region_count = core.to_int(input_ird.read(1), self.ORDER) + self.region_hashes = [] + for i in range(0, self.region_count): + self.region_hashes.append(input_ird.read(16)) + + self.file_count = core.to_int(input_ird.read(4), self.ORDER) + self.file_hashes = [] + for i in range(0, self.file_count): + key = core.to_int(input_ird.read(8), self.ORDER) + val = input_ird.read(16) + self.file_hashes.append({'key': key, 'val': val}) + + if self.version >= 9: + self.pic = input_ird.read(115) + + unused_bytes = input_ird.read(4) # Yeah, I don't know either. + + self.data1 = input_ird.read(16) + self.data2 = input_ird.read(16) + + if self.version < 9: + self.pic = input_ird.read(115) + + if self.version < 7: + self.uid = core.to_int(input_ird.read(4), self.ORDER) + + if args.verbose: + self.print_info() + + os.remove(self.TEMP_FILE) + + + def get_if_exists(self, input_ird): + starting_address = input_ird.tell() + length = core.read_seven_bit_encoded_int(input_ird, self.ORDER) + print(length) + if length: + return input_ird.read(length) + + input_ird.seek(starting_address) + return None + + + def uncompress(self, filename): + uncompress = False + with open(filename, 'rb') as input_ird: + if input_ird.read(4) != self.MAGIC_STRING: + uncompress = True + + if uncompress: + with gzip.open(filename, 'rb') as gzfile: + with open(self.TEMP_FILE, 'wb') as tmpfile: + tmpfile.write(gzfile.read()) + else: + shutil.copyfile(filename, self.TEMP_FILE) + + + + def print_info(self): + print('Info from IRD:') + print('Version: %s' % self.version) + print('Game ID: %s' % self.game_id) + print('Game Name: %s' % self.game_name) + print('Update Version: %s' % self.update_version) + print('Game Version: %s' % self.game_version) + print('App Version: %s' % self.app_version) + print('Region Count: %s' % self.region_count) + print('File Count: %s' % self.file_count) + print('Data1: %s' % self.data1.hex()) + print('Data2: %s' % self.data2.hex()) + + diff --git a/libray/iso.py b/libray/iso.py new file mode 100644 index 0000000..fdd8a53 --- /dev/null +++ b/libray/iso.py @@ -0,0 +1,106 @@ +# -*- coding: utf8 -*- + +# libray - Libre Blu-Ray PS3 ISO Tool +# Copyright (C) 2018 Nichlas Severinsen +# +# This file is part of libray. +# +# libray is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# libray is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with libray. If not, see . + +from Crypto.Cipher import AES + +try: + from libray import core + from libray import ird +except ImportError: + import core + import ird + + +class ISO: + + + NUM_INFO_BYTES = 4 + + + def __init__(self, args): + with open(args.iso, 'rb') as input_iso: + self.number_of_regions = core.to_int(input_iso.read(self.NUM_INFO_BYTES)) + unused_bytes = input_iso.read(self.NUM_INFO_BYTES) # Yeah, I don't know either. + + self.regions = self.read_regions(input_iso, args.iso) + + if args.verbose: + self.print_info() + + self.ird = ird.IRD(args) + + cipher = AES.new(core.ISO_SECRET, AES.MODE_CBC, core.ISO_IV) + self.disc_key = cipher.encrypt(self.ird.data1) + + + def decrypt(self, args): + + print('Decrypting with disc key: %s' % self.disc_key.hex()) + + with open(args.iso, 'rb') as input_iso: + with open(args.output, 'wb') as output_iso: + for i, region in enumerate(self.regions): + input_iso.seek(region['start']) + + if not region['enc']: + while input_iso.tell() < region['end']: + data = input_iso.read(core.SECTOR) + output_iso.write(data) + continue + else: + while input_iso.tell() < region['end']: + num = input_iso.tell() // 2048 + iv = bytearray([0 for i in range(0,16)]) + for j in range(0,16): + iv[16 - j - 1] = (num & 0xFF) + num >>= 8 + + data = input_iso.read(core.SECTOR) + + cipher = AES.new(self.disc_key, AES.MODE_CBC, bytes(iv)) + decrypted = cipher.decrypt(data) + + output_iso.write(decrypted) + + + def read_regions(self, input_iso, filename): + regions = [] + + encrypted = False + for i in range(0, self.number_of_regions*2): + 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 + }) + input_iso.seek(input_iso.tell() - self.NUM_INFO_BYTES) + encrypted = not encrypted + regions[-1]['end'] = core.filesize(filename) + + return regions + + + def print_info(self): + print('Info from ISO:') + print('Regions: %s (%s)' % (self.number_of_regions, self.number_of_regions*2) ) + for i, region in enumerate(self.regions): + print(i, region) + + \ No newline at end of file diff --git a/libray/libray b/libray/libray new file mode 120000 index 0000000..211fc97 --- /dev/null +++ b/libray/libray @@ -0,0 +1 @@ +libray.py \ No newline at end of file diff --git a/libray/libray.py b/libray/libray.py new file mode 100755 index 0000000..f0b55b2 --- /dev/null +++ b/libray/libray.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# -*- coding: utf8 -*- + +# libray - Libre Blu-Ray PS3 ISO Tool +# Copyright (C) 2018 Nichlas Severinsen +# +# This file is part of libray. +# +# libray is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# libray is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with libray. If not, see . + + +import argparse + +try: + from libray import core +except ImportError: + import core + + +if __name__ == '__main__': + + # Parse command line arguments with argpase + parser = argparse.ArgumentParser(description='A Libre (FLOSS) Python application for unencrypting, extracting, repackaging, and encrypting PS3 ISOs') + parser.add_argument('-v', '--verbose', help="Increase verbosity", action='count') + parser.add_argument('-o', '--output', dest='output', type=str, help="Output filename", default='output.iso') + required = parser.add_argument_group('required arguments') + required.add_argument('-i', '--iso', dest='iso', type=str, help="Path to .iso file", required=True) + required.add_argument('-k', '--ird', dest='ird', type=str, help="Path to .ird file", required=True) + args = parser.parse_args() + + core.decrypt(args) + + \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 904545b..d033bb0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -pycrypto +pycrypto==2.6.1 \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..2b72a64 --- /dev/null +++ b/setup.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# -*- coding: utf8 -*- + +from setuptools import setup + +setup( + name="libray", + version="0.0.1", + description='A Libre (FLOSS) Python application for unencrypting, extracting, repackaging, and encrypting PS3 ISOs', + author="Nichlas Severinsen", + author_email="ns@nsz.no", + url="https://notabug.org/necklace/libray", + packages=['libray'], + scripts=['libray/libray'], + install_requires=['pycrypto==2.6.1'], +) \ No newline at end of file