mirror of
https://github.com/DragonMinded/bemaniutils.git
synced 2026-03-21 17:24:33 -05:00
Add a utility for encrypting/decrypting NVRAM files.
This commit is contained in:
parent
98d245f824
commit
61ed4d39cf
|
|
@ -41,7 +41,7 @@ class EAmuseProtocol:
|
|||
self.last_text_encoding: Optional[str] = None
|
||||
self.last_packet_encoding: Optional[int] = None
|
||||
|
||||
def _rc4_crypt(self, data: bytes, key: bytes) -> bytes:
|
||||
def rc4_crypt(self, data: bytes, key: bytes) -> bytes:
|
||||
"""
|
||||
Given a data blob and a key blob, perform RC4 encryption/decryption.
|
||||
|
||||
|
|
@ -58,7 +58,10 @@ class EAmuseProtocol:
|
|||
|
||||
# KSA Phase
|
||||
for i in range(256):
|
||||
j = (j + S[i] + key[i % len(key)]) & 0xFF
|
||||
if key:
|
||||
j = (j + S[i] + key[i % len(key)]) & 0xFF
|
||||
else:
|
||||
j = (j + S[i]) & 0xFF
|
||||
S[i], S[j] = S[j], S[i]
|
||||
|
||||
# PRGA Phase
|
||||
|
|
@ -97,7 +100,7 @@ class EAmuseProtocol:
|
|||
|
||||
if key:
|
||||
# This is an encrypted old-style packet
|
||||
return self._rc4_crypt(data, key)
|
||||
return self.rc4_crypt(data, key)
|
||||
|
||||
# No encryption
|
||||
return data
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ class TestRC4Cipher(unittest.TestCase):
|
|||
encrypted = b"\x04]Q\x11\x0cw\x7fO\xfa\x03\xa3\xdf\xb6\x02\xb7d\x9f\x13U\x19\xc9-j\x96\x15yl\x98\xee_<\xfa\x9b\x8f\xbe}\xf4\x05l5\x0e\xd6"
|
||||
proto = EAmuseProtocol()
|
||||
|
||||
cyphertext = proto._rc4_crypt(data, key)
|
||||
cyphertext = proto.rc4_crypt(data, key)
|
||||
self.assertEqual(encrypted, cyphertext)
|
||||
|
||||
plaintext = proto._rc4_crypt(cyphertext, key)
|
||||
plaintext = proto.rc4_crypt(cyphertext, key)
|
||||
self.assertEqual(data, plaintext)
|
||||
|
||||
def test_small_data_random(self) -> None:
|
||||
|
|
@ -23,10 +23,10 @@ class TestRC4Cipher(unittest.TestCase):
|
|||
key = bytes([random.randint(0, 255) for _ in range(16)])
|
||||
proto = EAmuseProtocol()
|
||||
|
||||
cyphertext = proto._rc4_crypt(data, key)
|
||||
cyphertext = proto.rc4_crypt(data, key)
|
||||
self.assertNotEqual(data, cyphertext)
|
||||
|
||||
plaintext = proto._rc4_crypt(cyphertext, key)
|
||||
plaintext = proto.rc4_crypt(cyphertext, key)
|
||||
self.assertEqual(data, plaintext)
|
||||
|
||||
def test_large_data_random(self) -> None:
|
||||
|
|
@ -34,8 +34,8 @@ class TestRC4Cipher(unittest.TestCase):
|
|||
key = bytes([random.randint(0, 255) for _ in range(16)])
|
||||
proto = EAmuseProtocol()
|
||||
|
||||
cyphertext = proto._rc4_crypt(data, key)
|
||||
cyphertext = proto.rc4_crypt(data, key)
|
||||
self.assertNotEqual(data, cyphertext)
|
||||
|
||||
plaintext = proto._rc4_crypt(cyphertext, key)
|
||||
plaintext = proto.rc4_crypt(cyphertext, key)
|
||||
self.assertEqual(data, plaintext)
|
||||
|
|
|
|||
62
bemani/utils/nvram.py
Normal file
62
bemani/utils/nvram.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import argparse
|
||||
import os
|
||||
|
||||
from bemani.protocol import EAmuseProtocol
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="A utility to encrypt or decrypt NVRAM files.")
|
||||
parser.add_argument(
|
||||
"file",
|
||||
help="File to encrypt or decrypt.",
|
||||
type=str,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-o",
|
||||
"--output",
|
||||
default=None,
|
||||
type=str,
|
||||
help="Output to a different file instead of overwriting original.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--strip-padding",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Strip null padding on decryption.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--add-padding",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Add null padding on encryption.",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(args.file, "rb") as bfp:
|
||||
data = bfp.read()
|
||||
|
||||
if args.add_padding:
|
||||
off_by = len(data) % 768
|
||||
if off_by != 0:
|
||||
data = data + b"\x00" * (768 - off_by)
|
||||
|
||||
assert (len(data) % 768) == 0
|
||||
|
||||
chunks = [data[x:x + 768] for x in range(0, len(data), 768)]
|
||||
outputs = []
|
||||
proto = EAmuseProtocol()
|
||||
|
||||
for chunk in chunks:
|
||||
outputs.append(proto.rc4_crypt(chunk, b""))
|
||||
|
||||
output = b"".join(outputs)
|
||||
if args.strip_padding:
|
||||
while output[-1] == 0:
|
||||
output = output[:-1]
|
||||
|
||||
with open(args.output or args.file, "wb") as bfp:
|
||||
bfp.write(output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
12
nvram
Executable file
12
nvram
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
#! /usr/bin/env python3
|
||||
if __name__ == "__main__":
|
||||
import os
|
||||
path = os.path.abspath(os.path.dirname(__file__))
|
||||
name = os.path.basename(__file__)
|
||||
|
||||
import sys
|
||||
sys.path.append(path)
|
||||
os.environ["SQLALCHEMY_SILENCE_UBER_WARNING"] = "1"
|
||||
|
||||
import runpy
|
||||
runpy.run_module(f"bemani.utils.{name}", run_name="__main__")
|
||||
Loading…
Reference in New Issue
Block a user