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_text_encoding: Optional[str] = None
|
||||||
self.last_packet_encoding: Optional[int] = 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.
|
Given a data blob and a key blob, perform RC4 encryption/decryption.
|
||||||
|
|
||||||
|
|
@ -58,7 +58,10 @@ class EAmuseProtocol:
|
||||||
|
|
||||||
# KSA Phase
|
# KSA Phase
|
||||||
for i in range(256):
|
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]
|
S[i], S[j] = S[j], S[i]
|
||||||
|
|
||||||
# PRGA Phase
|
# PRGA Phase
|
||||||
|
|
@ -97,7 +100,7 @@ class EAmuseProtocol:
|
||||||
|
|
||||||
if key:
|
if key:
|
||||||
# This is an encrypted old-style packet
|
# This is an encrypted old-style packet
|
||||||
return self._rc4_crypt(data, key)
|
return self.rc4_crypt(data, key)
|
||||||
|
|
||||||
# No encryption
|
# No encryption
|
||||||
return data
|
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"
|
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()
|
proto = EAmuseProtocol()
|
||||||
|
|
||||||
cyphertext = proto._rc4_crypt(data, key)
|
cyphertext = proto.rc4_crypt(data, key)
|
||||||
self.assertEqual(encrypted, cyphertext)
|
self.assertEqual(encrypted, cyphertext)
|
||||||
|
|
||||||
plaintext = proto._rc4_crypt(cyphertext, key)
|
plaintext = proto.rc4_crypt(cyphertext, key)
|
||||||
self.assertEqual(data, plaintext)
|
self.assertEqual(data, plaintext)
|
||||||
|
|
||||||
def test_small_data_random(self) -> None:
|
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)])
|
key = bytes([random.randint(0, 255) for _ in range(16)])
|
||||||
proto = EAmuseProtocol()
|
proto = EAmuseProtocol()
|
||||||
|
|
||||||
cyphertext = proto._rc4_crypt(data, key)
|
cyphertext = proto.rc4_crypt(data, key)
|
||||||
self.assertNotEqual(data, cyphertext)
|
self.assertNotEqual(data, cyphertext)
|
||||||
|
|
||||||
plaintext = proto._rc4_crypt(cyphertext, key)
|
plaintext = proto.rc4_crypt(cyphertext, key)
|
||||||
self.assertEqual(data, plaintext)
|
self.assertEqual(data, plaintext)
|
||||||
|
|
||||||
def test_large_data_random(self) -> None:
|
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)])
|
key = bytes([random.randint(0, 255) for _ in range(16)])
|
||||||
proto = EAmuseProtocol()
|
proto = EAmuseProtocol()
|
||||||
|
|
||||||
cyphertext = proto._rc4_crypt(data, key)
|
cyphertext = proto.rc4_crypt(data, key)
|
||||||
self.assertNotEqual(data, cyphertext)
|
self.assertNotEqual(data, cyphertext)
|
||||||
|
|
||||||
plaintext = proto._rc4_crypt(cyphertext, key)
|
plaintext = proto.rc4_crypt(cyphertext, key)
|
||||||
self.assertEqual(data, plaintext)
|
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