/** * Encrypt database with new password * * @param oldPassword the old password * @param newPassword the new password * @param encrypt * @return re-encrypted database */ boolean changeMasterPassword(String oldPassword, String newPassword, boolean encrypt) { if (!setMasterPassword(oldPassword)) { return false; } byte[] oldKey = key.get(); byte[] newKey = EncryptionUtil.genPasswordKey(newPassword); ByteArrayWrapper testKey = new ByteArrayWrapper( EncryptionUtil.dbKey(oldKey, MasterKeyPasswordSafe.class, testKey(oldPassword))); HashMap<ByteArrayWrapper, byte[]> oldDb = new HashMap<ByteArrayWrapper, byte[]>(); database.copyTo(oldDb); HashMap<ByteArrayWrapper, byte[]> newDb = new HashMap<ByteArrayWrapper, byte[]>(); for (Map.Entry<ByteArrayWrapper, byte[]> e : oldDb.entrySet()) { if (testKey.equals(e.getKey())) { continue; } byte[] decryptedKey = EncryptionUtil.decryptKey(oldKey, e.getKey().unwrap()); String decryptedText = EncryptionUtil.decryptText(oldKey, e.getValue()); newDb.put( new ByteArrayWrapper(EncryptionUtil.encryptKey(newKey, decryptedKey)), EncryptionUtil.encryptText(newKey, decryptedText)); } synchronized (database.getDbLock()) { resetMasterPassword(newPassword, encrypt); database.putAll(newDb); } return true; }
/** * Reset password for the password safe (clears password database). The method is used from * plugin's UI. * * @param password the password to set * @param encrypt if the password should be encrypted an stored is master database */ void resetMasterPassword(String password, boolean encrypt) { this.key.set(EncryptionUtil.genPasswordKey(password)); database.clear(); try { storePassword(null, MasterKeyPasswordSafe.class, testKey(password), TEST_PASSWORD_VALUE); if (encrypt) { database.setPasswordInfo(encryptPassword(password)); } else { database.setPasswordInfo(new byte[0]); } } catch (PasswordSafeException e) { throw new IllegalStateException("There should be no problem with password at this point", e); } }
@Override protected byte[] key(@Nullable final Project project) throws PasswordSafeException { ApplicationEx application = (ApplicationEx) ApplicationManager.getApplication(); if (!isTestMode() && application.isHeadlessEnvironment()) { throw new MasterPasswordUnavailableException( "The provider is not available in headless environment"); } if (key.get() == null) { if (isPasswordEncrypted()) { try { String s = decryptPassword(database.getPasswordInfo()); setMasterPassword(s); } catch (PasswordSafeException e) { // ignore exception and ask password } } if (key.get() == null) { final Ref<PasswordSafeException> ex = new Ref<PasswordSafeException>(); if (application.holdsReadLock()) { throw new IllegalStateException( "Access from read action is not allowed, because it might lead to a deadlock."); } application.invokeAndWait( new Runnable() { public void run() { if (key.get() == null) { try { if (isTestMode()) { throw new MasterPasswordUnavailableException( "Master password must be specified in test mode."); } if (database.isEmpty()) { if (!ResetPasswordDialog.newPassword(project, MasterKeyPasswordSafe.this)) { throw new MasterPasswordUnavailableException( "Master password is required to store passwords in the database."); } } else { MasterPasswordDialog.askPassword(project, MasterKeyPasswordSafe.this); } } catch (PasswordSafeException e) { ex.set(e); } catch (Exception e) { //noinspection ThrowableInstanceNeverThrown ex.set( new MasterPasswordUnavailableException( "The problem with retrieving the password", e)); } } } }, ModalityState.defaultModalityState()); //noinspection ThrowableResultOfMethodCallIgnored if (ex.get() != null) { throw ex.get(); } } } return this.key.get(); }
/** {@inheritDoc} */ @Override public void removePassword(@Nullable Project project, Class requester, String key) throws PasswordSafeException { if (database.isEmpty()) { return; } super.removePassword(project, requester, key); }
/** {@inheritDoc} */ @Override public String getPassword(@Nullable Project project, Class requester, String key) throws PasswordSafeException { if (database.isEmpty()) { return null; } return super.getPassword(project, requester, key); }
/** @return check if provider database is empty */ public boolean isEmpty() { return database.isEmpty(); }
/** @return true, if the password is currently encrypted in the database */ public boolean isPasswordEncrypted() { byte[] i = database.getPasswordInfo(); return i != null && i.length > 0; }
/** {@inheritDoc} */ @Override protected void storeEncryptedPassword(byte[] key, byte[] encryptedPassword) { database.put(key, encryptedPassword); }
/** {@inheritDoc} */ @Override protected void removeEncryptedPassword(byte[] key) { database.remove(key); }
/** {@inheritDoc} */ @Override protected byte[] getEncryptedPassword(byte[] key) { return database.get(key); }