-
-
Save halmartin/28e013a9034be04777073bccc918cb95 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3 | |
# https://watchmysys.com/blog/2023/01/fujitsu-irmc-s4-license/ | |
import argparse | |
import base64 | |
import binascii | |
import zlib | |
import hmac | |
import hashlib | |
import struct | |
from Crypto.Cipher import AES | |
# obtain values from /usr/local/lib/libfts_license.so.1.12.1 | |
# Note that in python, you enter binary hex values as b"\x0d\x0e..." | |
HMAC_KEY = b"" | |
HMAC_MSG = b"" * 4 | |
AES_IV = b"" | |
def init_lookup_table(): | |
out = [] | |
for i in range(0x100): | |
lookup_table_entry = i << 0x18 | |
for k in range(8): | |
if lookup_table_entry >> 31: | |
inlr = lookup_table_entry << 1 | |
if lookup_table_entry >> 31: | |
lookup_table_entry = inlr ^ 0x4c11db7 | |
else: | |
lookup_table_entry = lookup_table_entry << 1 | |
lookup_table_entry &= 0xffffffff | |
out.append(lookup_table_entry) | |
return out | |
def spd_crc32(param_1, x): | |
tbl = init_lookup_table() | |
for pbVar1 in param_1: | |
x = (tbl[(pbVar1 ^ x >> 0x18) & 0xff] ^ x << 8) & 0xffffffff | |
return x | |
def simple_generator(ext_features, type, serial): | |
if ext_features.lower() == "kvm": | |
features = b"\x01\x00\x00\x00" | |
elif ext_features.lower() == "kvm_media": | |
features = b"\x03\x00\x00\x00" | |
elif ext_features.lower() == "kvm_media_elcm": | |
# this license type doesn't validate on my TX chassis | |
# but apparently works on RX chassis | |
if type.lower() == "tx": | |
print("License may not be valid for TX chassis with eLCM enabled") | |
features = b"\x0f\x00\x00\x00" | |
return license_generator(serial, features, type.lower()) | |
def license_generator(serial, features, type): | |
# chassis type TX | |
struct_data = 0xffffff00 | |
if type == "rx": | |
# chassis type RX | |
struct_data = 0xffffff05 | |
DATA = b'iRMC' \ | |
+ features \ | |
+ struct.pack('>I', struct_data) + \ | |
struct.pack('<I', spd_crc32(serial.encode("ASCII"), 1)) | |
print(binascii.hexlify(DATA).decode('utf-8')) | |
aes_key = hmac.new(HMAC_KEY, HMAC_MSG, hashlib.sha1).digest() | |
# this is AES-128, so only take the first 16 bytes of the aes_key | |
cipher = AES.new(aes_key[:16], AES.MODE_CBC, iv=AES_IV) | |
encrypted_license = cipher.encrypt(DATA) | |
encoded_license = base64.b32encode(encrypted_license) | |
license = encoded_license.decode("UTF-8").replace("=","") | |
return '-'.join(license[i:i+4] for i in range(0, len(license), 4)) | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser() | |
parser.add_argument("-t", "--type", type=str, default="tx", help="License type, valid values are 'TX' or 'RX'") | |
parser.add_argument("-f", "--features", type=str, default="kvm_media", help="License type, valid values are 'KVM', 'KVM_Media', or 'KVM_Media_eLCM'") | |
parser.add_argument("serial") | |
args = parser.parse_args() | |
if len(HMAC_KEY) != 16 or len(HMAC_MSG) != 16*4 or len(AES_IV) != 16: | |
print("You are missing the HMAC and AES values") | |
else: | |
print(simple_generator(args.features, args.type, args.serial)) |
If you want to investigate the exported license (using “iRMC S4” -> “Save Configuration” -> “Include License Information”), here is a validation script:
#!/usr/bin/env python3
import argparse
import base64
import binascii
import zlib
import hmac
import hashlib
import struct
from sys import exit
from Crypto.Cipher import AES
# obtain values from /usr/local/lib/libfts_license.so.1.12.1
# Note that in python, you enter binary hex values as b"\x0d\x0e..."
HMAC_KEY = b""
HMAC_MSG = b"" * 4
AES_IV = b""
aes_key = hmac.new(HMAC_KEY, HMAC_MSG, hashlib.sha1).digest()
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("license")
args = parser.parse_args()
if len(args.license) != 32:
print("'%s' is not a valid license" % args.license)
exit(1)
try:
encrypted_license = base64.b32decode(args.license)
except binascii.Error:
encrypted_license_fujitsu = args.license.replace("-","")
padding = 32-len(encrypted_license_fujitsu)
padded_license = encrypted_license_fujitsu + padding*"="
encrypted_license = base64.b32decode(padded_license)
cipher = AES.new(aes_key[:16], mode=AES.MODE_CBC, iv=AES_IV)
decrypted_license = cipher.decrypt(encrypted_license)
if decrypted_license[:4].decode("UTF-8") == "iRMC":
if ((decrypted_license[4] & 0x04) >> 2 == 1):
print("eLCM: enabled")
if ((decrypted_license[4] & 0x02) >> 1 == 1):
print("Media: enabled")
if ((decrypted_license[4] & 0x01) == 1):
print("KVM: enabled")
print("(Probably) valid license: %s" % binascii.hexlify(decrypted_license))
else:
print("License is missing 'iRMC' magic")
I am trying to recover the values from the firmware file and I manage to get the libfts_license.so.1.12.1 most of the file is just @ and not really readable. The only thing that makes "sense" is:
^K^N^N^O^@^A^B^C ^H^G^FH!^@^@^A^@^@^@�!^@^@^B^@^@^@�!^@^@^H^@^@^@^@^@^@^@^@^@^@^@^A^B^C^D^A^B^C^D^A^B^C^D^A^B^C^DFujitsu!^A^A�(^@^@��AES CBC 128 Decrypt Fail
^@^@^@AES CBC 128 Decrypt final Fail
^@AES CBC 128 Encrypt updated in Confidentiality Trailer Fail
^@^@^@^@Confidentiality Trailer AES CBC 128 Encryption Fail
^@^@^@^@/conf/fts/license_key^@^@^@rb^@^@wb^@^@KVM^@2015-01-01 00:00:00^@%F %H:%M:%S^@Rejecting valid volume license due to cutoff date '%s'
^@sh /etc/init.d/licenseapp.sh manual &^@^@^@Could not decode license '%s' len=%d
^@^@^@MEDIA^@^@^@eLCM^@^@^@^@^@^@^@^@X^Q^@^@�^P^@^@^@^@^@^@^A^@^@^@8^C^@^@^A^@^@^@B^C^@^@^A^@^@^@R^C^@^@^A^@^@^@e^C^@^@^N^@^@^@�^C^@^@^O^@^@^@�^C^@^@^L^@^@^@�
I guess I have missed something on the way here? I am trying to open the file with nano after extracted the firmware with binwalk -e.
I guess I have missed something on the way here? I am trying to open the file with nano after extracted the firmware with binwalk -e.
libfts_license in Ghidra, showing decompiled function and hexdump
@Alotire432 Please do not post personal information in a public comment on GitHub. My contact information is available on my profile.
Your values for HMAC_KEY
, HMAC_MSG
, and AES_IV
are incorrect.
For people who are having trouble unpacking the firmware:
Then you can run
binwalk -e
on the firmware update to extract the relevant file.Using the iRMC 9.69F release.