├── .gitignore ├── src ├── Makefile └── genpass.c ├── LICENCE └── README /.gitignore: -------------------------------------------------------------------------------- 1 | Debug 2 | Release 3 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc genpass.c -o genpass -lcrypto 3 | 4 | clean: 5 | rm -rf genpass 6 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | (c)2010 Chronic Dev Team 2 | All rights reserved. 3 | Private release, please do not redistribute. 4 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Used to generate vfdecrypt passwords to decrypt iPhone/iPod filesystems. 2 | 3 | Usage: 4 | genpass 5 | 6 | platform = s5l8900x (for iphone2g, iphone3g, and ipod1g), s5l8720x (for ipod2g), s5l8920x (for iphone3gs), s5l8922x (for ipod3g), or s5l8930 (for ipad1g) 7 | ramdisk.dmg = a decrypted restore or upgrade ramdisk from the IPSW with the target filesystem 8 | filesystem.dmg = the encrypted filesystem you're trying to discover the vfdecrypt key for 9 | -------------------------------------------------------------------------------- /src/genpass.c: -------------------------------------------------------------------------------- 1 | //by posixninja, geohot, and chronic 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define BUF_SIZE 0x100000 13 | #define SHA256_DIGEST_LENGTH 32 14 | 15 | #define FLIPENDIAN(x) flip_endian((unsigned char*)(&(x)), sizeof(x)) 16 | 17 | typedef unsigned char uint8; 18 | typedef unsigned int uint32; 19 | typedef unsigned long long uint64; 20 | 21 | typedef struct { 22 | uint8 sig[8]; 23 | uint32 version; 24 | uint32 enc_iv_size; 25 | uint32 unk1; 26 | uint32 unk2; 27 | uint32 unk3; 28 | uint32 unk4; 29 | uint32 unk5; 30 | uint8 uuid[16]; 31 | uint32 blocksize; 32 | uint64 datasize; 33 | uint64 dataoffset; 34 | } encrcdsa_header; 35 | 36 | typedef struct { 37 | uint32 unk1; 38 | uint32 unk2; 39 | uint32 unk3; 40 | uint32 unk4; 41 | uint32 unk5; 42 | } encrcdsa_block; 43 | 44 | static inline void flip_endian(unsigned char* x, int length) { 45 | unsigned int i = 0; 46 | unsigned char tmp = '\0'; 47 | for(i = 0; i < (length / 2); i++) { 48 | tmp = x[i]; 49 | x[i] = x[length - i - 1]; 50 | x[length - i - 1] = tmp; 51 | } 52 | } 53 | 54 | static inline uint64 u32_to_u64(uint32 msq, uint32 lsq) { 55 | uint64 ms = (uint64) msq; 56 | uint64 ls = (uint64) lsq; 57 | return ls | (ms << 32); 58 | } 59 | 60 | static uint64 hash_platform(const char* platform) { 61 | uint8 md[SHA_DIGEST_LENGTH]; 62 | SHA1((const unsigned char*) platform, strlen(platform), (unsigned char*) &md); 63 | 64 | uint64 hash = u32_to_u64(((md[0] << 24) | (md[1] << 16) | (md[2] << 8) 65 | | md[3]), ((md[4] << 24) | (md[5] << 16) | (md[6] << 8) | md[7])); 66 | 67 | return hash; 68 | } 69 | 70 | static uint64 ramdisk_size(const char* ramdisk) { 71 | struct stat filestat; 72 | if (stat(ramdisk, &filestat) < 0) { 73 | return 0; 74 | } 75 | return (uint64) filestat.st_size; 76 | } 77 | 78 | void print_hex(uint8* hex, int size) { 79 | int i = 0; 80 | for (i = 0; i < size; i++) { 81 | printf("%02x", hex[i]); 82 | } 83 | printf("\n"); 84 | } 85 | 86 | int compare(const uint32* a, const uint32* b) { 87 | if (*a < *b) 88 | return -1; 89 | 90 | if (*a > *b) 91 | return 1; 92 | 93 | return 0; 94 | } 95 | 96 | uint8* generate_passphrase(const char* platform, const char* ramdisk) { 97 | SHA256_CTX ctx; 98 | uint64 salt[4]; 99 | uint32 saltedHash[4]; 100 | uint64 totalSize = ramdisk_size(ramdisk); 101 | uint64 platformHash = hash_platform(platform); 102 | 103 | salt[0] = u32_to_u64(0xad79d29d, 0xe5e2ac9e); 104 | salt[1] = u32_to_u64(0xe6af2eb1, 0x9e23925b); 105 | salt[2] = u32_to_u64(0x3f1375b4, 0xbd88815c); 106 | salt[3] = u32_to_u64(0x3bdff4e5, 0x564a9f87); 107 | 108 | FILE* fd = fopen(ramdisk, "rb"); 109 | if (!fd) { 110 | fprintf(stderr, "error opening file: %s\n", ramdisk); 111 | return NULL; 112 | } 113 | 114 | int i = 0; 115 | for (i = 0; i < 4; i++) { 116 | salt[i] += platformHash; 117 | saltedHash[i] = ((uint32) (salt[i] % totalSize)) & 0xFFFFFE00; 118 | } 119 | qsort(&saltedHash, 4, 4, (int(*)(const void *, const void *)) &compare); 120 | 121 | SHA256_Init(&ctx); 122 | SHA256_Update(&ctx, salt, 32);//SHA256_DIGEST_LENGTH); 123 | 124 | int count = 0; 125 | uint8* buffer = malloc(BUF_SIZE); 126 | uint8* passphrase = malloc(SHA256_DIGEST_LENGTH); 127 | while (count < totalSize) { 128 | unsigned int bytes = fread(buffer, 1, BUF_SIZE, fd); 129 | SHA256_Update(&ctx, buffer, bytes); 130 | 131 | for (i = 0; i < 4; i++) { //some salts remain 132 | if (count < saltedHash[i] && saltedHash[i] < (count + bytes)) { 133 | if ((saltedHash[i] + 0x4000) < count) { 134 | SHA256_Update(&ctx, buffer, saltedHash[i] - count); 135 | 136 | } else { 137 | SHA256_Update(&ctx, buffer + (saltedHash[i] - count), ((bytes 138 | - (saltedHash[i] - count)) < 0x4000) ? (bytes 139 | - (saltedHash[i] - count)) : 0x4000); 140 | } 141 | } 142 | } 143 | count += bytes; 144 | } 145 | 146 | fclose(fd); 147 | SHA256_Final(passphrase, &ctx); 148 | return passphrase; 149 | } 150 | 151 | uint8* decrypt_key(const char* filesystem, uint8* passphrase) { 152 | int i = 0; 153 | EVP_CIPHER_CTX ctx; 154 | uint8 data[0x30]; 155 | int outlen, tmplen = 0; 156 | 157 | FILE* fd = fopen(filesystem, "rb"); 158 | if (fd == NULL) { 159 | fprintf(stderr, "error opening file: %s", filesystem); 160 | return NULL; 161 | } 162 | 163 | uint8* buffer = (uint8*) malloc(BUF_SIZE); 164 | if(buffer == NULL) { 165 | fprintf(stderr, "unable to allocate memory\n"); 166 | fclose(fd); 167 | return NULL; 168 | } 169 | 170 | fread(buffer, 1, sizeof(encrcdsa_header), fd); 171 | 172 | uint32 blocks = 0; 173 | fread(&blocks, 1, sizeof(uint32), fd); 174 | FLIPENDIAN(blocks); 175 | 176 | fread(buffer, 1, sizeof(encrcdsa_block) * blocks, fd); 177 | fread(buffer, 1, 0x80, fd); 178 | 179 | uint32 skip = 0; 180 | fread(&skip, 1, sizeof(uint32), fd); 181 | FLIPENDIAN(skip); 182 | fread(buffer, 1, skip-3, fd); 183 | 184 | uint8* out = malloc(0x30); 185 | free(buffer); 186 | 187 | for (i = 0; i < 0x20; i++) { 188 | if (fread(data, 1, 0x30, fd) <= 0) { 189 | fprintf(stderr, "Error reading filesystem image"); 190 | free(out); 191 | return NULL; 192 | } 193 | 194 | if(data[0] == 0) break; 195 | 196 | EVP_CIPHER_CTX_init(&ctx); 197 | EVP_DecryptInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, passphrase, 198 | &passphrase[24]); 199 | 200 | EVP_DecryptUpdate(&ctx, out, &outlen, data, 0x30); 201 | if (EVP_DecryptFinal_ex(&ctx, out + outlen, &tmplen)) { 202 | return out; 203 | } 204 | 205 | fseek(fd, 0x238, SEEK_CUR); 206 | } 207 | 208 | fclose(fd); 209 | return out; 210 | } 211 | 212 | int main(int argc, char* argv[]) { 213 | uint8* pass = NULL; 214 | uint8* key = NULL; 215 | 216 | if (argc < 3) { 217 | fprintf(stderr, 218 | "usage: genpass \n"); 219 | return -1; 220 | } 221 | 222 | char* platform = argv[1]; 223 | char* ramdisk = argv[2]; 224 | char* filesystem = argv[3]; 225 | 226 | pass = generate_passphrase(platform, ramdisk); 227 | if (pass == NULL) { 228 | fprintf(stderr, "unable to generate asr passphrase\n"); 229 | return -1; 230 | } 231 | //printf("asr passphrase: "); 232 | //print_hex(pass, 0x20); 233 | 234 | key = decrypt_key(filesystem, pass); 235 | if (key == NULL) { 236 | fprintf(stderr, "unable to decrypt vfdecrypt key\n"); 237 | return -1; 238 | } 239 | printf("vfdecrypt key: "); 240 | print_hex(key, 0x24); 241 | 242 | if (pass) 243 | free(pass); 244 | if (key) 245 | free(key); 246 | 247 | return 0; 248 | } 249 | --------------------------------------------------------------------------------