Class: IosBackupExtractor::Keybag
- Inherits:
-
Object
- Object
- IosBackupExtractor::Keybag
- Includes:
- NauktisUtils::Logging
- Defined in:
- lib/ios_backup_extractor/keybag.rb
Constant Summary collapse
- KEYBAG_TYPES =
['System', 'Backup', 'Escrow', 'OTA (icloud)']
- CLASSKEY_TAGS =
%w(UUID CLAS WRAP WPKY KTYP PBKY)- WRAP_DEVICE =
1- WRAP_PASSCODE =
2
Class Method Summary collapse
-
.create_with_backup_manifest(manifest, password, version_major, version_minor) ⇒ Object
Creates a new Keybag.
Instance Method Summary collapse
- #get_passcode_key_from_passcode(password) ⇒ Object
-
#initialize(data, version_major, version_minor) ⇒ Keybag
constructor
A new instance of Keybag.
- #parse_binary_blob(data) ⇒ Object
-
#print_info ⇒ Object
Prints information about the Keybag.
- #unlock_backup_keybag_with_passcode(password) ⇒ Object
- #unwrap_class_keys(passcodekey) ⇒ Object
- #unwrap_key_for_class(protection_class, persistent_key) ⇒ Object
Constructor Details
#initialize(data, version_major, version_minor) ⇒ Keybag
Returns a new instance of Keybag.
9 10 11 12 13 |
# File 'lib/ios_backup_extractor/keybag.rb', line 9 def initialize(data, version_major, version_minor) @version_major = version_major @version_minor = version_minor parse_binary_blob(data) end |
Class Method Details
.create_with_backup_manifest(manifest, password, version_major, version_minor) ⇒ Object
Creates a new Keybag
75 76 77 78 79 |
# File 'lib/ios_backup_extractor/keybag.rb', line 75 def self.create_with_backup_manifest(manifest, password, version_major, version_minor) kb = Keybag.new(manifest['BackupKeyBag'], version_major, version_minor) kb.unlock_backup_keybag_with_passcode(password) kb end |
Instance Method Details
#get_passcode_key_from_passcode(password) ⇒ Object
58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/ios_backup_extractor/keybag.rb', line 58 def get_passcode_key_from_passcode(password) raise 'This is not a backup/icloud keybag' unless @type == 1 or @type == 3 if @version_major == 10 && @version_minor < 2 return OpenSSL::PKCS5.pbkdf2_hmac_sha1(password, @attributes['SALT'], @attributes['ITER'], 32) end # Version >= 10.2 digest = OpenSSL::Digest::SHA256.new len = digest.digest_length kek = OpenSSL::PKCS5.pbkdf2_hmac(password, @attributes['DPSL'], @attributes['DPIC'], len, digest) OpenSSL::PKCS5.pbkdf2_hmac_sha1(kek, @attributes['SALT'], @attributes['ITER'], 32) end |
#parse_binary_blob(data) ⇒ Object
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/ios_backup_extractor/keybag.rb', line 15 def parse_binary_blob(data) @class_keys = {} @attributes = {} current_class = {} loop_tlv_blocks(data) do |tag, value| if value.size == 4 value = value.unpack('L>')[0] end if tag == 'TYPE' @type = value & 0x3FFFFFFF # Ignore the flags raise "Error: Keybag type #{@type} > 3" if @type > 3 logger.debug(self.class){"Keybag of type #{KEYBAG_TYPES[@type]}"} end @uuid = value if tag == 'UUID' and @uuid.nil? @wrap = value if tag == 'WRAP' and @wrap.nil? current_class = {} if tag == 'UUID' # New class starts by the UUID tag. current_class[tag] = value if CLASSKEY_TAGS.include?(tag) @class_keys[current_class['CLAS'] & 0xF] = current_class if current_class.has_key?('CLAS') @attributes[tag] = value end end |
#print_info ⇒ Object
Prints information about the Keybag
84 85 86 87 88 89 90 |
# File 'lib/ios_backup_extractor/keybag.rb', line 84 def print_info puts '== Keybag' puts "Keybag type: #{KEYBAG_TYPES[@type]} keybag (#{@type})" puts "Keybag version: #{@attributes['VERS']}" puts "Keybag iterations: #{@attributes['ITER']}, iv=#{@attributes['SALT'].unpack('H*')[0]}" puts "Keybag UUID: #{@uuid.unpack('H*')[0]}" end |
#unlock_backup_keybag_with_passcode(password) ⇒ Object
37 38 39 40 |
# File 'lib/ios_backup_extractor/keybag.rb', line 37 def unlock_backup_keybag_with_passcode(password) raise 'This is not a backup keybag' unless @type == 1 or @type == 2 unwrap_class_keys(get_passcode_key_from_passcode(password)) end |
#unwrap_class_keys(passcodekey) ⇒ Object
42 43 44 45 46 47 48 49 50 |
# File 'lib/ios_backup_extractor/keybag.rb', line 42 def unwrap_class_keys(passcodekey) @class_keys.each_value do |classkey| k = classkey['WPKY'] if classkey['WRAP'] & WRAP_PASSCODE > 0 k = AESKeyWrap.unwrap!(classkey['WPKY'].to_s, passcodekey) classkey['KEY'] = k end end end |
#unwrap_key_for_class(protection_class, persistent_key) ⇒ Object
52 53 54 55 56 |
# File 'lib/ios_backup_extractor/keybag.rb', line 52 def unwrap_key_for_class(protection_class, persistent_key) raise "Keybag key #{protection_class} missing or locked" unless @class_keys.has_key?(protection_class) and @class_keys[protection_class].has_key?('KEY') raise 'Invalid key length' unless persistent_key.length == 0x28 AESKeyWrap.unwrap!(persistent_key, @class_keys[protection_class]['KEY']) end |