def write_handy_store(page, data): cdb = [0xDA, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00] i = 2 for c in htonl(page): cdb[i] = c i += 1 py_sg.write(dev, _scsi_pack_cdb(cdb), data)
def unlock(save_passwd, unlock_with_saved_passwd): cdb = [0xC1, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00] sec_status, cipher_id, key_reset = get_encryption_status() ## Device should be in the correct state if (sec_status == 0x00 or sec_status == 0x02): print(fail("Your device is already unlocked!")) return elif (sec_status != 0x01): print(fail("Wrong device status!")) sys.exit(1) if cipher_id == 0x10 or cipher_id == 0x12 or cipher_id == 0x18: pwblen = 16 elif cipher_id == 0x20 or cipher_id == 0x22 or cipher_id == 0x28: pwblen = 32 elif cipher_id == 0x30: pwblen = 32 else: print(fail("Unsupported cipher %s" % cipher_id)) sys.exit(1) ## Get password from user if not unlock_with_saved_passwd: print(question("Insert password to Unlock the device")) passwd = getpass.getpass() iteration, salt, hint = read_handy_store_block1() pwd_hashed = mk_password_block(passwd, iteration, salt) else: print(success("Unlock use saved password")) passwd_bin = open("passwd.bin", "r") pwd_hashed = pickle.load(passwd_bin) if save_passwd: passwd_bin = open("passwd.bin", "w") pickle.dump(pwd_hashed, passwd_bin) pw_block = [0x45, 0x00, 0x00, 0x00, 0x00, 0x00] for c in htons(pwblen): pw_block.append(ord(c)) pwblen = pwblen + 8 cdb[8] = pwblen try: ## If there aren't exceptions the unlock operation is OK. py_sg.write(dev, _scsi_pack_cdb(cdb), _scsi_pack_cdb(pw_block) + pwd_hashed) print(success("Device unlocked.")) except: ## Wrong password or something bad is happened. print(fail("Wrong password.")) pass
def secure_erase(cipher_id=0): cdb = [0xC1, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00] status, current_cipher_id, key_reset = get_encryption_status() if cipher_id == 0: cipher_id = current_cipher_id pw_block = [0x45, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00] if cipher_id == 0x10 or cipher_id == 0x12 or cipher_id == 0x18: pwblen = 16 pw_block[3] = 0x01 elif cipher_id == 0x20 or cipher_id == 0x22 or cipher_id == 0x28: pwblen = 32 pw_block[3] = 0x01 elif cipher_id == 0x30: pwblen = 32 # pw_block[3] = 0x00 else: print(fail("Unsupported cipher %s" % cipher_id)) sys.exit(1) ## Set the actual lenght of pw_block (8 bytes + pwblen pseudorandom data) cdb[8] = pwblen + 8 ## Fill pw_block with random data for rand_byte in os.urandom(pwblen): pw_block.append(ord(rand_byte)) ## key_reset needs to be retrieved immidiatly before the reset request #status, current_cipher_id, key_reset = get_encryption_status() key_reset = get_encryption_status()[2] i = 2 for c in key_reset: cdb[i] = ord(c) i += 1 try: py_sg.write(dev, _scsi_pack_cdb(cdb), _scsi_pack_cdb(pw_block)) print( success( "Device erased. You need to create a new partition on the device (Hint: fdisk and mkfs)" )) except: ## Something bad is happened. print(fail("Something wrong.")) pass
def secure_erase(cipher_id = 0): cdb = [0xC1, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00] status, current_cipher_id, key_reset = get_encryption_status() if cipher_id == 0: cipher_id = current_cipher_id pw_block = [0x45,0x00,0x00,0x00,0x30,0x00,0x00,0x00] if cipher_id == 0x10 or cipher_id == 0x12 or cipher_id == 0x18: pwblen = 16; pw_block[3] = 0x01 elif cipher_id == 0x20 or cipher_id == 0x22 or cipher_id == 0x28: pwblen = 32; pw_block[3] = 0x01 elif cipher_id == 0x30: pwblen = 32; # pw_block[3] = 0x00 else: print fail("Unsupported cipher %s" % cipher_id) sys.exit(1) ## Set the actual lenght of pw_block (8 bytes + pwblen pseudorandom data) cdb[8] = pwblen + 8 ## Fill pw_block with random data for rand_byte in os.urandom(pwblen): pw_block.append(ord(rand_byte)) ## key_reset needs to be retrieved immidiatly before the reset request #status, current_cipher_id, key_reset = get_encryption_status() key_reset = get_encryption_status()[2] i = 2 for c in key_reset: cdb[i] = ord(c) i += 1 try: py_sg.write(dev, _scsi_pack_cdb(cdb), _scsi_pack_cdb(pw_block)) print success("Device erased. You need to create a new partition on the device (Hint: fdisk and mkfs)") except: ## Something bad is happened. print fail("Something wrong.") pass
def unlock(): cdb = [0xC1,0xE1,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00] sec_status, cipher_id, key_reset = get_encryption_status() ## Device should be in the correct state if (sec_status == 0x00 or sec_status == 0x02): print fail("Your device is already unlocked!") return elif (sec_status != 0x01): print fail("Wrong device status!") sys.exit(1) if cipher_id == 0x10 or cipher_id == 0x12 or cipher_id == 0x18: pwblen = 16; elif cipher_id == 0x20 or cipher_id == 0x22 or cipher_id == 0x28: pwblen = 32; elif cipher_id == 0x30: pwblen = 32; else: print fail("Unsupported cipher %s" % cipher_id) sys.exit(1) ## Get password from user print question("Insert password to Unlock the device") passwd = getpass.getpass() iteration,salt,hint = read_handy_store_block1() pwd_hashed = mk_password_block(passwd, iteration, salt) pw_block = [0x45,0x00,0x00,0x00,0x00,0x00] for c in htons(pwblen): pw_block.append(ord(c)) pwblen = pwblen + 8 cdb[8] = pwblen try: ## If there aren't exceptions the unlock operation is OK. py_sg.write(dev, _scsi_pack_cdb(cdb), _scsi_pack_cdb(pw_block) + pwd_hashed) print success("Device unlocked.") except: ## Wrong password or something bad is happened. print fail("Wrong password.") pass
def unlock(): global device_name ## Device should be in the correct state status = get_encryption_status() if (status["Locked"] in (0x00, 0x02)): print(fail("Your device is already unlocked!")) return elif (status["Locked"] != 0x01): print(fail("Wrong device status!")) sys.exit(1) ## Get password from user passwd = getpass.getpass( "[wdpassport] password for {}: ".format(device_name)) hash_parameters = read_handy_store_block1() if not hash_parameters: print(fail("Key hash parameters are not valid.")) sys.exit(1) iteration, salt, hint = hash_parameters pwd_hashed = mk_password_block(passwd, iteration, salt) pw_block = [0x45, 0x00, 0x00, 0x00, 0x00, 0x00] pwblen = status["PasswordLength"] for c in htons(pwblen): pw_block.append(c) pwblen = pwblen + 8 cdb = [0xC1, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00] cdb[8] = pwblen try: ## If there aren't exceptions the unlock operation is OK. py_sg.write(dev, _scsi_pack_cdb(cdb), _scsi_pack_cdb(pw_block) + pwd_hashed) print(success("Device unlocked.")) except: ## Wrong password or something bad is happened. print(fail("Wrong password.")) pass
def secure_erase(): cdb = [0xC1, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00] status = get_encryption_status() cipher_id = status["Cipher"] pw_block = [0x45, 0x00, 0x00, 0x00, cipher_id, 0x00, 0x00, 0x00] # For old ciphers, this code used to set the "combine" flag. # pw_block[3] = 0x01 ## Set the actual lenght of pw_block (8 bytes + pwblen pseudorandom data) pwblen = status["PasswordLength"] cdb[8] = pwblen + 8 ## Fill pw_block with random data for rand_byte in os.urandom(pwblen): pw_block.append(rand_byte) ## key_reset needs to be retrieved immidiatly before the reset request #status, current_cipher_id, key_reset = get_encryption_status() key_reset = status["KeyResetEnabler"] i = 2 for c in key_reset: cdb[i] = c i += 1 try: py_sg.write(dev, _scsi_pack_cdb(cdb), _scsi_pack_cdb(pw_block)) print( success( "Device erased. You need to create a new partition on the device (Hint: fdisk and mkfs)" )) except: ## Something bad is happened. print(fail("Something went wrong.")) pass
def change_password(): cdb = [0xC1, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00] sec_status, cipher_id, key_reset = get_encryption_status() if (sec_status != 0x02 and sec_status != 0x00): print fail("Device has to be unlocked or without encryption to perform this operation") sys.exit(1) if cipher_id == 0x10 or cipher_id == 0x12 or cipher_id == 0x18: pwblen = 16; elif cipher_id == 0x20 or cipher_id == 0x22 or cipher_id == 0x28: pwblen = 32; elif cipher_id == 0x30: pwblen = 32; else: print fail("Unsupported cipher %s" % cipher_id) sys.exit(1) print question("Insert the OLD password") old_passwd = getpass.getpass() print question("Insert the NEW password") new_passwd = getpass.getpass() print question("Confirm the NEW password") new_passwd2 = getpass.getpass() if new_passwd != new_passwd2: print fail("Password confirmation doesn't match the given password") sys.exit(1) ## Both passwords shouldn't be empty if (len(old_passwd) <= 0 and len(new_passwd) <= 0): print fail("Both passwords shouldn't be empty") sys.exit(1) iteration,salt,hint = read_handy_store_block1() pw_block = [0x45,0x00,0x00,0x00,0x00,0x00] for c in htons(pwblen): pw_block.append(ord(c)) if (len(old_passwd) > 0): old_passwd_hashed = mk_password_block(old_passwd, iteration, salt) pw_block[3] = pw_block[3] | 0x10 else: old_passwd_hashed = "" for i in range(32): old_passwd_hashed = old_passwd_hashed + chr(0x00) if (len(new_passwd) > 0): new_passwd_hashed = mk_password_block(new_passwd, iteration, salt) pw_block[3] = pw_block[3] | 0x01 else: new_passwd_hashed = "" for i in range(32): new_passwd_hashed = new_passwd_hashed + chr(0x00) if pw_block[3] & 0x11 == 0x11: pw_block[3] = pw_block[3] & 0xEE pwblen = 8 + 2 * pwblen cdb[8] = pwblen try: ## If exception isn't raised the unlock operation gone ok. py_sg.write(dev, _scsi_pack_cdb(cdb), _scsi_pack_cdb(pw_block) + old_passwd_hashed + new_passwd_hashed) print success("Password changed.") except: ## Wrong password or something bad is happened. print fail("Error changing password") pass
def change_password(): # Check drive's current status. status = get_encryption_status() if (status["Locked"] not in (0x00, 0x02)): print( fail( "Device has to be unlocked or without encryption to perform this operation." )) sys.exit(1) # Get and confirm the current and new password. if status["Locked"] == 0x00: # The device doesn't have a password. old_passwd = "" else: old_passwd = getpass.getpass("Current password: "******"New password: "******"New password (again): ") if new_passwd != new_passwd2: print(fail("Password didn't match.")) sys.exit(1) ## Both passwords shouldn't be empty if (len(old_passwd) <= 0 and len(new_passwd) <= 0): print( fail( "Password can't be empty. The device doesn't yet have a password." )) sys.exit(1) # Construct the command. pw_block = [0x45, 0x00, 0x00, 0x00, 0x00, 0x00] # Get the length in bytes of the key for the drive's current cipher # and put that length into the command. pwblen = status["PasswordLength"] pw_block += list(htons(pwblen)) # For compatibility with the WD encryption tool, use the same # hashing mechanism and parameters to turn the user's password # input into a key. The parameters are stored in unencrypted data. hash_parameters = read_handy_store_block1() if hash_parameters is None: # No password hashing parameters are stored on the device. # Make some up and write them to the device. hash_parameters = ( 1000, ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(8)).encode("ascii"), # eight-byte salt b'wdpassport-utils'.ljust(202)) write_handy_store_block1(*hash_parameters) assert read_handy_store_block1() == hash_parameters iteration, salt, hint = hash_parameters if (len(old_passwd) > 0): old_passwd_hashed = mk_password_block(old_passwd, iteration, salt) pw_block[3] = pw_block[3] | 0x10 else: old_passwd_hashed = bytes([0x00] * 32) if (len(new_passwd) > 0): new_passwd_hashed = mk_password_block(new_passwd, iteration, salt) pw_block[3] = pw_block[3] | 0x01 else: new_passwd_hashed = bytes([0x00] * 32) if pw_block[3] & 0x11 == 0x11: pw_block[3] = pw_block[3] & 0xEE cdb = [0xC1, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00] pwblen = 8 + 2 * pwblen cdb[8] = pwblen try: ## If exception isn't raised the unlock operation gone ok. py_sg.write( dev, _scsi_pack_cdb(cdb), _scsi_pack_cdb(pw_block) + old_passwd_hashed + new_passwd_hashed) print(success("Password changed.")) except: ## Wrong password or something bad is happened. print(fail("Error changing password.")) pass
def change_password(): cdb = [0xC1, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00] sec_status, cipher_id, key_reset = get_encryption_status() if (sec_status != 0x02 and sec_status != 0x00): print fail( "Device has to be unlocked or without encryption to perform this operation" ) sys.exit(1) if cipher_id == 0x10 or cipher_id == 0x12 or cipher_id == 0x18: pwblen = 16 elif cipher_id == 0x20 or cipher_id == 0x22 or cipher_id == 0x28: pwblen = 32 elif cipher_id == 0x30: pwblen = 32 else: print fail("Unsupported cipher %s" % cipher_id) sys.exit(1) print question("Insert the OLD password") old_passwd = getpass.getpass() print question("Insert the NEW password") new_passwd = getpass.getpass() print question("Confirm the NEW password") new_passwd2 = getpass.getpass() if new_passwd != new_passwd2: print fail("Password confirmation doesn't match the given password") sys.exit(1) ## Both passwords shouldn't be empty if (len(old_passwd) <= 0 and len(new_passwd) <= 0): print fail("Both passwords shouldn't be empty") sys.exit(1) iteration, salt, hint = read_handy_store_block1() pw_block = [0x45, 0x00, 0x00, 0x00, 0x00, 0x00] for c in htons(pwblen): pw_block.append(ord(c)) if (len(old_passwd) > 0): old_passwd_hashed = mk_password_block(old_passwd, iteration, salt) pw_block[3] = pw_block[3] | 0x10 else: old_passwd_hashed = "" for i in range(32): old_passwd_hashed = old_passwd_hashed + chr(0x00) if (len(new_passwd) > 0): new_passwd_hashed = mk_password_block(new_passwd, iteration, salt) pw_block[3] = pw_block[3] | 0x01 else: new_passwd_hashed = "" for i in range(32): new_passwd_hashed = new_passwd_hashed + chr(0x00) if pw_block[3] & 0x11 == 0x11: pw_block[3] = pw_block[3] & 0xEE pwblen = 8 + 2 * pwblen cdb[8] = pwblen try: ## If exception isn't raised the unlock operation gone ok. py_sg.write( dev, _scsi_pack_cdb(cdb), _scsi_pack_cdb(pw_block) + old_passwd_hashed + new_passwd_hashed) print success("Password changed.") except: ## Wrong password or something bad is happened. print fail("Error changing password") pass