Skip to content

Commit

Permalink
Clean-up and simplify LinuxPasswordProvider and WinCrypto
Browse files Browse the repository at this point in the history
  • Loading branch information
HannesWell committed Mar 24, 2024
1 parent 1b16627 commit 55591ec
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 82 deletions.
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2021 IBM Corporation and others.
* Copyright (c) 2017, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -17,7 +17,6 @@

import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.spec.PBEKeySpec;
Expand All @@ -42,26 +41,14 @@ public class LinuxPasswordProvider extends PasswordProvider implements IValidati
private static final int PASSWORD_LENGTH = 64;

private static final String SECRET_COLLECTION_DEFAULT = "default"; //$NON-NLS-1$
private static final Map<String, Object> LIB_LOAD_OPTIONS = new HashMap<>();
// open flags = (RTLD_NODELETE | RTLD_GLOBAL | RTLD_LAZY)
private static final Map<String, Object> LIB_LOAD_OPTIONS = Map.of(Library.OPTION_OPEN_FLAGS, 0x1101);

private SecretSchema fEquinoxSchema;
private final SecretSchema fEquinoxSchema = new SecretSchema("org.eclipse.equinox", //$NON-NLS-1$
SecretSchemaFlags.SECRET_SCHEMA_NONE, new SecretSchemaAttribute(null, 0));
private LibSecret fLibSecret;
private LibGio fLibGio;

static {
// open flags = (RTLD_NODELETE | RTLD_GLOBAL | RTLD_LAZY)
LIB_LOAD_OPTIONS.put(Library.OPTION_OPEN_FLAGS, 0x1101);
}

public LinuxPasswordProvider() {
initEquinoxSchema();
}

private void initEquinoxSchema() {
fEquinoxSchema = new SecretSchema("org.eclipse.equinox", //$NON-NLS-1$
SecretSchemaFlags.SECRET_SCHEMA_NONE, new SecretSchemaAttribute(null, 0));
}

private interface LibGio extends Library {
Pointer g_bus_get_sync(int bus_type, Pointer cancellable, PointerByReference gerror);

Expand Down Expand Up @@ -98,29 +85,20 @@ private void unlockSecretService() {
gerror.setValue(Pointer.NULL);
fLibGio.g_bus_get_sync(GBusType.G_BUS_TYPE_SESSION, Pointer.NULL, gerror);
if (gerror.getValue() != Pointer.NULL) {
GError error = new GError(gerror.getValue());
String message = "Unable to get DBus session bus: " + error.message; //$NON-NLS-1$
fLibGio.g_error_free(gerror.getValue());
throw new SecurityException(message);
throw toSecurityException(gerror, "Unable to get DBus session bus: "); //$NON-NLS-1$
}

fLibSecret = Native.load("secret-1", LibSecret.class, LIB_LOAD_OPTIONS); //$NON-NLS-1$
Pointer secretService = fLibSecret.secret_service_get_sync(SecretServiceFlags.SECRET_SERVICE_LOAD_COLLECTIONS,
Pointer.NULL, gerror);
if (gerror.getValue() != Pointer.NULL) {
GError error = new GError(gerror.getValue());
String message = "Unable to get secret service: " + error.message; //$NON-NLS-1$
fLibGio.g_error_free(gerror.getValue());
throw new SecurityException(message);
throw toSecurityException(gerror, "Unable to get secret service: "); //$NON-NLS-1$
}

Pointer defaultCollection = fLibSecret.secret_collection_for_alias_sync(secretService,
SECRET_COLLECTION_DEFAULT, SecretCollectionFlags.SECRET_COLLECTION_NONE, Pointer.NULL, gerror);
if (gerror.getValue() != Pointer.NULL) {
GError error = new GError(gerror.getValue());
String message = "Unable to get secret collection: " + error.message; //$NON-NLS-1$
fLibGio.g_error_free(gerror.getValue());
throw new SecurityException(message);
throw toSecurityException(gerror, "Unable to get secret collection: "); //$NON-NLS-1$
}
if (defaultCollection == Pointer.NULL) {
throw new SecurityException("Unable to find default secret collection"); //$NON-NLS-1$
Expand All @@ -133,34 +111,19 @@ private void unlockSecretService() {
fLibGio.g_error_free(unlocked.getValue());
fLibGio.g_error_free(list.getPointer());
if (gerror.getValue() != Pointer.NULL) {
GError error = new GError(gerror.getValue());
String message = "Unable to unlock: " + error.message; //$NON-NLS-1$
fLibGio.g_error_free(gerror.getValue());
throw new SecurityException(message);
throw toSecurityException(gerror, "Unable to unlock: "); //$NON-NLS-1$
}
}

}

private boolean canUnlock() {
try {
unlockSecretService();
} catch (SecurityException e) {
return false;
}
return true;
}

private String getMasterPassword() throws SecurityException {
unlockSecretService();
PointerByReference gerror = new PointerByReference();
String password = fLibSecret.secret_password_lookup_sync(fEquinoxSchema, Pointer.NULL, gerror, Pointer.NULL);

if (gerror.getValue() != Pointer.NULL) {
GError error = new GError(gerror.getValue());
String message = error.message;
fLibGio.g_error_free(gerror.getValue());
throw new SecurityException(message);
throw toSecurityException(gerror, ""); //$NON-NLS-1$
} else if (password == null) {
throw new SecurityException("Unable to find password"); //$NON-NLS-1$
}
Expand All @@ -171,23 +134,25 @@ private String getMasterPassword() throws SecurityException {

private void saveMasterPassword(String password) throws SecurityException {
unlockSecretService();
String passwordUTF8 = password;
PointerByReference gerror = new PointerByReference();

byte[] utfbytes = password.getBytes();
passwordUTF8 = new String(utfbytes, StandardCharsets.UTF_8);
password = new String(password.getBytes(), StandardCharsets.UTF_8);

fLibSecret.secret_password_store_sync(fEquinoxSchema, SECRET_COLLECTION_DEFAULT, "Equinox master password", //$NON-NLS-1$
passwordUTF8, Pointer.NULL, gerror, Pointer.NULL);
password, Pointer.NULL, gerror, Pointer.NULL);

if (gerror.getValue() != Pointer.NULL) {
GError error = new GError(gerror.getValue());
String message = error.message;
fLibGio.g_error_free(gerror.getValue());
throw new SecurityException(message);
throw toSecurityException(gerror, ""); //$NON-NLS-1$
}
}

private SecurityException toSecurityException(PointerByReference gerror, String string) {
GError error = new GError(gerror.getValue());
String message = string + error.message;
fLibGio.g_error_free(gerror.getValue());
return new SecurityException(message);
}

@Override
public PBEKeySpec getPassword(IPreferencesContainer container, int passwordType) {

Expand Down Expand Up @@ -224,7 +189,8 @@ public PBEKeySpec getPassword(IPreferencesContainer container, int passwordType)
@Override
public boolean isValid() {
try {
return canUnlock();
unlockSecretService();
return true;
} catch (SecurityException e) {
return false;
}
Expand Down
@@ -1,13 +1,13 @@
/*******************************************************************************
* Copyright (c) 2008, 2017 IBM Corporation and others.
* Copyright (c) 2008, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
Expand Down Expand Up @@ -41,21 +41,22 @@ public class WinCrypto extends PasswordProvider {
System.loadLibrary("jnicrypt64");
}

private final static String WIN_PROVIDER_NODE = "/org.eclipse.equinox.secure.storage/windows64";
private final static String PASSWORD_KEY = "encryptedPassword";
private static final String WIN_PROVIDER_NODE = "/org.eclipse.equinox.secure.storage/windows64";
private static final String PASSWORD_KEY = "encryptedPassword";

/**
* The length of the randomly generated password in bytes
*/
private final static int PASSWORD_LENGTH = 250;
private static final int PASSWORD_LENGTH = 250;

@Override
public PBEKeySpec getPassword(IPreferencesContainer container, int passwordType) {
byte[] encryptedPassword;
if ((passwordType & CREATE_NEW_PASSWORD) == 0)
if ((passwordType & CREATE_NEW_PASSWORD) == 0) {
encryptedPassword = getEncryptedPassword(container);
else
} else {
encryptedPassword = null;
}

if (encryptedPassword != null) {
byte[] decryptedPassword = windecrypt(encryptedPassword);
Expand All @@ -78,24 +79,24 @@ public PBEKeySpec getPassword(IPreferencesContainer container, int passwordType)
random.setSeed(System.currentTimeMillis());
random.nextBytes(rawPassword);
String password = Base64.encode(rawPassword);
if (savePassword(password, container))
if (savePassword(password, container)) {
return new PBEKeySpec(password.toCharArray());
else
} else {
return null;
}
}

private byte[] getEncryptedPassword(IPreferencesContainer container) {
ISecurePreferences node = container.getPreferences().node(WIN_PROVIDER_NODE);
String passwordHint;
try {
passwordHint = node.get(PASSWORD_KEY, null);
String passwordHint = node.get(PASSWORD_KEY, null);
if (passwordHint != null) {
return Base64.decode(passwordHint);
}
} catch (StorageException e) { // should never happen in this scenario
AuthPlugin.getDefault().logError(WinCryptoMessages.decryptPasswordFailed, e);
return null;
}
if (passwordHint == null)
return null;
return Base64.decode(passwordHint);
return null;
}

private boolean savePassword(String password, IPreferencesContainer container) {
Expand Down
Expand Up @@ -31,7 +31,7 @@
* password provider module to the secure storage system.
* </p>
*/
abstract public class PasswordProvider {
public abstract class PasswordProvider {

/**
* Bit mask for the password type field of the
Expand All @@ -40,15 +40,15 @@ abstract public class PasswordProvider {
* otherwise this is a request for the password previously used for this secure
* storage.
*/
final public static int CREATE_NEW_PASSWORD = 1 << 0;
public static final int CREATE_NEW_PASSWORD = 1 << 0;

/**
* Bit mask for the password type field of the
* {@link #getPassword(IPreferencesContainer, int)} method. If value at this bit
* set to <code>1</code>, it indicates that a new password is requested as a
* part of the password change operation.
*/
final public static int PASSWORD_CHANGE = 1 << 1;
public static final int PASSWORD_CHANGE = 1 << 1;

/**
* This method should return the password used to encrypt entries in the secure
Expand All @@ -63,14 +63,7 @@ abstract public class PasswordProvider {
* @return password used to encrypt entries in the secure preferences,
* <code>null</code> if unable to obtain password
*/
abstract public PBEKeySpec getPassword(IPreferencesContainer container, int passwordType);

/**
* Constructor.
*/
public PasswordProvider() {
// placeholder
}
public abstract PBEKeySpec getPassword(IPreferencesContainer container, int passwordType);

/**
* The framework might call this method if it suspects that the password is
Expand Down

0 comments on commit 55591ec

Please sign in to comment.