├── .gitignore ├── README.md ├── __init__.py ├── chunkserver.proto ├── chunkserver_pb2.py ├── crypto ├── PBKDF2.py ├── __init__.py ├── aes.py ├── aes_ctypes.py ├── aeswrap.py ├── curve25519.py └── gcm.py ├── icloud.proto ├── icloud_pb2.py ├── iloot.png ├── iloot.py ├── keystore ├── __init__.py ├── effaceable.py └── keybag.py ├── pbuf.py ├── requirements.txt └── util ├── __init__.py ├── asciitables.py ├── bdev.py ├── bplist.py ├── bruteforce.py ├── cert.py ├── lzss.py ├── ramdiskclient.py └── tlv.py /.gitignore: -------------------------------------------------------------------------------- 1 | output 2 | *.pyc 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | iLoot 2 | ===== 3 | 4 | Using this CLI tool you can download backups of devices assigned to your AppleID. Based on [iphone-dataprotection](https://code.google.com/p/iphone-dataprotection/) script, so copyrights belong to respective owners. Offset operations added and other minor bugs fixed. Thanks to [dlo](https://github.com/dlo) for his additions. 5 | 6 | **This tool is for educational purposes only. Before you start, make sure it's not illegal in your country.** 7 | 8 | Follow us on twitter [@hackappcom](https://twitter.com/hackappcom) and [facebook](https://www.facebook.com/groups/1480690882187595/) 9 | 10 | Hackapp [blog](blog.hackapp.com) 11 | 12 | Mobile Applications Scanner [hackapp.com](https://hackapp.com) 13 | 14 | Requirements 15 | ============ 16 | 17 | ```bash 18 | pip install -r requirements.txt 19 | ``` 20 | 21 | Example 22 | ====== 23 | 24 | ```bash 25 | $ python iloot.py -h 26 | usage: iloot [-h] [--threads THREADS] [--output OUTPUT] [--combined] 27 | [--snapshot SNAPSHOT] [--itunes-style] 28 | [--item-types ITEM_TYPES [ITEM_TYPES ...]] [--domain DOMAIN] 29 | [--keep-existing] 30 | apple_id password 31 | 32 | positional arguments: 33 | apple_id Apple ID 34 | password Password 35 | 36 | optional arguments: 37 | -h, --help Show this help message and exit. 38 | --threads THREADS Download thread pool size 39 | --output OUTPUT, -o OUTPUT 40 | Output directory. 41 | --combined Do not separate each snapshot into its own folder 42 | --snapshot SNAPSHOT Only download data the snapshot with the specified ID. 43 | Negative numbers will indicate relative position from 44 | newest backup, with -1 being the newest, -2 second, 45 | etc. 46 | --itunes-style Save the files in a flat iTunes-style backup, with 47 | mangled names. 48 | --item-types ITEM_TYPES [ITEM_TYPES ...], -t ITEM_TYPES [ITEM_TYPES ...] 49 | Only download the specified item types. Options 50 | include address_book, calendar, sms, call_history, 51 | voicemails, movies and photos. E.g., --types sms 52 | voicemail 53 | --domain DOMAIN, -d DOMAIN 54 | Limit files to those within a specific application 55 | domain 56 | --keep-existing Do not download files that has already been downloaded 57 | in a previous run. Skip files that already exist 58 | locally and that has the same file size locally as in 59 | the backup. 60 | ``` 61 | 62 | By default, the tool will download everything in a backup. If you'd only like to download a specific item type (such as all SMSs), just specify the `--item-types` argument. For instance: 63 | 64 | ```bash 65 | python iloot.py --item-types sms call_history voicemails 66 | ``` 67 | 68 | ![iLoot](https://raw.githubusercontent.com/hackappcom/iloot/master/iloot.png "iloot") 69 | 70 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackappcom/iloot/9362ac94dbb77a611e654f0622c89cb7ad31ed8a/__init__.py -------------------------------------------------------------------------------- /chunkserver.proto: -------------------------------------------------------------------------------- 1 | //source: http://pastebin.com/ZwxqpcNA 2 | // MMCS protobuf definitions v 2011-11-01 3 | // MobileMe Content Stream aka iCloud 4 | // 5 | // reversed by Lokkju 6 | // 7 | 8 | package chunkserver; 9 | 10 | message ChunkInfo { 11 | required bytes chunk_checksum = 1; 12 | optional bytes chunk_encryption_key = 2; 13 | required uint32 chunk_length = 3; 14 | } 15 | message NameValuePair { 16 | required string name = 1; 17 | required string value = 2; 18 | } 19 | message HostInfo { 20 | required string hostname = 1; 21 | required uint32 port = 2; 22 | required string method = 3; 23 | required string uri = 4; 24 | required string transport_protocol = 5; 25 | required string transport_protocol_version = 6; 26 | required string scheme = 7; 27 | repeated NameValuePair headers = 8; 28 | } 29 | message ErrorResponse { 30 | required string domain = 1; 31 | required int32 error_code = 2; 32 | optional string error_description = 3; 33 | repeated ErrorResponse underlying_errors = 4; 34 | repeated NameValuePair name_value_pair = 5; 35 | } 36 | message FileError { 37 | required bytes file_checksum = 1; 38 | required ErrorResponse error_response = 2; 39 | } 40 | message ChunkError { 41 | required bytes chunk_checksum = 1; 42 | required ErrorResponse error_response = 2; 43 | } 44 | message ChunkErrorIndex { 45 | required bytes chunk_checksum = 1; 46 | required ErrorResponse error_response = 2; 47 | required uint32 chunk_index = 3; 48 | } 49 | message FileChunkError { 50 | required bytes file_checksum = 1; 51 | repeated ChunkErrorIndex chunk_error = 2; 52 | } 53 | message StorageContainerError { 54 | required string storage_container_key = 1; 55 | required ErrorResponse error_response = 2; 56 | } 57 | message MethodCompletionInfo { 58 | required string url = 1; 59 | required uint32 response_status_code = 2; 60 | optional string response_status_line = 3; 61 | repeated NameValuePair vendor_response_headers = 4; 62 | optional bytes response_body = 5; 63 | optional ErrorResponse error = 6; 64 | optional bytes client_computed_md5 = 7; 65 | repeated NameValuePair vendor_nv_pairs = 8; 66 | repeated NameValuePair client_nv_pairs = 9; 67 | required string storage_container_authorization_token = 10; 68 | } 69 | message MethodCompletionInfoList { 70 | repeated MethodCompletionInfo method_completion_info = 1; 71 | } 72 | message FileChunkList { 73 | required bytes file_checksum = 1; 74 | required string authorization = 2; 75 | repeated ChunkInfo chunk_info = 3; 76 | } 77 | message FileChunkLists { 78 | repeated FileChunkList file_chunk_list = 1; 79 | } 80 | message StorageContainerChunkList { 81 | required bytes storage_container_key = 1; 82 | required HostInfo host_info = 2; 83 | repeated bytes chunk_checksum = 3; 84 | required string storage_container_authorization_token = 4; 85 | } 86 | message StorageContainerChunkLists { 87 | repeated StorageContainerChunkList storage_container_chunk_list = 1; 88 | repeated FileError file_error = 2; 89 | optional uint32 verbosity_level = 3; 90 | } 91 | message StorageContainerErrorList { 92 | repeated StorageContainerError storage_container_error = 1; 93 | } 94 | message FileChecksumAuthorization { 95 | required bytes file_checksum = 1; 96 | required string authorization = 2; 97 | repeated bytes chunk_checksums = 3; 98 | } 99 | message FileChecksumAuthorizationList { 100 | repeated FileChecksumAuthorization file_checksum_authorization = 1; 101 | } 102 | message ChunkReference { 103 | required uint64 container_index = 1; 104 | required uint64 chunk_index = 2; 105 | } 106 | message FileChecksumChunkReferences { 107 | required bytes file_checksum = 1; 108 | repeated ChunkReference chunk_references = 2; 109 | } 110 | message FileChecksumStorageHostChunkLists { 111 | repeated StorageHostChunkList storage_host_chunk_list = 1; 112 | repeated FileChecksumChunkReferences file_checksum_chunk_references = 2; 113 | } 114 | message FileGroups { 115 | repeated FileChecksumStorageHostChunkLists file_groups = 1; 116 | repeated FileError file_error = 2; 117 | repeated FileChunkError file_chunk_error = 3; 118 | optional uint32 verbosity_level = 4; 119 | } 120 | message ChunkChecksumList { 121 | repeated bytes chunk_checksum = 1; 122 | } 123 | message StorageHostChunkList { 124 | required HostInfo host_info = 1; 125 | repeated ChunkInfo chunk_info = 2; 126 | required string storage_container_key = 3; 127 | required string storage_container_authorization_token = 4; 128 | } 129 | message StorageHostChunkLists { 130 | repeated StorageHostChunkList storage_host_chunk_list = 1; 131 | repeated ChunkError chunk_error = 2; 132 | } 133 | 134 | -------------------------------------------------------------------------------- /chunkserver_pb2.py: -------------------------------------------------------------------------------- 1 | # Generated by the protocol buffer compiler. DO NOT EDIT! 2 | # source: chunkserver.proto 3 | 4 | from google.protobuf import descriptor as _descriptor 5 | from google.protobuf import message as _message 6 | from google.protobuf import reflection as _reflection 7 | from google.protobuf import descriptor_pb2 8 | # @@protoc_insertion_point(imports) 9 | 10 | 11 | 12 | 13 | DESCRIPTOR = _descriptor.FileDescriptor( 14 | name='chunkserver.proto', 15 | package='chunkserver', 16 | serialized_pb='\n\x11\x63hunkserver.proto\x12\x0b\x63hunkserver\"W\n\tChunkInfo\x12\x16\n\x0e\x63hunk_checksum\x18\x01 \x02(\x0c\x12\x1c\n\x14\x63hunk_encryption_key\x18\x02 \x01(\x0c\x12\x14\n\x0c\x63hunk_length\x18\x03 \x02(\r\",\n\rNameValuePair\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\r\n\x05value\x18\x02 \x02(\t\"\xc4\x01\n\x08HostInfo\x12\x10\n\x08hostname\x18\x01 \x02(\t\x12\x0c\n\x04port\x18\x02 \x02(\r\x12\x0e\n\x06method\x18\x03 \x02(\t\x12\x0b\n\x03uri\x18\x04 \x02(\t\x12\x1a\n\x12transport_protocol\x18\x05 \x02(\t\x12\"\n\x1atransport_protocol_version\x18\x06 \x02(\t\x12\x0e\n\x06scheme\x18\x07 \x02(\t\x12+\n\x07headers\x18\x08 \x03(\x0b\x32\x1a.chunkserver.NameValuePair\"\xba\x01\n\rErrorResponse\x12\x0e\n\x06\x64omain\x18\x01 \x02(\t\x12\x12\n\nerror_code\x18\x02 \x02(\x05\x12\x19\n\x11\x65rror_description\x18\x03 \x01(\t\x12\x35\n\x11underlying_errors\x18\x04 \x03(\x0b\x32\x1a.chunkserver.ErrorResponse\x12\x33\n\x0fname_value_pair\x18\x05 \x03(\x0b\x32\x1a.chunkserver.NameValuePair\"V\n\tFileError\x12\x15\n\rfile_checksum\x18\x01 \x02(\x0c\x12\x32\n\x0e\x65rror_response\x18\x02 \x02(\x0b\x32\x1a.chunkserver.ErrorResponse\"X\n\nChunkError\x12\x16\n\x0e\x63hunk_checksum\x18\x01 \x02(\x0c\x12\x32\n\x0e\x65rror_response\x18\x02 \x02(\x0b\x32\x1a.chunkserver.ErrorResponse\"r\n\x0f\x43hunkErrorIndex\x12\x16\n\x0e\x63hunk_checksum\x18\x01 \x02(\x0c\x12\x32\n\x0e\x65rror_response\x18\x02 \x02(\x0b\x32\x1a.chunkserver.ErrorResponse\x12\x13\n\x0b\x63hunk_index\x18\x03 \x02(\r\"Z\n\x0e\x46ileChunkError\x12\x15\n\rfile_checksum\x18\x01 \x02(\x0c\x12\x31\n\x0b\x63hunk_error\x18\x02 \x03(\x0b\x32\x1c.chunkserver.ChunkErrorIndex\"j\n\x15StorageContainerError\x12\x1d\n\x15storage_container_key\x18\x01 \x02(\t\x12\x32\n\x0e\x65rror_response\x18\x02 \x02(\x0b\x32\x1a.chunkserver.ErrorResponse\"\x94\x03\n\x14MethodCompletionInfo\x12\x0b\n\x03url\x18\x01 \x02(\t\x12\x1c\n\x14response_status_code\x18\x02 \x02(\r\x12\x1c\n\x14response_status_line\x18\x03 \x01(\t\x12;\n\x17vendor_response_headers\x18\x04 \x03(\x0b\x32\x1a.chunkserver.NameValuePair\x12\x15\n\rresponse_body\x18\x05 \x01(\x0c\x12)\n\x05\x65rror\x18\x06 \x01(\x0b\x32\x1a.chunkserver.ErrorResponse\x12\x1b\n\x13\x63lient_computed_md5\x18\x07 \x01(\x0c\x12\x33\n\x0fvendor_nv_pairs\x18\x08 \x03(\x0b\x32\x1a.chunkserver.NameValuePair\x12\x33\n\x0f\x63lient_nv_pairs\x18\t \x03(\x0b\x32\x1a.chunkserver.NameValuePair\x12-\n%storage_container_authorization_token\x18\n \x02(\t\"]\n\x18MethodCompletionInfoList\x12\x41\n\x16method_completion_info\x18\x01 \x03(\x0b\x32!.chunkserver.MethodCompletionInfo\"i\n\rFileChunkList\x12\x15\n\rfile_checksum\x18\x01 \x02(\x0c\x12\x15\n\rauthorization\x18\x02 \x02(\t\x12*\n\nchunk_info\x18\x03 \x03(\x0b\x32\x16.chunkserver.ChunkInfo\"E\n\x0e\x46ileChunkLists\x12\x33\n\x0f\x66ile_chunk_list\x18\x01 \x03(\x0b\x32\x1a.chunkserver.FileChunkList\"\xab\x01\n\x19StorageContainerChunkList\x12\x1d\n\x15storage_container_key\x18\x01 \x02(\x0c\x12(\n\thost_info\x18\x02 \x02(\x0b\x32\x15.chunkserver.HostInfo\x12\x16\n\x0e\x63hunk_checksum\x18\x03 \x03(\x0c\x12-\n%storage_container_authorization_token\x18\x04 \x02(\t\"\xaf\x01\n\x1aStorageContainerChunkLists\x12L\n\x1cstorage_container_chunk_list\x18\x01 \x03(\x0b\x32&.chunkserver.StorageContainerChunkList\x12*\n\nfile_error\x18\x02 \x03(\x0b\x32\x16.chunkserver.FileError\x12\x17\n\x0fverbosity_level\x18\x03 \x01(\r\"`\n\x19StorageContainerErrorList\x12\x43\n\x17storage_container_error\x18\x01 \x03(\x0b\x32\".chunkserver.StorageContainerError\"b\n\x19\x46ileChecksumAuthorization\x12\x15\n\rfile_checksum\x18\x01 \x02(\x0c\x12\x15\n\rauthorization\x18\x02 \x02(\t\x12\x17\n\x0f\x63hunk_checksums\x18\x03 \x03(\x0c\"l\n\x1d\x46ileChecksumAuthorizationList\x12K\n\x1b\x66ile_checksum_authorization\x18\x01 \x03(\x0b\x32&.chunkserver.FileChecksumAuthorization\">\n\x0e\x43hunkReference\x12\x17\n\x0f\x63ontainer_index\x18\x01 \x02(\x04\x12\x13\n\x0b\x63hunk_index\x18\x02 \x02(\x04\"k\n\x1b\x46ileChecksumChunkReferences\x12\x15\n\rfile_checksum\x18\x01 \x02(\x0c\x12\x35\n\x10\x63hunk_references\x18\x02 \x03(\x0b\x32\x1b.chunkserver.ChunkReference\"\xb9\x01\n!FileChecksumStorageHostChunkLists\x12\x42\n\x17storage_host_chunk_list\x18\x01 \x03(\x0b\x32!.chunkserver.StorageHostChunkList\x12P\n\x1e\x66ile_checksum_chunk_references\x18\x02 \x03(\x0b\x32(.chunkserver.FileChecksumChunkReferences\"\xcd\x01\n\nFileGroups\x12\x43\n\x0b\x66ile_groups\x18\x01 \x03(\x0b\x32..chunkserver.FileChecksumStorageHostChunkLists\x12*\n\nfile_error\x18\x02 \x03(\x0b\x32\x16.chunkserver.FileError\x12\x35\n\x10\x66ile_chunk_error\x18\x03 \x03(\x0b\x32\x1b.chunkserver.FileChunkError\x12\x17\n\x0fverbosity_level\x18\x04 \x01(\r\"+\n\x11\x43hunkChecksumList\x12\x16\n\x0e\x63hunk_checksum\x18\x01 \x03(\x0c\"\xba\x01\n\x14StorageHostChunkList\x12(\n\thost_info\x18\x01 \x02(\x0b\x32\x15.chunkserver.HostInfo\x12*\n\nchunk_info\x18\x02 \x03(\x0b\x32\x16.chunkserver.ChunkInfo\x12\x1d\n\x15storage_container_key\x18\x03 \x02(\t\x12-\n%storage_container_authorization_token\x18\x04 \x02(\t\"\x89\x01\n\x15StorageHostChunkLists\x12\x42\n\x17storage_host_chunk_list\x18\x01 \x03(\x0b\x32!.chunkserver.StorageHostChunkList\x12,\n\x0b\x63hunk_error\x18\x02 \x03(\x0b\x32\x17.chunkserver.ChunkError') 17 | 18 | 19 | 20 | 21 | _CHUNKINFO = _descriptor.Descriptor( 22 | name='ChunkInfo', 23 | full_name='chunkserver.ChunkInfo', 24 | filename=None, 25 | file=DESCRIPTOR, 26 | containing_type=None, 27 | fields=[ 28 | _descriptor.FieldDescriptor( 29 | name='chunk_checksum', full_name='chunkserver.ChunkInfo.chunk_checksum', index=0, 30 | number=1, type=12, cpp_type=9, label=2, 31 | has_default_value=False, default_value="", 32 | message_type=None, enum_type=None, containing_type=None, 33 | is_extension=False, extension_scope=None, 34 | options=None), 35 | _descriptor.FieldDescriptor( 36 | name='chunk_encryption_key', full_name='chunkserver.ChunkInfo.chunk_encryption_key', index=1, 37 | number=2, type=12, cpp_type=9, label=1, 38 | has_default_value=False, default_value="", 39 | message_type=None, enum_type=None, containing_type=None, 40 | is_extension=False, extension_scope=None, 41 | options=None), 42 | _descriptor.FieldDescriptor( 43 | name='chunk_length', full_name='chunkserver.ChunkInfo.chunk_length', index=2, 44 | number=3, type=13, cpp_type=3, label=2, 45 | has_default_value=False, default_value=0, 46 | message_type=None, enum_type=None, containing_type=None, 47 | is_extension=False, extension_scope=None, 48 | options=None), 49 | ], 50 | extensions=[ 51 | ], 52 | nested_types=[], 53 | enum_types=[ 54 | ], 55 | options=None, 56 | is_extendable=False, 57 | extension_ranges=[], 58 | serialized_start=34, 59 | serialized_end=121, 60 | ) 61 | 62 | 63 | _NAMEVALUEPAIR = _descriptor.Descriptor( 64 | name='NameValuePair', 65 | full_name='chunkserver.NameValuePair', 66 | filename=None, 67 | file=DESCRIPTOR, 68 | containing_type=None, 69 | fields=[ 70 | _descriptor.FieldDescriptor( 71 | name='name', full_name='chunkserver.NameValuePair.name', index=0, 72 | number=1, type=9, cpp_type=9, label=2, 73 | has_default_value=False, default_value=unicode("", "utf-8"), 74 | message_type=None, enum_type=None, containing_type=None, 75 | is_extension=False, extension_scope=None, 76 | options=None), 77 | _descriptor.FieldDescriptor( 78 | name='value', full_name='chunkserver.NameValuePair.value', index=1, 79 | number=2, type=9, cpp_type=9, label=2, 80 | has_default_value=False, default_value=unicode("", "utf-8"), 81 | message_type=None, enum_type=None, containing_type=None, 82 | is_extension=False, extension_scope=None, 83 | options=None), 84 | ], 85 | extensions=[ 86 | ], 87 | nested_types=[], 88 | enum_types=[ 89 | ], 90 | options=None, 91 | is_extendable=False, 92 | extension_ranges=[], 93 | serialized_start=123, 94 | serialized_end=167, 95 | ) 96 | 97 | 98 | _HOSTINFO = _descriptor.Descriptor( 99 | name='HostInfo', 100 | full_name='chunkserver.HostInfo', 101 | filename=None, 102 | file=DESCRIPTOR, 103 | containing_type=None, 104 | fields=[ 105 | _descriptor.FieldDescriptor( 106 | name='hostname', full_name='chunkserver.HostInfo.hostname', index=0, 107 | number=1, type=9, cpp_type=9, label=2, 108 | has_default_value=False, default_value=unicode("", "utf-8"), 109 | message_type=None, enum_type=None, containing_type=None, 110 | is_extension=False, extension_scope=None, 111 | options=None), 112 | _descriptor.FieldDescriptor( 113 | name='port', full_name='chunkserver.HostInfo.port', index=1, 114 | number=2, type=13, cpp_type=3, label=2, 115 | has_default_value=False, default_value=0, 116 | message_type=None, enum_type=None, containing_type=None, 117 | is_extension=False, extension_scope=None, 118 | options=None), 119 | _descriptor.FieldDescriptor( 120 | name='method', full_name='chunkserver.HostInfo.method', index=2, 121 | number=3, type=9, cpp_type=9, label=2, 122 | has_default_value=False, default_value=unicode("", "utf-8"), 123 | message_type=None, enum_type=None, containing_type=None, 124 | is_extension=False, extension_scope=None, 125 | options=None), 126 | _descriptor.FieldDescriptor( 127 | name='uri', full_name='chunkserver.HostInfo.uri', index=3, 128 | number=4, type=9, cpp_type=9, label=2, 129 | has_default_value=False, default_value=unicode("", "utf-8"), 130 | message_type=None, enum_type=None, containing_type=None, 131 | is_extension=False, extension_scope=None, 132 | options=None), 133 | _descriptor.FieldDescriptor( 134 | name='transport_protocol', full_name='chunkserver.HostInfo.transport_protocol', index=4, 135 | number=5, type=9, cpp_type=9, label=2, 136 | has_default_value=False, default_value=unicode("", "utf-8"), 137 | message_type=None, enum_type=None, containing_type=None, 138 | is_extension=False, extension_scope=None, 139 | options=None), 140 | _descriptor.FieldDescriptor( 141 | name='transport_protocol_version', full_name='chunkserver.HostInfo.transport_protocol_version', index=5, 142 | number=6, type=9, cpp_type=9, label=2, 143 | has_default_value=False, default_value=unicode("", "utf-8"), 144 | message_type=None, enum_type=None, containing_type=None, 145 | is_extension=False, extension_scope=None, 146 | options=None), 147 | _descriptor.FieldDescriptor( 148 | name='scheme', full_name='chunkserver.HostInfo.scheme', index=6, 149 | number=7, type=9, cpp_type=9, label=2, 150 | has_default_value=False, default_value=unicode("", "utf-8"), 151 | message_type=None, enum_type=None, containing_type=None, 152 | is_extension=False, extension_scope=None, 153 | options=None), 154 | _descriptor.FieldDescriptor( 155 | name='headers', full_name='chunkserver.HostInfo.headers', index=7, 156 | number=8, type=11, cpp_type=10, label=3, 157 | has_default_value=False, default_value=[], 158 | message_type=None, enum_type=None, containing_type=None, 159 | is_extension=False, extension_scope=None, 160 | options=None), 161 | ], 162 | extensions=[ 163 | ], 164 | nested_types=[], 165 | enum_types=[ 166 | ], 167 | options=None, 168 | is_extendable=False, 169 | extension_ranges=[], 170 | serialized_start=170, 171 | serialized_end=366, 172 | ) 173 | 174 | 175 | _ERRORRESPONSE = _descriptor.Descriptor( 176 | name='ErrorResponse', 177 | full_name='chunkserver.ErrorResponse', 178 | filename=None, 179 | file=DESCRIPTOR, 180 | containing_type=None, 181 | fields=[ 182 | _descriptor.FieldDescriptor( 183 | name='domain', full_name='chunkserver.ErrorResponse.domain', index=0, 184 | number=1, type=9, cpp_type=9, label=2, 185 | has_default_value=False, default_value=unicode("", "utf-8"), 186 | message_type=None, enum_type=None, containing_type=None, 187 | is_extension=False, extension_scope=None, 188 | options=None), 189 | _descriptor.FieldDescriptor( 190 | name='error_code', full_name='chunkserver.ErrorResponse.error_code', index=1, 191 | number=2, type=5, cpp_type=1, label=2, 192 | has_default_value=False, default_value=0, 193 | message_type=None, enum_type=None, containing_type=None, 194 | is_extension=False, extension_scope=None, 195 | options=None), 196 | _descriptor.FieldDescriptor( 197 | name='error_description', full_name='chunkserver.ErrorResponse.error_description', index=2, 198 | number=3, type=9, cpp_type=9, label=1, 199 | has_default_value=False, default_value=unicode("", "utf-8"), 200 | message_type=None, enum_type=None, containing_type=None, 201 | is_extension=False, extension_scope=None, 202 | options=None), 203 | _descriptor.FieldDescriptor( 204 | name='underlying_errors', full_name='chunkserver.ErrorResponse.underlying_errors', index=3, 205 | number=4, type=11, cpp_type=10, label=3, 206 | has_default_value=False, default_value=[], 207 | message_type=None, enum_type=None, containing_type=None, 208 | is_extension=False, extension_scope=None, 209 | options=None), 210 | _descriptor.FieldDescriptor( 211 | name='name_value_pair', full_name='chunkserver.ErrorResponse.name_value_pair', index=4, 212 | number=5, type=11, cpp_type=10, label=3, 213 | has_default_value=False, default_value=[], 214 | message_type=None, enum_type=None, containing_type=None, 215 | is_extension=False, extension_scope=None, 216 | options=None), 217 | ], 218 | extensions=[ 219 | ], 220 | nested_types=[], 221 | enum_types=[ 222 | ], 223 | options=None, 224 | is_extendable=False, 225 | extension_ranges=[], 226 | serialized_start=369, 227 | serialized_end=555, 228 | ) 229 | 230 | 231 | _FILEERROR = _descriptor.Descriptor( 232 | name='FileError', 233 | full_name='chunkserver.FileError', 234 | filename=None, 235 | file=DESCRIPTOR, 236 | containing_type=None, 237 | fields=[ 238 | _descriptor.FieldDescriptor( 239 | name='file_checksum', full_name='chunkserver.FileError.file_checksum', index=0, 240 | number=1, type=12, cpp_type=9, label=2, 241 | has_default_value=False, default_value="", 242 | message_type=None, enum_type=None, containing_type=None, 243 | is_extension=False, extension_scope=None, 244 | options=None), 245 | _descriptor.FieldDescriptor( 246 | name='error_response', full_name='chunkserver.FileError.error_response', index=1, 247 | number=2, type=11, cpp_type=10, label=2, 248 | has_default_value=False, default_value=None, 249 | message_type=None, enum_type=None, containing_type=None, 250 | is_extension=False, extension_scope=None, 251 | options=None), 252 | ], 253 | extensions=[ 254 | ], 255 | nested_types=[], 256 | enum_types=[ 257 | ], 258 | options=None, 259 | is_extendable=False, 260 | extension_ranges=[], 261 | serialized_start=557, 262 | serialized_end=643, 263 | ) 264 | 265 | 266 | _CHUNKERROR = _descriptor.Descriptor( 267 | name='ChunkError', 268 | full_name='chunkserver.ChunkError', 269 | filename=None, 270 | file=DESCRIPTOR, 271 | containing_type=None, 272 | fields=[ 273 | _descriptor.FieldDescriptor( 274 | name='chunk_checksum', full_name='chunkserver.ChunkError.chunk_checksum', index=0, 275 | number=1, type=12, cpp_type=9, label=2, 276 | has_default_value=False, default_value="", 277 | message_type=None, enum_type=None, containing_type=None, 278 | is_extension=False, extension_scope=None, 279 | options=None), 280 | _descriptor.FieldDescriptor( 281 | name='error_response', full_name='chunkserver.ChunkError.error_response', index=1, 282 | number=2, type=11, cpp_type=10, label=2, 283 | has_default_value=False, default_value=None, 284 | message_type=None, enum_type=None, containing_type=None, 285 | is_extension=False, extension_scope=None, 286 | options=None), 287 | ], 288 | extensions=[ 289 | ], 290 | nested_types=[], 291 | enum_types=[ 292 | ], 293 | options=None, 294 | is_extendable=False, 295 | extension_ranges=[], 296 | serialized_start=645, 297 | serialized_end=733, 298 | ) 299 | 300 | 301 | _CHUNKERRORINDEX = _descriptor.Descriptor( 302 | name='ChunkErrorIndex', 303 | full_name='chunkserver.ChunkErrorIndex', 304 | filename=None, 305 | file=DESCRIPTOR, 306 | containing_type=None, 307 | fields=[ 308 | _descriptor.FieldDescriptor( 309 | name='chunk_checksum', full_name='chunkserver.ChunkErrorIndex.chunk_checksum', index=0, 310 | number=1, type=12, cpp_type=9, label=2, 311 | has_default_value=False, default_value="", 312 | message_type=None, enum_type=None, containing_type=None, 313 | is_extension=False, extension_scope=None, 314 | options=None), 315 | _descriptor.FieldDescriptor( 316 | name='error_response', full_name='chunkserver.ChunkErrorIndex.error_response', index=1, 317 | number=2, type=11, cpp_type=10, label=2, 318 | has_default_value=False, default_value=None, 319 | message_type=None, enum_type=None, containing_type=None, 320 | is_extension=False, extension_scope=None, 321 | options=None), 322 | _descriptor.FieldDescriptor( 323 | name='chunk_index', full_name='chunkserver.ChunkErrorIndex.chunk_index', index=2, 324 | number=3, type=13, cpp_type=3, label=2, 325 | has_default_value=False, default_value=0, 326 | message_type=None, enum_type=None, containing_type=None, 327 | is_extension=False, extension_scope=None, 328 | options=None), 329 | ], 330 | extensions=[ 331 | ], 332 | nested_types=[], 333 | enum_types=[ 334 | ], 335 | options=None, 336 | is_extendable=False, 337 | extension_ranges=[], 338 | serialized_start=735, 339 | serialized_end=849, 340 | ) 341 | 342 | 343 | _FILECHUNKERROR = _descriptor.Descriptor( 344 | name='FileChunkError', 345 | full_name='chunkserver.FileChunkError', 346 | filename=None, 347 | file=DESCRIPTOR, 348 | containing_type=None, 349 | fields=[ 350 | _descriptor.FieldDescriptor( 351 | name='file_checksum', full_name='chunkserver.FileChunkError.file_checksum', index=0, 352 | number=1, type=12, cpp_type=9, label=2, 353 | has_default_value=False, default_value="", 354 | message_type=None, enum_type=None, containing_type=None, 355 | is_extension=False, extension_scope=None, 356 | options=None), 357 | _descriptor.FieldDescriptor( 358 | name='chunk_error', full_name='chunkserver.FileChunkError.chunk_error', index=1, 359 | number=2, type=11, cpp_type=10, label=3, 360 | has_default_value=False, default_value=[], 361 | message_type=None, enum_type=None, containing_type=None, 362 | is_extension=False, extension_scope=None, 363 | options=None), 364 | ], 365 | extensions=[ 366 | ], 367 | nested_types=[], 368 | enum_types=[ 369 | ], 370 | options=None, 371 | is_extendable=False, 372 | extension_ranges=[], 373 | serialized_start=851, 374 | serialized_end=941, 375 | ) 376 | 377 | 378 | _STORAGECONTAINERERROR = _descriptor.Descriptor( 379 | name='StorageContainerError', 380 | full_name='chunkserver.StorageContainerError', 381 | filename=None, 382 | file=DESCRIPTOR, 383 | containing_type=None, 384 | fields=[ 385 | _descriptor.FieldDescriptor( 386 | name='storage_container_key', full_name='chunkserver.StorageContainerError.storage_container_key', index=0, 387 | number=1, type=9, cpp_type=9, label=2, 388 | has_default_value=False, default_value=unicode("", "utf-8"), 389 | message_type=None, enum_type=None, containing_type=None, 390 | is_extension=False, extension_scope=None, 391 | options=None), 392 | _descriptor.FieldDescriptor( 393 | name='error_response', full_name='chunkserver.StorageContainerError.error_response', index=1, 394 | number=2, type=11, cpp_type=10, label=2, 395 | has_default_value=False, default_value=None, 396 | message_type=None, enum_type=None, containing_type=None, 397 | is_extension=False, extension_scope=None, 398 | options=None), 399 | ], 400 | extensions=[ 401 | ], 402 | nested_types=[], 403 | enum_types=[ 404 | ], 405 | options=None, 406 | is_extendable=False, 407 | extension_ranges=[], 408 | serialized_start=943, 409 | serialized_end=1049, 410 | ) 411 | 412 | 413 | _METHODCOMPLETIONINFO = _descriptor.Descriptor( 414 | name='MethodCompletionInfo', 415 | full_name='chunkserver.MethodCompletionInfo', 416 | filename=None, 417 | file=DESCRIPTOR, 418 | containing_type=None, 419 | fields=[ 420 | _descriptor.FieldDescriptor( 421 | name='url', full_name='chunkserver.MethodCompletionInfo.url', index=0, 422 | number=1, type=9, cpp_type=9, label=2, 423 | has_default_value=False, default_value=unicode("", "utf-8"), 424 | message_type=None, enum_type=None, containing_type=None, 425 | is_extension=False, extension_scope=None, 426 | options=None), 427 | _descriptor.FieldDescriptor( 428 | name='response_status_code', full_name='chunkserver.MethodCompletionInfo.response_status_code', index=1, 429 | number=2, type=13, cpp_type=3, label=2, 430 | has_default_value=False, default_value=0, 431 | message_type=None, enum_type=None, containing_type=None, 432 | is_extension=False, extension_scope=None, 433 | options=None), 434 | _descriptor.FieldDescriptor( 435 | name='response_status_line', full_name='chunkserver.MethodCompletionInfo.response_status_line', index=2, 436 | number=3, type=9, cpp_type=9, label=1, 437 | has_default_value=False, default_value=unicode("", "utf-8"), 438 | message_type=None, enum_type=None, containing_type=None, 439 | is_extension=False, extension_scope=None, 440 | options=None), 441 | _descriptor.FieldDescriptor( 442 | name='vendor_response_headers', full_name='chunkserver.MethodCompletionInfo.vendor_response_headers', index=3, 443 | number=4, type=11, cpp_type=10, label=3, 444 | has_default_value=False, default_value=[], 445 | message_type=None, enum_type=None, containing_type=None, 446 | is_extension=False, extension_scope=None, 447 | options=None), 448 | _descriptor.FieldDescriptor( 449 | name='response_body', full_name='chunkserver.MethodCompletionInfo.response_body', index=4, 450 | number=5, type=12, cpp_type=9, label=1, 451 | has_default_value=False, default_value="", 452 | message_type=None, enum_type=None, containing_type=None, 453 | is_extension=False, extension_scope=None, 454 | options=None), 455 | _descriptor.FieldDescriptor( 456 | name='error', full_name='chunkserver.MethodCompletionInfo.error', index=5, 457 | number=6, type=11, cpp_type=10, label=1, 458 | has_default_value=False, default_value=None, 459 | message_type=None, enum_type=None, containing_type=None, 460 | is_extension=False, extension_scope=None, 461 | options=None), 462 | _descriptor.FieldDescriptor( 463 | name='client_computed_md5', full_name='chunkserver.MethodCompletionInfo.client_computed_md5', index=6, 464 | number=7, type=12, cpp_type=9, label=1, 465 | has_default_value=False, default_value="", 466 | message_type=None, enum_type=None, containing_type=None, 467 | is_extension=False, extension_scope=None, 468 | options=None), 469 | _descriptor.FieldDescriptor( 470 | name='vendor_nv_pairs', full_name='chunkserver.MethodCompletionInfo.vendor_nv_pairs', index=7, 471 | number=8, type=11, cpp_type=10, label=3, 472 | has_default_value=False, default_value=[], 473 | message_type=None, enum_type=None, containing_type=None, 474 | is_extension=False, extension_scope=None, 475 | options=None), 476 | _descriptor.FieldDescriptor( 477 | name='client_nv_pairs', full_name='chunkserver.MethodCompletionInfo.client_nv_pairs', index=8, 478 | number=9, type=11, cpp_type=10, label=3, 479 | has_default_value=False, default_value=[], 480 | message_type=None, enum_type=None, containing_type=None, 481 | is_extension=False, extension_scope=None, 482 | options=None), 483 | _descriptor.FieldDescriptor( 484 | name='storage_container_authorization_token', full_name='chunkserver.MethodCompletionInfo.storage_container_authorization_token', index=9, 485 | number=10, type=9, cpp_type=9, label=2, 486 | has_default_value=False, default_value=unicode("", "utf-8"), 487 | message_type=None, enum_type=None, containing_type=None, 488 | is_extension=False, extension_scope=None, 489 | options=None), 490 | ], 491 | extensions=[ 492 | ], 493 | nested_types=[], 494 | enum_types=[ 495 | ], 496 | options=None, 497 | is_extendable=False, 498 | extension_ranges=[], 499 | serialized_start=1052, 500 | serialized_end=1456, 501 | ) 502 | 503 | 504 | _METHODCOMPLETIONINFOLIST = _descriptor.Descriptor( 505 | name='MethodCompletionInfoList', 506 | full_name='chunkserver.MethodCompletionInfoList', 507 | filename=None, 508 | file=DESCRIPTOR, 509 | containing_type=None, 510 | fields=[ 511 | _descriptor.FieldDescriptor( 512 | name='method_completion_info', full_name='chunkserver.MethodCompletionInfoList.method_completion_info', index=0, 513 | number=1, type=11, cpp_type=10, label=3, 514 | has_default_value=False, default_value=[], 515 | message_type=None, enum_type=None, containing_type=None, 516 | is_extension=False, extension_scope=None, 517 | options=None), 518 | ], 519 | extensions=[ 520 | ], 521 | nested_types=[], 522 | enum_types=[ 523 | ], 524 | options=None, 525 | is_extendable=False, 526 | extension_ranges=[], 527 | serialized_start=1458, 528 | serialized_end=1551, 529 | ) 530 | 531 | 532 | _FILECHUNKLIST = _descriptor.Descriptor( 533 | name='FileChunkList', 534 | full_name='chunkserver.FileChunkList', 535 | filename=None, 536 | file=DESCRIPTOR, 537 | containing_type=None, 538 | fields=[ 539 | _descriptor.FieldDescriptor( 540 | name='file_checksum', full_name='chunkserver.FileChunkList.file_checksum', index=0, 541 | number=1, type=12, cpp_type=9, label=2, 542 | has_default_value=False, default_value="", 543 | message_type=None, enum_type=None, containing_type=None, 544 | is_extension=False, extension_scope=None, 545 | options=None), 546 | _descriptor.FieldDescriptor( 547 | name='authorization', full_name='chunkserver.FileChunkList.authorization', index=1, 548 | number=2, type=9, cpp_type=9, label=2, 549 | has_default_value=False, default_value=unicode("", "utf-8"), 550 | message_type=None, enum_type=None, containing_type=None, 551 | is_extension=False, extension_scope=None, 552 | options=None), 553 | _descriptor.FieldDescriptor( 554 | name='chunk_info', full_name='chunkserver.FileChunkList.chunk_info', index=2, 555 | number=3, type=11, cpp_type=10, label=3, 556 | has_default_value=False, default_value=[], 557 | message_type=None, enum_type=None, containing_type=None, 558 | is_extension=False, extension_scope=None, 559 | options=None), 560 | ], 561 | extensions=[ 562 | ], 563 | nested_types=[], 564 | enum_types=[ 565 | ], 566 | options=None, 567 | is_extendable=False, 568 | extension_ranges=[], 569 | serialized_start=1553, 570 | serialized_end=1658, 571 | ) 572 | 573 | 574 | _FILECHUNKLISTS = _descriptor.Descriptor( 575 | name='FileChunkLists', 576 | full_name='chunkserver.FileChunkLists', 577 | filename=None, 578 | file=DESCRIPTOR, 579 | containing_type=None, 580 | fields=[ 581 | _descriptor.FieldDescriptor( 582 | name='file_chunk_list', full_name='chunkserver.FileChunkLists.file_chunk_list', index=0, 583 | number=1, type=11, cpp_type=10, label=3, 584 | has_default_value=False, default_value=[], 585 | message_type=None, enum_type=None, containing_type=None, 586 | is_extension=False, extension_scope=None, 587 | options=None), 588 | ], 589 | extensions=[ 590 | ], 591 | nested_types=[], 592 | enum_types=[ 593 | ], 594 | options=None, 595 | is_extendable=False, 596 | extension_ranges=[], 597 | serialized_start=1660, 598 | serialized_end=1729, 599 | ) 600 | 601 | 602 | _STORAGECONTAINERCHUNKLIST = _descriptor.Descriptor( 603 | name='StorageContainerChunkList', 604 | full_name='chunkserver.StorageContainerChunkList', 605 | filename=None, 606 | file=DESCRIPTOR, 607 | containing_type=None, 608 | fields=[ 609 | _descriptor.FieldDescriptor( 610 | name='storage_container_key', full_name='chunkserver.StorageContainerChunkList.storage_container_key', index=0, 611 | number=1, type=12, cpp_type=9, label=2, 612 | has_default_value=False, default_value="", 613 | message_type=None, enum_type=None, containing_type=None, 614 | is_extension=False, extension_scope=None, 615 | options=None), 616 | _descriptor.FieldDescriptor( 617 | name='host_info', full_name='chunkserver.StorageContainerChunkList.host_info', index=1, 618 | number=2, type=11, cpp_type=10, label=2, 619 | has_default_value=False, default_value=None, 620 | message_type=None, enum_type=None, containing_type=None, 621 | is_extension=False, extension_scope=None, 622 | options=None), 623 | _descriptor.FieldDescriptor( 624 | name='chunk_checksum', full_name='chunkserver.StorageContainerChunkList.chunk_checksum', index=2, 625 | number=3, type=12, cpp_type=9, label=3, 626 | has_default_value=False, default_value=[], 627 | message_type=None, enum_type=None, containing_type=None, 628 | is_extension=False, extension_scope=None, 629 | options=None), 630 | _descriptor.FieldDescriptor( 631 | name='storage_container_authorization_token', full_name='chunkserver.StorageContainerChunkList.storage_container_authorization_token', index=3, 632 | number=4, type=9, cpp_type=9, label=2, 633 | has_default_value=False, default_value=unicode("", "utf-8"), 634 | message_type=None, enum_type=None, containing_type=None, 635 | is_extension=False, extension_scope=None, 636 | options=None), 637 | ], 638 | extensions=[ 639 | ], 640 | nested_types=[], 641 | enum_types=[ 642 | ], 643 | options=None, 644 | is_extendable=False, 645 | extension_ranges=[], 646 | serialized_start=1732, 647 | serialized_end=1903, 648 | ) 649 | 650 | 651 | _STORAGECONTAINERCHUNKLISTS = _descriptor.Descriptor( 652 | name='StorageContainerChunkLists', 653 | full_name='chunkserver.StorageContainerChunkLists', 654 | filename=None, 655 | file=DESCRIPTOR, 656 | containing_type=None, 657 | fields=[ 658 | _descriptor.FieldDescriptor( 659 | name='storage_container_chunk_list', full_name='chunkserver.StorageContainerChunkLists.storage_container_chunk_list', index=0, 660 | number=1, type=11, cpp_type=10, label=3, 661 | has_default_value=False, default_value=[], 662 | message_type=None, enum_type=None, containing_type=None, 663 | is_extension=False, extension_scope=None, 664 | options=None), 665 | _descriptor.FieldDescriptor( 666 | name='file_error', full_name='chunkserver.StorageContainerChunkLists.file_error', index=1, 667 | number=2, type=11, cpp_type=10, label=3, 668 | has_default_value=False, default_value=[], 669 | message_type=None, enum_type=None, containing_type=None, 670 | is_extension=False, extension_scope=None, 671 | options=None), 672 | _descriptor.FieldDescriptor( 673 | name='verbosity_level', full_name='chunkserver.StorageContainerChunkLists.verbosity_level', index=2, 674 | number=3, type=13, cpp_type=3, label=1, 675 | has_default_value=False, default_value=0, 676 | message_type=None, enum_type=None, containing_type=None, 677 | is_extension=False, extension_scope=None, 678 | options=None), 679 | ], 680 | extensions=[ 681 | ], 682 | nested_types=[], 683 | enum_types=[ 684 | ], 685 | options=None, 686 | is_extendable=False, 687 | extension_ranges=[], 688 | serialized_start=1906, 689 | serialized_end=2081, 690 | ) 691 | 692 | 693 | _STORAGECONTAINERERRORLIST = _descriptor.Descriptor( 694 | name='StorageContainerErrorList', 695 | full_name='chunkserver.StorageContainerErrorList', 696 | filename=None, 697 | file=DESCRIPTOR, 698 | containing_type=None, 699 | fields=[ 700 | _descriptor.FieldDescriptor( 701 | name='storage_container_error', full_name='chunkserver.StorageContainerErrorList.storage_container_error', index=0, 702 | number=1, type=11, cpp_type=10, label=3, 703 | has_default_value=False, default_value=[], 704 | message_type=None, enum_type=None, containing_type=None, 705 | is_extension=False, extension_scope=None, 706 | options=None), 707 | ], 708 | extensions=[ 709 | ], 710 | nested_types=[], 711 | enum_types=[ 712 | ], 713 | options=None, 714 | is_extendable=False, 715 | extension_ranges=[], 716 | serialized_start=2083, 717 | serialized_end=2179, 718 | ) 719 | 720 | 721 | _FILECHECKSUMAUTHORIZATION = _descriptor.Descriptor( 722 | name='FileChecksumAuthorization', 723 | full_name='chunkserver.FileChecksumAuthorization', 724 | filename=None, 725 | file=DESCRIPTOR, 726 | containing_type=None, 727 | fields=[ 728 | _descriptor.FieldDescriptor( 729 | name='file_checksum', full_name='chunkserver.FileChecksumAuthorization.file_checksum', index=0, 730 | number=1, type=12, cpp_type=9, label=2, 731 | has_default_value=False, default_value="", 732 | message_type=None, enum_type=None, containing_type=None, 733 | is_extension=False, extension_scope=None, 734 | options=None), 735 | _descriptor.FieldDescriptor( 736 | name='authorization', full_name='chunkserver.FileChecksumAuthorization.authorization', index=1, 737 | number=2, type=9, cpp_type=9, label=2, 738 | has_default_value=False, default_value=unicode("", "utf-8"), 739 | message_type=None, enum_type=None, containing_type=None, 740 | is_extension=False, extension_scope=None, 741 | options=None), 742 | _descriptor.FieldDescriptor( 743 | name='chunk_checksums', full_name='chunkserver.FileChecksumAuthorization.chunk_checksums', index=2, 744 | number=3, type=12, cpp_type=9, label=3, 745 | has_default_value=False, default_value=[], 746 | message_type=None, enum_type=None, containing_type=None, 747 | is_extension=False, extension_scope=None, 748 | options=None), 749 | ], 750 | extensions=[ 751 | ], 752 | nested_types=[], 753 | enum_types=[ 754 | ], 755 | options=None, 756 | is_extendable=False, 757 | extension_ranges=[], 758 | serialized_start=2181, 759 | serialized_end=2279, 760 | ) 761 | 762 | 763 | _FILECHECKSUMAUTHORIZATIONLIST = _descriptor.Descriptor( 764 | name='FileChecksumAuthorizationList', 765 | full_name='chunkserver.FileChecksumAuthorizationList', 766 | filename=None, 767 | file=DESCRIPTOR, 768 | containing_type=None, 769 | fields=[ 770 | _descriptor.FieldDescriptor( 771 | name='file_checksum_authorization', full_name='chunkserver.FileChecksumAuthorizationList.file_checksum_authorization', index=0, 772 | number=1, type=11, cpp_type=10, label=3, 773 | has_default_value=False, default_value=[], 774 | message_type=None, enum_type=None, containing_type=None, 775 | is_extension=False, extension_scope=None, 776 | options=None), 777 | ], 778 | extensions=[ 779 | ], 780 | nested_types=[], 781 | enum_types=[ 782 | ], 783 | options=None, 784 | is_extendable=False, 785 | extension_ranges=[], 786 | serialized_start=2281, 787 | serialized_end=2389, 788 | ) 789 | 790 | 791 | _CHUNKREFERENCE = _descriptor.Descriptor( 792 | name='ChunkReference', 793 | full_name='chunkserver.ChunkReference', 794 | filename=None, 795 | file=DESCRIPTOR, 796 | containing_type=None, 797 | fields=[ 798 | _descriptor.FieldDescriptor( 799 | name='container_index', full_name='chunkserver.ChunkReference.container_index', index=0, 800 | number=1, type=4, cpp_type=4, label=2, 801 | has_default_value=False, default_value=0, 802 | message_type=None, enum_type=None, containing_type=None, 803 | is_extension=False, extension_scope=None, 804 | options=None), 805 | _descriptor.FieldDescriptor( 806 | name='chunk_index', full_name='chunkserver.ChunkReference.chunk_index', index=1, 807 | number=2, type=4, cpp_type=4, label=2, 808 | has_default_value=False, default_value=0, 809 | message_type=None, enum_type=None, containing_type=None, 810 | is_extension=False, extension_scope=None, 811 | options=None), 812 | ], 813 | extensions=[ 814 | ], 815 | nested_types=[], 816 | enum_types=[ 817 | ], 818 | options=None, 819 | is_extendable=False, 820 | extension_ranges=[], 821 | serialized_start=2391, 822 | serialized_end=2453, 823 | ) 824 | 825 | 826 | _FILECHECKSUMCHUNKREFERENCES = _descriptor.Descriptor( 827 | name='FileChecksumChunkReferences', 828 | full_name='chunkserver.FileChecksumChunkReferences', 829 | filename=None, 830 | file=DESCRIPTOR, 831 | containing_type=None, 832 | fields=[ 833 | _descriptor.FieldDescriptor( 834 | name='file_checksum', full_name='chunkserver.FileChecksumChunkReferences.file_checksum', index=0, 835 | number=1, type=12, cpp_type=9, label=2, 836 | has_default_value=False, default_value="", 837 | message_type=None, enum_type=None, containing_type=None, 838 | is_extension=False, extension_scope=None, 839 | options=None), 840 | _descriptor.FieldDescriptor( 841 | name='chunk_references', full_name='chunkserver.FileChecksumChunkReferences.chunk_references', index=1, 842 | number=2, type=11, cpp_type=10, label=3, 843 | has_default_value=False, default_value=[], 844 | message_type=None, enum_type=None, containing_type=None, 845 | is_extension=False, extension_scope=None, 846 | options=None), 847 | ], 848 | extensions=[ 849 | ], 850 | nested_types=[], 851 | enum_types=[ 852 | ], 853 | options=None, 854 | is_extendable=False, 855 | extension_ranges=[], 856 | serialized_start=2455, 857 | serialized_end=2562, 858 | ) 859 | 860 | 861 | _FILECHECKSUMSTORAGEHOSTCHUNKLISTS = _descriptor.Descriptor( 862 | name='FileChecksumStorageHostChunkLists', 863 | full_name='chunkserver.FileChecksumStorageHostChunkLists', 864 | filename=None, 865 | file=DESCRIPTOR, 866 | containing_type=None, 867 | fields=[ 868 | _descriptor.FieldDescriptor( 869 | name='storage_host_chunk_list', full_name='chunkserver.FileChecksumStorageHostChunkLists.storage_host_chunk_list', index=0, 870 | number=1, type=11, cpp_type=10, label=3, 871 | has_default_value=False, default_value=[], 872 | message_type=None, enum_type=None, containing_type=None, 873 | is_extension=False, extension_scope=None, 874 | options=None), 875 | _descriptor.FieldDescriptor( 876 | name='file_checksum_chunk_references', full_name='chunkserver.FileChecksumStorageHostChunkLists.file_checksum_chunk_references', index=1, 877 | number=2, type=11, cpp_type=10, label=3, 878 | has_default_value=False, default_value=[], 879 | message_type=None, enum_type=None, containing_type=None, 880 | is_extension=False, extension_scope=None, 881 | options=None), 882 | ], 883 | extensions=[ 884 | ], 885 | nested_types=[], 886 | enum_types=[ 887 | ], 888 | options=None, 889 | is_extendable=False, 890 | extension_ranges=[], 891 | serialized_start=2565, 892 | serialized_end=2750, 893 | ) 894 | 895 | 896 | _FILEGROUPS = _descriptor.Descriptor( 897 | name='FileGroups', 898 | full_name='chunkserver.FileGroups', 899 | filename=None, 900 | file=DESCRIPTOR, 901 | containing_type=None, 902 | fields=[ 903 | _descriptor.FieldDescriptor( 904 | name='file_groups', full_name='chunkserver.FileGroups.file_groups', index=0, 905 | number=1, type=11, cpp_type=10, label=3, 906 | has_default_value=False, default_value=[], 907 | message_type=None, enum_type=None, containing_type=None, 908 | is_extension=False, extension_scope=None, 909 | options=None), 910 | _descriptor.FieldDescriptor( 911 | name='file_error', full_name='chunkserver.FileGroups.file_error', index=1, 912 | number=2, type=11, cpp_type=10, label=3, 913 | has_default_value=False, default_value=[], 914 | message_type=None, enum_type=None, containing_type=None, 915 | is_extension=False, extension_scope=None, 916 | options=None), 917 | _descriptor.FieldDescriptor( 918 | name='file_chunk_error', full_name='chunkserver.FileGroups.file_chunk_error', index=2, 919 | number=3, type=11, cpp_type=10, label=3, 920 | has_default_value=False, default_value=[], 921 | message_type=None, enum_type=None, containing_type=None, 922 | is_extension=False, extension_scope=None, 923 | options=None), 924 | _descriptor.FieldDescriptor( 925 | name='verbosity_level', full_name='chunkserver.FileGroups.verbosity_level', index=3, 926 | number=4, type=13, cpp_type=3, label=1, 927 | has_default_value=False, default_value=0, 928 | message_type=None, enum_type=None, containing_type=None, 929 | is_extension=False, extension_scope=None, 930 | options=None), 931 | ], 932 | extensions=[ 933 | ], 934 | nested_types=[], 935 | enum_types=[ 936 | ], 937 | options=None, 938 | is_extendable=False, 939 | extension_ranges=[], 940 | serialized_start=2753, 941 | serialized_end=2958, 942 | ) 943 | 944 | 945 | _CHUNKCHECKSUMLIST = _descriptor.Descriptor( 946 | name='ChunkChecksumList', 947 | full_name='chunkserver.ChunkChecksumList', 948 | filename=None, 949 | file=DESCRIPTOR, 950 | containing_type=None, 951 | fields=[ 952 | _descriptor.FieldDescriptor( 953 | name='chunk_checksum', full_name='chunkserver.ChunkChecksumList.chunk_checksum', index=0, 954 | number=1, type=12, cpp_type=9, label=3, 955 | has_default_value=False, default_value=[], 956 | message_type=None, enum_type=None, containing_type=None, 957 | is_extension=False, extension_scope=None, 958 | options=None), 959 | ], 960 | extensions=[ 961 | ], 962 | nested_types=[], 963 | enum_types=[ 964 | ], 965 | options=None, 966 | is_extendable=False, 967 | extension_ranges=[], 968 | serialized_start=2960, 969 | serialized_end=3003, 970 | ) 971 | 972 | 973 | _STORAGEHOSTCHUNKLIST = _descriptor.Descriptor( 974 | name='StorageHostChunkList', 975 | full_name='chunkserver.StorageHostChunkList', 976 | filename=None, 977 | file=DESCRIPTOR, 978 | containing_type=None, 979 | fields=[ 980 | _descriptor.FieldDescriptor( 981 | name='host_info', full_name='chunkserver.StorageHostChunkList.host_info', index=0, 982 | number=1, type=11, cpp_type=10, label=2, 983 | has_default_value=False, default_value=None, 984 | message_type=None, enum_type=None, containing_type=None, 985 | is_extension=False, extension_scope=None, 986 | options=None), 987 | _descriptor.FieldDescriptor( 988 | name='chunk_info', full_name='chunkserver.StorageHostChunkList.chunk_info', index=1, 989 | number=2, type=11, cpp_type=10, label=3, 990 | has_default_value=False, default_value=[], 991 | message_type=None, enum_type=None, containing_type=None, 992 | is_extension=False, extension_scope=None, 993 | options=None), 994 | _descriptor.FieldDescriptor( 995 | name='storage_container_key', full_name='chunkserver.StorageHostChunkList.storage_container_key', index=2, 996 | number=3, type=9, cpp_type=9, label=2, 997 | has_default_value=False, default_value=unicode("", "utf-8"), 998 | message_type=None, enum_type=None, containing_type=None, 999 | is_extension=False, extension_scope=None, 1000 | options=None), 1001 | _descriptor.FieldDescriptor( 1002 | name='storage_container_authorization_token', full_name='chunkserver.StorageHostChunkList.storage_container_authorization_token', index=3, 1003 | number=4, type=9, cpp_type=9, label=2, 1004 | has_default_value=False, default_value=unicode("", "utf-8"), 1005 | message_type=None, enum_type=None, containing_type=None, 1006 | is_extension=False, extension_scope=None, 1007 | options=None), 1008 | ], 1009 | extensions=[ 1010 | ], 1011 | nested_types=[], 1012 | enum_types=[ 1013 | ], 1014 | options=None, 1015 | is_extendable=False, 1016 | extension_ranges=[], 1017 | serialized_start=3006, 1018 | serialized_end=3192, 1019 | ) 1020 | 1021 | 1022 | _STORAGEHOSTCHUNKLISTS = _descriptor.Descriptor( 1023 | name='StorageHostChunkLists', 1024 | full_name='chunkserver.StorageHostChunkLists', 1025 | filename=None, 1026 | file=DESCRIPTOR, 1027 | containing_type=None, 1028 | fields=[ 1029 | _descriptor.FieldDescriptor( 1030 | name='storage_host_chunk_list', full_name='chunkserver.StorageHostChunkLists.storage_host_chunk_list', index=0, 1031 | number=1, type=11, cpp_type=10, label=3, 1032 | has_default_value=False, default_value=[], 1033 | message_type=None, enum_type=None, containing_type=None, 1034 | is_extension=False, extension_scope=None, 1035 | options=None), 1036 | _descriptor.FieldDescriptor( 1037 | name='chunk_error', full_name='chunkserver.StorageHostChunkLists.chunk_error', index=1, 1038 | number=2, type=11, cpp_type=10, label=3, 1039 | has_default_value=False, default_value=[], 1040 | message_type=None, enum_type=None, containing_type=None, 1041 | is_extension=False, extension_scope=None, 1042 | options=None), 1043 | ], 1044 | extensions=[ 1045 | ], 1046 | nested_types=[], 1047 | enum_types=[ 1048 | ], 1049 | options=None, 1050 | is_extendable=False, 1051 | extension_ranges=[], 1052 | serialized_start=3195, 1053 | serialized_end=3332, 1054 | ) 1055 | 1056 | _HOSTINFO.fields_by_name['headers'].message_type = _NAMEVALUEPAIR 1057 | _ERRORRESPONSE.fields_by_name['underlying_errors'].message_type = _ERRORRESPONSE 1058 | _ERRORRESPONSE.fields_by_name['name_value_pair'].message_type = _NAMEVALUEPAIR 1059 | _FILEERROR.fields_by_name['error_response'].message_type = _ERRORRESPONSE 1060 | _CHUNKERROR.fields_by_name['error_response'].message_type = _ERRORRESPONSE 1061 | _CHUNKERRORINDEX.fields_by_name['error_response'].message_type = _ERRORRESPONSE 1062 | _FILECHUNKERROR.fields_by_name['chunk_error'].message_type = _CHUNKERRORINDEX 1063 | _STORAGECONTAINERERROR.fields_by_name['error_response'].message_type = _ERRORRESPONSE 1064 | _METHODCOMPLETIONINFO.fields_by_name['vendor_response_headers'].message_type = _NAMEVALUEPAIR 1065 | _METHODCOMPLETIONINFO.fields_by_name['error'].message_type = _ERRORRESPONSE 1066 | _METHODCOMPLETIONINFO.fields_by_name['vendor_nv_pairs'].message_type = _NAMEVALUEPAIR 1067 | _METHODCOMPLETIONINFO.fields_by_name['client_nv_pairs'].message_type = _NAMEVALUEPAIR 1068 | _METHODCOMPLETIONINFOLIST.fields_by_name['method_completion_info'].message_type = _METHODCOMPLETIONINFO 1069 | _FILECHUNKLIST.fields_by_name['chunk_info'].message_type = _CHUNKINFO 1070 | _FILECHUNKLISTS.fields_by_name['file_chunk_list'].message_type = _FILECHUNKLIST 1071 | _STORAGECONTAINERCHUNKLIST.fields_by_name['host_info'].message_type = _HOSTINFO 1072 | _STORAGECONTAINERCHUNKLISTS.fields_by_name['storage_container_chunk_list'].message_type = _STORAGECONTAINERCHUNKLIST 1073 | _STORAGECONTAINERCHUNKLISTS.fields_by_name['file_error'].message_type = _FILEERROR 1074 | _STORAGECONTAINERERRORLIST.fields_by_name['storage_container_error'].message_type = _STORAGECONTAINERERROR 1075 | _FILECHECKSUMAUTHORIZATIONLIST.fields_by_name['file_checksum_authorization'].message_type = _FILECHECKSUMAUTHORIZATION 1076 | _FILECHECKSUMCHUNKREFERENCES.fields_by_name['chunk_references'].message_type = _CHUNKREFERENCE 1077 | _FILECHECKSUMSTORAGEHOSTCHUNKLISTS.fields_by_name['storage_host_chunk_list'].message_type = _STORAGEHOSTCHUNKLIST 1078 | _FILECHECKSUMSTORAGEHOSTCHUNKLISTS.fields_by_name['file_checksum_chunk_references'].message_type = _FILECHECKSUMCHUNKREFERENCES 1079 | _FILEGROUPS.fields_by_name['file_groups'].message_type = _FILECHECKSUMSTORAGEHOSTCHUNKLISTS 1080 | _FILEGROUPS.fields_by_name['file_error'].message_type = _FILEERROR 1081 | _FILEGROUPS.fields_by_name['file_chunk_error'].message_type = _FILECHUNKERROR 1082 | _STORAGEHOSTCHUNKLIST.fields_by_name['host_info'].message_type = _HOSTINFO 1083 | _STORAGEHOSTCHUNKLIST.fields_by_name['chunk_info'].message_type = _CHUNKINFO 1084 | _STORAGEHOSTCHUNKLISTS.fields_by_name['storage_host_chunk_list'].message_type = _STORAGEHOSTCHUNKLIST 1085 | _STORAGEHOSTCHUNKLISTS.fields_by_name['chunk_error'].message_type = _CHUNKERROR 1086 | DESCRIPTOR.message_types_by_name['ChunkInfo'] = _CHUNKINFO 1087 | DESCRIPTOR.message_types_by_name['NameValuePair'] = _NAMEVALUEPAIR 1088 | DESCRIPTOR.message_types_by_name['HostInfo'] = _HOSTINFO 1089 | DESCRIPTOR.message_types_by_name['ErrorResponse'] = _ERRORRESPONSE 1090 | DESCRIPTOR.message_types_by_name['FileError'] = _FILEERROR 1091 | DESCRIPTOR.message_types_by_name['ChunkError'] = _CHUNKERROR 1092 | DESCRIPTOR.message_types_by_name['ChunkErrorIndex'] = _CHUNKERRORINDEX 1093 | DESCRIPTOR.message_types_by_name['FileChunkError'] = _FILECHUNKERROR 1094 | DESCRIPTOR.message_types_by_name['StorageContainerError'] = _STORAGECONTAINERERROR 1095 | DESCRIPTOR.message_types_by_name['MethodCompletionInfo'] = _METHODCOMPLETIONINFO 1096 | DESCRIPTOR.message_types_by_name['MethodCompletionInfoList'] = _METHODCOMPLETIONINFOLIST 1097 | DESCRIPTOR.message_types_by_name['FileChunkList'] = _FILECHUNKLIST 1098 | DESCRIPTOR.message_types_by_name['FileChunkLists'] = _FILECHUNKLISTS 1099 | DESCRIPTOR.message_types_by_name['StorageContainerChunkList'] = _STORAGECONTAINERCHUNKLIST 1100 | DESCRIPTOR.message_types_by_name['StorageContainerChunkLists'] = _STORAGECONTAINERCHUNKLISTS 1101 | DESCRIPTOR.message_types_by_name['StorageContainerErrorList'] = _STORAGECONTAINERERRORLIST 1102 | DESCRIPTOR.message_types_by_name['FileChecksumAuthorization'] = _FILECHECKSUMAUTHORIZATION 1103 | DESCRIPTOR.message_types_by_name['FileChecksumAuthorizationList'] = _FILECHECKSUMAUTHORIZATIONLIST 1104 | DESCRIPTOR.message_types_by_name['ChunkReference'] = _CHUNKREFERENCE 1105 | DESCRIPTOR.message_types_by_name['FileChecksumChunkReferences'] = _FILECHECKSUMCHUNKREFERENCES 1106 | DESCRIPTOR.message_types_by_name['FileChecksumStorageHostChunkLists'] = _FILECHECKSUMSTORAGEHOSTCHUNKLISTS 1107 | DESCRIPTOR.message_types_by_name['FileGroups'] = _FILEGROUPS 1108 | DESCRIPTOR.message_types_by_name['ChunkChecksumList'] = _CHUNKCHECKSUMLIST 1109 | DESCRIPTOR.message_types_by_name['StorageHostChunkList'] = _STORAGEHOSTCHUNKLIST 1110 | DESCRIPTOR.message_types_by_name['StorageHostChunkLists'] = _STORAGEHOSTCHUNKLISTS 1111 | 1112 | class ChunkInfo(_message.Message): 1113 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1114 | DESCRIPTOR = _CHUNKINFO 1115 | 1116 | # @@protoc_insertion_point(class_scope:chunkserver.ChunkInfo) 1117 | 1118 | class NameValuePair(_message.Message): 1119 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1120 | DESCRIPTOR = _NAMEVALUEPAIR 1121 | 1122 | # @@protoc_insertion_point(class_scope:chunkserver.NameValuePair) 1123 | 1124 | class HostInfo(_message.Message): 1125 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1126 | DESCRIPTOR = _HOSTINFO 1127 | 1128 | # @@protoc_insertion_point(class_scope:chunkserver.HostInfo) 1129 | 1130 | class ErrorResponse(_message.Message): 1131 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1132 | DESCRIPTOR = _ERRORRESPONSE 1133 | 1134 | # @@protoc_insertion_point(class_scope:chunkserver.ErrorResponse) 1135 | 1136 | class FileError(_message.Message): 1137 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1138 | DESCRIPTOR = _FILEERROR 1139 | 1140 | # @@protoc_insertion_point(class_scope:chunkserver.FileError) 1141 | 1142 | class ChunkError(_message.Message): 1143 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1144 | DESCRIPTOR = _CHUNKERROR 1145 | 1146 | # @@protoc_insertion_point(class_scope:chunkserver.ChunkError) 1147 | 1148 | class ChunkErrorIndex(_message.Message): 1149 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1150 | DESCRIPTOR = _CHUNKERRORINDEX 1151 | 1152 | # @@protoc_insertion_point(class_scope:chunkserver.ChunkErrorIndex) 1153 | 1154 | class FileChunkError(_message.Message): 1155 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1156 | DESCRIPTOR = _FILECHUNKERROR 1157 | 1158 | # @@protoc_insertion_point(class_scope:chunkserver.FileChunkError) 1159 | 1160 | class StorageContainerError(_message.Message): 1161 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1162 | DESCRIPTOR = _STORAGECONTAINERERROR 1163 | 1164 | # @@protoc_insertion_point(class_scope:chunkserver.StorageContainerError) 1165 | 1166 | class MethodCompletionInfo(_message.Message): 1167 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1168 | DESCRIPTOR = _METHODCOMPLETIONINFO 1169 | 1170 | # @@protoc_insertion_point(class_scope:chunkserver.MethodCompletionInfo) 1171 | 1172 | class MethodCompletionInfoList(_message.Message): 1173 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1174 | DESCRIPTOR = _METHODCOMPLETIONINFOLIST 1175 | 1176 | # @@protoc_insertion_point(class_scope:chunkserver.MethodCompletionInfoList) 1177 | 1178 | class FileChunkList(_message.Message): 1179 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1180 | DESCRIPTOR = _FILECHUNKLIST 1181 | 1182 | # @@protoc_insertion_point(class_scope:chunkserver.FileChunkList) 1183 | 1184 | class FileChunkLists(_message.Message): 1185 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1186 | DESCRIPTOR = _FILECHUNKLISTS 1187 | 1188 | # @@protoc_insertion_point(class_scope:chunkserver.FileChunkLists) 1189 | 1190 | class StorageContainerChunkList(_message.Message): 1191 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1192 | DESCRIPTOR = _STORAGECONTAINERCHUNKLIST 1193 | 1194 | # @@protoc_insertion_point(class_scope:chunkserver.StorageContainerChunkList) 1195 | 1196 | class StorageContainerChunkLists(_message.Message): 1197 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1198 | DESCRIPTOR = _STORAGECONTAINERCHUNKLISTS 1199 | 1200 | # @@protoc_insertion_point(class_scope:chunkserver.StorageContainerChunkLists) 1201 | 1202 | class StorageContainerErrorList(_message.Message): 1203 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1204 | DESCRIPTOR = _STORAGECONTAINERERRORLIST 1205 | 1206 | # @@protoc_insertion_point(class_scope:chunkserver.StorageContainerErrorList) 1207 | 1208 | class FileChecksumAuthorization(_message.Message): 1209 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1210 | DESCRIPTOR = _FILECHECKSUMAUTHORIZATION 1211 | 1212 | # @@protoc_insertion_point(class_scope:chunkserver.FileChecksumAuthorization) 1213 | 1214 | class FileChecksumAuthorizationList(_message.Message): 1215 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1216 | DESCRIPTOR = _FILECHECKSUMAUTHORIZATIONLIST 1217 | 1218 | # @@protoc_insertion_point(class_scope:chunkserver.FileChecksumAuthorizationList) 1219 | 1220 | class ChunkReference(_message.Message): 1221 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1222 | DESCRIPTOR = _CHUNKREFERENCE 1223 | 1224 | # @@protoc_insertion_point(class_scope:chunkserver.ChunkReference) 1225 | 1226 | class FileChecksumChunkReferences(_message.Message): 1227 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1228 | DESCRIPTOR = _FILECHECKSUMCHUNKREFERENCES 1229 | 1230 | # @@protoc_insertion_point(class_scope:chunkserver.FileChecksumChunkReferences) 1231 | 1232 | class FileChecksumStorageHostChunkLists(_message.Message): 1233 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1234 | DESCRIPTOR = _FILECHECKSUMSTORAGEHOSTCHUNKLISTS 1235 | 1236 | # @@protoc_insertion_point(class_scope:chunkserver.FileChecksumStorageHostChunkLists) 1237 | 1238 | class FileGroups(_message.Message): 1239 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1240 | DESCRIPTOR = _FILEGROUPS 1241 | 1242 | # @@protoc_insertion_point(class_scope:chunkserver.FileGroups) 1243 | 1244 | class ChunkChecksumList(_message.Message): 1245 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1246 | DESCRIPTOR = _CHUNKCHECKSUMLIST 1247 | 1248 | # @@protoc_insertion_point(class_scope:chunkserver.ChunkChecksumList) 1249 | 1250 | class StorageHostChunkList(_message.Message): 1251 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1252 | DESCRIPTOR = _STORAGEHOSTCHUNKLIST 1253 | 1254 | # @@protoc_insertion_point(class_scope:chunkserver.StorageHostChunkList) 1255 | 1256 | class StorageHostChunkLists(_message.Message): 1257 | __metaclass__ = _reflection.GeneratedProtocolMessageType 1258 | DESCRIPTOR = _STORAGEHOSTCHUNKLISTS 1259 | 1260 | # @@protoc_insertion_point(class_scope:chunkserver.StorageHostChunkLists) 1261 | 1262 | 1263 | # @@protoc_insertion_point(module_scope) 1264 | -------------------------------------------------------------------------------- /crypto/PBKDF2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: ascii -*- 3 | ########################################################################### 4 | # PBKDF2.py - PKCS#5 v2.0 Password-Based Key Derivation 5 | # 6 | # Copyright (C) 2007, 2008 Dwayne C. Litzenberger 7 | # All rights reserved. 8 | # 9 | # Permission to use, copy, modify, and distribute this software and its 10 | # documentation for any purpose and without fee is hereby granted, 11 | # provided that the above copyright notice appear in all copies and that 12 | # both that copyright notice and this permission notice appear in 13 | # supporting documentation. 14 | # 15 | # THE AUTHOR PROVIDES THIS SOFTWARE ``AS IS'' AND ANY EXPRESSED OR 16 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | # Country of origin: Canada 27 | # 28 | ########################################################################### 29 | # Sample PBKDF2 usage: 30 | # from Crypto.Cipher import AES 31 | # from PBKDF2 import PBKDF2 32 | # import os 33 | # 34 | # salt = os.urandom(8) # 64-bit salt 35 | # key = PBKDF2("This passphrase is a secret.", salt).read(32) # 256-bit key 36 | # iv = os.urandom(16) # 128-bit IV 37 | # cipher = AES.new(key, AES.MODE_CBC, iv) 38 | # ... 39 | # 40 | # Sample crypt() usage: 41 | # from PBKDF2 import crypt 42 | # pwhash = crypt("secret") 43 | # alleged_pw = raw_input("Enter password: ") 44 | # if pwhash == crypt(alleged_pw, pwhash): 45 | # print "Password good" 46 | # else: 47 | # print "Invalid password" 48 | # 49 | ########################################################################### 50 | # History: 51 | # 52 | # 2007-07-27 Dwayne C. Litzenberger 53 | # - Initial Release (v1.0) 54 | # 55 | # 2007-07-31 Dwayne C. Litzenberger 56 | # - Bugfix release (v1.1) 57 | # - SECURITY: The PyCrypto XOR cipher (used, if available, in the _strxor 58 | # function in the previous release) silently truncates all keys to 64 59 | # bytes. The way it was used in the previous release, this would only be 60 | # problem if the pseudorandom function that returned values larger than 61 | # 64 bytes (so SHA1, SHA256 and SHA512 are fine), but I don't like 62 | # anything that silently reduces the security margin from what is 63 | # expected. 64 | # 65 | # 2008-06-17 Dwayne C. Litzenberger 66 | # - Compatibility release (v1.2) 67 | # - Add support for older versions of Python (2.2 and 2.3). 68 | # 69 | ########################################################################### 70 | 71 | __version__ = "1.2" 72 | 73 | from struct import pack 74 | from binascii import b2a_hex 75 | from random import randint 76 | import string 77 | 78 | try: 79 | # Use PyCrypto (if available) 80 | from Crypto.Hash import HMAC, SHA as SHA1 81 | 82 | except ImportError: 83 | # PyCrypto not available. Use the Python standard library. 84 | import hmac as HMAC 85 | import sha as SHA1 86 | 87 | def strxor(a, b): 88 | return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b)]) 89 | 90 | def b64encode(data, chars="+/"): 91 | tt = string.maketrans("+/", chars) 92 | return data.encode('base64').replace("\n", "").translate(tt) 93 | 94 | class PBKDF2(object): 95 | """PBKDF2.py : PKCS#5 v2.0 Password-Based Key Derivation 96 | 97 | This implementation takes a passphrase and a salt (and optionally an 98 | iteration count, a digest module, and a MAC module) and provides a 99 | file-like object from which an arbitrarily-sized key can be read. 100 | 101 | If the passphrase and/or salt are unicode objects, they are encoded as 102 | UTF-8 before they are processed. 103 | 104 | The idea behind PBKDF2 is to derive a cryptographic key from a 105 | passphrase and a salt. 106 | 107 | PBKDF2 may also be used as a strong salted password hash. The 108 | 'crypt' function is provided for that purpose. 109 | 110 | Remember: Keys generated using PBKDF2 are only as strong as the 111 | passphrases they are derived from. 112 | """ 113 | 114 | def __init__(self, passphrase, salt, iterations=1000, 115 | digestmodule=SHA1, macmodule=HMAC): 116 | self.__macmodule = macmodule 117 | self.__digestmodule = digestmodule 118 | self._setup(passphrase, salt, iterations, self._pseudorandom) 119 | 120 | def _pseudorandom(self, key, msg): 121 | """Pseudorandom function. e.g. HMAC-SHA1""" 122 | return self.__macmodule.new(key=key, msg=msg, 123 | digestmod=self.__digestmodule).digest() 124 | 125 | def read(self, bytes): 126 | """Read the specified number of key bytes.""" 127 | if self.closed: 128 | raise ValueError("file-like object is closed") 129 | 130 | size = len(self.__buf) 131 | blocks = [self.__buf] 132 | i = self.__blockNum 133 | while size < bytes: 134 | i += 1 135 | if i > 0xffffffffL or i < 1: 136 | # We could return "" here, but 137 | raise OverflowError("derived key too long") 138 | block = self.__f(i) 139 | blocks.append(block) 140 | size += len(block) 141 | buf = "".join(blocks) 142 | retval = buf[:bytes] 143 | self.__buf = buf[bytes:] 144 | self.__blockNum = i 145 | return retval 146 | 147 | def __f(self, i): 148 | # i must fit within 32 bits 149 | assert 1 <= i <= 0xffffffffL 150 | U = self.__prf(self.__passphrase, self.__salt + pack("!L", i)) 151 | result = U 152 | for j in xrange(2, 1+self.__iterations): 153 | U = self.__prf(self.__passphrase, U) 154 | result = strxor(result, U) 155 | return result 156 | 157 | def hexread(self, octets): 158 | """Read the specified number of octets. Return them as hexadecimal. 159 | 160 | Note that len(obj.hexread(n)) == 2*n. 161 | """ 162 | return b2a_hex(self.read(octets)) 163 | 164 | def _setup(self, passphrase, salt, iterations, prf): 165 | # Sanity checks: 166 | 167 | # passphrase and salt must be str or unicode (in the latter 168 | # case, we convert to UTF-8) 169 | if isinstance(passphrase, unicode): 170 | passphrase = passphrase.encode("UTF-8") 171 | if not isinstance(passphrase, str): 172 | raise TypeError("passphrase must be str or unicode") 173 | if isinstance(salt, unicode): 174 | salt = salt.encode("UTF-8") 175 | if not isinstance(salt, str): 176 | raise TypeError("salt must be str or unicode") 177 | 178 | # iterations must be an integer >= 1 179 | if not isinstance(iterations, (int, long)): 180 | raise TypeError("iterations must be an integer") 181 | if iterations < 1: 182 | raise ValueError("iterations must be at least 1") 183 | 184 | # prf must be callable 185 | if not callable(prf): 186 | raise TypeError("prf must be callable") 187 | 188 | self.__passphrase = passphrase 189 | self.__salt = salt 190 | self.__iterations = iterations 191 | self.__prf = prf 192 | self.__blockNum = 0 193 | self.__buf = "" 194 | self.closed = False 195 | 196 | def close(self): 197 | """Close the stream.""" 198 | if not self.closed: 199 | del self.__passphrase 200 | del self.__salt 201 | del self.__iterations 202 | del self.__prf 203 | del self.__blockNum 204 | del self.__buf 205 | self.closed = True 206 | 207 | def crypt(word, salt=None, iterations=None): 208 | """PBKDF2-based unix crypt(3) replacement. 209 | 210 | The number of iterations specified in the salt overrides the 'iterations' 211 | parameter. 212 | 213 | The effective hash length is 192 bits. 214 | """ 215 | 216 | # Generate a (pseudo-)random salt if the user hasn't provided one. 217 | if salt is None: 218 | salt = _makesalt() 219 | 220 | # salt must be a string or the us-ascii subset of unicode 221 | if isinstance(salt, unicode): 222 | salt = salt.encode("us-ascii") 223 | if not isinstance(salt, str): 224 | raise TypeError("salt must be a string") 225 | 226 | # word must be a string or unicode (in the latter case, we convert to UTF-8) 227 | if isinstance(word, unicode): 228 | word = word.encode("UTF-8") 229 | if not isinstance(word, str): 230 | raise TypeError("word must be a string or unicode") 231 | 232 | # Try to extract the real salt and iteration count from the salt 233 | if salt.startswith("$p5k2$"): 234 | (iterations, salt, dummy) = salt.split("$")[2:5] 235 | if iterations == "": 236 | iterations = 400 237 | else: 238 | converted = int(iterations, 16) 239 | if iterations != "%x" % converted: # lowercase hex, minimum digits 240 | raise ValueError("Invalid salt") 241 | iterations = converted 242 | if not (iterations >= 1): 243 | raise ValueError("Invalid salt") 244 | 245 | # Make sure the salt matches the allowed character set 246 | allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./" 247 | for ch in salt: 248 | if ch not in allowed: 249 | raise ValueError("Illegal character %r in salt" % (ch,)) 250 | 251 | if iterations is None or iterations == 400: 252 | iterations = 400 253 | salt = "$p5k2$$" + salt 254 | else: 255 | salt = "$p5k2$%x$%s" % (iterations, salt) 256 | rawhash = PBKDF2(word, salt, iterations).read(24) 257 | return salt + "$" + b64encode(rawhash, "./") 258 | 259 | # Add crypt as a static method of the PBKDF2 class 260 | # This makes it easier to do "from PBKDF2 import PBKDF2" and still use 261 | # crypt. 262 | PBKDF2.crypt = staticmethod(crypt) 263 | 264 | def _makesalt(): 265 | """Return a 48-bit pseudorandom salt for crypt(). 266 | 267 | This function is not suitable for generating cryptographic secrets. 268 | """ 269 | binarysalt = "".join([pack("@H", randint(0, 0xffff)) for i in range(3)]) 270 | return b64encode(binarysalt, "./") 271 | 272 | def test_pbkdf2(): 273 | """Module self-test""" 274 | from binascii import a2b_hex 275 | 276 | # 277 | # Test vectors from RFC 3962 278 | # 279 | 280 | # Test 1 281 | result = PBKDF2("password", "ATHENA.MIT.EDUraeburn", 1).read(16) 282 | expected = a2b_hex("cdedb5281bb2f801565a1122b2563515") 283 | if result != expected: 284 | raise RuntimeError("self-test failed") 285 | 286 | # Test 2 287 | result = PBKDF2("password", "ATHENA.MIT.EDUraeburn", 1200).hexread(32) 288 | expected = ("5c08eb61fdf71e4e4ec3cf6ba1f5512b" 289 | "a7e52ddbc5e5142f708a31e2e62b1e13") 290 | if result != expected: 291 | raise RuntimeError("self-test failed") 292 | 293 | # Test 3 294 | result = PBKDF2("X"*64, "pass phrase equals block size", 1200).hexread(32) 295 | expected = ("139c30c0966bc32ba55fdbf212530ac9" 296 | "c5ec59f1a452f5cc9ad940fea0598ed1") 297 | if result != expected: 298 | raise RuntimeError("self-test failed") 299 | 300 | # Test 4 301 | result = PBKDF2("X"*65, "pass phrase exceeds block size", 1200).hexread(32) 302 | expected = ("9ccad6d468770cd51b10e6a68721be61" 303 | "1a8b4d282601db3b36be9246915ec82a") 304 | if result != expected: 305 | raise RuntimeError("self-test failed") 306 | 307 | # 308 | # Other test vectors 309 | # 310 | 311 | # Chunked read 312 | f = PBKDF2("kickstart", "workbench", 256) 313 | result = f.read(17) 314 | result += f.read(17) 315 | result += f.read(1) 316 | result += f.read(2) 317 | result += f.read(3) 318 | expected = PBKDF2("kickstart", "workbench", 256).read(40) 319 | if result != expected: 320 | raise RuntimeError("self-test failed") 321 | 322 | # 323 | # crypt() test vectors 324 | # 325 | 326 | # crypt 1 327 | result = crypt("cloadm", "exec") 328 | expected = '$p5k2$$exec$r1EWMCMk7Rlv3L/RNcFXviDefYa0hlql' 329 | if result != expected: 330 | raise RuntimeError("self-test failed") 331 | 332 | # crypt 2 333 | result = crypt("gnu", '$p5k2$c$u9HvcT4d$.....') 334 | expected = '$p5k2$c$u9HvcT4d$Sd1gwSVCLZYAuqZ25piRnbBEoAesaa/g' 335 | if result != expected: 336 | raise RuntimeError("self-test failed") 337 | 338 | # crypt 3 339 | result = crypt("dcl", "tUsch7fU", iterations=13) 340 | expected = "$p5k2$d$tUsch7fU$nqDkaxMDOFBeJsTSfABsyn.PYUXilHwL" 341 | if result != expected: 342 | raise RuntimeError("self-test failed") 343 | 344 | # crypt 4 (unicode) 345 | result = crypt(u'\u0399\u03c9\u03b1\u03bd\u03bd\u03b7\u03c2', 346 | '$p5k2$$KosHgqNo$9mjN8gqjt02hDoP0c2J0ABtLIwtot8cQ') 347 | expected = '$p5k2$$KosHgqNo$9mjN8gqjt02hDoP0c2J0ABtLIwtot8cQ' 348 | if result != expected: 349 | raise RuntimeError("self-test failed") 350 | 351 | if __name__ == '__main__': 352 | test_pbkdf2() 353 | 354 | # vim:set ts=4 sw=4 sts=4 expandtab: 355 | -------------------------------------------------------------------------------- /crypto/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackappcom/iloot/9362ac94dbb77a611e654f0622c89cb7ad31ed8a/crypto/__init__.py -------------------------------------------------------------------------------- /crypto/aes.py: -------------------------------------------------------------------------------- 1 | from Crypto.Cipher import AES 2 | 3 | ZEROIV = "\x00"*16 4 | def removePadding(blocksize, s): 5 | 'Remove rfc 1423 padding from string.' 6 | n = ord(s[-1]) # last byte contains number of padding bytes 7 | if n > blocksize or n > len(s): 8 | raise Exception('invalid padding') 9 | return s[:-n] 10 | 11 | 12 | def AESdecryptCBC(data, key, iv=ZEROIV, padding=False): 13 | if len(data) % 16: 14 | print "AESdecryptCBC: data length not /16, truncating" 15 | data = data[0:(len(data)/16) * 16] 16 | data = AES.new(key, AES.MODE_CBC, iv).decrypt(data) 17 | if padding: 18 | return removePadding(16, data) 19 | return data 20 | 21 | def AESencryptCBC(data, key, iv=ZEROIV, padding=False): 22 | if len(data) % 16: 23 | print "AESencryptCBC: data length not /16, truncating" 24 | data = data[0:(len(data)/16) * 16] 25 | data = AES.new(key, AES.MODE_CBC, iv).encrypt(data) 26 | return data 27 | 28 | #pycrypto MODE_CFB seems to give wrong results on icloud chunks ? 29 | def AESdecryptCFB(data, key, iv=ZEROIV): 30 | res = "" 31 | a = AES.new(key) 32 | ks = a.encrypt(iv) 33 | 34 | for i in xrange(0,len(data), 16): 35 | block = data[i:i+16] 36 | for j in xrange(0, len(block)): 37 | res += chr(ord(block[j]) ^ ord(ks[j])) 38 | if len(block) == 16: 39 | ks = a.encrypt(block) 40 | return res 41 | -------------------------------------------------------------------------------- /crypto/aes_ctypes.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | import sys 3 | 4 | if sys.platform == "darwin": 5 | kCCOptionECBMode=2 6 | kCCAlgorithmAES128=0 7 | kCCEncrypt=0 8 | kCCDecrypt=1 9 | 10 | Security = cdll.LoadLibrary("/System/Library/Frameworks/Security.framework/Security") 11 | #http://developer.apple.com/library/ios/documentation/System/Conceptual/ManPages_iPhoneOS/man3/CCCrypt.3cc.html 12 | #CCCryptorStatus 13 | # CCCrypt(CCOperation op, CCAlgorithm alg, CCOptions options, 14 | # const void *key, size_t keyLength, const void *iv, 15 | # const void *dataIn, size_t dataInLength, void *dataOut, 16 | # size_t dataOutAvailable, size_t *dataOutMoved); 17 | Security.CCCrypt.argtypes = [c_uint, c_uint, c_uint, c_void_p, 18 | c_size_t, c_void_p, c_void_p, 19 | c_size_t, c_void_p, c_size_t, c_void_p] 20 | class AES(object): 21 | def __init__(self, key, iv=None): 22 | self.key = key 23 | self.iv = None 24 | if iv: 25 | self.iv = create_string_buffer(iv) 26 | self.options = (self.iv == None) * kCCOptionECBMode 27 | 28 | def __del__(self): 29 | pass 30 | 31 | def cccrypt(self, op, data): 32 | iv = None 33 | keyb = create_string_buffer(self.key) 34 | clear = create_string_buffer(data) 35 | out = create_string_buffer("\x00" * len(data)) 36 | sizeout = c_ulonglong() 37 | r = Security.CCCrypt(op, kCCAlgorithmAES128, self.options, keyb, len(self.key), self.iv, clear, len(data), out, len(data), byref(sizeout)) 38 | return out.raw[:-1] 39 | 40 | def encrypt(self, data): 41 | return self.cccrypt(kCCEncrypt, data) 42 | 43 | def decrypt(self, data): 44 | return self.cccrypt(kCCDecrypt, data) 45 | 46 | elif sys.platform == "win32": 47 | PROV_RSA_AES = 24 48 | CRYPT_VERIFYCONTEXT = 0xF0000000 49 | PLAINTEXTKEYBLOB = 8 50 | CUR_BLOB_VERSION = 2 51 | KP_IV = 1 52 | KP_MODE = 4 53 | CRYPT_MODE_CBC = 1 54 | ALG_CLASS_DATA_ENCRYPT = (3 << 13) 55 | ALG_TYPE_BLOCK = (3 << 9) 56 | ALG_SID_AES_128 = 14 57 | ALG_SID_AES_192 = 15 58 | ALG_SID_AES_256 = 16 59 | CALG_AES_128 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES_128) 60 | CALG_AES_192 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES_192) 61 | CALG_AES_256 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES_256) 62 | 63 | CryptAcquireContext = windll.Advapi32.CryptAcquireContextA 64 | CryptReleaseContext = windll.Advapi32.CryptReleaseContext 65 | CryptImportKey = windll.Advapi32.CryptImportKey 66 | CryptSetKeyParam = windll.Advapi32.CryptSetKeyParam 67 | CryptDestroyKey = windll.Advapi32.CryptDestroyKey 68 | CryptEncrypt = windll.Advapi32.CryptEncrypt 69 | CryptDecrypt = windll.Advapi32.CryptDecrypt 70 | 71 | class AESBlob(Structure): 72 | _fields_ = [("bType", c_byte), 73 | ("bVersion", c_byte), 74 | ("reserved", c_short), 75 | ("aiKeyAlg", c_uint), 76 | ("keyLength", c_uint), 77 | ("key", c_byte * 32) 78 | ] 79 | 80 | class AES(object): 81 | def __init__(self, key, iv=None): 82 | self.hProvider = c_void_p() 83 | self.hKey = c_void_p() 84 | 85 | if iv and len(iv) != 16: 86 | print "Bad IV length %d" % len(iv) 87 | return 88 | 89 | blob = AESBlob() 90 | blob.bType = PLAINTEXTKEYBLOB 91 | blob.bVersion = CUR_BLOB_VERSION 92 | blob.reserved = 0 93 | if len(key) == 16: blob.aiKeyAlg = CALG_AES_128 94 | elif len(key) == 24: blob.aiKeyAlg = CALG_AES_192 95 | elif len(key) == 32: blob.aiKeyAlg = CALG_AES_256 96 | else: 97 | print "bad key size" 98 | return 99 | 100 | if CryptAcquireContext(byref(self.hProvider), 0, 0, PROV_RSA_AES, CRYPT_VERIFYCONTEXT) == 0: 101 | print "CryptAcquireContext failed" 102 | return 103 | 104 | blob.keyLength = len(key) 105 | for i in xrange(len(key)): 106 | blob.key[i] = ord(key[i]) 107 | 108 | if CryptImportKey(self.hProvider, byref(blob), sizeof(blob), 0, 0, byref(self.hKey)) == 0: 109 | print "CryptImportKey failed" 110 | CryptReleaseContext(self.hProvider, 0) 111 | return 112 | 113 | if iv: 114 | if CryptSetKeyParam(self.hKey, KP_IV, create_string_buffer(iv), 0 ) == 0: 115 | print "CryptSetKeyParam KP_MODE failed" 116 | 117 | dwMode = c_uint(CRYPT_MODE_CBC) 118 | if CryptSetKeyParam(self.hKey, KP_MODE, byref(dwMode), 0 ) == 0: 119 | print "CryptSetKeyParam KP_MODE failed" 120 | 121 | def __del__(self): 122 | CryptDestroyKey(self.hKey) 123 | CryptReleaseContext(self.hProvider, 0) 124 | 125 | def encrypt(self, data): 126 | pad = "" 127 | #dwBufLen must be at least 32 for AES with padding 128 | #if len(data) < 32: 129 | # pad = "\x00" * (32- len(data)) 130 | buf = create_string_buffer(data + pad) 131 | l = c_uint(len(data)) 132 | if CryptEncrypt(self.hKey, 0, False, 0, buf, byref(l), len(buf)) == 0: 133 | print "CryptEncrypt failed" 134 | return 135 | return buf.raw[:len(data)] 136 | 137 | def decrypt(self, data): 138 | buf = create_string_buffer(data) 139 | l = c_uint(len(data)) 140 | if CryptDecrypt(self.hKey, 0, False, 0, buf, byref(l)) == 0: 141 | print "CryptDecrypt failed" 142 | return 143 | return buf.raw[:-1] 144 | 145 | #replicate pycrypto interface 146 | MODE_ECB = 1 147 | MODE_CBC = 2 148 | def new(k,m,iv): 149 | return AES(k,iv) 150 | 151 | if __name__ == "__main__": 152 | tests = [("2b7e151628aed2a6abf7158809cf4f3c","6bc1bee22e409f96e93d7e117393172a","3ad77bb40d7a3660a89ecaf32466ef97"), 153 | ("2b7e151628aed2a6abf7158809cf4f3c","ae2d8a571e03ac9c9eb76fac45af8e51", "f5d3d58503b9699de785895a96fdbaaf"), 154 | ("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b","6bc1bee22e409f96e93d7e117393172a","bd334f1d6e45f25ff712a214571fa5cc"), 155 | ("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4","6bc1bee22e409f96e93d7e117393172a","f3eed1bdb5d2a03c064b5a7e3db181f8") 156 | ] 157 | print "Platform: %s" % sys.platform 158 | print "AES test vectors" 159 | 160 | for k,clear,ciph in tests: 161 | assert AES(k.decode("hex")).encrypt(clear.decode("hex")) == ciph.decode("hex") 162 | assert AES(k.decode("hex")).decrypt(ciph.decode("hex")) == clear.decode("hex") 163 | print "All tests OK !" 164 | -------------------------------------------------------------------------------- /crypto/aeswrap.py: -------------------------------------------------------------------------------- 1 | import struct 2 | from Crypto.Cipher import AES 3 | 4 | """ 5 | http://www.ietf.org/rfc/rfc3394.txt 6 | quick'n'dirty AES wrap implementation 7 | used by iOS 4 KeyStore kernel extension for wrapping/unwrapping encryption keys 8 | """ 9 | def unpack64bit(s): 10 | return struct.unpack(">Q",s)[0] 11 | def pack64bit(s): 12 | return struct.pack(">Q",s) 13 | 14 | def AESUnwrap(kek, wrapped): 15 | C = [] 16 | for i in xrange(len(wrapped)/8): 17 | C.append(unpack64bit(wrapped[i*8:i*8+8])) 18 | n = len(C) - 1 19 | R = [0] * (n+1) 20 | A = C[0] 21 | 22 | for i in xrange(1,n+1): 23 | R[i] = C[i] 24 | 25 | for j in reversed(xrange(0,6)): 26 | for i in reversed(xrange(1,n+1)): 27 | todec = pack64bit(A ^ (n*j+i)) 28 | todec += pack64bit(R[i]) 29 | B = AES.new(kek).decrypt(todec) 30 | A = unpack64bit(B[:8]) 31 | R[i] = unpack64bit(B[8:]) 32 | 33 | #assert A == 0xa6a6a6a6a6a6a6a6, "AESUnwrap: integrity check FAIL, wrong kek ?" 34 | if A != 0xa6a6a6a6a6a6a6a6: 35 | #print "AESUnwrap: integrity check FAIL, wrong kek ?" 36 | return None 37 | res = "".join(map(pack64bit, R[1:])) 38 | return res 39 | 40 | def AESwrap(kek, data): 41 | A = 0xa6a6a6a6a6a6a6a6 42 | R = [0] 43 | for i in xrange(len(data)/8): 44 | R.append(unpack64bit(data[i*8:i*8+8])) 45 | n = len(R) - 1 46 | 47 | for j in xrange(0,6): 48 | for i in xrange(1,n+1): 49 | B = AES.new(kek).encrypt(pack64bit(A) + pack64bit(R[i])) 50 | A = unpack64bit(B[:8]) ^ (n*j+i) 51 | R[i] = unpack64bit(B[8:]) 52 | 53 | res = pack64bit(A) + "".join(map(pack64bit, R[1:])) 54 | return res 55 | 56 | if __name__ == "__main__": 57 | #format (kek, data, expected_ciphertext) 58 | test_vectors = [ 59 | ("000102030405060708090A0B0C0D0E0F", "00112233445566778899AABBCCDDEEFF", "1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5"), 60 | ("000102030405060708090A0B0C0D0E0F1011121314151617", "00112233445566778899AABBCCDDEEFF", "96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D"), 61 | ("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", "00112233445566778899AABBCCDDEEFF", "64E8C3F9CE0F5BA263E9777905818A2A93C8191E7D6E8AE7"), 62 | ("000102030405060708090A0B0C0D0E0F1011121314151617", "00112233445566778899AABBCCDDEEFF0001020304050607", "031D33264E15D33268F24EC260743EDCE1C6C7DDEE725A936BA814915C6762D2"), 63 | ("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", "00112233445566778899AABBCCDDEEFF0001020304050607", "A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1"), 64 | ("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", "00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F", "28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21") 65 | ] 66 | for kek, data, expected in test_vectors: 67 | ciphertext = AESwrap(kek.decode("hex"), data.decode("hex")) 68 | assert ciphertext == expected.decode("hex") 69 | assert AESUnwrap(kek.decode("hex"), ciphertext) == data.decode("hex") 70 | print "All tests OK !" 71 | -------------------------------------------------------------------------------- /crypto/curve25519.py: -------------------------------------------------------------------------------- 1 | from Crypto.Util import number 2 | 3 | CURVE_P = (2**255 - 19) 4 | CURVE_A = 121665 5 | 6 | def curve25519_monty(x1, z1, x2, z2, qmqp): 7 | a = (x1 + z1) * (x2 - z2) % CURVE_P 8 | b = (x1 - z1) * (x2 + z2) % CURVE_P 9 | x4 = (a + b) * (a + b) % CURVE_P 10 | 11 | e = (a - b) * (a - b) % CURVE_P 12 | z4 = e * qmqp % CURVE_P 13 | 14 | a = (x1 + z1) * (x1 + z1) % CURVE_P 15 | b = (x1 - z1) * (x1 - z1) % CURVE_P 16 | x3 = a * b % CURVE_P 17 | 18 | g = (a - b) % CURVE_P 19 | h = (a + CURVE_A * g) % CURVE_P 20 | z3 = (g * h) % CURVE_P 21 | 22 | return x3, z3, x4, z4 23 | 24 | def curve25519_mult(n, q): 25 | nqpqx, nqpqz = q, 1 26 | nqx, nqz = 1, 0 27 | 28 | for i in range(255, -1, -1): 29 | if (n >> i) & 1: 30 | nqpqx,nqpqz,nqx,nqz = curve25519_monty(nqpqx, nqpqz, nqx, nqz, q) 31 | else: 32 | nqx,nqz,nqpqx,nqpqz = curve25519_monty(nqx, nqz, nqpqx, nqpqz, q) 33 | return nqx, nqz 34 | 35 | def curve25519(secret, basepoint): 36 | a = ord(secret[0]) 37 | a &= 248 38 | b = ord(secret[31]) 39 | b &= 127 40 | b |= 64 41 | s = chr(a) + secret[1:-1] + chr(b) 42 | 43 | s = number.bytes_to_long(s[::-1]) 44 | basepoint = number.bytes_to_long(basepoint[::-1]) 45 | 46 | x, z = curve25519_mult(s, basepoint) 47 | zmone = number.inverse(z, CURVE_P) 48 | z = x * zmone % CURVE_P 49 | return number.long_to_bytes(z)[::-1] 50 | 51 | 52 | if __name__ == "__main__": 53 | from crypto.aeswrap import AESUnwrap 54 | from Crypto.Hash import SHA256 55 | 56 | z="04000000080000000200000048000000000000000000000000000000000000000000000002917dc2542198edeb1078c4d1ebab74d9ca87890657ba02b9825dadf20a002f44360c6f87743fac0236df1f9eedbea801e31677aef3a09adfb4e10a37ae27facf419ab3ea3f39f4".decode("hex") 57 | 58 | mysecret = "99b66345829d8c05041eea1ba1ed5b2984c3e5ec7a756ef053473c7f22b49f14".decode("hex") 59 | mypublic = "b1c652786697a5feef36a56f36fde524a21193f4e563627977ab515f600fdb3a".decode("hex") 60 | hispublic = z[36:36+32] 61 | 62 | #c4d9fe462a2ebbf0745195ce7dc5e8b49947bbd5b42da74175d5f8125b44582b 63 | shared = curve25519(mysecret, hispublic) 64 | print shared.encode("hex") 65 | 66 | h = SHA256.new() 67 | h.update('\x00\x00\x00\x01') 68 | h.update(shared) 69 | h.update(hispublic) 70 | h.update(mypublic) 71 | md = h.digest() 72 | 73 | #e442c81b91ea876d3cf42d3aea75f4b0c3f90f9fd045e1f5784b91260f3bdc9c 74 | print AESUnwrap(md, z[32+36:]).encode("hex") 75 | -------------------------------------------------------------------------------- /crypto/gcm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from Crypto.Cipher import AES 4 | from Crypto.Util import strxor 5 | from struct import pack, unpack 6 | 7 | def gcm_rightshift(vec): 8 | for x in range(15, 0, -1): 9 | c = vec[x] >> 1 10 | c |= (vec[x-1] << 7) & 0x80 11 | vec[x] = c 12 | vec[0] >>= 1 13 | return vec 14 | 15 | def gcm_gf_mult(a, b): 16 | mask = [ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 ] 17 | poly = [ 0x00, 0xe1 ] 18 | 19 | Z = [0] * 16 20 | V = [c for c in a] 21 | 22 | for x in range(128): 23 | if b[x >> 3] & mask[x & 7]: 24 | Z = [V[y] ^ Z[y] for y in range(16)] 25 | bit = V[15] & 1 26 | V = gcm_rightshift(V) 27 | V[0] ^= poly[bit] 28 | return Z 29 | 30 | def ghash(h, auth_data, data): 31 | u = (16 - len(data)) % 16 32 | v = (16 - len(auth_data)) % 16 33 | 34 | x = auth_data + chr(0) * v + data + chr(0) * u 35 | x += pack('>QQ', len(auth_data) * 8, len(data) * 8) 36 | 37 | y = [0] * 16 38 | vec_h = [ord(c) for c in h] 39 | 40 | for i in range(0, len(x), 16): 41 | block = [ord(c) for c in x[i:i+16]] 42 | y = [y[j] ^ block[j] for j in range(16)] 43 | y = gcm_gf_mult(y, vec_h) 44 | 45 | return ''.join(chr(c) for c in y) 46 | 47 | def inc32(block): 48 | counter, = unpack('>L', block[12:]) 49 | counter += 1 50 | return block[:12] + pack('>L', counter) 51 | 52 | def gctr(k, icb, plaintext): 53 | y = '' 54 | if len(plaintext) == 0: 55 | return y 56 | 57 | aes = AES.new(k) 58 | cb = icb 59 | 60 | for i in range(0, len(plaintext), aes.block_size): 61 | cb = inc32(cb) 62 | encrypted = aes.encrypt(cb) 63 | plaintext_block = plaintext[i:i+aes.block_size] 64 | y += strxor.strxor(plaintext_block, encrypted[:len(plaintext_block)]) 65 | 66 | return y 67 | 68 | def gcm_decrypt(k, iv, encrypted, auth_data, tag): 69 | aes = AES.new(k) 70 | h = aes.encrypt(chr(0) * aes.block_size) 71 | 72 | if len(iv) == 12: 73 | y0 = iv + "\x00\x00\x00\x01" 74 | else: 75 | y0 = ghash(h, '', iv) 76 | 77 | decrypted = gctr(k, y0, encrypted) 78 | s = ghash(h, auth_data, encrypted) 79 | 80 | t = aes.encrypt(y0) 81 | T = strxor.strxor(s, t) 82 | if T != tag: 83 | raise ValueError('Decrypted data is invalid') 84 | else: 85 | return decrypted 86 | 87 | def gcm_encrypt(k, iv, plaintext, auth_data): 88 | aes = AES.new(k) 89 | h = aes.encrypt(chr(0) * aes.block_size) 90 | 91 | if len(iv) == 12: 92 | y0 = iv + "\x00\x00\x00\x01" 93 | else: 94 | y0 = ghash(h, '', iv) 95 | 96 | encrypted = gctr(k, y0, plaintext) 97 | s = ghash(h, auth_data, encrypted) 98 | 99 | t = aes.encrypt(y0) 100 | T = strxor.strxor(s, t) 101 | return (encrypted, T) 102 | 103 | def main(): 104 | #http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf 105 | k = 'AD7A2BD03EAC835A6F620FDCB506B345'.decode("hex") 106 | p = '' 107 | a = 'D609B1F056637A0D46DF998D88E5222AB2C2846512153524C0895E8108000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F30313233340001'.decode("hex") 108 | iv = '12153524C0895E81B2C28465'.decode("hex") 109 | c, t = gcm_encrypt(k, iv, '', a) 110 | assert c == "" 111 | assert t == "f09478a9b09007d06f46e9b6a1da25dd".decode("hex") 112 | 113 | k = 'AD7A2BD03EAC835A6F620FDCB506B345'.decode("hex") 114 | p = '08000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A0002'.decode("hex") 115 | a = 'D609B1F056637A0D46DF998D88E52E00B2C2846512153524C0895E81'.decode("hex") 116 | iv = '12153524C0895E81B2C28465'.decode("hex") 117 | c, t = gcm_encrypt(k, iv, p, a) 118 | assert c == '701AFA1CC039C0D765128A665DAB69243899BF7318CCDC81C9931DA17FBE8EDD7D17CB8B4C26FC81E3284F2B7FBA713D'.decode("hex") 119 | assert t == '4F8D55E7D3F06FD5A13C0C29B9D5B880'.decode("hex") 120 | 121 | key = "91bfb6cbcff07b93a4c68bbfe99ac63b713f0627025c0fb1ffc5b0812dc284f8".decode("hex") 122 | data = "020000000B00000028000000DE44D22E96B1966BAEF4CBEA8675871D40BA669401BD4EBB52AF9C025134187E70549012058456BF0EC0FA1F8FF9F822AC4312AB2141FA712E6D1482358EAC1421A1BFFA81EF38BD0BF2E52675D665EFE3C534E188F575774FAA92E74345575E370B9982661FAE8BD9243B7AD7D2105B275424C0CA1145B9D43AFF04F2747E40D62EC60563960D62A894BE66F267B14D75C0572BE60CC9B339D440FCB418D4F729BBF15C14E0D3A43E4A8B44523D8B3B0F3E7DF85AA67A707EE19CB893277D2392234D7DBC17DA4A0BD7F166189FC54C16C20D287E20FD2FB11BD2CE09ADBDABB95124CD4BFE219E34D3C80E69570A5A506555D7094916C5D75E0065F1796F556EDF0DAA1AA758E0C85AE3951BD363F26B1D43F6CBAEE12D97AD3B60CFA89C1C76BB29F2B54BE31B6CE166F4860C5E5DA92588EF53AA946DF159E60E6F05009D12FB1E37".decode("hex") 123 | ciphertext = data[12+40:-16] 124 | tag = data[-16:] 125 | print repr(gcm_decrypt(key, '', ciphertext, '', tag)) 126 | 127 | 128 | if __name__ == '__main__': 129 | main() 130 | -------------------------------------------------------------------------------- /icloud.proto: -------------------------------------------------------------------------------- 1 | package icloud; 2 | 3 | message MBSAccount { 4 | optional string AccountID = 1; 5 | repeated bytes backupUDID = 2; 6 | } 7 | 8 | message MBSBackup { 9 | optional bytes backupUDID = 1; 10 | optional uint64 QuotaUsed = 2; 11 | repeated MBSSnapshot Snapshot = 3; 12 | optional MBSBackupAttributes Attributes = 4; 13 | optional uint64 KeysLastModified = 5; 14 | } 15 | 16 | message MBSBackupAttributes { 17 | optional string DeviceClass = 1; 18 | optional string ProductType = 2; 19 | optional string SerialNumber = 3; 20 | optional string DeviceColor = 4; 21 | optional string HardwareModel = 5; 22 | optional string MarketingName = 6; 23 | } 24 | 25 | message MBSFile { 26 | optional bytes FileID = 1; 27 | optional string Domain = 2; 28 | optional string RelativePath = 3; 29 | optional bytes Signature = 4; 30 | optional uint64 Size = 5; 31 | optional MBSFileAttributes Attributes = 6; 32 | } 33 | 34 | message MBSFileAttributes { 35 | optional uint32 KeybagID = 1; 36 | optional string Target = 2; 37 | optional bytes EncryptionKey = 3; 38 | optional uint64 InodeNumber = 4; 39 | optional uint32 Mode = 5; 40 | optional uint32 UserID = 6; 41 | optional uint32 GroupID = 7; 42 | optional uint64 LastModified = 8; 43 | optional uint64 LastStatusChange = 9; 44 | optional uint64 Birth = 10; 45 | optional uint32 ProtectionClass = 12; 46 | optional MBSFileExtendedAttribute ExtendedAttribute = 13; 47 | optional uint32 EncryptionKeyVersion = 14; 48 | optional uint64 DecryptedSize = 15; 49 | } 50 | 51 | message MBSSnapshot { 52 | optional uint32 SnapshotID = 1; 53 | optional uint64 QuotaReserved = 2; 54 | optional uint64 LastModified = 3; 55 | optional MBSSnapshotAttributes Attributes = 5; 56 | optional uint64 Committed = 6; 57 | } 58 | 59 | message MBSSnapshotAttributes { 60 | optional string DeviceName = 1; 61 | optional string ProductVersion = 2; 62 | optional string BuildVersion = 3; 63 | optional uint32 KeybagID = 4; 64 | optional bytes KeybagUUID = 5; 65 | optional int32 BackupReason = 6; 66 | optional int32 BackupType = 7; 67 | } 68 | 69 | message MBSSnapshotID { 70 | optional uint32 SnapshotID = 1; 71 | } 72 | 73 | message MBSFileAuthToken { 74 | required bytes FileID = 1; 75 | optional string AuthToken = 2; 76 | } 77 | message MBSFileAuthTokens { 78 | repeated MBSFileAuthToken tokens = 1; 79 | } 80 | 81 | message MBSFileID { 82 | required bytes FileID = 1; 83 | } 84 | 85 | message MBSKey { 86 | optional uint32 KeyID = 1; 87 | optional bytes KeyData = 2; 88 | } 89 | 90 | message MBSKeySet { 91 | repeated MBSKey Key = 1; 92 | } 93 | 94 | message MBSFileExtendedAttribute { 95 | optional string Name = 1; 96 | optional bytes Value = 2; 97 | } 98 | -------------------------------------------------------------------------------- /icloud_pb2.py: -------------------------------------------------------------------------------- 1 | # Generated by the protocol buffer compiler. DO NOT EDIT! 2 | # source: icloud.proto 3 | 4 | from google.protobuf import descriptor as _descriptor 5 | from google.protobuf import message as _message 6 | from google.protobuf import reflection as _reflection 7 | from google.protobuf import descriptor_pb2 8 | # @@protoc_insertion_point(imports) 9 | 10 | 11 | 12 | 13 | DESCRIPTOR = _descriptor.FileDescriptor( 14 | name='icloud.proto', 15 | package='icloud', 16 | serialized_pb='\n\x0cicloud.proto\x12\x06icloud\"3\n\nMBSAccount\x12\x11\n\tAccountID\x18\x01 \x01(\t\x12\x12\n\nbackupUDID\x18\x02 \x03(\x0c\"\xa4\x01\n\tMBSBackup\x12\x12\n\nbackupUDID\x18\x01 \x01(\x0c\x12\x11\n\tQuotaUsed\x18\x02 \x01(\x04\x12%\n\x08Snapshot\x18\x03 \x01(\x0b\x32\x13.icloud.MBSSnapshot\x12/\n\nAttributes\x18\x04 \x01(\x0b\x32\x1b.icloud.MBSBackupAttributes\x12\x18\n\x10KeysLastModified\x18\x05 \x01(\x04\"\x98\x01\n\x13MBSBackupAttributes\x12\x13\n\x0b\x44\x65viceClass\x18\x01 \x01(\t\x12\x13\n\x0bProductType\x18\x02 \x01(\t\x12\x14\n\x0cSerialNumber\x18\x03 \x01(\t\x12\x13\n\x0b\x44\x65viceColor\x18\x04 \x01(\t\x12\x15\n\rHardwareModel\x18\x05 \x01(\t\x12\x15\n\rMarketingName\x18\x06 \x01(\t\"\x8f\x01\n\x07MBSFile\x12\x0e\n\x06\x46ileID\x18\x01 \x01(\x0c\x12\x0e\n\x06\x44omain\x18\x02 \x01(\t\x12\x14\n\x0cRelativePath\x18\x03 \x01(\t\x12\x11\n\tSignature\x18\x04 \x01(\x0c\x12\x0c\n\x04Size\x18\x05 \x01(\x04\x12-\n\nAttributes\x18\x06 \x01(\x0b\x32\x19.icloud.MBSFileAttributes\"\xda\x02\n\x11MBSFileAttributes\x12\x10\n\x08KeybagID\x18\x01 \x01(\r\x12\x0e\n\x06Target\x18\x02 \x01(\t\x12\x15\n\rEncryptionKey\x18\x03 \x01(\x0c\x12\x13\n\x0bInodeNumber\x18\x04 \x01(\x04\x12\x0c\n\x04Mode\x18\x05 \x01(\r\x12\x0e\n\x06UserID\x18\x06 \x01(\r\x12\x0f\n\x07GroupID\x18\x07 \x01(\r\x12\x14\n\x0cLastModified\x18\x08 \x01(\x04\x12\x18\n\x10LastStatusChange\x18\t \x01(\x04\x12\r\n\x05\x42irth\x18\n \x01(\x04\x12\x17\n\x0fProtectionClass\x18\x0c \x01(\r\x12;\n\x11\x45xtendedAttribute\x18\r \x01(\x0b\x32 .icloud.MBSFileExtendedAttribute\x12\x1c\n\x14\x45ncryptionKeyVersion\x18\x0e \x01(\r\x12\x15\n\rDecryptedSize\x18\x0f \x01(\x04\"\x94\x01\n\x0bMBSSnapshot\x12\x12\n\nSnapshotID\x18\x01 \x01(\r\x12\x15\n\rQuotaReserved\x18\x02 \x01(\x04\x12\x14\n\x0cLastModified\x18\x03 \x01(\x04\x12\x31\n\nAttributes\x18\x05 \x01(\x0b\x32\x1d.icloud.MBSSnapshotAttributes\x12\x11\n\tCommitted\x18\x06 \x01(\x04\"\xa9\x01\n\x15MBSSnapshotAttributes\x12\x12\n\nDeviceName\x18\x01 \x01(\t\x12\x16\n\x0eProductVersion\x18\x02 \x01(\t\x12\x14\n\x0c\x42uildVersion\x18\x03 \x01(\t\x12\x10\n\x08KeybagID\x18\x04 \x01(\r\x12\x12\n\nKeybagUUID\x18\x05 \x01(\x0c\x12\x14\n\x0c\x42\x61\x63kupReason\x18\x06 \x01(\x05\x12\x12\n\nBackupType\x18\x07 \x01(\x05\"#\n\rMBSSnapshotID\x12\x12\n\nSnapshotID\x18\x01 \x01(\r\"5\n\x10MBSFileAuthToken\x12\x0e\n\x06\x46ileID\x18\x01 \x02(\x0c\x12\x11\n\tAuthToken\x18\x02 \x01(\t\"=\n\x11MBSFileAuthTokens\x12(\n\x06tokens\x18\x01 \x03(\x0b\x32\x18.icloud.MBSFileAuthToken\"\x1b\n\tMBSFileID\x12\x0e\n\x06\x46ileID\x18\x01 \x02(\x0c\"(\n\x06MBSKey\x12\r\n\x05KeyID\x18\x01 \x01(\r\x12\x0f\n\x07KeyData\x18\x02 \x01(\x0c\"(\n\tMBSKeySet\x12\x1b\n\x03Key\x18\x01 \x03(\x0b\x32\x0e.icloud.MBSKey\"7\n\x18MBSFileExtendedAttribute\x12\x0c\n\x04Name\x18\x01 \x01(\t\x12\r\n\x05Value\x18\x02 \x01(\x0c') 17 | 18 | 19 | 20 | 21 | _MBSACCOUNT = _descriptor.Descriptor( 22 | name='MBSAccount', 23 | full_name='icloud.MBSAccount', 24 | filename=None, 25 | file=DESCRIPTOR, 26 | containing_type=None, 27 | fields=[ 28 | _descriptor.FieldDescriptor( 29 | name='AccountID', full_name='icloud.MBSAccount.AccountID', index=0, 30 | number=1, type=9, cpp_type=9, label=1, 31 | has_default_value=False, default_value=unicode("", "utf-8"), 32 | message_type=None, enum_type=None, containing_type=None, 33 | is_extension=False, extension_scope=None, 34 | options=None), 35 | _descriptor.FieldDescriptor( 36 | name='backupUDID', full_name='icloud.MBSAccount.backupUDID', index=1, 37 | number=2, type=12, cpp_type=9, label=3, 38 | has_default_value=False, default_value=[], 39 | message_type=None, enum_type=None, containing_type=None, 40 | is_extension=False, extension_scope=None, 41 | options=None), 42 | ], 43 | extensions=[ 44 | ], 45 | nested_types=[], 46 | enum_types=[ 47 | ], 48 | options=None, 49 | is_extendable=False, 50 | extension_ranges=[], 51 | serialized_start=24, 52 | serialized_end=75, 53 | ) 54 | 55 | 56 | _MBSBACKUP = _descriptor.Descriptor( 57 | name='MBSBackup', 58 | full_name='icloud.MBSBackup', 59 | filename=None, 60 | file=DESCRIPTOR, 61 | containing_type=None, 62 | fields=[ 63 | _descriptor.FieldDescriptor( 64 | name='backupUDID', full_name='icloud.MBSBackup.backupUDID', index=0, 65 | number=1, type=12, cpp_type=9, label=1, 66 | has_default_value=False, default_value="", 67 | message_type=None, enum_type=None, containing_type=None, 68 | is_extension=False, extension_scope=None, 69 | options=None), 70 | _descriptor.FieldDescriptor( 71 | name='QuotaUsed', full_name='icloud.MBSBackup.QuotaUsed', index=1, 72 | number=2, type=4, cpp_type=4, label=1, 73 | has_default_value=False, default_value=0, 74 | message_type=None, enum_type=None, containing_type=None, 75 | is_extension=False, extension_scope=None, 76 | options=None), 77 | _descriptor.FieldDescriptor( 78 | name='Snapshot', full_name='icloud.MBSBackup.Snapshot', index=2, 79 | number=3, type=11, cpp_type=10, label=1, 80 | has_default_value=False, default_value=None, 81 | message_type=None, enum_type=None, containing_type=None, 82 | is_extension=False, extension_scope=None, 83 | options=None), 84 | _descriptor.FieldDescriptor( 85 | name='Attributes', full_name='icloud.MBSBackup.Attributes', index=3, 86 | number=4, type=11, cpp_type=10, label=1, 87 | has_default_value=False, default_value=None, 88 | message_type=None, enum_type=None, containing_type=None, 89 | is_extension=False, extension_scope=None, 90 | options=None), 91 | _descriptor.FieldDescriptor( 92 | name='KeysLastModified', full_name='icloud.MBSBackup.KeysLastModified', index=4, 93 | number=5, type=4, cpp_type=4, label=1, 94 | has_default_value=False, default_value=0, 95 | message_type=None, enum_type=None, containing_type=None, 96 | is_extension=False, extension_scope=None, 97 | options=None), 98 | ], 99 | extensions=[ 100 | ], 101 | nested_types=[], 102 | enum_types=[ 103 | ], 104 | options=None, 105 | is_extendable=False, 106 | extension_ranges=[], 107 | serialized_start=78, 108 | serialized_end=242, 109 | ) 110 | 111 | 112 | _MBSBACKUPATTRIBUTES = _descriptor.Descriptor( 113 | name='MBSBackupAttributes', 114 | full_name='icloud.MBSBackupAttributes', 115 | filename=None, 116 | file=DESCRIPTOR, 117 | containing_type=None, 118 | fields=[ 119 | _descriptor.FieldDescriptor( 120 | name='DeviceClass', full_name='icloud.MBSBackupAttributes.DeviceClass', index=0, 121 | number=1, type=9, cpp_type=9, label=1, 122 | has_default_value=False, default_value=unicode("", "utf-8"), 123 | message_type=None, enum_type=None, containing_type=None, 124 | is_extension=False, extension_scope=None, 125 | options=None), 126 | _descriptor.FieldDescriptor( 127 | name='ProductType', full_name='icloud.MBSBackupAttributes.ProductType', index=1, 128 | number=2, type=9, cpp_type=9, label=1, 129 | has_default_value=False, default_value=unicode("", "utf-8"), 130 | message_type=None, enum_type=None, containing_type=None, 131 | is_extension=False, extension_scope=None, 132 | options=None), 133 | _descriptor.FieldDescriptor( 134 | name='SerialNumber', full_name='icloud.MBSBackupAttributes.SerialNumber', index=2, 135 | number=3, type=9, cpp_type=9, label=1, 136 | has_default_value=False, default_value=unicode("", "utf-8"), 137 | message_type=None, enum_type=None, containing_type=None, 138 | is_extension=False, extension_scope=None, 139 | options=None), 140 | _descriptor.FieldDescriptor( 141 | name='DeviceColor', full_name='icloud.MBSBackupAttributes.DeviceColor', index=3, 142 | number=4, type=9, cpp_type=9, label=1, 143 | has_default_value=False, default_value=unicode("", "utf-8"), 144 | message_type=None, enum_type=None, containing_type=None, 145 | is_extension=False, extension_scope=None, 146 | options=None), 147 | _descriptor.FieldDescriptor( 148 | name='HardwareModel', full_name='icloud.MBSBackupAttributes.HardwareModel', index=4, 149 | number=5, type=9, cpp_type=9, label=1, 150 | has_default_value=False, default_value=unicode("", "utf-8"), 151 | message_type=None, enum_type=None, containing_type=None, 152 | is_extension=False, extension_scope=None, 153 | options=None), 154 | _descriptor.FieldDescriptor( 155 | name='MarketingName', full_name='icloud.MBSBackupAttributes.MarketingName', index=5, 156 | number=6, type=9, cpp_type=9, label=1, 157 | has_default_value=False, default_value=unicode("", "utf-8"), 158 | message_type=None, enum_type=None, containing_type=None, 159 | is_extension=False, extension_scope=None, 160 | options=None), 161 | ], 162 | extensions=[ 163 | ], 164 | nested_types=[], 165 | enum_types=[ 166 | ], 167 | options=None, 168 | is_extendable=False, 169 | extension_ranges=[], 170 | serialized_start=245, 171 | serialized_end=397, 172 | ) 173 | 174 | 175 | _MBSFILE = _descriptor.Descriptor( 176 | name='MBSFile', 177 | full_name='icloud.MBSFile', 178 | filename=None, 179 | file=DESCRIPTOR, 180 | containing_type=None, 181 | fields=[ 182 | _descriptor.FieldDescriptor( 183 | name='FileID', full_name='icloud.MBSFile.FileID', index=0, 184 | number=1, type=12, cpp_type=9, label=1, 185 | has_default_value=False, default_value="", 186 | message_type=None, enum_type=None, containing_type=None, 187 | is_extension=False, extension_scope=None, 188 | options=None), 189 | _descriptor.FieldDescriptor( 190 | name='Domain', full_name='icloud.MBSFile.Domain', index=1, 191 | number=2, type=9, cpp_type=9, label=1, 192 | has_default_value=False, default_value=unicode("", "utf-8"), 193 | message_type=None, enum_type=None, containing_type=None, 194 | is_extension=False, extension_scope=None, 195 | options=None), 196 | _descriptor.FieldDescriptor( 197 | name='RelativePath', full_name='icloud.MBSFile.RelativePath', index=2, 198 | number=3, type=9, cpp_type=9, label=1, 199 | has_default_value=False, default_value=unicode("", "utf-8"), 200 | message_type=None, enum_type=None, containing_type=None, 201 | is_extension=False, extension_scope=None, 202 | options=None), 203 | _descriptor.FieldDescriptor( 204 | name='Signature', full_name='icloud.MBSFile.Signature', index=3, 205 | number=4, type=12, cpp_type=9, label=1, 206 | has_default_value=False, default_value="", 207 | message_type=None, enum_type=None, containing_type=None, 208 | is_extension=False, extension_scope=None, 209 | options=None), 210 | _descriptor.FieldDescriptor( 211 | name='Size', full_name='icloud.MBSFile.Size', index=4, 212 | number=5, type=4, cpp_type=4, label=1, 213 | has_default_value=False, default_value=0, 214 | message_type=None, enum_type=None, containing_type=None, 215 | is_extension=False, extension_scope=None, 216 | options=None), 217 | _descriptor.FieldDescriptor( 218 | name='Attributes', full_name='icloud.MBSFile.Attributes', index=5, 219 | number=6, type=11, cpp_type=10, label=1, 220 | has_default_value=False, default_value=None, 221 | message_type=None, enum_type=None, containing_type=None, 222 | is_extension=False, extension_scope=None, 223 | options=None), 224 | ], 225 | extensions=[ 226 | ], 227 | nested_types=[], 228 | enum_types=[ 229 | ], 230 | options=None, 231 | is_extendable=False, 232 | extension_ranges=[], 233 | serialized_start=400, 234 | serialized_end=543, 235 | ) 236 | 237 | 238 | _MBSFILEATTRIBUTES = _descriptor.Descriptor( 239 | name='MBSFileAttributes', 240 | full_name='icloud.MBSFileAttributes', 241 | filename=None, 242 | file=DESCRIPTOR, 243 | containing_type=None, 244 | fields=[ 245 | _descriptor.FieldDescriptor( 246 | name='KeybagID', full_name='icloud.MBSFileAttributes.KeybagID', index=0, 247 | number=1, type=13, cpp_type=3, label=1, 248 | has_default_value=False, default_value=0, 249 | message_type=None, enum_type=None, containing_type=None, 250 | is_extension=False, extension_scope=None, 251 | options=None), 252 | _descriptor.FieldDescriptor( 253 | name='Target', full_name='icloud.MBSFileAttributes.Target', index=1, 254 | number=2, type=9, cpp_type=9, label=1, 255 | has_default_value=False, default_value=unicode("", "utf-8"), 256 | message_type=None, enum_type=None, containing_type=None, 257 | is_extension=False, extension_scope=None, 258 | options=None), 259 | _descriptor.FieldDescriptor( 260 | name='EncryptionKey', full_name='icloud.MBSFileAttributes.EncryptionKey', index=2, 261 | number=3, type=12, cpp_type=9, label=1, 262 | has_default_value=False, default_value="", 263 | message_type=None, enum_type=None, containing_type=None, 264 | is_extension=False, extension_scope=None, 265 | options=None), 266 | _descriptor.FieldDescriptor( 267 | name='InodeNumber', full_name='icloud.MBSFileAttributes.InodeNumber', index=3, 268 | number=4, type=4, cpp_type=4, label=1, 269 | has_default_value=False, default_value=0, 270 | message_type=None, enum_type=None, containing_type=None, 271 | is_extension=False, extension_scope=None, 272 | options=None), 273 | _descriptor.FieldDescriptor( 274 | name='Mode', full_name='icloud.MBSFileAttributes.Mode', index=4, 275 | number=5, type=13, cpp_type=3, label=1, 276 | has_default_value=False, default_value=0, 277 | message_type=None, enum_type=None, containing_type=None, 278 | is_extension=False, extension_scope=None, 279 | options=None), 280 | _descriptor.FieldDescriptor( 281 | name='UserID', full_name='icloud.MBSFileAttributes.UserID', index=5, 282 | number=6, type=13, cpp_type=3, label=1, 283 | has_default_value=False, default_value=0, 284 | message_type=None, enum_type=None, containing_type=None, 285 | is_extension=False, extension_scope=None, 286 | options=None), 287 | _descriptor.FieldDescriptor( 288 | name='GroupID', full_name='icloud.MBSFileAttributes.GroupID', index=6, 289 | number=7, type=13, cpp_type=3, label=1, 290 | has_default_value=False, default_value=0, 291 | message_type=None, enum_type=None, containing_type=None, 292 | is_extension=False, extension_scope=None, 293 | options=None), 294 | _descriptor.FieldDescriptor( 295 | name='LastModified', full_name='icloud.MBSFileAttributes.LastModified', index=7, 296 | number=8, type=4, cpp_type=4, label=1, 297 | has_default_value=False, default_value=0, 298 | message_type=None, enum_type=None, containing_type=None, 299 | is_extension=False, extension_scope=None, 300 | options=None), 301 | _descriptor.FieldDescriptor( 302 | name='LastStatusChange', full_name='icloud.MBSFileAttributes.LastStatusChange', index=8, 303 | number=9, type=4, cpp_type=4, label=1, 304 | has_default_value=False, default_value=0, 305 | message_type=None, enum_type=None, containing_type=None, 306 | is_extension=False, extension_scope=None, 307 | options=None), 308 | _descriptor.FieldDescriptor( 309 | name='Birth', full_name='icloud.MBSFileAttributes.Birth', index=9, 310 | number=10, type=4, cpp_type=4, label=1, 311 | has_default_value=False, default_value=0, 312 | message_type=None, enum_type=None, containing_type=None, 313 | is_extension=False, extension_scope=None, 314 | options=None), 315 | _descriptor.FieldDescriptor( 316 | name='ProtectionClass', full_name='icloud.MBSFileAttributes.ProtectionClass', index=10, 317 | number=12, type=13, cpp_type=3, label=1, 318 | has_default_value=False, default_value=0, 319 | message_type=None, enum_type=None, containing_type=None, 320 | is_extension=False, extension_scope=None, 321 | options=None), 322 | _descriptor.FieldDescriptor( 323 | name='ExtendedAttribute', full_name='icloud.MBSFileAttributes.ExtendedAttribute', index=11, 324 | number=13, type=11, cpp_type=10, label=1, 325 | has_default_value=False, default_value=None, 326 | message_type=None, enum_type=None, containing_type=None, 327 | is_extension=False, extension_scope=None, 328 | options=None), 329 | _descriptor.FieldDescriptor( 330 | name='EncryptionKeyVersion', full_name='icloud.MBSFileAttributes.EncryptionKeyVersion', index=12, 331 | number=14, type=13, cpp_type=3, label=1, 332 | has_default_value=False, default_value=0, 333 | message_type=None, enum_type=None, containing_type=None, 334 | is_extension=False, extension_scope=None, 335 | options=None), 336 | _descriptor.FieldDescriptor( 337 | name='DecryptedSize', full_name='icloud.MBSFileAttributes.DecryptedSize', index=13, 338 | number=15, type=4, cpp_type=4, label=1, 339 | has_default_value=False, default_value=0, 340 | message_type=None, enum_type=None, containing_type=None, 341 | is_extension=False, extension_scope=None, 342 | options=None), 343 | ], 344 | extensions=[ 345 | ], 346 | nested_types=[], 347 | enum_types=[ 348 | ], 349 | options=None, 350 | is_extendable=False, 351 | extension_ranges=[], 352 | serialized_start=546, 353 | serialized_end=892, 354 | ) 355 | 356 | 357 | _MBSSNAPSHOT = _descriptor.Descriptor( 358 | name='MBSSnapshot', 359 | full_name='icloud.MBSSnapshot', 360 | filename=None, 361 | file=DESCRIPTOR, 362 | containing_type=None, 363 | fields=[ 364 | _descriptor.FieldDescriptor( 365 | name='SnapshotID', full_name='icloud.MBSSnapshot.SnapshotID', index=0, 366 | number=1, type=13, cpp_type=3, label=1, 367 | has_default_value=False, default_value=0, 368 | message_type=None, enum_type=None, containing_type=None, 369 | is_extension=False, extension_scope=None, 370 | options=None), 371 | _descriptor.FieldDescriptor( 372 | name='QuotaReserved', full_name='icloud.MBSSnapshot.QuotaReserved', index=1, 373 | number=2, type=4, cpp_type=4, label=1, 374 | has_default_value=False, default_value=0, 375 | message_type=None, enum_type=None, containing_type=None, 376 | is_extension=False, extension_scope=None, 377 | options=None), 378 | _descriptor.FieldDescriptor( 379 | name='LastModified', full_name='icloud.MBSSnapshot.LastModified', index=2, 380 | number=3, type=4, cpp_type=4, label=1, 381 | has_default_value=False, default_value=0, 382 | message_type=None, enum_type=None, containing_type=None, 383 | is_extension=False, extension_scope=None, 384 | options=None), 385 | _descriptor.FieldDescriptor( 386 | name='Attributes', full_name='icloud.MBSSnapshot.Attributes', index=3, 387 | number=5, type=11, cpp_type=10, label=1, 388 | has_default_value=False, default_value=None, 389 | message_type=None, enum_type=None, containing_type=None, 390 | is_extension=False, extension_scope=None, 391 | options=None), 392 | _descriptor.FieldDescriptor( 393 | name='Committed', full_name='icloud.MBSSnapshot.Committed', index=4, 394 | number=6, type=4, cpp_type=4, label=1, 395 | has_default_value=False, default_value=0, 396 | message_type=None, enum_type=None, containing_type=None, 397 | is_extension=False, extension_scope=None, 398 | options=None), 399 | ], 400 | extensions=[ 401 | ], 402 | nested_types=[], 403 | enum_types=[ 404 | ], 405 | options=None, 406 | is_extendable=False, 407 | extension_ranges=[], 408 | serialized_start=895, 409 | serialized_end=1043, 410 | ) 411 | 412 | 413 | _MBSSNAPSHOTATTRIBUTES = _descriptor.Descriptor( 414 | name='MBSSnapshotAttributes', 415 | full_name='icloud.MBSSnapshotAttributes', 416 | filename=None, 417 | file=DESCRIPTOR, 418 | containing_type=None, 419 | fields=[ 420 | _descriptor.FieldDescriptor( 421 | name='DeviceName', full_name='icloud.MBSSnapshotAttributes.DeviceName', index=0, 422 | number=1, type=9, cpp_type=9, label=1, 423 | has_default_value=False, default_value=unicode("", "utf-8"), 424 | message_type=None, enum_type=None, containing_type=None, 425 | is_extension=False, extension_scope=None, 426 | options=None), 427 | _descriptor.FieldDescriptor( 428 | name='ProductVersion', full_name='icloud.MBSSnapshotAttributes.ProductVersion', index=1, 429 | number=2, type=9, cpp_type=9, label=1, 430 | has_default_value=False, default_value=unicode("", "utf-8"), 431 | message_type=None, enum_type=None, containing_type=None, 432 | is_extension=False, extension_scope=None, 433 | options=None), 434 | _descriptor.FieldDescriptor( 435 | name='BuildVersion', full_name='icloud.MBSSnapshotAttributes.BuildVersion', index=2, 436 | number=3, type=9, cpp_type=9, label=1, 437 | has_default_value=False, default_value=unicode("", "utf-8"), 438 | message_type=None, enum_type=None, containing_type=None, 439 | is_extension=False, extension_scope=None, 440 | options=None), 441 | _descriptor.FieldDescriptor( 442 | name='KeybagID', full_name='icloud.MBSSnapshotAttributes.KeybagID', index=3, 443 | number=4, type=13, cpp_type=3, label=1, 444 | has_default_value=False, default_value=0, 445 | message_type=None, enum_type=None, containing_type=None, 446 | is_extension=False, extension_scope=None, 447 | options=None), 448 | _descriptor.FieldDescriptor( 449 | name='KeybagUUID', full_name='icloud.MBSSnapshotAttributes.KeybagUUID', index=4, 450 | number=5, type=12, cpp_type=9, label=1, 451 | has_default_value=False, default_value="", 452 | message_type=None, enum_type=None, containing_type=None, 453 | is_extension=False, extension_scope=None, 454 | options=None), 455 | _descriptor.FieldDescriptor( 456 | name='BackupReason', full_name='icloud.MBSSnapshotAttributes.BackupReason', index=5, 457 | number=6, type=5, cpp_type=1, label=1, 458 | has_default_value=False, default_value=0, 459 | message_type=None, enum_type=None, containing_type=None, 460 | is_extension=False, extension_scope=None, 461 | options=None), 462 | _descriptor.FieldDescriptor( 463 | name='BackupType', full_name='icloud.MBSSnapshotAttributes.BackupType', index=6, 464 | number=7, type=5, cpp_type=1, label=1, 465 | has_default_value=False, default_value=0, 466 | message_type=None, enum_type=None, containing_type=None, 467 | is_extension=False, extension_scope=None, 468 | options=None), 469 | ], 470 | extensions=[ 471 | ], 472 | nested_types=[], 473 | enum_types=[ 474 | ], 475 | options=None, 476 | is_extendable=False, 477 | extension_ranges=[], 478 | serialized_start=1046, 479 | serialized_end=1215, 480 | ) 481 | 482 | 483 | _MBSSNAPSHOTID = _descriptor.Descriptor( 484 | name='MBSSnapshotID', 485 | full_name='icloud.MBSSnapshotID', 486 | filename=None, 487 | file=DESCRIPTOR, 488 | containing_type=None, 489 | fields=[ 490 | _descriptor.FieldDescriptor( 491 | name='SnapshotID', full_name='icloud.MBSSnapshotID.SnapshotID', index=0, 492 | number=1, type=13, cpp_type=3, label=1, 493 | has_default_value=False, default_value=0, 494 | message_type=None, enum_type=None, containing_type=None, 495 | is_extension=False, extension_scope=None, 496 | options=None), 497 | ], 498 | extensions=[ 499 | ], 500 | nested_types=[], 501 | enum_types=[ 502 | ], 503 | options=None, 504 | is_extendable=False, 505 | extension_ranges=[], 506 | serialized_start=1217, 507 | serialized_end=1252, 508 | ) 509 | 510 | 511 | _MBSFILEAUTHTOKEN = _descriptor.Descriptor( 512 | name='MBSFileAuthToken', 513 | full_name='icloud.MBSFileAuthToken', 514 | filename=None, 515 | file=DESCRIPTOR, 516 | containing_type=None, 517 | fields=[ 518 | _descriptor.FieldDescriptor( 519 | name='FileID', full_name='icloud.MBSFileAuthToken.FileID', index=0, 520 | number=1, type=12, cpp_type=9, label=2, 521 | has_default_value=False, default_value="", 522 | message_type=None, enum_type=None, containing_type=None, 523 | is_extension=False, extension_scope=None, 524 | options=None), 525 | _descriptor.FieldDescriptor( 526 | name='AuthToken', full_name='icloud.MBSFileAuthToken.AuthToken', index=1, 527 | number=2, type=9, cpp_type=9, label=1, 528 | has_default_value=False, default_value=unicode("", "utf-8"), 529 | message_type=None, enum_type=None, containing_type=None, 530 | is_extension=False, extension_scope=None, 531 | options=None), 532 | ], 533 | extensions=[ 534 | ], 535 | nested_types=[], 536 | enum_types=[ 537 | ], 538 | options=None, 539 | is_extendable=False, 540 | extension_ranges=[], 541 | serialized_start=1254, 542 | serialized_end=1307, 543 | ) 544 | 545 | 546 | _MBSFILEAUTHTOKENS = _descriptor.Descriptor( 547 | name='MBSFileAuthTokens', 548 | full_name='icloud.MBSFileAuthTokens', 549 | filename=None, 550 | file=DESCRIPTOR, 551 | containing_type=None, 552 | fields=[ 553 | _descriptor.FieldDescriptor( 554 | name='tokens', full_name='icloud.MBSFileAuthTokens.tokens', index=0, 555 | number=1, type=11, cpp_type=10, label=3, 556 | has_default_value=False, default_value=[], 557 | message_type=None, enum_type=None, containing_type=None, 558 | is_extension=False, extension_scope=None, 559 | options=None), 560 | ], 561 | extensions=[ 562 | ], 563 | nested_types=[], 564 | enum_types=[ 565 | ], 566 | options=None, 567 | is_extendable=False, 568 | extension_ranges=[], 569 | serialized_start=1309, 570 | serialized_end=1370, 571 | ) 572 | 573 | 574 | _MBSFILEID = _descriptor.Descriptor( 575 | name='MBSFileID', 576 | full_name='icloud.MBSFileID', 577 | filename=None, 578 | file=DESCRIPTOR, 579 | containing_type=None, 580 | fields=[ 581 | _descriptor.FieldDescriptor( 582 | name='FileID', full_name='icloud.MBSFileID.FileID', index=0, 583 | number=1, type=12, cpp_type=9, label=2, 584 | has_default_value=False, default_value="", 585 | message_type=None, enum_type=None, containing_type=None, 586 | is_extension=False, extension_scope=None, 587 | options=None), 588 | ], 589 | extensions=[ 590 | ], 591 | nested_types=[], 592 | enum_types=[ 593 | ], 594 | options=None, 595 | is_extendable=False, 596 | extension_ranges=[], 597 | serialized_start=1372, 598 | serialized_end=1399, 599 | ) 600 | 601 | 602 | _MBSKEY = _descriptor.Descriptor( 603 | name='MBSKey', 604 | full_name='icloud.MBSKey', 605 | filename=None, 606 | file=DESCRIPTOR, 607 | containing_type=None, 608 | fields=[ 609 | _descriptor.FieldDescriptor( 610 | name='KeyID', full_name='icloud.MBSKey.KeyID', index=0, 611 | number=1, type=13, cpp_type=3, label=1, 612 | has_default_value=False, default_value=0, 613 | message_type=None, enum_type=None, containing_type=None, 614 | is_extension=False, extension_scope=None, 615 | options=None), 616 | _descriptor.FieldDescriptor( 617 | name='KeyData', full_name='icloud.MBSKey.KeyData', index=1, 618 | number=2, type=12, cpp_type=9, label=1, 619 | has_default_value=False, default_value="", 620 | message_type=None, enum_type=None, containing_type=None, 621 | is_extension=False, extension_scope=None, 622 | options=None), 623 | ], 624 | extensions=[ 625 | ], 626 | nested_types=[], 627 | enum_types=[ 628 | ], 629 | options=None, 630 | is_extendable=False, 631 | extension_ranges=[], 632 | serialized_start=1401, 633 | serialized_end=1441, 634 | ) 635 | 636 | 637 | _MBSKEYSET = _descriptor.Descriptor( 638 | name='MBSKeySet', 639 | full_name='icloud.MBSKeySet', 640 | filename=None, 641 | file=DESCRIPTOR, 642 | containing_type=None, 643 | fields=[ 644 | _descriptor.FieldDescriptor( 645 | name='Key', full_name='icloud.MBSKeySet.Key', index=0, 646 | number=1, type=11, cpp_type=10, label=3, 647 | has_default_value=False, default_value=[], 648 | message_type=None, enum_type=None, containing_type=None, 649 | is_extension=False, extension_scope=None, 650 | options=None), 651 | ], 652 | extensions=[ 653 | ], 654 | nested_types=[], 655 | enum_types=[ 656 | ], 657 | options=None, 658 | is_extendable=False, 659 | extension_ranges=[], 660 | serialized_start=1443, 661 | serialized_end=1483, 662 | ) 663 | 664 | 665 | _MBSFILEEXTENDEDATTRIBUTE = _descriptor.Descriptor( 666 | name='MBSFileExtendedAttribute', 667 | full_name='icloud.MBSFileExtendedAttribute', 668 | filename=None, 669 | file=DESCRIPTOR, 670 | containing_type=None, 671 | fields=[ 672 | _descriptor.FieldDescriptor( 673 | name='Name', full_name='icloud.MBSFileExtendedAttribute.Name', index=0, 674 | number=1, type=9, cpp_type=9, label=1, 675 | has_default_value=False, default_value=unicode("", "utf-8"), 676 | message_type=None, enum_type=None, containing_type=None, 677 | is_extension=False, extension_scope=None, 678 | options=None), 679 | _descriptor.FieldDescriptor( 680 | name='Value', full_name='icloud.MBSFileExtendedAttribute.Value', index=1, 681 | number=2, type=12, cpp_type=9, label=1, 682 | has_default_value=False, default_value="", 683 | message_type=None, enum_type=None, containing_type=None, 684 | is_extension=False, extension_scope=None, 685 | options=None), 686 | ], 687 | extensions=[ 688 | ], 689 | nested_types=[], 690 | enum_types=[ 691 | ], 692 | options=None, 693 | is_extendable=False, 694 | extension_ranges=[], 695 | serialized_start=1485, 696 | serialized_end=1540, 697 | ) 698 | 699 | _MBSBACKUP.fields_by_name['Snapshot'].message_type = _MBSSNAPSHOT 700 | _MBSBACKUP.fields_by_name['Attributes'].message_type = _MBSBACKUPATTRIBUTES 701 | _MBSFILE.fields_by_name['Attributes'].message_type = _MBSFILEATTRIBUTES 702 | _MBSFILEATTRIBUTES.fields_by_name['ExtendedAttribute'].message_type = _MBSFILEEXTENDEDATTRIBUTE 703 | _MBSSNAPSHOT.fields_by_name['Attributes'].message_type = _MBSSNAPSHOTATTRIBUTES 704 | _MBSFILEAUTHTOKENS.fields_by_name['tokens'].message_type = _MBSFILEAUTHTOKEN 705 | _MBSKEYSET.fields_by_name['Key'].message_type = _MBSKEY 706 | DESCRIPTOR.message_types_by_name['MBSAccount'] = _MBSACCOUNT 707 | DESCRIPTOR.message_types_by_name['MBSBackup'] = _MBSBACKUP 708 | DESCRIPTOR.message_types_by_name['MBSBackupAttributes'] = _MBSBACKUPATTRIBUTES 709 | DESCRIPTOR.message_types_by_name['MBSFile'] = _MBSFILE 710 | DESCRIPTOR.message_types_by_name['MBSFileAttributes'] = _MBSFILEATTRIBUTES 711 | DESCRIPTOR.message_types_by_name['MBSSnapshot'] = _MBSSNAPSHOT 712 | DESCRIPTOR.message_types_by_name['MBSSnapshotAttributes'] = _MBSSNAPSHOTATTRIBUTES 713 | DESCRIPTOR.message_types_by_name['MBSSnapshotID'] = _MBSSNAPSHOTID 714 | DESCRIPTOR.message_types_by_name['MBSFileAuthToken'] = _MBSFILEAUTHTOKEN 715 | DESCRIPTOR.message_types_by_name['MBSFileAuthTokens'] = _MBSFILEAUTHTOKENS 716 | DESCRIPTOR.message_types_by_name['MBSFileID'] = _MBSFILEID 717 | DESCRIPTOR.message_types_by_name['MBSKey'] = _MBSKEY 718 | DESCRIPTOR.message_types_by_name['MBSKeySet'] = _MBSKEYSET 719 | DESCRIPTOR.message_types_by_name['MBSFileExtendedAttribute'] = _MBSFILEEXTENDEDATTRIBUTE 720 | 721 | class MBSAccount(_message.Message): 722 | __metaclass__ = _reflection.GeneratedProtocolMessageType 723 | DESCRIPTOR = _MBSACCOUNT 724 | 725 | # @@protoc_insertion_point(class_scope:icloud.MBSAccount) 726 | 727 | class MBSBackup(_message.Message): 728 | __metaclass__ = _reflection.GeneratedProtocolMessageType 729 | DESCRIPTOR = _MBSBACKUP 730 | 731 | # @@protoc_insertion_point(class_scope:icloud.MBSBackup) 732 | 733 | class MBSBackupAttributes(_message.Message): 734 | __metaclass__ = _reflection.GeneratedProtocolMessageType 735 | DESCRIPTOR = _MBSBACKUPATTRIBUTES 736 | 737 | # @@protoc_insertion_point(class_scope:icloud.MBSBackupAttributes) 738 | 739 | class MBSFile(_message.Message): 740 | __metaclass__ = _reflection.GeneratedProtocolMessageType 741 | DESCRIPTOR = _MBSFILE 742 | 743 | # @@protoc_insertion_point(class_scope:icloud.MBSFile) 744 | 745 | class MBSFileAttributes(_message.Message): 746 | __metaclass__ = _reflection.GeneratedProtocolMessageType 747 | DESCRIPTOR = _MBSFILEATTRIBUTES 748 | 749 | # @@protoc_insertion_point(class_scope:icloud.MBSFileAttributes) 750 | 751 | class MBSSnapshot(_message.Message): 752 | __metaclass__ = _reflection.GeneratedProtocolMessageType 753 | DESCRIPTOR = _MBSSNAPSHOT 754 | 755 | # @@protoc_insertion_point(class_scope:icloud.MBSSnapshot) 756 | 757 | class MBSSnapshotAttributes(_message.Message): 758 | __metaclass__ = _reflection.GeneratedProtocolMessageType 759 | DESCRIPTOR = _MBSSNAPSHOTATTRIBUTES 760 | 761 | # @@protoc_insertion_point(class_scope:icloud.MBSSnapshotAttributes) 762 | 763 | class MBSSnapshotID(_message.Message): 764 | __metaclass__ = _reflection.GeneratedProtocolMessageType 765 | DESCRIPTOR = _MBSSNAPSHOTID 766 | 767 | # @@protoc_insertion_point(class_scope:icloud.MBSSnapshotID) 768 | 769 | class MBSFileAuthToken(_message.Message): 770 | __metaclass__ = _reflection.GeneratedProtocolMessageType 771 | DESCRIPTOR = _MBSFILEAUTHTOKEN 772 | 773 | # @@protoc_insertion_point(class_scope:icloud.MBSFileAuthToken) 774 | 775 | class MBSFileAuthTokens(_message.Message): 776 | __metaclass__ = _reflection.GeneratedProtocolMessageType 777 | DESCRIPTOR = _MBSFILEAUTHTOKENS 778 | 779 | # @@protoc_insertion_point(class_scope:icloud.MBSFileAuthTokens) 780 | 781 | class MBSFileID(_message.Message): 782 | __metaclass__ = _reflection.GeneratedProtocolMessageType 783 | DESCRIPTOR = _MBSFILEID 784 | 785 | # @@protoc_insertion_point(class_scope:icloud.MBSFileID) 786 | 787 | class MBSKey(_message.Message): 788 | __metaclass__ = _reflection.GeneratedProtocolMessageType 789 | DESCRIPTOR = _MBSKEY 790 | 791 | # @@protoc_insertion_point(class_scope:icloud.MBSKey) 792 | 793 | class MBSKeySet(_message.Message): 794 | __metaclass__ = _reflection.GeneratedProtocolMessageType 795 | DESCRIPTOR = _MBSKEYSET 796 | 797 | # @@protoc_insertion_point(class_scope:icloud.MBSKeySet) 798 | 799 | class MBSFileExtendedAttribute(_message.Message): 800 | __metaclass__ = _reflection.GeneratedProtocolMessageType 801 | DESCRIPTOR = _MBSFILEEXTENDEDATTRIBUTE 802 | 803 | # @@protoc_insertion_point(class_scope:icloud.MBSFileExtendedAttribute) 804 | 805 | 806 | # @@protoc_insertion_point(module_scope) 807 | -------------------------------------------------------------------------------- /iloot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackappcom/iloot/9362ac94dbb77a611e654f0622c89cb7ad31ed8a/iloot.png -------------------------------------------------------------------------------- /iloot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # from __future__ import print_function 3 | 4 | import gevent 5 | from gevent.pool import Pool 6 | from gevent import monkey 7 | monkey.patch_all() 8 | 9 | from datetime import datetime 10 | from httplib import HTTPSConnection 11 | from pprint import pprint 12 | import ssl, socket 13 | import argparse 14 | import base64 15 | import errno 16 | import hashlib 17 | import os 18 | import plistlib 19 | import re 20 | import struct 21 | import urllib 22 | import urlparse 23 | 24 | import hurry.filesize 25 | from chunkserver_pb2 import FileGroups 26 | from crypto.aes import AESencryptCBC, AESdecryptCBC, AESdecryptCFB 27 | from icloud_pb2 import MBSAccount, MBSBackup, MBSKeySet, MBSFile, MBSFileAuthToken, MBSFileAuthTokens 28 | from keystore.keybag import Keybag 29 | from pbuf import decode_protobuf_array, encode_protobuf_array 30 | from util import hexdump 31 | 32 | CLIENT_INFO = " " 33 | USER_AGENT_UBD = "ubd (unknown version) CFNetwork/548.1.4 Darwin/11.0.0" 34 | USER_AGENT_MOBILE_BACKUP = "MobileBackup/9.0.2 (13A452; iPhone6,2)" 35 | USER_AGENT_BACKUPD = "backupd (unknown version) CFNetwork/548.1.4 Darwin/11.0.0" 36 | CLIENT_INFO_BACKUP = " " 37 | DEFAULT_THREADS = 100 38 | DOWNLOAD_CHUNKS_ATTEMPTS_MAX = 10 39 | ITEM_TYPES_TO_FILE_NAMES = { 40 | 'address_book': "addressbook.sqlitedb", 41 | 'calendar': "Calendar.sqlitedb", 42 | 'call_history': "call_history.db", 43 | 'photos': ".jpg", 44 | 'movies':".mov", 45 | 'sms': "sms.db", 46 | 'voicemails': "voicemail", 47 | 'notes' : "notes." 48 | } 49 | 50 | def mkdir_p(path): 51 | try: 52 | os.makedirs(path) 53 | except OSError as exc: # Python >2.5 54 | if exc.errno == errno.EEXIST and os.path.isdir(path): 55 | pass 56 | else: 57 | raise 58 | 59 | #XXX handle all signature types 60 | def chunk_signature(data): 61 | h = hashlib.sha256(data).digest() 62 | return hashlib.sha256(h).digest()[:20] 63 | 64 | def decrypt_chunk(data, chunk_encryption_key, chunk_checksum): 65 | clear = AESdecryptCFB(data, chunk_encryption_key[1:]) 66 | if chunk_checksum[1:] == chunk_signature(clear): 67 | return clear 68 | 69 | print "chunk decryption Failed" 70 | return None 71 | 72 | def plist_request(host, method, url, body, headers): 73 | conn = HTTPSConnection(host) 74 | sock = socket.create_connection((conn.host, conn.port), conn.timeout, conn.source_address) 75 | conn.sock = ssl.wrap_socket(sock, conn.key_file, conn.cert_file, ssl_version=ssl.PROTOCOL_TLSv1) 76 | request = conn.request(method, url, body, headers) 77 | response = conn.getresponse() 78 | 79 | data = response.read() 80 | try: 81 | plist_data = plistlib.readPlistFromString(data) 82 | except: 83 | plist_data = None 84 | 85 | if response.status != 200: 86 | if plist_data is None: 87 | print "Request %s returned code %d" % (url, response.status) 88 | else: 89 | print "{}: {}".format(plist_data.title, plist_data.message) 90 | 91 | return 92 | 93 | return plist_data 94 | 95 | def probobuf_request(host, method, url, body, headers, msg=None): 96 | conn = HTTPSConnection(host) 97 | sock = socket.create_connection((conn.host, conn.port), conn.timeout, conn.source_address) 98 | conn.sock = ssl.wrap_socket(sock, conn.key_file, conn.cert_file, ssl_version=ssl.PROTOCOL_TLSv1) 99 | request = conn.request(method, url, body, headers) 100 | response = conn.getresponse() 101 | length = response.getheader("content-length") 102 | 103 | if length is None: 104 | length = 0 105 | else: 106 | length = int(length) 107 | 108 | data = response.read() 109 | 110 | while len(data) < length: 111 | d = response.read() 112 | data += d 113 | 114 | conn.close() 115 | if msg == None: 116 | return data 117 | 118 | res = msg() 119 | res.ParseFromString(data) 120 | return res 121 | 122 | 123 | class URLFactory(object): 124 | def __init__(self, base=None): 125 | self.components = [] 126 | self.base = base 127 | 128 | if self.base is not None: 129 | self.components.append(self.base) 130 | 131 | def __getattr__(self, k): 132 | self.components.append(k) 133 | return self 134 | 135 | def __getitem__(self, k): 136 | self.components.append(str(k)) 137 | return self 138 | 139 | def __call__(self, *args, **kwargs): 140 | url = "/{}".format("/".join(self.components)) 141 | 142 | self.components = [] 143 | if self.base is not None: 144 | self.components.append(self.base) 145 | 146 | if len(kwargs) > 0: 147 | params = urllib.urlencode(kwargs) 148 | return "{}?{}".format(url, params) 149 | else: 150 | return url 151 | 152 | 153 | MBS = URLFactory("mbs") 154 | URL = URLFactory() 155 | 156 | def host_from_url(url): 157 | return urlparse.urlparse(url).hostname 158 | 159 | class MobileBackupClient(object): 160 | def __init__(self, account_settings, dsPrsID, auth, output_folder): 161 | mobilebackup_url = account_settings["com.apple.mobileme"]["com.apple.Dataclass.Backup"]["url"] 162 | content_url = account_settings["com.apple.mobileme"]["com.apple.Dataclass.Content"]["url"] 163 | 164 | self.mobilebackup_host = host_from_url(mobilebackup_url) 165 | self.content_host = host_from_url(content_url) 166 | self.dsPrsID = dsPrsID 167 | self.headers = { 168 | 'Authorization': auth, 169 | 'X-MMe-Client-Info': CLIENT_INFO, 170 | 'User-Agent': USER_AGENT_MOBILE_BACKUP, 171 | 'X-Apple-MBS-Protocol-Version': "1.7" 172 | } 173 | self.headers2 = { 174 | 'x-apple-mmcs-proto-version': "3.3", 175 | 'x-apple-mmcs-dataclass': "com.apple.Dataclass.Backup", 176 | 'x-apple-mme-dsid': str(self.dsPrsID), 177 | 'User-Agent': USER_AGENT_BACKUPD, 178 | 'Accept': "application/vnd.com.apple.me.ubchunk+protobuf", 179 | 'Content-Type': "application/vnd.com.apple.me.ubchunk+protobuf", 180 | 'x-mme-client-info': CLIENT_INFO_BACKUP 181 | } 182 | 183 | self.files = {} 184 | self.output_folder = output_folder 185 | 186 | self.chosen_snapshot_id = None 187 | self.combined = False 188 | self.itunes_style = False 189 | self.downloaded_files = [] 190 | self.domain_filter = None 191 | self.threads = DEFAULT_THREADS 192 | 193 | def mobile_backup_request(self, method, url, msg=None, body=""): 194 | return probobuf_request(self.mobilebackup_host, method, url, body, self.headers, msg) 195 | 196 | def get_account(self): 197 | return self.mobile_backup_request("GET", MBS[self.dsPrsID](), MBSAccount) 198 | 199 | def get_backup(self, backupUDID): 200 | return self.mobile_backup_request("GET", MBS[self.dsPrsID][backupUDID.encode("hex")](), MBSBackup) 201 | 202 | def get_keys(self, backupUDID): 203 | return self.mobile_backup_request("GET", MBS[self.dsPrsID][backupUDID.encode("hex")].getKeys(), MBSKeySet) 204 | 205 | def list_files(self, backupUDID, snapshotId): 206 | limit = 5000 207 | files = "" 208 | 209 | offset = 0 210 | new_files = self.mobile_backup_request("GET", MBS[self.dsPrsID][backupUDID.encode("hex")][snapshotId]['listFiles'](offset=offset, limit=limit)) 211 | while new_files: 212 | files = files + new_files 213 | offset += limit 214 | 215 | new_files = self.mobile_backup_request("GET", MBS[self.dsPrsID][backupUDID.encode("hex")][snapshotId].listFiles(offset=offset, limit=limit)) 216 | print "\tShifting offset: ", offset 217 | 218 | return decode_protobuf_array(files, MBSFile) 219 | 220 | def get_files(self, backupUDID, snapshotId, files): 221 | r = [] 222 | h = {} 223 | for file in files: 224 | if file.Size == 0: 225 | continue 226 | 227 | ff = MBSFile() 228 | ff.FileID = file.FileID 229 | h[file.FileID] = file.Signature 230 | r.append(ff) 231 | self.files[file.Signature] = file 232 | 233 | body = encode_protobuf_array(r) 234 | z = self.mobile_backup_request("POST", MBS[self.dsPrsID][backupUDID.encode("hex")][snapshotId].getFiles(), None, body) 235 | tokens = decode_protobuf_array(z, MBSFileAuthToken) 236 | z = MBSFileAuthTokens() 237 | 238 | for token in tokens: 239 | toto = z.tokens.add() 240 | toto.FileID = h[token.FileID] 241 | toto.AuthToken = token.AuthToken 242 | 243 | return z 244 | 245 | def authorize_get(self, tokens, snapshot): 246 | if len(tokens.tokens) == 0: 247 | return 248 | 249 | self.headers2["x-apple-mmcs-auth"]= "%s %s" % (tokens.tokens[0].FileID.encode("hex"), tokens.tokens[0].AuthToken) 250 | body = tokens.SerializeToString() 251 | 252 | file_groups = probobuf_request(self.content_host, "POST", URL[self.dsPrsID].authorizeGet(), body, self.headers2, FileGroups) 253 | file_chunks = {} 254 | pool = Pool(self.threads) 255 | 256 | containers = [] 257 | for group in file_groups.file_groups: 258 | for container_index, container in enumerate(group.storage_host_chunk_list): 259 | containers.append([group, container_index, container]) 260 | 261 | for res in pool.imap_unordered(self.download_chunks, containers): 262 | args, data = res 263 | group, container_index, container = args 264 | 265 | for file_ref in group.file_checksum_chunk_references: 266 | if file_ref.file_checksum not in self.files: 267 | continue 268 | 269 | decrypted_chunks = file_chunks.setdefault(file_ref.file_checksum, {}) 270 | 271 | for i, reference in enumerate(file_ref.chunk_references): 272 | if reference.container_index == container_index: 273 | if (len(data) > reference.chunk_index): 274 | decrypted_chunks[i] = data[reference.chunk_index] 275 | else: 276 | break 277 | 278 | if len(decrypted_chunks) == len(file_ref.chunk_references): 279 | file = self.files[file_ref.file_checksum] 280 | try: 281 | self.write_file(file, decrypted_chunks, snapshot) 282 | except: 283 | raise 284 | else: 285 | # With iTunes style we need to keep the file 286 | if self.itunes_style : 287 | self.downloaded_files.append(file) 288 | 289 | del self.files[file_ref.file_checksum] 290 | 291 | pool.join() 292 | return file_groups 293 | 294 | def get_complete(self, mmcs_auth): 295 | self.headers2["x-apple-mmcs-auth"] = mmcs_auth 296 | body = "" 297 | probobuf_request(self.content_host, "POST", URL[self.dsPrsID].getComplete(), body, self.headers2) 298 | 299 | def download_chunks(self, args): 300 | group, container_index, container = args 301 | 302 | headers = {} 303 | # XXX 304 | for header in container.host_info.headers: 305 | headers[header.name] = header.value 306 | 307 | # Attempt to download chunks in the container maximum of DOWNLOAD_CHUNKS_ATTEMPTS_MAX times. Re-raise 308 | # the exception if still not successful. 309 | attempts = DOWNLOAD_CHUNKS_ATTEMPTS_MAX 310 | while attempts: 311 | try: 312 | d = probobuf_request(container.host_info.hostname, 313 | container.host_info.method, 314 | container.host_info.uri, "", headers) 315 | 316 | if attempts < DOWNLOAD_CHUNKS_ATTEMPTS_MAX: 317 | print "Downloading chunks (container %d) - success on attempt %d" % \ 318 | (container_index, DOWNLOAD_CHUNKS_ATTEMPTS_MAX - attempts + 1) 319 | 320 | except Exception as e: 321 | print "Error downloading chunks (container %d) (%s) attempt %d of %d" % \ 322 | (container_index, repr(e), DOWNLOAD_CHUNKS_ATTEMPTS_MAX - attempts + 1, DOWNLOAD_CHUNKS_ATTEMPTS_MAX) 323 | attempts -= 1 324 | if 0 == attempts: 325 | raise 326 | else: 327 | break 328 | 329 | decrypted = [] 330 | i = 0 331 | for chunk in container.chunk_info: 332 | dchunk = decrypt_chunk(d[i:i+chunk.chunk_length], chunk.chunk_encryption_key, chunk.chunk_checksum) 333 | if dchunk: 334 | decrypted.append(dchunk) 335 | i += chunk.chunk_length 336 | 337 | return args, decrypted 338 | 339 | def write_file(self, file, decrypted_chunks, snapshot): 340 | path = self.create_output_path(file, snapshot) 341 | 342 | mkdir_p(os.path.dirname(path)) 343 | 344 | print '\t', file.Domain, '\t', path 345 | with open(path, "wb") as ff: 346 | hash = hashlib.sha1() 347 | for key, chunk in decrypted_chunks.iteritems(): 348 | hash.update(chunk) 349 | ff.write(chunk) 350 | 351 | # If file is encrypted 352 | if file.Attributes.EncryptionKey: 353 | key = file.Attributes.EncryptionKey 354 | ProtectionClass = struct.unpack(">L", key[0x18:0x1C])[0] 355 | if ProtectionClass == file.Attributes.ProtectionClass: 356 | wrapped_key = None 357 | filekey = None 358 | if file.Attributes.EncryptionKeyVersion and file.Attributes.EncryptionKeyVersion == 2: 359 | if self.kb.uuid == key[:0x10]: 360 | keyLength = struct.unpack(">L", key[0x20:0x24])[0] 361 | if keyLength == 0x48: 362 | wrapped_key = key[0x24:] 363 | else: 364 | wrapped_key = key[0x1C:] 365 | 366 | if wrapped_key: 367 | filekey = self.kb.unwrapCurve25519(ProtectionClass, wrapped_key) 368 | 369 | if not filekey: 370 | print "Failed to unwrap file key for file %s !!!" % file.RelativePath 371 | else: 372 | print "\tfilekey", filekey.encode("hex") 373 | self.decrypt_protected_file(path, filekey, file.Attributes.DecryptedSize) 374 | else: 375 | print "\tUnable to decrypt file, possible old backup format", file.RelativePath 376 | 377 | def create_output_path(self, file, snapshot): 378 | # If the filename should be left in the iTunes backup style 379 | if self.itunes_style: 380 | if self.combined: 381 | directory = self.output_folder 382 | else: 383 | directory = os.path.join(self.output_folder, "snapshot_"+str(snapshot)) 384 | 385 | path_hash = hashlib.sha1(file.Domain.encode('utf-8')+"-"+file.RelativePath.encode('utf-8')).hexdigest() 386 | path = os.path.join(directory, path_hash) 387 | else: 388 | if self.combined: 389 | directory = os.path.join(self.output_folder, re.sub(r'[:|*<>?"]', "_", file.Domain)) 390 | path = os.path.join(directory, file.RelativePath) 391 | else: 392 | directory = os.path.join(self.output_folder, re.sub(r'[:|*<>?"]', "_", "snapshot_"+str(snapshot)+"/"+file.Domain)) 393 | path = os.path.join(directory, file.RelativePath) 394 | 395 | return path 396 | 397 | def decrypt_protected_file(self, path, filekey, decrypted_size=0): 398 | ivkey = hashlib.sha1(filekey).digest()[:16] 399 | hash = hashlib.sha1() 400 | sz = os.path.getsize(path) 401 | 402 | oldpath = path + ".encrypted" 403 | try: 404 | os.rename(path, oldpath) 405 | except: 406 | pass 407 | 408 | with open(oldpath, "rb") as old_file: 409 | with open(path, "wb") as new_file: 410 | n = sz / 0x1000 411 | if decrypted_size: 412 | n += 1 413 | 414 | for block in xrange(n): 415 | iv = AESencryptCBC(self.computeIV(block * 0x1000), ivkey) 416 | old_data = old_file.read(0x1000) 417 | hash.update(old_data) 418 | new_file.write(AESdecryptCBC(old_data, filekey, iv)) 419 | 420 | if decrypted_size == 0: #old iOS 5 format 421 | trailer = old_file.read(0x1C) 422 | decrypted_size = struct.unpack(">Q", trailer[:8])[0] 423 | assert hash.digest() == trailer[8:] 424 | 425 | new_file.truncate(decrypted_size) 426 | old_file.close() 427 | os.remove(oldpath) # Delete the encrypted file 428 | 429 | def computeIV(self, lba): 430 | iv = "" 431 | lba &= 0xffffffff 432 | for _ in xrange(4): 433 | if (lba & 1): 434 | lba = 0x80000061 ^ (lba >> 1) 435 | else: 436 | lba = lba >> 1 437 | 438 | iv += struct.pack(" 3: 469 | snapshot_list = [1, mbsbackup.Snapshot.SnapshotID - 1, mbsbackup.Snapshot.SnapshotID] 470 | else: 471 | snapshot_list = range(1, mbsbackup.Snapshot.SnapshotID + 1) 472 | elif self.chosen_snapshot_id < 0: 473 | snapshot_list = [mbsbackup.Snapshot.SnapshotID + self.chosen_snapshot_id + 1] # Remember chosen_snapshot_id is negative 474 | else: 475 | snapshot_list = [self.chosen_snapshot_id] 476 | 477 | for snapshot in snapshot_list: 478 | print "Listing snapshot %d..." % (snapshot) 479 | files = self.list_files(backupUDID, snapshot) 480 | print "Files in snapshot %d" % (len(files)) 481 | 482 | def matches_allowed_domain(a_file): 483 | return self.domain_filter in a_file.Domain 484 | 485 | def matches_allowed_item_types(a_file): 486 | return any(ITEM_TYPES_TO_FILE_NAMES[item_type] in a_file.RelativePath.lower() \ 487 | for item_type in item_types) 488 | 489 | def matches_missing_or_partial_files(a_file): 490 | path = self.create_output_path(a_file, snapshot) 491 | return not os.path.isfile(path) or os.stat(path).st_size != a_file.Size 492 | 493 | if self.domain_filter: 494 | files = filter(matches_allowed_domain, files) 495 | 496 | if len(item_types) > 0: 497 | files = filter(matches_allowed_item_types, files) 498 | 499 | print "Downloading %d files due to filter" % (len(files)) 500 | 501 | if (self.keep_existing): 502 | file_count = len(files) 503 | files = filter(matches_missing_or_partial_files, files) 504 | print "Skipping %d files that have already been downloaded, " \ 505 | "downloading %d files" % ((file_count - len(files)), len(files)) 506 | 507 | if len(files): 508 | authTokens = self.get_files(backupUDID, snapshot, files) 509 | if len(authTokens.tokens) > 0: 510 | self.authorize_get(authTokens, snapshot) 511 | 512 | if self.itunes_style: 513 | self.write_info_plist(mbsbackup, snapshot) 514 | self.write_manifest_mbdb(snapshot) 515 | else: 516 | print "Unable to download snapshot. This snapshot may not have finished uploading yet." 517 | 518 | # Clean up self.files 519 | if not self.combined : 520 | self.downloaded_files = [] 521 | 522 | 523 | # Writes a plist file in the output_directory simular to that created by iTunes during backup 524 | def write_info_plist(self, mbsbackup, snapshot): 525 | if self.combined: 526 | directory = self.output_folder 527 | else: 528 | directory = os.path.join(self.output_folder, "snapshot_"+str(snapshot)) 529 | 530 | info_plist = { 531 | "Device Name" : mbsbackup.Attributes.DeviceClass, 532 | "Display Name" : mbsbackup.Attributes.DeviceClass, 533 | "Product Type" : mbsbackup.Attributes.ProductType, 534 | "Serial Number" : mbsbackup.Attributes.SerialNumber, 535 | "Target Type" : "Device", 536 | "iTunes Version" : "12.3", 537 | "Product Version" : "9.0.2", # Must be higher than 4.0, current iTunes backup sets to 8.1.1 538 | "Target Identifier" : mbsbackup.backupUDID.encode("hex"), 539 | "Unique Identifier" : mbsbackup.backupUDID.encode("hex") 540 | } 541 | 542 | with open(directory+"/Info.plist", 'wb') as fp: 543 | plistlib.writePlist(info_plist, fp) 544 | 545 | def write_manifest_mbdb(self, snapshot): 546 | if self.combined: 547 | directory = self.output_folder 548 | else: 549 | directory = os.path.join(self.output_folder, "snapshot_"+str(snapshot)) 550 | 551 | filename = os.path.join(directory, "Manifest.mbdb") 552 | 553 | # Generate the bare minimum MBDB file 554 | 555 | # Open file 556 | mbdb_file = open(filename, "wb") 557 | 558 | # Write file header 559 | mbdb_file.write("mbdb") 560 | mbdb_file.write("\x00\x00") 561 | 562 | # For each file 563 | for file in self.downloaded_files: 564 | # Write App Domain length 565 | mbdb_file.write( struct.pack('>h', len(file.Domain)) ) 566 | # Write App Domain 567 | mbdb_file.write( file.Domain ) 568 | # Write iPhone Filename length 569 | mbdb_file.write( struct.pack('>h', len(file.RelativePath)) ) 570 | # Write iPhone Filename 571 | mbdb_file.write( file.RelativePath ) 572 | # Write 0xFFFF for Link Target Length signifying that it is not present 573 | mbdb_file.write("\xFF\xFF") 574 | # Write 0xFFFF for SHAChecksum Length signifying the checksum is not present 575 | mbdb_file.write("\xFF\xFF") 576 | # Write 0xFFFF for the length of some unknown value, signifying it is not present 577 | mbdb_file.write("\xFF\xFF") 578 | # Write 0x27 bytes of 0x00, for the file properties as set by the iPhone during restore 579 | mbdb_file.write("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") 580 | # Write 0x00 for extended property count 581 | mbdb_file.write("\x00") 582 | 583 | # Close file 584 | mbdb_file.close() 585 | 586 | 587 | def download_backup(login, password, output_folder, types, chosen_snapshot_id, combined, itunes_style, domain, threads, keep_existing): 588 | print 'Working with %s : %s' % (login, password) 589 | print 'Output directory :', output_folder 590 | 591 | auth = "Basic %s" % base64.b64encode("%s:%s" % (login, password)) 592 | authenticateResponse = plist_request("setup.icloud.com", "POST", "/setup/authenticate/$APPLE_ID$", "", {"Authorization": auth}) 593 | if not authenticateResponse: 594 | # There was an error authenticating the user. 595 | return 596 | 597 | dsPrsID = authenticateResponse["appleAccountInfo"]["dsPrsID"] 598 | auth = "Basic %s" % base64.b64encode("%s:%s" % (dsPrsID, authenticateResponse["tokens"]["mmeAuthToken"])) 599 | 600 | headers = { 601 | 'Authorization': auth, 602 | 'X-MMe-Client-Info': CLIENT_INFO, 603 | 'User-Agent': USER_AGENT_UBD 604 | } 605 | account_settings = plist_request("setup.icloud.com", "POST", "/setup/get_account_settings", "", headers) 606 | auth = "X-MobileMe-AuthToken %s" % base64.b64encode("%s:%s" % (dsPrsID, authenticateResponse["tokens"]["mmeAuthToken"])) 607 | client = MobileBackupClient(account_settings, dsPrsID, auth, output_folder) 608 | 609 | client.chosen_snapshot_id = chosen_snapshot_id 610 | client.combined = combined 611 | client.itunes_style = itunes_style 612 | client.domain_filter = domain 613 | client.threads = threads 614 | client.keep_existing = keep_existing 615 | 616 | mbsacct = client.get_account() 617 | 618 | print "Available Devices: ", len(mbsacct.backupUDID) 619 | if len(mbsacct.backupUDID) > 0: 620 | for i, device in enumerate(mbsacct.backupUDID): 621 | backup = client.get_backup(device) 622 | print "===[", i, "]===" 623 | print "\tUDID: ", backup.backupUDID.encode("hex") 624 | print "\tDevice: ", backup.Attributes.MarketingName 625 | print "\tVersion: ", backup.Snapshot.Attributes.ProductVersion 626 | print "\tSize: ", hurry.filesize.size(backup.QuotaUsed) 627 | print "\tLastUpdate: ", datetime.utcfromtimestamp(backup.Snapshot.LastModified) 628 | 629 | if i == 0: 630 | UDID = mbsacct.backupUDID[0] 631 | else: 632 | id = raw_input("\nSelect backup to download (0-{}): ".format(i)) 633 | UDID = mbsacct.backupUDID[int(id)] 634 | 635 | client.download(UDID, types) 636 | 637 | else: 638 | print "There are no backups to download!" 639 | 640 | def backup_summary(mbsbackup): 641 | d = datetime.utcfromtimestamp(mbsbackup.Snapshot.LastModified) 642 | return "%s %s %s %s" % (str(d), mbsbackup.Attributes.MarketingName, mbsbackup.Snapshot.Attributes.DeviceName, mbsbackup.Snapshot.Attributes.ProductVersion) 643 | 644 | if __name__ == "__main__": 645 | parser = argparse.ArgumentParser(prog='iloot') 646 | parser.add_argument("apple_id", type=str, default=None, help="Apple ID") 647 | parser.add_argument("password", type=str, default=None, help="Password") 648 | 649 | parser.add_argument("--threads", type=int, default=DEFAULT_THREADS, help="Download thread pool size") 650 | parser.add_argument("--output", "-o", type=str, default="output", 651 | help="Output Directory") 652 | 653 | parser.add_argument("--combined", action="store_true", 654 | help="Do not separate each snapshot into its own folder") 655 | 656 | parser.add_argument("--snapshot", type=int, default=None, 657 | help="Only download data the snapshot with the specified ID. " \ 658 | "Negative numbers will indicate relative position from " \ 659 | "newest backup, with -1 being the newest, -2 second, etc.") 660 | 661 | parser.add_argument("--itunes-style", action="store_true", 662 | help="Save the files in a flat iTunes-style backup, with " \ 663 | "mangled names") 664 | 665 | parser.add_argument("--item-types", "-t", nargs="+", type=str, default="", 666 | help="Only download the specified item types. Options include " \ 667 | "address_book, calendar, sms, call_history, voicemails, " \ 668 | "movies and photos. E.g., --types sms voicemail") 669 | 670 | parser.add_argument("--domain", "-d", type=str, default=None, 671 | help="Limit files to those within a specific application domain") 672 | 673 | parser.add_argument("--keep-existing", action="store_true", 674 | help="Do not download files that has already been downloaded in " \ 675 | "a previous run. Skip files that already exist locally " \ 676 | "and that has the same file size locally as in the backup.") 677 | 678 | args = parser.parse_args() 679 | download_backup(args.apple_id, args.password, args.output, args.item_types, args.snapshot, args.combined, args.itunes_style, args.domain, args.threads, args.keep_existing) 680 | 681 | -------------------------------------------------------------------------------- /keystore/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackappcom/iloot/9362ac94dbb77a611e654f0622c89cb7ad31ed8a/keystore/__init__.py -------------------------------------------------------------------------------- /keystore/effaceable.py: -------------------------------------------------------------------------------- 1 | from construct import RepeatUntil 2 | from construct.core import Struct, Union 3 | from construct.macros import * 4 | from crypto.aes import AESdecryptCBC 5 | from crypto.aeswrap import AESUnwrap 6 | from zipfile import crc32 7 | import struct 8 | 9 | Dkey = 0x446B6579 10 | EMF = 0x454D4621 11 | BAG1 = 0x42414731 12 | DONE = 0x444f4e45 #locker sentinel 13 | #**** = 0x2A2A2A2A #wildcard for erase 14 | 15 | #MAGIC (kL) | LEN (2bytes) | TAG (4) | DATA (LEN) 16 | Locker = Struct("Locker", 17 | String("magic",2), 18 | ULInt16("length"), 19 | Union("tag", 20 | ULInt32("int"), 21 | String("tag",4)) 22 | , 23 | String("data", lambda ctx: ctx["length"]) 24 | ) 25 | 26 | Lockers = RepeatUntil(lambda obj, ctx: obj.tag.int == DONE, Locker) 27 | 28 | def xor_strings(s, key): 29 | res = "" 30 | for i in xrange(len(s)): 31 | res += chr(ord(s[i]) ^ ord(key[i%len(key)])) 32 | return res 33 | 34 | def check_effaceable_header(plog): 35 | z = xor_strings(plog[:16], plog[16:32]) 36 | if z[:4] != "ecaF": 37 | return False 38 | plog_generation = struct.unpack("= iPad 3) 22 | FLAG_UNKNOWN = 0x80000000 23 | 24 | WRAP_DEVICE = 1 25 | WRAP_PASSCODE = 2 26 | 27 | KEY_TYPES = ["AES", "Curve25519"] 28 | PROTECTION_CLASSES={ 29 | 1:"NSFileProtectionComplete", 30 | 2:"NSFileProtectionCompleteUnlessOpen", 31 | 3:"NSFileProtectionCompleteUntilFirstUserAuthentication", 32 | 4:"NSFileProtectionNone", 33 | 5:"NSFileProtectionRecovery?", 34 | 35 | 6: "kSecAttrAccessibleWhenUnlocked", 36 | 7: "kSecAttrAccessibleAfterFirstUnlock", 37 | 8: "kSecAttrAccessibleAlways", 38 | 9: "kSecAttrAccessibleWhenUnlockedThisDeviceOnly", 39 | 10: "kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly", 40 | 11: "kSecAttrAccessibleAlwaysThisDeviceOnly" 41 | } 42 | 43 | """ 44 | device key : key 0x835 45 | """ 46 | class Keybag(object): 47 | def __init__(self, data): 48 | self.type = None 49 | self.uuid = None 50 | self.wrap = None 51 | self.deviceKey = None 52 | self.unlocked = False 53 | self.passcodeComplexity = 0 54 | self.attrs = {} 55 | self.classKeys = {} 56 | self.KeyBagKeys = None #DATASIGN blob 57 | self.parseBinaryBlob(data) 58 | 59 | @staticmethod 60 | def getSystemkbfileWipeID(filename): 61 | mkb = BPlistReader.plistWithFile(filename) 62 | return mkb["_MKBWIPEID"] 63 | 64 | @staticmethod 65 | def createWithPlist(pldict): 66 | k835 = pldict.key835.decode("hex") 67 | data = "" 68 | if pldict.has_key("KeyBagKeys"): 69 | data = pldict["KeyBagKeys"].data 70 | else: 71 | data = "" 72 | keybag = Keybag.createWithDataSignBlob(data, k835) 73 | 74 | if pldict.has_key("passcodeKey"): 75 | if keybag.unlockWithPasscodeKey(pldict["passcodeKey"].decode("hex")): 76 | print "Keybag unlocked with passcode key" 77 | else: 78 | print "FAILed to unlock keybag with passcode key" 79 | #HAX: inject DKey 80 | keybag.setDKey(pldict) 81 | return keybag 82 | 83 | def setDKey(self, device_infos): 84 | self.classKeys[4] = {"CLAS": 4, "KEY": device_infos["DKey"].decode("hex")} 85 | 86 | @staticmethod 87 | def createWithSystemkbfile(filename, bag1key, deviceKey=None): 88 | if filename.startswith("bplist"): #HAX 89 | mkb = BPlistReader.plistWithString(filename) 90 | else: 91 | mkb = BPlistReader.plistWithFile(filename) 92 | try: 93 | decryptedPlist = AESdecryptCBC(mkb["_MKBPAYLOAD"].data, bag1key, mkb["_MKBIV"].data, padding=True) 94 | except: 95 | print "FAIL: AESdecryptCBC _MKBPAYLOAD => wrong BAG1 key ?" 96 | return None 97 | if not decryptedPlist.startswith("bplist"): 98 | print "FAIL: decrypted _MKBPAYLOAD is not bplist" 99 | return None 100 | decryptedPlist = BPlistReader.plistWithString(decryptedPlist) 101 | blob = decryptedPlist["KeyBagKeys"].data 102 | kb = Keybag.createWithDataSignBlob(blob, deviceKey) 103 | if decryptedPlist.has_key("OpaqueStuff"): 104 | OpaqueStuff = BPlistReader.plistWithString(decryptedPlist["OpaqueStuff"].data) 105 | kb.passcodeComplexity = OpaqueStuff.get("keyboardType") 106 | return kb 107 | 108 | 109 | @staticmethod 110 | def createWithDataSignBlob(blob, deviceKey=None): 111 | keybag = tlvToDict(blob) 112 | 113 | kb = Keybag(keybag.get("DATA", "")) 114 | kb.deviceKey = deviceKey 115 | kb.KeyBagKeys = blob 116 | kb.unlockAlwaysAccessible() 117 | 118 | if len(keybag.get("SIGN", "")): 119 | hmackey = AESUnwrap(deviceKey, kb.attrs["HMCK"]) 120 | #hmac key and data are swapped (on purpose or by mistake ?) 121 | sigcheck = hmac.new(key=keybag["DATA"], msg=hmackey, digestmod=sha1).digest() 122 | #fixed in ios 7 123 | if kb.attrs["VERS"] >= 4: 124 | sigcheck = hmac.new(key=hmackey, msg=keybag["DATA"], digestmod=sha1).digest() 125 | if sigcheck != keybag.get("SIGN", ""): 126 | print "Keybag: SIGN check FAIL" 127 | return kb 128 | 129 | @staticmethod 130 | def createWithBackupManifest(manifest, password, deviceKey=None): 131 | kb = Keybag(manifest["BackupKeyBag"].data) 132 | kb.deviceKey = deviceKey 133 | if not kb.unlockBackupKeybagWithPasscode(password): 134 | print "Cannot decrypt backup keybag. Wrong password ?" 135 | return 136 | return kb 137 | 138 | def isBackupKeybag(self): 139 | return self.type == BACKUP_KEYBAG 140 | 141 | def parseBinaryBlob(self, data): 142 | currentClassKey = None 143 | 144 | for tag, data in loopTLVBlocks(data): 145 | if len(data) == 4: 146 | data = struct.unpack(">L", data)[0] 147 | if tag == "TYPE": 148 | self.type = data & 0x3FFFFFFF #ignore the flags 149 | if self.type > 3: 150 | print "FAIL: keybag type > 3 : %d" % self.type 151 | elif tag == "UUID" and self.uuid is None: 152 | self.uuid = data 153 | elif tag == "WRAP" and self.wrap is None: 154 | self.wrap = data 155 | elif tag == "UUID": 156 | if currentClassKey: 157 | self.classKeys[currentClassKey["CLAS"] & 0xF] = currentClassKey 158 | currentClassKey = {"UUID": data} 159 | elif tag in CLASSKEY_TAGS: 160 | currentClassKey[tag] = data 161 | else: 162 | self.attrs[tag] = data 163 | if currentClassKey: 164 | self.classKeys[currentClassKey["CLAS"] & 0xF] = currentClassKey 165 | 166 | def getPasscodekeyFromPasscode(self, passcode): 167 | if self.type == BACKUP_KEYBAG or self.type == OTA_KEYBAG: 168 | return PBKDF2(passcode, self.attrs["SALT"], iterations=self.attrs["ITER"]).read(32) 169 | else: 170 | #Warning, need to run derivation on device with this result 171 | return PBKDF2(passcode, self.attrs["SALT"], iterations=1).read(32) 172 | 173 | def unlockBackupKeybagWithPasscode(self, passcode): 174 | if self.type != BACKUP_KEYBAG and self.type != OTA_KEYBAG: 175 | print "unlockBackupKeybagWithPasscode: not a backup keybag" 176 | return False 177 | return self.unlockWithPasscodeKey(self.getPasscodekeyFromPasscode(passcode)) 178 | 179 | def unlockAlwaysAccessible(self): 180 | for classkey in self.classKeys.values(): 181 | k = classkey["WPKY"] 182 | if classkey["WRAP"] == WRAP_DEVICE: 183 | if not self.deviceKey: 184 | continue 185 | k = AESdecryptCBC(k, self.deviceKey) 186 | classkey["KEY"] = k 187 | return True 188 | 189 | def unlockWithPasscodeKey(self, passcodekey): 190 | if self.type != BACKUP_KEYBAG and self.type != OTA_KEYBAG: 191 | if not self.deviceKey: 192 | print "ERROR, need device key to unlock keybag" 193 | return False 194 | 195 | for classkey in self.classKeys.values(): 196 | if not classkey.has_key("WPKY"): 197 | continue 198 | k = classkey["WPKY"] 199 | if classkey["WRAP"] & WRAP_PASSCODE: 200 | k = AESUnwrap(passcodekey, classkey["WPKY"]) 201 | if not k: 202 | return False 203 | if classkey["WRAP"] & WRAP_DEVICE: 204 | if not self.deviceKey: 205 | continue 206 | k = AESdecryptCBC(k, self.deviceKey) 207 | classkey["KEY"] = k 208 | self.unlocked = True 209 | return True 210 | 211 | def unwrapCurve25519(self, persistent_class, persistent_key): 212 | assert len(persistent_key) == 0x48 213 | #assert persistent_class == 2 #NSFileProtectionCompleteUnlessOpen 214 | mysecret = self.classKeys[persistent_class]["KEY"] 215 | mypublic = self.classKeys[persistent_class]["PBKY"] 216 | hispublic = persistent_key[:32] 217 | shared = curve25519(mysecret, hispublic) 218 | md = sha256('\x00\x00\x00\x01' + shared + hispublic + mypublic).digest() 219 | return AESUnwrap(md, persistent_key[32:]) 220 | 221 | def unwrapKeyForClass(self, clas, persistent_key, printError=True): 222 | if not self.classKeys.has_key(clas) or not self.classKeys[clas].has_key("KEY"): 223 | if printError: print "Keybag key %d missing or locked" % clas 224 | return "" 225 | ck = self.classKeys[clas]["KEY"] 226 | #if self.attrs.get("VERS", 2) >= 3 and clas == 2: 227 | if self.attrs.get("VERS", 2) >= 3 and self.classKeys[clas].get("KTYP", 0) == 1: 228 | return self.unwrapCurve25519(clas, persistent_key) 229 | if len(persistent_key) == 0x28: 230 | return AESUnwrap(ck, persistent_key) 231 | return 232 | 233 | def wrapKeyForClass(self, clas, persistent_key): 234 | if not self.classKeys.has_key(clas) or not self.classKeys[clas].has_key("KEY"): 235 | print "Keybag key %d missing or locked" % clas 236 | return "" 237 | ck = self.classKeys[clas]["KEY"] 238 | return AESwrap(ck, persistent_key) 239 | 240 | def printClassKeys(self): 241 | print "Keybag type : %s keybag (%d)" % (KEYBAG_TYPES[self.type], self.type) 242 | print "Keybag version : %d" % self.attrs["VERS"] 243 | print "Keybag UUID : %s" % self.uuid.encode("hex") 244 | print "-"*128 245 | print "".join(["Class".ljust(53), 246 | "WRAP".ljust(5), 247 | "Type".ljust(11), 248 | "Key".ljust(65), 249 | "Public key"]) 250 | print "-"*128 251 | for k, ck in self.classKeys.items(): 252 | if k == 6: print "" 253 | print "".join([PROTECTION_CLASSES.get(k, "%d" % k).ljust(53), 254 | str(ck.get("WRAP","")).ljust(5), 255 | KEY_TYPES[ck.get("KTYP",0)].ljust(11), 256 | ck.get("KEY", "").encode("hex").ljust(65), 257 | ck.get("PBKY", "").encode("hex")]) 258 | print "" 259 | 260 | def getClearClassKeysDict(self): 261 | if self.unlocked: 262 | d = {} 263 | for ck in self.classKeys.values(): 264 | d["%d" % (ck["CLAS"] & 0xF)] = ck.get("KEY","").encode("hex") 265 | return d 266 | -------------------------------------------------------------------------------- /pbuf.py: -------------------------------------------------------------------------------- 1 | def decode_protobuf_array(data, obj_class): 2 | n = len(data) 3 | i = 0 4 | res = [] 5 | while i < n: 6 | (length, i) = _DecodeVarint(data, i) 7 | l3 = obj_class() 8 | l3.ParseFromString(data[i:i+length]) 9 | res.append(l3) 10 | i += length 11 | return res 12 | 13 | def encode_protobuf_array(res): 14 | z = "" 15 | for o in res: 16 | d = o.SerializeToString() 17 | z += _EncodeVarint(len(d)) 18 | z += d 19 | return z 20 | 21 | #decoder.py 22 | def _VarintDecoder(mask): 23 | local_ord = ord 24 | def DecodeVarint(buffer, pos): 25 | result = 0 26 | shift = 0 27 | while True: 28 | b = local_ord(buffer[pos]) 29 | result |= ((b & 0x7f) << shift) 30 | pos += 1 31 | if not (b & 0x80): 32 | result &= mask 33 | return (result, pos) 34 | shift += 7 35 | if shift >= 64: 36 | raise _DecodeError('Too many bytes when decoding varint.') 37 | return DecodeVarint 38 | 39 | _DecodeVarint = _VarintDecoder((1 << 64) - 1) 40 | 41 | 42 | def _VarintEncoder(): 43 | """Return an encoder for a basic varint value (does not include tag).""" 44 | 45 | local_chr = chr 46 | def EncodeVarint( value): 47 | bits = value & 0x7f 48 | value >>= 7 49 | z="" 50 | while value: 51 | z += local_chr(0x80|bits) 52 | bits = value & 0x7f 53 | value >>= 7 54 | return z + local_chr(bits) 55 | 56 | return EncodeVarint 57 | 58 | _EncodeVarint = _VarintEncoder() 59 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | gevent 2 | hurry.filesize 3 | pycrypto 4 | protobuf 5 | -------------------------------------------------------------------------------- /util/__init__.py: -------------------------------------------------------------------------------- 1 | import cPickle 2 | import glob 3 | import gzip 4 | import os 5 | import plistlib 6 | 7 | from bplist import BPlistReader 8 | 9 | def read_file(filename): 10 | f = open(filename, "rb") 11 | data = f.read() 12 | f.close() 13 | return data 14 | 15 | def write_file(filename,data): 16 | f = open(filename, "wb") 17 | f.write(data) 18 | f.close() 19 | 20 | def getHomePath(foldername, filename): 21 | home = os.path.expanduser('~') 22 | folderpath = os.path.join(home, foldername) 23 | if not os.path.exists(folderpath): 24 | os.makedirs(folderpath) 25 | 26 | return os.path.join(folderpath, filename) 27 | 28 | def readHomeFile(foldername, filename): 29 | path = getHomePath(foldername, filename) 30 | if not os.path.exists(path): 31 | return None 32 | return read_file(path) 33 | 34 | #return path to HOME+foldername+filename 35 | def writeHomeFile(foldername, filename, data): 36 | filepath = getHomePath(foldername, filename) 37 | write_file(filepath, data) 38 | return filepath 39 | 40 | def readPlist(filename): 41 | f = open(filename,"rb") 42 | d = f.read(16) 43 | f.close() 44 | if d.startswith("bplist"): 45 | return BPlistReader.plistWithFile(filename) 46 | else: 47 | return plistlib.readPlist(filename) 48 | 49 | def parsePlist(s): 50 | if s.startswith("bplist"): 51 | return BPlistReader.plistWithString(s) 52 | else: 53 | return plistlib.readPlistFromString(s) 54 | 55 | #http://stackoverflow.com/questions/1094841/reusable-library-to-get-human-readable-version-of-file-size 56 | def sizeof_fmt(num): 57 | for x in ['bytes','KB','MB','GB','TB']: 58 | if num < 1024.0: 59 | return "%d%s" % (num, x) 60 | num /= 1024.0 61 | 62 | #http://www.5dollarwhitebox.org/drupal/node/84 63 | def convert_bytes(bytes): 64 | bytes = float(bytes) 65 | if bytes >= 1099511627776: 66 | terabytes = bytes / 1099511627776 67 | size = '%.2fT' % terabytes 68 | elif bytes >= 1073741824: 69 | gigabytes = bytes / 1073741824 70 | size = '%.2fG' % gigabytes 71 | elif bytes >= 1048576: 72 | megabytes = bytes / 1048576 73 | size = '%.2fM' % megabytes 74 | elif bytes >= 1024: 75 | kilobytes = bytes / 1024 76 | size = '%.2fK' % kilobytes 77 | else: 78 | size = '%.2fb' % bytes 79 | return size 80 | 81 | def xor_strings(a,b): 82 | r="" 83 | for i in xrange(len(a)): 84 | r+= chr(ord(a[i])^ord(b[i])) 85 | return r 86 | 87 | hex = lambda data: " ".join("%02X" % ord(i) for i in data) 88 | ascii = lambda data: "".join(c if 31 < ord(c) < 127 else "." for c in data) 89 | 90 | def hexdump(d): 91 | for i in xrange(0,len(d),16): 92 | data = d[i:i+16] 93 | print "%08X | %s | %s" % (i, hex(data).ljust(47), ascii(data)) 94 | 95 | def search_plist(directory, matchDict): 96 | for p in map(os.path.normpath, glob.glob(directory + "/*.plist")): 97 | try: 98 | d = plistlib.readPlist(p) 99 | ok = True 100 | for k,v in matchDict.items(): 101 | if d.get(k) != v: 102 | ok = False 103 | break 104 | if ok: 105 | print "Using plist file %s" % p 106 | return d 107 | except: 108 | continue 109 | 110 | def save_pickle(filename,data): 111 | f = gzip.open(filename,"wb") 112 | cPickle.dump(data, f, cPickle.HIGHEST_PROTOCOL) 113 | f.close() 114 | 115 | def load_pickle(filename): 116 | f = gzip.open(filename,"rb") 117 | data = cPickle.load(f) 118 | f.close() 119 | return data 120 | -------------------------------------------------------------------------------- /util/asciitables.py: -------------------------------------------------------------------------------- 1 | 2 | def print_table(title, headers, rows): 3 | widths = [] 4 | 5 | for i in xrange(len(headers)): 6 | z = map(len, [str(row[i]) for row in rows]) 7 | z.append(len(headers[i])) 8 | widths.append(max(z)) 9 | 10 | width = sum(widths) + len(headers) + 1 11 | print "-"* width 12 | print "|" + title.center(width-2) + "|" 13 | print "-"* width 14 | hline = "|" 15 | for i in xrange(len(headers)): 16 | hline += headers[i].ljust(widths[i]) + "|" 17 | print hline 18 | 19 | print "-"* width 20 | for row in rows: 21 | line = "|" 22 | for i in xrange(len(row)): 23 | line += str(row[i]).ljust(widths[i]) + "|" 24 | print line 25 | 26 | if len(rows) == 0: 27 | print "|" + "No entries".center(width-2) + "|" 28 | print "-"* width 29 | print "" 30 | -------------------------------------------------------------------------------- /util/bdev.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from util import sizeof_fmt, hexdump 4 | from progressbar import ProgressBar 5 | from crypto.aes import AESdecryptCBC, AESencryptCBC 6 | 7 | class FileBlockDevice(object): 8 | def __init__(self, filename, offset=0, write=False): 9 | flag = os.O_RDONLY if not write else os.O_RDWR 10 | if sys.platform == 'win32': 11 | flag = flag | os.O_BINARY 12 | self.filename = filename 13 | self.fd = os.open(filename, flag) 14 | self.offset = offset 15 | self.writeFlag = write 16 | self.size = os.path.getsize(filename) 17 | self.setBlockSize(8192) 18 | 19 | def setBlockSize(self, bs): 20 | self.blockSize = bs 21 | self.nBlocks = self.size / bs 22 | 23 | def readBlock(self, blockNum): 24 | off = self.offset + self.blockSize * blockNum 25 | if off > self.size: 26 | raise Exception("fail to seek at %d" % off) 27 | os.lseek(self.fd, off, os.SEEK_SET) 28 | return os.read(self.fd, self.blockSize) 29 | 30 | def write(self, offset, data): 31 | if self.writeFlag: #fail silently for testing 32 | os.lseek(self.fd, self.offset + offset, os.SEEK_SET) 33 | return os.write(self.fd, data) 34 | 35 | def writeBlock(self, lba, block): 36 | return self.write(lba*self.blockSize, block) 37 | 38 | class FTLBlockDevice(object): 39 | def __init__(self, nand, first_lba, last_lba, defaultKey=None): 40 | self.nand = nand 41 | self.pageSize = nand.logicalPageSize 42 | self.blockSize = 0 #not used 43 | self.key = defaultKey 44 | self.lbaoffset = first_lba 45 | self.last_lba = last_lba 46 | self.setBlockSize(self.pageSize) 47 | 48 | def setBlockSize(self, bs): 49 | self.blockSize = bs 50 | self.lbasPerPage = self.pageSize / bs 51 | self.lbaToLpnFactor = bs / (self.pageSize+0.0) 52 | self.pagesPerLBA = bs / self.pageSize 53 | if bs > self.pageSize: 54 | pass#raise Exception("FTLBlockDevice lba-size > pageSize not handled") 55 | 56 | def readBlock(self, blockNum): 57 | #if (self.lbaoffset + blockNum / self.lbasPerPage) > self.last_lba: 58 | # print "readBlock past last lba", blockNum 59 | # print "readBlock past last lba", blockNum 60 | # return "\x00" * self.blockSize 61 | lpn = int(self.lbaoffset + blockNum * self.lbaToLpnFactor) 62 | d = self.nand.readLPN(lpn, self.key) 63 | for i in xrange(1, self.pagesPerLBA): 64 | d += self.nand.readLPN(lpn + i, self.key) 65 | if self.lbasPerPage: 66 | zz = blockNum % self.lbasPerPage 67 | return d[zz*self.blockSize:(zz+1)*self.blockSize] 68 | return d 69 | 70 | def write(self, offset, data): 71 | raise Exception("FTLBlockDevice write method not implemented") 72 | 73 | def writeBlock(self, lba, block): 74 | raise Exception("FTLBlockDevice writeBlock method not implemented") 75 | 76 | def dumpToFile(self, outputfilename): 77 | hs = sizeof_fmt((self.last_lba - self.lbaoffset) * self.pageSize) 78 | print "Dumping partition to %s (%s)" % (outputfilename, hs) 79 | flags = os.O_CREAT | os.O_RDWR 80 | if sys.platform == "win32": 81 | flags |= os.O_BINARY 82 | fd=os.open(outputfilename, flags) 83 | 84 | pbar = ProgressBar(self.last_lba - self.lbaoffset - 1) 85 | pbar.start() 86 | for i in xrange(self.lbaoffset, self.last_lba): 87 | pbar.update(i-self.lbaoffset) 88 | d = self.nand.readLPN(i, self.key) 89 | if i == self.lbaoffset and d[0x400:0x402] != "HX": 90 | print "FAIL? Not HFS partition or wrong key" 91 | os.write(fd, d) 92 | pbar.finish() 93 | os.close(fd) 94 | 95 | class IMG3BlockDevice(object): 96 | def __init__(self, filename, key, iv, write=False): 97 | flag = os.O_RDONLY if not write else os.O_RDWR 98 | if sys.platform == 'win32': 99 | flag = flag | os.O_BINARY 100 | self.filename = filename 101 | self.fd = os.open(filename, flag) 102 | self.writeFlag = write 103 | d = os.read(self.fd, 8192) 104 | if d[:4] != "3gmI": 105 | raise Exception("IMG3BlockDevice bad magic %s" % d[:4]) 106 | if d[0x34:0x38] != "ATAD": 107 | raise Exception("Fu") 108 | self.encrypted = True 109 | self.key = key 110 | self.iv0 = iv 111 | self.offset = 0x40 112 | self.size = os.path.getsize(filename) 113 | self.setBlockSize(8192) 114 | 115 | def setBlockSize(self, bs): 116 | self.blockSize = bs 117 | self.nBlocks = self.size / bs 118 | self.ivs = {0: self.iv0} 119 | 120 | def getIVforBlock(self, blockNum): 121 | #read last 16 bytes of previous block to get IV 122 | if not self.ivs.has_key(blockNum): 123 | os.lseek(self.fd, self.offset + self.blockSize * blockNum - 16, os.SEEK_SET) 124 | self.ivs[blockNum] = os.read(self.fd, 16) 125 | return self.ivs[blockNum] 126 | 127 | def readBlock(self, blockNum): 128 | os.lseek(self.fd, self.offset + self.blockSize * blockNum, os.SEEK_SET) 129 | data = os.read(self.fd, self.blockSize) 130 | if self.encrypted: 131 | data = AESdecryptCBC(data, self.key, self.getIVforBlock(blockNum)) 132 | return data 133 | 134 | def _write(self, offset, data): 135 | if self.writeFlag: #fail silently for testing 136 | os.lseek(self.fd, self.offset + offset, os.SEEK_SET) 137 | return os.write(self.fd, data) 138 | 139 | def writeBlock(self, lba, data): 140 | if self.encrypted: 141 | data = AESencryptCBC(data, self.key, self.getIVforBlock(lba)) 142 | return self._write(lba*self.blockSize, data) 143 | -------------------------------------------------------------------------------- /util/bplist.py: -------------------------------------------------------------------------------- 1 | """ 2 | http://github.com/farcaller/bplist-python/blob/master/bplist.py 3 | """ 4 | import struct 5 | import plistlib 6 | from datetime import datetime, timedelta 7 | 8 | class BPListWriter(object): 9 | def __init__(self, objects): 10 | self.bplist = "" 11 | self.objects = objects 12 | 13 | def binary(self): 14 | '''binary -> string 15 | 16 | Generates bplist 17 | ''' 18 | self.data = 'bplist00' 19 | 20 | # TODO: flatten objects and count max length size 21 | 22 | # TODO: write objects and save offsets 23 | 24 | # TODO: write offsets 25 | 26 | # TODO: write metadata 27 | 28 | return self.data 29 | 30 | def write(self, filename): 31 | ''' 32 | 33 | Writes bplist to file 34 | ''' 35 | if self.bplist != "": 36 | pass 37 | # TODO: save self.bplist to file 38 | else: 39 | raise Exception('BPlist not yet generated') 40 | 41 | class BPlistReader(object): 42 | def __init__(self, s): 43 | self.data = s 44 | self.objects = [] 45 | self.resolved = {} 46 | 47 | def __unpackIntStruct(self, sz, s): 48 | '''__unpackIntStruct(size, string) -> int 49 | 50 | Unpacks the integer of given size (1, 2 or 4 bytes) from string 51 | ''' 52 | if sz == 1: 53 | ot = '!B' 54 | elif sz == 2: 55 | ot = '!H' 56 | elif sz == 4: 57 | ot = '!I' 58 | elif sz == 8: 59 | ot = '!Q' 60 | else: 61 | raise Exception('int unpack size '+str(sz)+' unsupported') 62 | return struct.unpack(ot, s)[0] 63 | 64 | def __unpackInt(self, offset): 65 | '''__unpackInt(offset) -> int 66 | 67 | Unpacks int field from plist at given offset 68 | ''' 69 | return self.__unpackIntMeta(offset)[1] 70 | 71 | def __unpackIntMeta(self, offset): 72 | '''__unpackIntMeta(offset) -> (size, int) 73 | 74 | Unpacks int field from plist at given offset and returns its size and value 75 | ''' 76 | obj_header = struct.unpack('!B', self.data[offset])[0] 77 | obj_type, obj_info = (obj_header & 0xF0), (obj_header & 0x0F) 78 | int_sz = 2**obj_info 79 | return int_sz, self.__unpackIntStruct(int_sz, self.data[offset+1:offset+1+int_sz]) 80 | 81 | def __resolveIntSize(self, obj_info, offset): 82 | '''__resolveIntSize(obj_info, offset) -> (count, offset) 83 | 84 | Calculates count of objref* array entries and returns count and offset to first element 85 | ''' 86 | if obj_info == 0x0F: 87 | ofs, obj_count = self.__unpackIntMeta(offset+1) 88 | objref = offset+2+ofs 89 | else: 90 | obj_count = obj_info 91 | objref = offset+1 92 | return obj_count, objref 93 | 94 | def __unpackFloatStruct(self, sz, s): 95 | '''__unpackFloatStruct(size, string) -> float 96 | 97 | Unpacks the float of given size (4 or 8 bytes) from string 98 | ''' 99 | if sz == 4: 100 | ot = '!f' 101 | elif sz == 8: 102 | ot = '!d' 103 | else: 104 | raise Exception('float unpack size '+str(sz)+' unsupported') 105 | return struct.unpack(ot, s)[0] 106 | 107 | def __unpackFloat(self, offset): 108 | '''__unpackFloat(offset) -> float 109 | 110 | Unpacks float field from plist at given offset 111 | ''' 112 | obj_header = struct.unpack('!B', self.data[offset])[0] 113 | obj_type, obj_info = (obj_header & 0xF0), (obj_header & 0x0F) 114 | int_sz = 2**obj_info 115 | return int_sz, self.__unpackFloatStruct(int_sz, self.data[offset+1:offset+1+int_sz]) 116 | 117 | def __unpackDate(self, offset): 118 | td = int(struct.unpack(">d", self.data[offset+1:offset+9])[0]) 119 | return datetime(year=2001,month=1,day=1) + timedelta(seconds=td) 120 | 121 | def __unpackItem(self, offset): 122 | '''__unpackItem(offset) 123 | 124 | Unpacks and returns an item from plist 125 | ''' 126 | obj_header = struct.unpack('!B', self.data[offset])[0] 127 | obj_type, obj_info = (obj_header & 0xF0), (obj_header & 0x0F) 128 | if obj_type == 0x00: 129 | if obj_info == 0x00: # null 0000 0000 130 | return None 131 | elif obj_info == 0x08: # bool 0000 1000 // false 132 | return False 133 | elif obj_info == 0x09: # bool 0000 1001 // true 134 | return True 135 | elif obj_info == 0x0F: # fill 0000 1111 // fill byte 136 | raise Exception("0x0F Not Implemented") # this is really pad byte, FIXME 137 | else: 138 | raise Exception('unpack item type '+str(obj_header)+' at '+str(offset)+ 'failed') 139 | elif obj_type == 0x10: # int 0001 nnnn ... // # of bytes is 2^nnnn, big-endian bytes 140 | return self.__unpackInt(offset) 141 | elif obj_type == 0x20: # real 0010 nnnn ... // # of bytes is 2^nnnn, big-endian bytes 142 | return self.__unpackFloat(offset) 143 | elif obj_type == 0x30: # date 0011 0011 ... // 8 byte float follows, big-endian bytes 144 | return self.__unpackDate(offset) 145 | elif obj_type == 0x40: # data 0100 nnnn [int] ... // nnnn is number of bytes unless 1111 then int count follows, followed by bytes 146 | obj_count, objref = self.__resolveIntSize(obj_info, offset) 147 | return plistlib.Data(self.data[objref:objref+obj_count]) # XXX: we return data as str 148 | elif obj_type == 0x50: # string 0101 nnnn [int] ... // ASCII string, nnnn is # of chars, else 1111 then int count, then bytes 149 | obj_count, objref = self.__resolveIntSize(obj_info, offset) 150 | return self.data[objref:objref+obj_count] 151 | elif obj_type == 0x60: # string 0110 nnnn [int] ... // Unicode string, nnnn is # of chars, else 1111 then int count, then big-endian 2-byte uint16_t 152 | obj_count, objref = self.__resolveIntSize(obj_info, offset) 153 | return self.data[objref:objref+obj_count*2].decode('utf-16be') 154 | elif obj_type == 0x80: # uid 1000 nnnn ... // nnnn+1 is # of bytes 155 | # FIXME: Accept as a string for now 156 | obj_count, objref = self.__resolveIntSize(obj_info, offset) 157 | return plistlib.Data(self.data[objref:objref+obj_count]) 158 | elif obj_type == 0xA0: # array 1010 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows 159 | obj_count, objref = self.__resolveIntSize(obj_info, offset) 160 | arr = [] 161 | for i in range(obj_count): 162 | arr.append(self.__unpackIntStruct(self.object_ref_size, self.data[objref+i*self.object_ref_size:objref+i*self.object_ref_size+self.object_ref_size])) 163 | return arr 164 | elif obj_type == 0xC0: # set 1100 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows 165 | # XXX: not serializable via apple implementation 166 | raise Exception("0xC0 Not Implemented") # FIXME: implement 167 | elif obj_type == 0xD0: # dict 1101 nnnn [int] keyref* objref* // nnnn is count, unless '1111', then int count follows 168 | obj_count, objref = self.__resolveIntSize(obj_info, offset) 169 | keys = [] 170 | for i in range(obj_count): 171 | keys.append(self.__unpackIntStruct(self.object_ref_size, self.data[objref+i*self.object_ref_size:objref+i*self.object_ref_size+self.object_ref_size])) 172 | values = [] 173 | objref += obj_count*self.object_ref_size 174 | for i in range(obj_count): 175 | values.append(self.__unpackIntStruct(self.object_ref_size, self.data[objref+i*self.object_ref_size:objref+i*self.object_ref_size+self.object_ref_size])) 176 | dic = {} 177 | for i in range(obj_count): 178 | dic[keys[i]] = values[i] 179 | return dic 180 | else: 181 | raise Exception('don\'t know how to unpack obj type '+hex(obj_type)+' at '+str(offset)) 182 | 183 | def __resolveObject(self, idx): 184 | try: 185 | return self.resolved[idx] 186 | except KeyError: 187 | obj = self.objects[idx] 188 | if type(obj) == list: 189 | newArr = [] 190 | for i in obj: 191 | newArr.append(self.__resolveObject(i)) 192 | self.resolved[idx] = newArr 193 | return newArr 194 | if type(obj) == dict: 195 | newDic = {} 196 | for k,v in obj.iteritems(): 197 | rk = self.__resolveObject(k) 198 | rv = self.__resolveObject(v) 199 | newDic[rk] = rv 200 | self.resolved[idx] = newDic 201 | return newDic 202 | else: 203 | self.resolved[idx] = obj 204 | return obj 205 | 206 | def parse(self): 207 | # read header 208 | if self.data[:8] != 'bplist00': 209 | raise Exception('Bad magic') 210 | 211 | # read trailer 212 | self.offset_size, self.object_ref_size, self.number_of_objects, self.top_object, self.table_offset = struct.unpack('!6xBB4xI4xI4xI', self.data[-32:]) 213 | #print "** plist offset_size:",self.offset_size,"objref_size:",self.object_ref_size,"num_objs:",self.number_of_objects,"top:",self.top_object,"table_ofs:",self.table_offset 214 | 215 | # read offset table 216 | self.offset_table = self.data[self.table_offset:-32] 217 | self.offsets = [] 218 | ot = self.offset_table 219 | for i in xrange(self.number_of_objects): 220 | offset_entry = ot[:self.offset_size] 221 | ot = ot[self.offset_size:] 222 | self.offsets.append(self.__unpackIntStruct(self.offset_size, offset_entry)) 223 | #print "** plist offsets:",self.offsets 224 | 225 | # read object table 226 | self.objects = [] 227 | k = 0 228 | for i in self.offsets: 229 | obj = self.__unpackItem(i) 230 | #print "** plist unpacked",k,type(obj),obj,"at",i 231 | k += 1 232 | self.objects.append(obj) 233 | 234 | # rebuild object tree 235 | #for i in range(len(self.objects)): 236 | # self.__resolveObject(i) 237 | 238 | # return root object 239 | return self.__resolveObject(self.top_object) 240 | 241 | @classmethod 242 | def plistWithString(cls, s): 243 | parser = cls(s) 244 | return parser.parse() 245 | 246 | @classmethod 247 | def plistWithFile(cls, f): 248 | file = open(f,"rb") 249 | parser = cls(file.read()) 250 | file.close() 251 | return parser.parse() 252 | -------------------------------------------------------------------------------- /util/bruteforce.py: -------------------------------------------------------------------------------- 1 | from keystore.keybag import Keybag 2 | from keystore.effaceable import EffaceableLockers 3 | from util.ramdiskclient import RamdiskToolClient 4 | import plistlib 5 | 6 | COMPLEXITY={ 7 | 0: "4 digits", 8 | 1: "n digits", 9 | 2: "n alphanum" 10 | } 11 | 12 | def checkPasscodeComplexity(data_volume): 13 | pl = data_volume.readFile("/mobile/Library/ConfigurationProfiles/UserSettings.plist", returnString=True) 14 | if not pl: 15 | print "Failed to read UserSettings.plist, assuming simple passcode" 16 | return 0 17 | pl = plistlib.readPlistFromString(pl) 18 | #print "passcodeKeyboardComplexity :", pl["restrictedValue"]["passcodeKeyboardComplexity"] 19 | value = pl["restrictedValue"]["passcodeKeyboardComplexity"]["value"] 20 | print "passcodeKeyboardComplexity %d => %s" % (value, COMPLEXITY.get(value)) 21 | return pl["restrictedValue"]["passcodeKeyboardComplexity"]["value"] 22 | 23 | def loadKeybagFromVolume(volume, device_infos): 24 | systembag = volume.readFile("/keybags/systembag.kb", returnString=True) 25 | if not systembag or not systembag.startswith("bplist"): 26 | print "FAIL: could not read /keybags/systembag.kb from data partition" 27 | return False 28 | lockers = EffaceableLockers(device_infos["lockers"].data) 29 | bag1key = lockers.get("BAG1")[-32:] 30 | keybag = Keybag.createWithSystemkbfile(systembag, bag1key, device_infos.get("key835", "").decode("hex")) 31 | keybag.setDKey(device_infos) 32 | if device_infos.has_key("passcodeKey"): 33 | keybag.unlockWithPasscodeKey(device_infos.get("passcodeKey").decode("hex")) 34 | return keybag 35 | 36 | def bruteforcePasscode(device_infos, data_volume): 37 | if device_infos.has_key("passcode"): 38 | print "Passcode already found, no bruteforce required" 39 | return False 40 | kb = data_volume.keybag 41 | if not kb: 42 | return False 43 | 44 | rd = RamdiskToolClient.get() 45 | if rd.device_infos.udid != device_infos.udid: 46 | print "Wrong device connected" 47 | return 48 | 49 | print "Passcode comlexity (from OpaqueStuff) : %s" % COMPLEXITY.get(kb.passcodeComplexity) 50 | print "Enter passcode or leave blank for bruteforce:" 51 | z = raw_input() 52 | bf = rd.getPasscodeKey(kb.KeyBagKeys, z) 53 | if kb.unlockWithPasscodeKey(bf.get("passcodeKey").decode("hex")): 54 | print "Passcode \"%s\" OK" % z 55 | else: 56 | if z != "": 57 | print "Wrong passcode, trying to bruteforce !" 58 | if kb.passcodeComplexity != 0: 59 | print "Complex passcode used, not bruteforcing" 60 | return False 61 | 62 | bf = rd.bruteforceKeyBag(kb.KeyBagKeys) 63 | if bf and kb.unlockWithPasscodeKey(bf.get("passcodeKey").decode("hex")): 64 | print "Bruteforce successful, passcode : %s" % bf["passcode"] 65 | print "Passcode key : %s" % bf.get("passcodeKey") 66 | if kb.unlocked: 67 | device_infos.update(bf) 68 | device_infos["classKeys"] = kb.getClearClassKeysDict() 69 | device_infos["KeyBagKeys"] = plistlib.Data(kb.KeyBagKeys) 70 | return True 71 | return False 72 | -------------------------------------------------------------------------------- /util/cert.py: -------------------------------------------------------------------------------- 1 | import base64 2 | 3 | def chunks(l, n): 4 | return (l[i:i+n] for i in xrange(0, len(l), n)) 5 | 6 | def RSA_KEY_DER_to_PEM(data): 7 | a = ["-----BEGIN RSA PRIVATE KEY-----"] 8 | a.extend(chunks(base64.b64encode(data),64)) 9 | a.append("-----END RSA PRIVATE KEY-----") 10 | return "\n".join(a) 11 | 12 | def CERT_DER_to_PEM(data): 13 | a = ["-----BEGIN CERTIFICATE-----"] 14 | a.extend(chunks(base64.b64encode(data),64)) 15 | a.append("-----END CERTIFICATE-----") 16 | return "\n".join(a) 17 | -------------------------------------------------------------------------------- /util/lzss.py: -------------------------------------------------------------------------------- 1 | """ 2 | /************************************************************** 3 | LZSS.C -- A Data Compression Program 4 | *************************************************************** 5 | 4/6/1989 Haruhiko Okumura 6 | Use, distribute, and modify this program freely. 7 | Please send me your improved versions. 8 | PC-VAN SCIENCE 9 | NIFTY-Serve PAF01022 10 | CompuServe 74050,1022 11 | 12 | **************************************************************/ 13 | /* 14 | * lzss.c - Package for decompressing lzss compressed objects 15 | * 16 | * Copyright (c) 2003 Apple Computer, Inc. 17 | * 18 | * DRI: Josh de Cesare 19 | */ 20 | """ 21 | from array import array 22 | import struct 23 | 24 | N = 4096 25 | F = 18 26 | THRESHOLD = 2 27 | NIL = N 28 | 29 | def decompress_lzss(str): 30 | if str[:8] !="complzss": 31 | print "decompress_lzss: complzss magic missing" 32 | return 33 | decompsize = struct.unpack(">L", str[12:16])[0] 34 | text_buf = array("B", " "*(N + F - 1)) 35 | src = array("B", str[0x180:]) 36 | srclen = len(src) 37 | dst = array("B", " "*decompsize) 38 | r = N - F 39 | srcidx, dstidx, flags, c = 0, 0, 0, 0 40 | 41 | while True: 42 | flags >>= 1 43 | if ((flags & 0x100) == 0): 44 | if (srcidx >= srclen): 45 | break 46 | c = src[srcidx]; srcidx += 1 47 | flags = c | 0xFF00; 48 | 49 | if (flags & 1): 50 | if (srcidx >= srclen): 51 | break 52 | c = src[srcidx]; srcidx += 1 53 | dst[dstidx] = c; dstidx += 1 54 | text_buf[r] = c; r += 1 55 | r &= (N - 1); 56 | else: 57 | if (srcidx >= srclen): 58 | break 59 | i = src[srcidx]; srcidx += 1 60 | if (srcidx >= srclen): 61 | break 62 | j = src[srcidx]; srcidx += 1 63 | i |= ((j & 0xF0) << 4) 64 | j = (j & 0x0F) + THRESHOLD 65 | for k in xrange(j+1): 66 | c = text_buf[(i + k) & (N - 1)] 67 | dst[dstidx] = c; dstidx += 1 68 | text_buf[r] = c; r += 1 69 | r &= (N - 1) 70 | return dst.tostring() 71 | 72 | -------------------------------------------------------------------------------- /util/ramdiskclient.py: -------------------------------------------------------------------------------- 1 | import plistlib 2 | import struct 3 | import socket 4 | from datetime import datetime 5 | from progressbar import ProgressBar, Percentage, Bar, SimpleProgress, ETA 6 | from usbmux import usbmux 7 | from util import sizeof_fmt 8 | 9 | kIOAESAcceleratorEncrypt = 0 10 | kIOAESAcceleratorDecrypt = 1 11 | 12 | kIOAESAcceleratorGIDMask = 0x3E8 13 | kIOAESAcceleratorUIDMask = 0x7D0 14 | 15 | 16 | class DeviceInfo(dict): 17 | @staticmethod 18 | def create(dict): 19 | try: 20 | assert dict.has_key("dataVolumeUUID") 21 | filename = "%s.plist" % dict.get("dataVolumeUUID") 22 | return DeviceInfo(plistlib.readPlist(filename)) 23 | except: 24 | return DeviceInfo(dict) 25 | 26 | def save(self): 27 | filename = "%s.plist" % self.get("dataVolumeUUID", "unk") 28 | plistlib.writePlist(self, filename) 29 | 30 | #stop doing magic stuff 31 | #def __del__(self): 32 | # self.save() 33 | 34 | class RamdiskToolClient(object): 35 | instance = None 36 | @staticmethod 37 | def get(): 38 | if not RamdiskToolClient.instance: 39 | RamdiskToolClient.instance = RamdiskToolClient() 40 | return RamdiskToolClient.instance 41 | 42 | def __init__(self, udid=None, host="localhost", port=1999): 43 | self.host = host 44 | self.port = port 45 | self.device_infos = {} 46 | self.s = None 47 | self.connect(udid) 48 | self.getDeviceInfos() 49 | 50 | def close(self): 51 | if self.s: 52 | self.s.close() 53 | self.s = None 54 | 55 | def connect(self, udid=None): 56 | mux = usbmux.USBMux() 57 | mux.process(1.0) 58 | if not mux.devices: 59 | print "Waiting for iOS device" 60 | while not mux.devices: 61 | mux.process(1.0) 62 | if not mux.devices: 63 | print "No device found" 64 | return 65 | dev = mux.devices[0] 66 | print "Connecting to device : " + dev.serial 67 | try: 68 | self.s = mux.connect(dev, self.port) 69 | except: 70 | raise Exception("Connexion to device port %d failed" % self.port) 71 | 72 | def getDeviceInfos(self): 73 | self.device_infos = self.send_req({"Request":"DeviceInfo"}) 74 | keys = self.grabDeviceKeys() 75 | if keys: 76 | self.device_infos.update(keys) 77 | return DeviceInfo.create(self.device_infos) 78 | 79 | def downloadFile(self, path): 80 | res = self.send_req({"Request": "DownloadFile", 81 | "Path": path}) 82 | if type(res) == plistlib._InternalDict and res.has_key("Data"): 83 | return res["Data"].data 84 | 85 | def getSystemKeyBag(self): 86 | return self.send_req({"Request":"GetSystemKeyBag"}) 87 | 88 | def bruteforceKeyBag(self, KeyBagKeys): 89 | return self.send_req({"Request":"BruteforceSystemKeyBag", 90 | "KeyBagKeys": plistlib.Data(KeyBagKeys)}) 91 | 92 | def getEscrowRecord(self, hostID): 93 | return self.send_req({"Request":"GetEscrowRecord", 94 | "HostID": hostID}) 95 | 96 | def getPasscodeKey(self, keybagkeys, passcode): 97 | return self.send_req({"Request":"KeyBagGetPasscodeKey", 98 | "KeyBagKeys": plistlib.Data(keybagkeys), 99 | "passcode": passcode}) 100 | 101 | def send_msg(self, dict): 102 | plist = plistlib.writePlistToString(dict) 103 | data = struct.pack("L",blob[i+4:i+8])[0] 17 | data = blob[i+8:i+8+length] 18 | yield (tag,data) 19 | i += 8 + length 20 | --------------------------------------------------------------------------------