Skip to content

Instantly share code, notes, and snippets.

@wbowling
Last active October 1, 2021 17:13
Show Gist options
  • Save wbowling/6bcb6d5c0a2d86b28dc408bf64587c7e to your computer and use it in GitHub Desktop.
Save wbowling/6bcb6d5c0a2d86b28dc408bf64587c7e to your computer and use it in GitHub Desktop.
Decryptor for signalino - Midnight Sun CTF 2021
#!/usr/bin/env python3
"""
Based on https://github.com/xperylabhub/ios_keychain_decrypter/blob/d7f3089067816cd2adc1ce910c9e1b927a356f37/keychain_decrypt.py#L113
"""
import plistlib
from bpylist import archiver, archive_types
import dataclasses
from Crypto.Cipher import AES
from pyasn1.codec.der.decoder import decode
@dataclasses.dataclass
class SFAuthenticatedCiphertext(archive_types.DataclassArchiver):
SFCiphertext: bytes = b""
SFInitializationVector: bytes = b""
SFAuthenticationCode: bytes = b""
archiver.update_class_map({'_SFAuthenticatedCiphertext': SFAuthenticatedCiphertext})
def decript_entry(entry):
if 'data' not in entry:
return None
c = archiver.unarchive(entry['data']['ciphertext'])
unwrapedKey = entry['data']['unwrappedKey']
authCode = c.SFAuthenticationCode
iv = c.SFInitializationVector
ciphertext = c.SFCiphertext
gcm = AES.new(unwrapedKey, AES.MODE_GCM, iv)
decrypted = gcm.decrypt_and_verify(ciphertext, authCode)
decoded = decode(decrypted)[0]
data = {}
for k in decoded:
if 'Octet' in str(type(k[1])):
data.update({str(k[0]): bytes(k[1])})
else:
data.update({str(k[0]): str(k[1])})
return data
if __name__ == "__main__":
with open("backup_keychain_v2.plist", "rb") as f:
plist = plistlib.load(f)
for i in range(len(plist['keychainEntries'])):
print("Entry {}".format(i))
print(decript_entry(plist['keychainEntries'][i]))
print("\n")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment