Пример #1
0
 def unwrapKeyForClass(self, clas, persistent_key, printError=True):
     if not self.classKeys.has_key(clas) or not self.classKeys[clas].has_key("KEY"):
         if printError: print "Keybag key %d missing or locked" % clas
         return ""
     ck = self.classKeys[clas]["KEY"]
     #if self.attrs.get("VERS", 2) >= 3 and clas == 2:
     if self.attrs.get("VERS", 2) >= 3 and self.classKeys[clas].get("KTYP", 0) == 1:
         return self.unwrapCurve25519(clas, persistent_key)
     if len(persistent_key) == 0x28:
         return AESUnwrap(ck, persistent_key)
     return
Пример #2
0
    def Decryption(self):

        if self.keybag['version'] >= 5:
            wrap_iv_digest = sha256(struct.pack('<ll', 0, 5))
            wrap_iv_digest.update(unhexlify(self.keybag['salt']))
            key_store_wrap_iv = wrap_iv_digest.digest()[:16]

        dict = {}
        for type, data in tlvs(self.fbuf[KEYBAG_DATA_SIZE +
                                         KEYBAG_HEADER_SIZE:self.endofdata]):
            #if type == 'UUID':
            #print '%s : %s'%(type, uuid.UUID(bytes=data) )
            if type == 'CLAS':
                print ' [-] %s : %s %d' % (
                    type, get_class_name(int(hexlify(data),
                                             16)), int(hexlify(data), 16))
                dict['CLAS'] = int(hexlify(data), 16)
            elif type == 'WRAP':
                print ' [-] %s : %s' % (type,
                                        get_wrap_name(int(hexlify(data), 16)))
                dict['WRAP'] = int(hexlify(data), 16)
            elif type == 'KTYP':
                print ' [-] %s : %s' % (type,
                                        get_key_type(int(hexlify(data), 16)))
                dict['KTYP'] = int(hexlify(data), 16)
            elif type == 'WPKY':
                decryptedkey = ''

                if dict['WRAP'] == 1:
                    if self.keybag['version'] >= 5:
                        decryptedkey = AESdecryptCBC(data, self.devicekey,
                                                     key_store_wrap_iv)
                    else:
                        decryptedkey = AESdecryptCBC(data, self.devicekey)
                    print ' [-] Decrypted Key : %s' % hexlify(decryptedkey)
                elif dict['WRAP'] == 3:
                    if self.keybag['version'] >= 5:
                        data = AESdecryptCBC(data[:32], self.devicekey,
                                             key_store_wrap_iv) + data[32:40]

                    try:
                        unwrapped = AESUnwrap(self.passcodekey, data)
                    except ValueError:
                        print '[!] Invalid Password. Enter the valid user password'
                        sys.exit()

                    if self.keybag['version'] >= 5:
                        decryptedkey = unwrapped
                    else:
                        decryptedkey = AESdecryptCBC(unwrapped, self.devicekey)
                    print ' [-] Decrypted Key : %s' % hexlify(decryptedkey)

                self.keyring[dict['CLAS']] = decryptedkey  # Key
Пример #3
0
    def device_key_validation(self):
        if self.devicekey == '':
            return False

        if self.keybag['sign']:
            hmackey = AESUnwrap(self.devicekey, unhexlify(self.keybag['hmck']))
            sigcheck = hmac.new(key=hmackey,
                                msg=self.keybag['data'],
                                digestmod=sha1).digest()
            if hexlify(sigcheck) != self.keybag['sign']:
                return False
        else:
            return False
        return True
    def createWithDataSignBlob(blob, deviceKey=None):
        keybag = tlvToDict(blob)

        kb = Keybag(keybag["DATA"])
        kb.deviceKey = deviceKey

        if len(keybag.get("SIGN", "")):
            hmackey = AESUnwrap(deviceKey, kb.attrs["HMCK"])
            #hmac key and data are swapped (on purpose or by mistake ?)
            sigcheck = hmac.new(keybag["DATA"], hmackey, hashlib.sha1).digest()
            if sigcheck == keybag.get("SIGN", ""):
                print "Keybag: SIGN check OK"
            else:
                print "Keybag: SIGN check FAIL"
        return kb
Пример #5
0
    def createWithDataSignBlob(blob, deviceKey=None):
        keybag = tlvToDict(blob)

        kb = Keybag(keybag.get("DATA", ""))
        kb.deviceKey = deviceKey
        kb.KeyBagKeys = blob
        kb.unlockAlwaysAccessible()

        if len(keybag.get("SIGN", "")):
            hmackey = AESUnwrap(deviceKey, kb.attrs["HMCK"])
            #hmac key and data are swapped (on purpose or by mistake ?)
            sigcheck = hmac.new(keybag["DATA"], hmackey, sha1).digest()
            if sigcheck != keybag.get("SIGN", ""):
                print "Keybag: SIGN check FAIL"
        return kb
Пример #6
0
def try_password(password, iosFlag, dpsl, dpic, salt, iter, kb):
    if iosFlag:
        password = pbkdf2_hmac('sha256', password, dpsl, dpic, 32)
    code = pbkdf2_hmac('sha1', password, salt, iter, 32)
    for classkey in kb.classKeys.values():
        k = classkey["WPKY"]
        if classkey["WRAP"] & WRAP_PASSCODE:
            k = AESUnwrap(code, classkey["WPKY"])
            if not k:
                break
        if classkey["WRAP"] & WRAP_DEVICE:
            if not kb.deviceKey:
                continue
            k = AESdecryptCBC(k, kb.deviceKey)
    else:
        return password
Пример #7
0
    def decrypt_secret_data(self, class_key):
        key = AESUnwrap(class_key, self.encrypted_secret_data_wrapped_key)
        if not key:
            raise ValueError("Failed to unwrap key. Bad class key?")

        plist = readPlistFromString(self.protobuf_item.encryptedSecretData.ciphertext)
        authenticated = ns_keyed_unarchiver(plist)
        decrypted = gcm_decrypt(key,
                                authenticated['SFInitializationVector'],
                                authenticated['SFCiphertext'], '',
                                authenticated['SFAuthenticationCode'])

        if not decrypted:
            raise ValueError("Failed to decrypt")

        return decrypted
Пример #8
0
    def unlockWithPasscodeKey(self, passcodekey):
        if self.type != BACKUP_KEYBAG:
            if not self.deviceKey:
                print "ERROR, need device key to unlock keybag"
                return False

        for classkey in self.classKeys.values():
            k = classkey["WPKY"]
            if classkey["WRAP"] & WRAP_PASSCODE:
                k = AESUnwrap(passcodekey, classkey["WPKY"])
                if not k:
                    return False
            if classkey["WRAP"] & WRAP_DEVICE:
                if not self.deviceKey:
                    continue
                k = AESdecryptCBC(k, self.deviceKey)
            classkey["KEY"] = k
        self.unlocked = True
        return True
Пример #9
0
def main():

    parser = argparse.ArgumentParser(
        description='Tool for iCloud Keychain Analysis by @n0fate')
    parser.add_argument(
        '-p',
        '--path',
        nargs=1,
        help='iCloud Keychain Path(~/Library/Keychains/[UUID]/)',
        required=True)
    parser.add_argument('-k',
                        '--key',
                        nargs=1,
                        help='User Password',
                        required=True)
    parser.add_argument(
        '-x',
        '--exportfile',
        nargs=1,
        help='Write a decrypted contents to SQLite file (optional)',
        required=False)
    parser.add_argument('-v',
                        '--version',
                        nargs=1,
                        help='macOS version(ex. 10.13)',
                        required=True)

    args = parser.parse_args()

    Pathoficloudkeychain = args.path[0]

    if os.path.isdir(Pathoficloudkeychain) is False:
        print '[!] Path is not directory'
        parser.print_help()
        sys.exit()

    if os.path.exists(Pathoficloudkeychain) is False:
        print '[!] Path is not exists'
        parser.print_help()
        sys.exit()

    # version check
    import re
    gcmIV = ''
    re1 = '(10)'  # Integer Number 1
    re2 = '(\\.)'  # Any Single Character 1
    re3 = '(\\d+)'  # Integer Number 2

    rg = re.compile(re1 + re2 + re3, re.IGNORECASE | re.DOTALL)
    m = rg.match(args.version[0])
    if m:
        minorver = m.group(3)
        if minorver >= 12:
            # Security-57740.51.3/OSX/sec/securityd/SecDbKeychainItem.c:97
            #
            # // echo "keychainblobstaticiv" | openssl dgst -sha256 | cut -c1-24 | xargs -I {} echo "0x{}" | xxd -r | xxd -p  -i
            # static const uint8_t gcmIV[kIVSizeAESGCM] = {
            #     0x1e, 0xa0, 0x5c, 0xa9, 0x98, 0x2e, 0x87, 0xdc, 0xf1, 0x45, 0xe8, 0x24
            # };
            gcmIV = '\x1e\xa0\x5c\xa9\x98\x2e\x87\xdc\xf1\x45\xe8\x24'
        else:
            gcmIV = ''
    else:
        print '[!] Invalid version'
        parser.print_help()
        sys.exit()

    export = 0
    if args.exportfile is not None:

        if os.path.exists(args.exportfile[0]):
            print '[*] Export DB File is exists.'
            sys.exit()
        export = 1

    # Start to analysis
    print 'Tool for iCloud Keychain Analysis by @n0fate'

    MachineUUID = os.path.basename(os.path.normpath(Pathoficloudkeychain))
    PathofKeybag = os.path.join(Pathoficloudkeychain, 'user.kb')
    PathofKeychain = os.path.join(Pathoficloudkeychain, 'keychain-2.db')

    print '[*] macOS version is %s' % args.version[0]
    print '[*] UUID : %s' % MachineUUID
    print '[*] Keybag : %s' % PathofKeybag
    print '[*] iCloud Keychain File : %s' % PathofKeychain

    if os.path.exists(PathofKeybag) is False or os.path.exists(
            PathofKeychain) is False:
        print '[!] Can not found KeyBag or iCloud Keychain File'
        sys.exit()

    keybag = Keybag(PathofKeybag)
    keybag.load_keybag_header()
    keybag.debug_print_header()

    devicekey = keybag.device_key_init(uuid.UUID(MachineUUID).bytes)
    print '[*] The Device key : %s' % hexlify(devicekey)

    bresult = keybag.device_key_validation()

    if bresult == False:
        print '[!] Device Key validation : Failed. Maybe Invalid PlatformUUID'
        return
    else:
        print '[*] Device Key validation : Pass'

    passcodekey = keybag.generatepasscodekey(args.key[0])

    print '[*] The passcode key : %s' % hexlify(passcodekey)

    keybag.Decryption()

    con = lite.connect(PathofKeychain)
    con.text_factory = str
    cur = con.cursor()

    tablelist = ['genp', 'inet', 'cert', 'keys']

    if export:
        # Create DB
        exportDB = ExporySQLiteDB()
        exportDB.createDB(args.exportfile[0])
        print '[*] Export DB Name : %s' % args.exportfile[0]

    for tablename in tablelist:
        if export is not 1:
            print '[+] Table Name : %s' % GetTableFullName(tablename)
        try:
            cur.execute("SELECT data FROM %s" % tablename)
        except lite.OperationalError:
            continue

        if export:
            # Get Table Schema
            sql = con.execute("pragma table_info('%s')" % tablename).fetchall()

            # Create a table
            exportDB.createTable(tablename, sql)

        for data, in cur:
            encblobheader = _memcpy(data[:sizeof(_EncryptedBlobHeader)],
                                    _EncryptedBlobHeader)
            encblobheader.clas &= 0x0F

            wrappedkey = data[sizeof(_EncryptedBlobHeader
                                     ):sizeof(_EncryptedBlobHeader) +
                              encblobheader.length]
            if encblobheader.clas == 11:
                encrypted_data = data[sizeof(_EncryptedBlobHeader) +
                                      encblobheader.length:]
                auth_tag = data[-20:-4]
            else:
                encrypted_data = data[sizeof(_EncryptedBlobHeader) +
                                      encblobheader.length:-16]
                auth_tag = data[-16:]

            key = keybag.GetKeybyClass(encblobheader.clas)

            if key == '':
                print '[!] Could not found any key at %d' % encblobheader.clas
                continue

            unwrappedkey = AESUnwrap(key, wrappedkey)

            decrypted = gcm_decrypt(unwrappedkey, gcmIV, encrypted_data,
                                    data[:sizeof(_EncryptedBlobHeader)],
                                    auth_tag)

            if len(decrypted) is 0:
                #print(" [-] Decryption Process Failed. Invalid Key or Data is corrupted.")
                continue

            if export is 0:
                print '[+] DECRYPTED INFO'

            blobparse = BlobParser()
            record = blobparse.ParseIt(decrypted, tablename, export)

            if export is 0:
                for k, v in record.items():
                    if k == 'Data':
                        print ' [-]', k
                        hexdump(v)
                    elif k == 'Type' and GetTableFullName(tablename) == 'Keys':
                        print ' [-]', k, ':', blobparse.GetKeyType(int(v))
                    else:
                        print ' [-]', k, ':', v
                print ''
            else:  # export is 1
                record_lst = []
                for k, v in record.items():
                    record_lst.append([k, v])

                exportDB.insertData(tablename, record_lst)

    if export:
        exportDB.commit()
        exportDB.close()

    cur.close()
    con.close()
Пример #10
0
 def get_DKey(self, k835):
     if self.lockers.has_key("Dkey"):
         return AESUnwrap(k835, self.lockers["Dkey"])
Пример #11
0
    z = x * zmone % CURVE_P
    return number.long_to_bytes(z)[::-1]


if __name__ == "__main__":
    from crypto.aeswrap import AESUnwrap
    from Crypto.Hash import SHA256

    z = "04000000080000000200000048000000000000000000000000000000000000000000000002917dc2542198edeb1078c4d1ebab74d9ca87890657ba02b9825dadf20a002f44360c6f87743fac0236df1f9eedbea801e31677aef3a09adfb4e10a37ae27facf419ab3ea3f39f4".decode(
        "hex")

    mysecret = "99b66345829d8c05041eea1ba1ed5b2984c3e5ec7a756ef053473c7f22b49f14".decode(
        "hex")
    mypublic = "b1c652786697a5feef36a56f36fde524a21193f4e563627977ab515f600fdb3a".decode(
        "hex")
    hispublic = z[36:36 + 32]

    #c4d9fe462a2ebbf0745195ce7dc5e8b49947bbd5b42da74175d5f8125b44582b
    shared = curve25519(mysecret, hispublic)
    print shared.encode("hex")

    h = SHA256.new()
    h.update('\x00\x00\x00\x01')
    h.update(shared)
    h.update(hispublic)
    h.update(mypublic)
    md = h.digest()

    #e442c81b91ea876d3cf42d3aea75f4b0c3f90f9fd045e1f5784b91260f3bdc9c
    print AESUnwrap(md, z[32 + 36:]).encode("hex")
Пример #12
0
def main():
    if len(sys.argv) not in [3, 4]:
        print "Usage: %s <backup path> <output path> [password]" % sys.argv[0]
        sys.exit(1)

    backup_path = sys.argv[1]
    output_path = sys.argv[2]
    if len(sys.argv) == 4:
        password = sys.argv[3]
    else:
        password = ''

    mbdb = MBDB(backup_path)

    kb = getBackupKeyBag(backup_path, password)
    if kb is None:
        raise Exception("Cannot decrypt keybag. Wrong pass?")

    for record in mbdb.files.values():
        # create directories if they do not exist
        # makedirs throw an exception, my code is ugly =)
        if record.is_directory():
            try:
                os.makedirs(output_path + '/' + record.path)
            except:
                pass

    for (filename, record) in mbdb.files.items():
        # skip directories
        if record.is_directory():
            continue

        # adjust output file name
        if record.is_symbolic_link():
            out_file = record.target
        else:
            out_file = record.path

        # read backup file
        try:
            f = file(backup_path + '/' + filename, 'rb')
            file_data = f.read()
            f.close()
        except (IOError):
            warn("File %s (%s) has not been found" % (filename, record.path))
            continue

        if record.encryption_key is not None:  # file is encrypted!
            if kb.classKeys.has_key(record.protection_class):
                kek = kb.classKeys[record.protection_class]['KEY']

                k = AESUnwrap(kek, record.encryption_key[4:])
                if k is not None:
                    c = AES.new(k, AES.MODE_CBC)
                    file_data = c.decrypt(file_data)

                    padding = file_data[record.size:]
                    if len(padding) > AES.block_size or padding != chr(
                            len(padding)) * len(padding):
                        warn("Incorrect padding for file %s" % record.path)
                    file_data = file_data[:record.size]

                else:
                    warn("Cannot unwrap key")
                    continue
            else:
                warn("Cannot load encryption key for file %s" % f)

        # write output file
        print("Writing %s" % out_file)
        f = file(output_path + '/' + out_file, 'wb')
        f.write(file_data)
        f.close()
    pass
def main():
  # Get the arguments
  if len(sys.argv) != 3:
    print "Usage: backup_passwd_guess.py iOS_Backup_Dir Password_Dictionary"
    sys.exit(1)
  backup = sys.argv[1]
  pwddict = sys.argv[2]

  # Open the manifest plist
  manifest_loc = backup + "/Manifest.plist"
  if not os.path.exists(manifest_loc):
    print "Can't find Manifest.plist - bad backup?"
    sys.exit(1)
  manifest = readPlist(manifest_loc)

  # Open the dictionary
  if not os.path.exists(pwddict):
    print "Can't find dictionary"
    sys.exit(1)
  dictfile = open(pwddict)

  # Get the backup information
  info = readPlist(backup + "/Info.plist")
  print "Backup Details:"
  print "  Device:   %s" % (info['Product Name'])
  print "  Serial:   %s" % (info['Serial Number'])
  print "  Firmware: %s" % (info['Product Version'])
  print ""

  # Make sure the backup is encrypted
  if not manifest["IsEncrypted"]:
    print "Backup is not encrypted"
    sys.exit(1)

  # Determine if we have the new format of the backup encryption
  iosFlag = False
  if 'ManifestKey' in manifest:
    print "***** Backup is encrypted using newer algorithm. Time per try is now minutes instead of seconds *****"
    print ""
    iosFlag = True

  # Get the keybag
  kb = Keybag(manifest["BackupKeyBag"].data)
  kb.deviceKey = None
  if kb.type != BACKUP_KEYBAG and kb.type != OTA_KEYBAG:
    print "Backup does not contain a backup keybag"
    sys.exit(1)
  salt = kb.attrs["SALT"]
  iter = kb.attrs["ITER"]
  if iosFlag:
    dpsl = kb.attrs["DPSL"]
    dpic = kb.attrs["DPIC"]

  # Loop through the passwords in the file
  while True:
    password = dictfile.readline()
    if password == "":
      break
    password = password[:-1]
    opassword = password
    print "Trying %s" % (opassword)

    # Check the password
    if iosFlag:
      password = PBKDF2(password, dpsl, iterations = dpic, digestmodule=SHA256).read(32)
    code = PBKDF2(password, salt, iterations=iter).read(32)
    success = 0
    for classkey in kb.classKeys.values():
      k = classkey["WPKY"]
      if classkey["WRAP"] & WRAP_PASSCODE:
        k = AESUnwrap(code, classkey["WPKY"])
        if not k:
          success = 1
          break
      if classkey["WRAP"] & WRAP_DEVICE:
        if not kb.deviceKey:
          continue
        k = AESdecryptCBC(k, kb.deviceKey)
    if success == 0:
      print "Password found - ",opassword
      break