def computePSK(ssid, key): """ Compute the PSK for the given SSID and Key. Returns None if the Key does not have the necessary length. """ if((len(key)>=8) and (len(key)<=63)): if(QUICK_MODE): return pbkdf2.pbkdf2_bin(key, ssid, 256, 32) else: return pbkdf2.pbkdf2_bin(key, ssid, 4096, 32) else: return None
def computePSK(ssid, key): """ Compute the PSK for the given SSID and Key. Returns None if the Key does not have the necessary length. """ if ((len(key) >= 8) and (len(key) <= 63)): if (QUICK_MODE): return pbkdf2.pbkdf2_bin(key, ssid, 256, 32) else: return pbkdf2.pbkdf2_bin(key, ssid, 4096, 32) else: return None
def _gen_password(self, password, salt_info=None): if salt_info is None: salt_info = self._get_salt() iterations = SALT_VERSIONS[salt_info['version']] key = pbkdf2_bin(password, salt_info['salt'], iterations=iterations, keylen=32) return b_encode(key)
def derive_password(password, salt, length, iteration=10000): '''Use pbkdf2 to create a new password.''' def finalize_password(encoded_password): '''Pad length and add special characters/numbers to passwords. Necessary when desired length is not a valid base64 length. ''' # substitute letters for special characters or numbers encoded_password = encoded_password.replace("i", "!") encoded_password = encoded_password.replace("a", "@") encoded_password = encoded_password.replace("s", "$") encoded_password = encoded_password.replace("I", "1") encoded_password = encoded_password.replace("O", "0") difference = length - len(encoded_password) final_password = encoded_password + "+" * difference return final_password[0:length] # chop off any excess # hash the password because why not? hashed_password = sha512(password).hexdigest() # and the salt hashed_salt = sha512(salt).hexdigest() keylen = calc_keysize(length) key = pbkdf2_bin(hashed_password, hashed_salt, keylen=keylen, iterations=iteration) new_password = b64encode(key) return finalize_password(new_password)
def generate(password): '''Generate a ShadowHashData structure as used by macOS 10.8+''' iterations = arc4random.randrange(30000, 50000) salt = make_salt(32) keylen = 128 try: entropy = hashlib.pbkdf2_hmac('sha512', password, salt, iterations, dklen=keylen) except AttributeError: # old Python, do it a different way entropy = pbkdf2.pbkdf2_bin(password, salt, iterations=iterations, keylen=keylen, hashfunc=hashlib.sha512) data = { 'SALTED-SHA512-PBKDF2': { 'entropy': buffer(entropy), 'iterations': iterations, 'salt': buffer(salt) }, } return plistutils.write_plist(data, plist_format='binary')
def stretch(emailUTF8, passwordUTF8, PBKDF2_rounds_1, scrypt_N, scrypt_r, scrypt_p, PBKDF2_rounds_2): k1 = pbkdf2_bin(passwordUTF8, KWE("first-PBKDF", emailUTF8), PBKDF2_rounds_1, keylen=1*32, hashfunc=sha256) time_k1 = time.time() printhex("K1", k1) k2 = scrypt.hash(k1, KW("scrypt"), N=scrypt_N, r=scrypt_r, p=scrypt_p, buflen=1*32) time_k2 = time.time() printhex("K2", k2) stretchedPW = pbkdf2_bin(k2+passwordUTF8, KWE("second-PBKDF", emailUTF8), PBKDF2_rounds_2, keylen=1*32, hashfunc=sha256) printhex("stretchedPW", stretchedPW) return stretchedPW
def check_hash(password, hash_, hash_cache=None): """Check a password against an existing hash. The optional hash_cache dictionary argument can be used to cache recent lookups to save time in e.g. webdav where each operation triggers hash check. """ if isinstance(password, unicode): password = password.encode('utf-8') pw_hash = hashlib.md5(password).hexdigest() if isinstance(hash_cache, dict) and \ hash_cache.get(pw_hash, None) == hash_: # print "found cached hash: %s" % hash_cache.get(pw_hash, None) return True algorithm, hash_function, cost_factor, salt, hash_a = hash_.split('$') assert algorithm == 'PBKDF2' hash_a = b64decode(hash_a) hash_b = pbkdf2_bin(password, salt, int(cost_factor), len(hash_a), getattr(hashlib, hash_function)) assert len(hash_a) == len(hash_b) # we requested this from pbkdf2_bin() # Same as "return hash_a == hash_b" but takes a constant time. # See http://carlos.bueno.org/2011/10/timing.html diff = 0 for char_a, char_b in izip(hash_a, hash_b): diff |= ord(char_a) ^ ord(char_b) match = (diff == 0) if isinstance(hash_cache, dict) and match: hash_cache[pw_hash] = hash_ # print "cached hash: %s" % hash_cache.get(pw_hash, None) return match
def _make_password(cls, password, salt=None, iterations=None): if not salt: salt = binascii.b2a_hex(os.urandom(15)) if not iterations: iterations = 10000 hash_val = pbkdf2_bin(bytes(password), bytes(salt), iterations, keylen=32, hashfunc=hashlib.sha256) hash_val = hash_val.encode('base64').strip() return '%s$%s$%s$%s' % ('pbkdf2_sha256', iterations, salt, hash_val)
def encrypt(password): """Generate a random salt and return a new hash for the password.""" if isinstance(password, unicode): password = password.encode('utf-8') salt = b64encode(urandom(SALT_LENGTH)) return 'PBKDF2${}${}${}${}'.format( HASH_FUNCTION, COST_FACTOR, salt, b64encode( pbkdf2_bin(password, salt, COST_FACTOR, KEY_LENGTH, getattr(hashlib, HASH_FUNCTION))))
def _derive_pbkdf2(self, password): key_and_iv = pbkdf2_bin( password, self._encrypted_key.salt, self.iterations, keylen=32, ) return ( key_and_iv[0:16], key_and_iv[16:], )
def make_hash(password): """Generate a random salt and return a new hash for the password.""" if isinstance(password, unicode): password = password.encode('utf-8') salt = b64encode(urandom(SALT_LENGTH)) return 'PBKDF2${}${}${}${}'.format( HASH_FUNCTION, COST_FACTOR, salt, b64encode(pbkdf2_bin(password, salt, COST_FACTOR, KEY_LENGTH, getattr(hashlib, HASH_FUNCTION))))
def hash(password, algorithm, salt, cost_factor, **kwargs): """ Returns a hashed password (not a HashSeal) in binary format. **kwargs are passed to the underlying hash function unchanged. """ if algorithm == "pbkdf2": return pbkdf2.pbkdf2_bin(str(password), salt, cost_factor, **kwargs) else: raise ValueError("algorithm: Specified algorithm is not recognized.")
def make_hash(password): """Generate a random salt and return a new hash for the password.""" if isinstance(password, unicode): password = password.encode('utf-8') salt = b64encode(urandom(SALT_LENGTH)) # Python 2.6 fails to parse implicit positional args (-Jonas) # return 'PBKDF2${}${}${}${}'.format( return 'PBKDF2${0}${1}${2}${3}'.format( HASH_FUNCTION, COST_FACTOR, salt, b64encode( pbkdf2_bin(password, salt, COST_FACTOR, KEY_LENGTH, getattr(hashlib, HASH_FUNCTION))))
def make_hash(password): """Generate a random salt and return a new hash for the password.""" if isinstance(password, unicode): password = password.encode('utf-8') salt = b64encode(os.urandom(PBKDKF2.SALT_LENGTH)) return 'PBKDF2${}${}${}${}'.format( PBKDKF2.HASH_FUNCTION, PBKDKF2.COST_FACTOR, salt, b64encode(pbkdf2.pbkdf2_bin(password, salt, PBKDKF2.COST_FACTOR, PBKDKF2.KEY_LENGTH, getattr(hashlib, PBKDKF2.HASH_FUNCTION))))
def make_hash(password): """Generate a random salt and return a new hash for the password.""" if isinstance(password, unicode): password = password.encode('utf-8') salt = b64encode(urandom(SALT_LENGTH)) # Python 2.6 fails to parse implicit positional args (-Jonas) #return 'PBKDF2${}${}${}${}'.format( return 'PBKDF2${0}${1}${2}${3}'.format( HASH_FUNCTION, COST_FACTOR, salt, b64encode(pbkdf2_bin(password, salt, COST_FACTOR, KEY_LENGTH, getattr(hashlib, HASH_FUNCTION))))
def _make_password(cls, password, salt=None, iterations=None): if not salt: salt = binascii.b2a_hex(os.urandom(15)) if not iterations: iterations = 10000 hash_val = pbkdf2_bin(password.encode('utf-8'), salt, iterations, keylen=32, hashfunc=hashlib.sha256) hash_val = hash_val.encode('base64').strip() return '%s$%s$%s$%s' % ('pbkdf2_sha256', iterations, salt, hash_val)
def check_hash(password, hash_): """Check a password against an existing hash.""" if isinstance(password, unicode): password = password.encode('utf-8') algorithm, hash_function, cost_factor, salt, hash_a = hash_.split('$') assert algorithm == 'PBKDF2' hash_a = b64decode(hash_a) hash_b = pbkdf2.pbkdf2_bin(password, salt, int(cost_factor), len(hash_a), getattr(hashlib, hash_function)) assert len(hash_a) == len(hash_b) diff = 0 for char_a, char_b in izip(hash_a, hash_b): diff |= ord(char_a) ^ ord(char_b) return diff == 0
def check_hash(password, hash_): """Check a password against an existing hash.""" if isinstance(password, unicode): password = password.encode('utf-8') algorithm, hash_function, cost_factor, salt, hash_a = hash_.split('$') assert algorithm == 'PBKDF2' hash_a = b64decode(hash_a) hash_b = pbkdf2_bin(password, salt, int(cost_factor), len(hash_a), getattr(hashlib, hash_function)) assert len(hash_a) == len(hash_b) # we requested this from pbkdf2_bin() # Same as "return hash_a == hash_b" but takes a constant time. # See http://carlos.bueno.org/2011/10/timing.html diff = 0 for char_a, char_b in izip(hash_a, hash_b): diff |= ord(char_a) ^ ord(char_b) return diff == 0
def check_hash(password, hash_): """Check a password against an existing hash.""" if isinstance(password, str): password = password.encode('utf-8') algorithm, hash_function, cost_factor, salt, hash_a = hash_.split('$') assert algorithm == 'PBKDF2' hash_a = b64decode(hash_a) hash_b = pbkdf2_bin(password, salt, int(cost_factor), len(hash_a), getattr(hashlib, hash_function)) assert len(hash_a) == len(hash_b) # we requested this from pbkdf2_bin() # Same as "return hash_a == hash_b" but takes a constant time. # See http://carlos.bueno.org/2011/10/timing.html diff = 0 for char_a, char_b in zip(hash_a, hash_b): diff |= ord(char_a) ^ ord(char_b) return diff == 0
def decrypt_password(self, encrypted_pass): salt = self.get_salt() if self.master_password_used and constant.jitsi_masterpass: self.masterpass = constant.jitsi_masterpass elif self.master_password_used and not constant.jitsi_masterpass: return '\n[!] A master password is used, the password cannot be decrypted. Provide a masterpassword using the -ma option' # --- Decrypting the password --- # generate hash secret = pbkdf2_bin(bytes(self.masterpass), salt, self.iterations, self.keylen, hashfunc=hashlib.sha1) # decrypt password cipher = AES.new(secret) plaintext = cipher.decrypt(b64decode(encrypted_pass)).rstrip(self.padding) return plaintext.strip()
def generate(password): '''Generate a ShadowHashData structure as used by macOS 10.8+''' iterations = arc4random.randrange(30000, 50000) salt = make_salt(32) keylen = 128 try: entropy = hashlib.pbkdf2_hmac( 'sha512', password, salt, iterations, dklen=keylen) except AttributeError: # old Python, do it a different way entropy = pbkdf2.pbkdf2_bin( password, salt, iterations=iterations, keylen=keylen, hashfunc=hashlib.sha512) data = {'SALTED-SHA512-PBKDF2': {'entropy': buffer(entropy), 'iterations': iterations, 'salt': buffer(salt)}, } return plistutils.write_plist(data, plist_format='binary')
def make_hash(password): """Generate a random salt and return a new hash for the password.""" if isinstance(password, str): password = password.encode("utf-8") salt = b64encode(urandom(SALT_LENGTH)) return "PBKDF2${}${}${}${}".format( HASH_FUNCTION, COST_FACTOR, str(salt, "utf-8"), str( b64encode( pbkdf2_bin( password, salt, COST_FACTOR, KEY_LENGTH, getattr(hashlib, HASH_FUNCTION), ) ), "utf-8", ), )
assert isinstance(s1, binary_type), type(s1) assert isinstance(s2, binary_type), type(s2) assert len(s1) == len(s2) return b"".join([int2byte(ord(s1[i:i+1])^ord(s2[i:i+1])) for i in range(len(s1))]) def fakeKey(start): return b"".join([int2byte(c) for c in range(start, start+32)]) printheader("client stretch-KDF") emailUTF8 = u"andré@example.org".encode("utf-8") passwordUTF8 = u"pässwörd".encode("utf-8") printhex("email", emailUTF8) printhex("password", passwordUTF8) # stretching quickStretchedPW = pbkdf2_bin(passwordUTF8, KWE("quickStretch", emailUTF8), 1000, keylen=1*32, hashfunc=sha256) printhex("quickStretchedPW", quickStretchedPW) authPW = HKDF(SKM=quickStretchedPW, XTS="", CTXinfo=KW("authPW"), dkLen=1*32) printhex("authPW", authPW) authSalt = b"\x00"+b"\xf0"+b"\x00"*(32-2) printhex("authSalt (normally random)", authSalt) bigStretchedPW = scrypt.hash(authPW, authSalt, N=64*1024, r=8, p=1, buflen=1*32) printhex("bigStretchedPW", bigStretchedPW) verifyHash = HKDF(SKM=bigStretchedPW, XTS="", CTXinfo=KW("verifyHash"), dkLen=1*32) printhex("verifyHash", verifyHash)
# We check policy AFTER cache lookup since it is already verified for those if strict_policy: try: assure_password_strength(configuration, password) except Exception, exc: _logger.warning( "%s password for %s does not fit local policy: %s" % (service, username, exc)) return False else: _logger.debug("password policy check disabled for %s login as %s" % (service, username)) algorithm, hash_function, cost_factor, salt, hash_a = hashed.split('$') assert algorithm == 'PBKDF2' hash_a = b64decode(hash_a) hash_b = pbkdf2_bin(password, salt, int(cost_factor), len(hash_a), getattr(hashlib, hash_function)) assert len(hash_a) == len(hash_b) # we requested this from pbkdf2_bin() # Same as "return hash_a == hash_b" but takes a constant time. # See http://carlos.bueno.org/2011/10/timing.html diff = 0 for char_a, char_b in izip(hash_a, hash_b): diff |= ord(char_a) ^ ord(char_b) match = (diff == 0) if isinstance(hash_cache, dict) and match: hash_cache[pw_hash] = hashed # print "cached hash: %s" % hash_cache.get(pw_hash, None) return match def scramble_digest(salt, digest): """Scramble digest for saving"""
def make_key(username, password, iterations=1): if iterations == 1: return hashlib.sha256(username + password).digest() else: return pbkdf2.pbkdf2_bin(password, username, iterations, 32, hashlib.sha256)
def decrypt_app_data(app_id): # ================================================= # Get the _xkp value # ================================================= print '[+] Getting _xkp value from Keychain' ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect('127.0.0.1', port=2222, username='******', password='******') outdata, errdata = '', '' chan = ssh.get_transport().open_session() chan.setblocking(0) chan.exec_command('/var/root/keychain_dumper | grep _xkp -B1 -A4 | grep ' + app_id + ' -B1 -A4 | grep "Keychain"') while True: # monitoring process # Reading from output streams while chan.recv_ready(): outdata += chan.recv(1000) while chan.recv_stderr_ready(): errdata += chan.recv_stderr(1000) if chan.exit_status_ready(): # If completed break time.sleep(0.1) chan.close() # print outdata xkp = outdata.split(':')[1].strip() print bcolors.OKGREEN + "[+]" + bcolors.ENDC + " xkp Value: " + xkp # ******************************************************************************** # # ***** Now the decryption starts ******# encrypted_acontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/.AContainer' decrypted_acontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/AContainer' encrypted_ccontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/.CContainer' decrypted_ccontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/CContainer' encrypted_dcontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/.DContainer' decrypted_dcontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/DContainer' encrypted_mcontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/.MContainer' decrypted_mcontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/MContainer' # Decryption of the .DComtainer files start with a HMAC calculation hmac_key = xkp[:32] # Decrypt .gdrestoredata file gdrestoredata = decrypt_restore_data(encrypted_dcontainer + '/.gdrestoredata') gdrestoredata = filter(lambda x: x in string.printable, gdrestoredata) gdrestoredata = json.loads(gdrestoredata.strip()) # print gdrestoredata # Decrypt .gdstartupdata gdstartupdata = decrypt_file(encrypted_dcontainer + '/.gdstartupdata', hmac_key) gdstartupdata = filter(lambda x: x in string.printable, gdstartupdata) gdstartupdata = json.loads(gdstartupdata.strip()) if not os.path.exists(decrypted_dcontainer): os.makedirs(decrypted_dcontainer) f = open(decrypted_dcontainer + '/gdstartupdata', 'w') f.write(json.dumps(gdstartupdata, indent=4)) f.close() f = open(decrypted_dcontainer + '/gdrestoredata', 'w') f.write(json.dumps(gdrestoredata, indent=4)) f.close() # ================================================= # Calculate the UserKeyHash to see if it matches, else quit # ================================================= # Get the salt RandomHashSalt = b64decode(gdstartupdata['RandomHashSalt']) # pbkdf2 values SALT_LENGTH = 8 KEY_LENGTH = 32 HASH_FUNCTION = 'sha512' ITER = 12345 # Ask user for user pass user_password = getpass.getpass('Please enter your user pass:'******'\n' + bcolors.WARNING + '[+]' + bcolors.ENDC + ' .gdstartupdata UserKeyHash: ' + gdstartupdata['UserKeyHash'] print bcolors.WARNING + '[+]' + bcolors.ENDC + ' Calculate UserKeyHash: ' + b64encode(hashlib.sha512(generated_UserKeyHash).digest()) if (gdstartupdata['UserKeyHash'] == b64encode(hashlib.sha512(generated_UserKeyHash).digest())): print bcolors.OKGREEN + 'Keys Match!' + bcolors.ENDC + '\n' else: print bcolors.FAIL + 'Keys DO NOT Match!' + bcolors.ENDC + '\n' print '[-] .DContainer decrypted.' print '[-] However, without the correct user key, the other containers cannot be decrypted.' quit() # ================================================= # Get keys to decrypt FS # ================================================= startupiv = b64decode(gdstartupdata['StartupIV']) # Encrypted Data Encryption Key, needs to be decrypted edek = b64decode(gdstartupdata['EncryptedMCKey']) dek = aes_cbc_decrypt(edek, startupiv, generated_UserKeyHash)[:32] print "[+] Data Encryption Key: " + dek.encode('hex') print '[+] Decrypting MContainer ...' shutil.copytree(encrypted_mcontainer, decrypted_mcontainer) for root, dirs, files in os.walk(decrypted_mcontainer): for d in dirs: orig_d = d d = b64_filename(d) if decode_base64(d)[0] == '\x02': folder_name = aes_cbc_decrypt(decode_base64(d)[1:], startupiv, dek).strip() else: folder_name = aes_cbc_decrypt(decode_base64(d), startupiv, dek).strip() folder_name = filter(lambda x: x in string.printable, folder_name) os.rename(decrypted_mcontainer + '/' + orig_d, decrypted_mcontainer + '/' + folder_name) for root, dirs, files in os.walk(decrypted_mcontainer): for f in files: orig_f = f f = b64_filename(f) try: if decode_base64(f)[0] == '\x02': file_name = aes_cbc_decrypt(decode_base64(f)[1:], startupiv, dek).strip() else: file_name = aes_cbc_decrypt(decode_base64(f), startupiv, dek).strip() except: e = sys.exc_info()[0] try: file_name = filter(lambda x: x in string.printable, file_name) os.rename(os.path.join(root, orig_f), os.path.join(root, file_name)) new_file_path = os.path.join(root, file_name) data = decrypt_file(new_file_path, dek) data = filter(lambda x: x in string.printable, data) if (os.path.splitext(new_file_path)[1] == '.cfg') or (os.path.splitext(new_file_path)[1] == '.data'): try: data = json.loads(data.strip()) data = json.dumps(data, indent=4) except: e = sys.exc_info()[0] f = open(new_file_path, 'w') f.write(data) f.close() except: e = sys.exc_info()[0] print '[+] Decrypting CContainer ...' shutil.copytree(encrypted_ccontainer, decrypted_ccontainer) for root, dirs, files in os.walk(decrypted_ccontainer): for d in dirs: orig_d = d d = b64_filename(d) if decode_base64(d)[0] == '\x02': folder_name = aes_cbc_decrypt(decode_base64(d)[1:], startupiv, dek).strip() else: folder_name = aes_cbc_decrypt(decode_base64(d), startupiv, dek).strip() folder_name = filter(lambda x: x in string.printable, folder_name) os.rename(decrypted_ccontainer + '/' + orig_d, decrypted_ccontainer + '/' + folder_name) for root, dirs, files in os.walk(decrypted_ccontainer): for f in files: orig_f = f f = b64_filename(f) try: if decode_base64(f)[0] == '\x02': file_name = aes_cbc_decrypt(decode_base64(f)[1:], startupiv, dek).strip() else: file_name = aes_cbc_decrypt(decode_base64(f), startupiv, dek).strip() except: e = sys.exc_info()[0] file_name = filter(lambda x: x in string.printable, file_name) os.rename(os.path.join(root, orig_f), os.path.join(root, file_name)) new_file_path = os.path.join(root, file_name) data = decrypt_file(new_file_path, dek) data = filter(lambda x: x in string.printable, data) if (os.path.splitext(new_file_path)[1] == '.cfg') or (os.path.splitext(new_file_path)[1] == '.data'): try: data = json.loads(data.strip()) data = json.dumps(data, indent=4) except: e = sys.exc_info()[0] f = open(new_file_path, 'w') f.write(data) f.close()
def get_key_and_iv(passphrase, salt): keyiv = pbkdf2_bin(passphrase, salt, iterations=HASH_COUNT, keylen=32) key = keyiv[0:KEY_LEN_BYTES] iv = keyiv[KEY_LEN_BYTES:IV_LEN_BYTES + KEY_LEN_BYTES] return key, iv
def decrypt_app_data(app_id): # ================================================= # Get the _xkp value # ================================================= print '[+] Getting _xkp value from Keychain' ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect('127.0.0.1', port=2222, username='******', password='******') outdata, errdata = '', '' chan = ssh.get_transport().open_session() chan.setblocking(0) chan.exec_command('/var/root/keychain_dumper | grep _xkp -B1 -A4 | grep ' + app_id + ' -B1 -A4 | grep "Keychain"') while True: # monitoring process # Reading from output streams while chan.recv_ready(): outdata += chan.recv(1000) while chan.recv_stderr_ready(): errdata += chan.recv_stderr(1000) if chan.exit_status_ready(): # If completed break time.sleep(0.1) chan.close() # print outdata xkp = outdata.split(':')[1].strip() print bcolors.OKGREEN + "[+]" + bcolors.ENDC + " xkp Value: " + xkp # ******************************************************************************** # # ***** Now the decryption starts ******# encrypted_acontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/.AContainer' decrypted_acontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/AContainer' encrypted_ccontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/.CContainer' decrypted_ccontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/CContainer' encrypted_dcontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/.DContainer' decrypted_dcontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/DContainer' encrypted_mcontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/.MContainer' decrypted_mcontainer = app_id + '/608f451bf3593931c3880ff5e2b7bf41/MContainer' # Decryption of the .DComtainer files start with a HMAC calculation hmac_key = xkp[:32] # Decrypt .gdrestoredata file gdrestoredata = decrypt_restore_data(encrypted_dcontainer + '/.gdrestoredata') gdrestoredata = filter(lambda x: x in string.printable, gdrestoredata) gdrestoredata = json.loads(gdrestoredata.strip()) # print gdrestoredata # Decrypt .gdstartupdata gdstartupdata = decrypt_file(encrypted_dcontainer + '/.gdstartupdata', hmac_key) gdstartupdata = filter(lambda x: x in string.printable, gdstartupdata) gdstartupdata = json.loads(gdstartupdata.strip()) if not os.path.exists(decrypted_dcontainer): os.makedirs(decrypted_dcontainer) f = open(decrypted_dcontainer + '/gdstartupdata', 'w') f.write(json.dumps(gdstartupdata, indent=4)) f.close() f = open(decrypted_dcontainer + '/gdrestoredata', 'w') f.write(json.dumps(gdrestoredata, indent=4)) f.close() # ================================================= # Calculate the UserKeyHash to see if it matches, else quit # ================================================= # Get the salt RandomHashSalt = b64decode(gdstartupdata['RandomHashSalt']) # pbkdf2 values SALT_LENGTH = 8 KEY_LENGTH = 32 HASH_FUNCTION = 'sha512' ITER = 12345 # Ask user for user pass user_password = getpass.getpass('Please enter your user pass:'******'\n' + bcolors.WARNING + '[+]' + bcolors.ENDC + ' .gdstartupdata UserKeyHash: ' + gdstartupdata[ 'UserKeyHash'] print bcolors.WARNING + '[+]' + bcolors.ENDC + ' Calculate UserKeyHash: ' + b64encode( hashlib.sha512(generated_UserKeyHash).digest()) if (gdstartupdata['UserKeyHash'] == b64encode( hashlib.sha512(generated_UserKeyHash).digest())): print bcolors.OKGREEN + 'Keys Match!' + bcolors.ENDC + '\n' else: print bcolors.FAIL + 'Keys DO NOT Match!' + bcolors.ENDC + '\n' print '[-] .DContainer decrypted.' print '[-] However, without the correct user key, the other containers cannot be decrypted.' quit() # ================================================= # Get keys to decrypt FS # ================================================= startupiv = b64decode(gdstartupdata['StartupIV']) # Encrypted Data Encryption Key, needs to be decrypted edek = b64decode(gdstartupdata['EncryptedMCKey']) dek = aes_cbc_decrypt(edek, startupiv, generated_UserKeyHash)[:32] print "[+] Data Encryption Key: " + dek.encode('hex') print '[+] Decrypting MContainer ...' shutil.copytree(encrypted_mcontainer, decrypted_mcontainer) for root, dirs, files in os.walk(decrypted_mcontainer): for d in dirs: orig_d = d d = b64_filename(d) if decode_base64(d)[0] == '\x02': folder_name = aes_cbc_decrypt( decode_base64(d)[1:], startupiv, dek).strip() else: folder_name = aes_cbc_decrypt(decode_base64(d), startupiv, dek).strip() folder_name = filter(lambda x: x in string.printable, folder_name) os.rename(decrypted_mcontainer + '/' + orig_d, decrypted_mcontainer + '/' + folder_name) for root, dirs, files in os.walk(decrypted_mcontainer): for f in files: orig_f = f f = b64_filename(f) try: if decode_base64(f)[0] == '\x02': file_name = aes_cbc_decrypt( decode_base64(f)[1:], startupiv, dek).strip() else: file_name = aes_cbc_decrypt(decode_base64(f), startupiv, dek).strip() except: e = sys.exc_info()[0] try: file_name = filter(lambda x: x in string.printable, file_name) os.rename(os.path.join(root, orig_f), os.path.join(root, file_name)) new_file_path = os.path.join(root, file_name) data = decrypt_file(new_file_path, dek) data = filter(lambda x: x in string.printable, data) if (os.path.splitext(new_file_path)[1] == '.cfg') or (os.path.splitext(new_file_path)[1] == '.data'): try: data = json.loads(data.strip()) data = json.dumps(data, indent=4) except: e = sys.exc_info()[0] f = open(new_file_path, 'w') f.write(data) f.close() except: e = sys.exc_info()[0] print '[+] Decrypting CContainer ...' shutil.copytree(encrypted_ccontainer, decrypted_ccontainer) for root, dirs, files in os.walk(decrypted_ccontainer): for d in dirs: orig_d = d d = b64_filename(d) if decode_base64(d)[0] == '\x02': folder_name = aes_cbc_decrypt( decode_base64(d)[1:], startupiv, dek).strip() else: folder_name = aes_cbc_decrypt(decode_base64(d), startupiv, dek).strip() folder_name = filter(lambda x: x in string.printable, folder_name) os.rename(decrypted_ccontainer + '/' + orig_d, decrypted_ccontainer + '/' + folder_name) for root, dirs, files in os.walk(decrypted_ccontainer): for f in files: orig_f = f f = b64_filename(f) try: if decode_base64(f)[0] == '\x02': file_name = aes_cbc_decrypt( decode_base64(f)[1:], startupiv, dek).strip() else: file_name = aes_cbc_decrypt(decode_base64(f), startupiv, dek).strip() except: e = sys.exc_info()[0] file_name = filter(lambda x: x in string.printable, file_name) os.rename(os.path.join(root, orig_f), os.path.join(root, file_name)) new_file_path = os.path.join(root, file_name) data = decrypt_file(new_file_path, dek) data = filter(lambda x: x in string.printable, data) if (os.path.splitext(new_file_path)[1] == '.cfg') or (os.path.splitext(new_file_path)[1] == '.data'): try: data = json.loads(data.strip()) data = json.dumps(data, indent=4) except: e = sys.exc_info()[0] f = open(new_file_path, 'w') f.write(data) f.close()
elif sys.argv[1] == "k": mode = "0-in-xk" elif sys.argv[1] == "M": mode = "0-in-xM" else: raise ValueError("unknown mode '%s'" % sys.argv[1]) printheader("stretch-KDF") emailUTF8 = u"andré@example.org".encode("utf-8") passwordUTF8 = u"pässwörd".encode("utf-8") printhex("email", emailUTF8) printhex("password", passwordUTF8) # stretching time_start = time.time() k1 = pbkdf2_bin(passwordUTF8, KWE("first-PBKDF", emailUTF8), 20 * 1000, keylen=1 * 32, hashfunc=sha256) time_k1 = time.time() printhex("K1 (scrypt input)", k1) k2 = scrypt.hash(k1, KW("scrypt"), N=64 * 1024, r=8, p=1, buflen=1 * 32) time_k2 = time.time() printhex("K2 (scrypt output)", k2) stretchedPW = pbkdf2_bin(k2 + passwordUTF8, KWE("second-PBKDF", emailUTF8), 20 * 1000, keylen=1 * 32, hashfunc=sha256) time_k3 = time.time() # print "stretching took %0.3f seconds (P=%0.3f + S=%0.3f + P=%0.3f)" % \ # (time_k3-time_start, # time_k1-time_start, time_k2-time_k1, time_k3-time_k2) printhex("stretchedPW", stretchedPW) def findMainSalt(stretchedPW):
def make_key(cls, username, password, key_iteration_count): if key_iteration_count == 1: return hashlib.sha256(username + password).digest() else: return pbkdf2.pbkdf2_bin(password, username, key_iteration_count, 32, hashlib.sha256)
def main(): emailUTF8, passwordUTF8, command = sys.argv[1:4] assert isinstance(emailUTF8, binary_type) printhex("email", emailUTF8) printhex("password", passwordUTF8) k1 = pbkdf2_bin(passwordUTF8, KWE("first-PBKDF", emailUTF8), 20*1000, keylen=1*32, hashfunc=sha256) time_k1 = time.time() printhex("K1", k1) k2 = scrypt.hash(k1, KW("scrypt"), N=64*1024, r=8, p=1, buflen=1*32) time_k2 = time.time() printhex("K2", k2) stretchedPW = pbkdf2_bin(k2+passwordUTF8, KWE("second-PBKDF", emailUTF8), 20*1000, keylen=1*32, hashfunc=sha256) printhex("stretchedPW", stretchedPW) GET("__heartbeat__") if command == "create": mainKDFSalt = makeRandom() srpSalt = makeRandom() else: r = POST("session/auth/start", {"email": #emailUTF8.encode("hex") emailUTF8.encode("utf-8") }) print "auth/start", r srpToken = r["srpToken"] B = r["srp"]["B"].decode("hex") srpSalt = r["srp"]["s"].decode("hex") mainKDFSalt = r["stretch"]["salt"].decode("hex") # ignore stretch.rounds, srp.N_bits, srp.alg printhex("mainKDFSalt", mainKDFSalt) printhex("srpSalt", srpSalt) (srpPW, unwrapBKey) = split(HKDF(SKM=stretchedPW, XTS=mainKDFSalt, CTXinfo=KW("mainKDF"), dkLen=2*32)) if command == "create": (srpVerifier, _, _, _, _) = mysrp.create_verifier(emailUTF8, srpPW, srpSalt) r = POST("account/create", {#"email": emailUTF8.encode("hex"), # TODO prefer hex "email": emailUTF8.encode("utf-8"), "verifier": srpVerifier.encode("hex"), "salt": srpSalt.encode("hex"), "params": {"srp": {"alg": "sha256", "N_bits": 2048}, "stretch": {"salt": mainKDFSalt.encode("hex"), "rounds": 20000} }, }) print r else: srpClient = mysrp.Client() A = srpClient.one() M1 = srpClient.two(B, srpSalt, emailUTF8, srpPW) r = POST("session/auth/finish", {"srpToken": srpToken, "A": A.encode("hex"), "M": M1.encode("hex")}) print "auth/finish:", r bundle = r["bundle"].decode("hex") print "bundlelen", len(bundle) # note: the server is not yet using the new protocol. The old one # returns keyFetchToken+sessionToken if 1: # old protocol x = HKDF(SKM=srpClient.get_key(), dkLen=3*32, XTS=None, CTXinfo=KW("session/auth")) respHMACkey = x[0:32] respXORkey = x[32:] ct,respMAC = bundle[:-32], bundle[-32:] respMAC2 = HMAC(respHMACkey, ct) printhex("respHMACkey", respHMACkey) printhex("respXORkey", respXORkey) printhex("ct", ct) assert respMAC2 == respMAC, (respMAC2.encode("hex"), respMAC.encode("hex")) keyFetchToken, sessionToken = split(xor(respXORkey,ct)) if 0: # new protocol authToken = getAuthToken(srpClient.get_key()) x = HKDF(SKM=srpClient.get_key(), dkLen=2*32, XTS=None, CTXinfo=KW("auth/finish")) respHMACkey = x[0:32] respXORkey = x[32:] ct,respMAC = bundle[:-32], bundle[-32:] respMAC2 = HMAC(respHMACkey, ct) assert respMAC2 == respMAC, (respMAC2.encode("hex"), respMAC.encode("hex")) authToken = xor(ct, respXORkey) printhex("authToken", authToken) keyFetchToken, sessionToken = createSession(authToken) printhex("keyFetchToken", keyFetchToken) printhex("sessionToken", sessionToken) kA,kB = getKeys(keyFetchToken, unwrapBKey) printhex("kA", kA) printhex("kB", kB)
def get_key_and_iv(passphrase, salt): keyiv = pbkdf2_bin(passphrase, salt, iterations = HASH_COUNT, keylen = 32) key = keyiv[0:KEY_LEN_BYTES] iv = keyiv[KEY_LEN_BYTES:IV_LEN_BYTES+KEY_LEN_BYTES] return key, iv