-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add possibility to remember password for shared databases. #1846
Changes from all commits
1c99a8f
6390dab
bf6d431
879fb22
09a41c2
aa719b8
a38ff25
f9edc2e
0a8fc3a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package net.sf.jabref.shared.prefs; | ||
|
||
import java.util.Optional; | ||
import java.util.prefs.BackingStoreException; | ||
import java.util.prefs.Preferences; | ||
|
||
import net.sf.jabref.Globals; | ||
import net.sf.jabref.JabRefMain; | ||
import net.sf.jabref.gui.shared.OpenSharedDatabaseDialog; | ||
|
||
/** | ||
* Stores and reads persistent data for {@link OpenSharedDatabaseDialog}. | ||
*/ | ||
public class SharedDatabasePreferences { | ||
|
||
private static final String SHARED_DATABASE_TYPE = "sharedDatabaseType"; | ||
private static final String SHARED_DATABASE_HOST = "sharedDatabaseHost"; | ||
private static final String SHARED_DATABASE_PORT = "sharedDatabasePort"; | ||
private static final String SHARED_DATABASE_NAME = "sharedDatabaseName"; | ||
private static final String SHARED_DATABASE_USER = "sharedDatabaseUser"; | ||
private static final String SHARED_DATABASE_PASSWORD = "sharedDatabasePassword"; | ||
private static final String SHARED_DATABASE_REMEMBER_PASSWORD = "sharedDatabaseRememberPassword"; | ||
|
||
// This {@link Preferences} is used only for things which should not appear in real JabRefPreferences due to security reasons. | ||
private final Preferences internalPrefs = Preferences.userNodeForPackage(JabRefMain.class).parent().node("jabref-pwdstorage"); | ||
|
||
|
||
public Optional<String> getType() { | ||
return Globals.prefs.getAsOptional(SHARED_DATABASE_TYPE); | ||
} | ||
|
||
public Optional<String> getHost() { | ||
return Globals.prefs.getAsOptional(SHARED_DATABASE_HOST); | ||
} | ||
|
||
public Optional<String> getPort() { | ||
return Globals.prefs.getAsOptional(SHARED_DATABASE_PORT); | ||
} | ||
|
||
public Optional<String> getName() { | ||
return Globals.prefs.getAsOptional(SHARED_DATABASE_NAME); | ||
} | ||
|
||
public Optional<String> getUser() { | ||
return Globals.prefs.getAsOptional(SHARED_DATABASE_USER); | ||
} | ||
|
||
public Optional<String> getPassword() { | ||
return Optional.ofNullable(internalPrefs.get(SHARED_DATABASE_PASSWORD, null)); | ||
} | ||
|
||
public boolean getRememberPassword() { | ||
return Globals.prefs.getBoolean(SHARED_DATABASE_REMEMBER_PASSWORD, false); | ||
} | ||
|
||
public void setType(String type) { | ||
Globals.prefs.put(SHARED_DATABASE_TYPE, type); | ||
} | ||
|
||
public void setHost(String host) { | ||
Globals.prefs.put(SHARED_DATABASE_HOST, host); | ||
} | ||
|
||
public void setPort(String port) { | ||
Globals.prefs.put(SHARED_DATABASE_PORT, port); | ||
} | ||
|
||
public void setName(String name) { | ||
Globals.prefs.put(SHARED_DATABASE_NAME, name); | ||
} | ||
|
||
public void setUser(String user) { | ||
Globals.prefs.put(SHARED_DATABASE_USER, user); | ||
} | ||
|
||
public void setPassword(String password) { | ||
internalPrefs.put(SHARED_DATABASE_PASSWORD, password); | ||
} | ||
|
||
public void setRememberPassword(boolean rememberPassword) { | ||
Globals.prefs.putBoolean(SHARED_DATABASE_REMEMBER_PASSWORD, rememberPassword); | ||
} | ||
|
||
public void clearPassword() { | ||
internalPrefs.remove(SHARED_DATABASE_PASSWORD); | ||
} | ||
|
||
public void clear() throws BackingStoreException { | ||
internalPrefs.clear(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package net.sf.jabref.shared.security; | ||
|
||
import java.io.UnsupportedEncodingException; | ||
import java.security.GeneralSecurityException; | ||
import java.security.MessageDigest; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.util.Arrays; | ||
import java.util.Base64; | ||
|
||
import javax.crypto.Cipher; | ||
import javax.crypto.NoSuchPaddingException; | ||
import javax.crypto.spec.IvParameterSpec; | ||
import javax.crypto.spec.SecretKeySpec; | ||
|
||
/** | ||
* {@link Password} contains methods which are useful to encrypt and decrypt passwords using symetric algorithms. | ||
*/ | ||
public class Password { | ||
|
||
private final byte[] phrase; | ||
private final Cipher cipher; | ||
private final SecretKeySpec secretKey; | ||
private final IvParameterSpec ivSpec; | ||
|
||
|
||
/** | ||
* @param phrase Phrase which should be encrypted or decrypted | ||
* @param key Key which is used to improve symmetric encryption | ||
*/ | ||
public Password(char[] phrase, String key) throws NoSuchAlgorithmException, NoSuchPaddingException { | ||
this.phrase = new String(phrase).getBytes(); | ||
this.cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); | ||
this.secretKey = new SecretKeySpec(get128BitHash(key.getBytes()), "AES"); | ||
this.ivSpec = new IvParameterSpec("ThisIsA128BitKey".getBytes()); | ||
} | ||
|
||
/** | ||
* Encrypts the set phrase/password with a symmetric encryption algorithm. | ||
* | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, AES 128 bit is a joke and not really secure, I personally would prefer at least 256biz, but using stronger encryption is only possible with the Cryptographic Extensions Policy and unfortunately those fall under the US import/export regulation laws. It would be possible to check if they are installed and use a greater key size. Not sure it if is really necessary here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This functionality is unsecure anyway. Aim: #1846 (comment). |
||
* @return Encrypted phrase/password | ||
*/ | ||
public String encrypt() throws GeneralSecurityException, UnsupportedEncodingException { | ||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec); | ||
return new String(Base64.getEncoder().encode(cipher.doFinal(phrase)), "UTF-8"); | ||
} | ||
|
||
/** | ||
* Decrypts the set phrase/password which was encrypted via {@link Password#encrypt()}. | ||
* | ||
* @return Decrypted phrase/password | ||
*/ | ||
public String decrypt() throws GeneralSecurityException, UnsupportedEncodingException { | ||
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec); | ||
return new String(cipher.doFinal(Base64.getDecoder().decode(phrase)), "UTF-8"); | ||
} | ||
|
||
/** | ||
* Returns a 128 bit hash using SHA-256. | ||
*/ | ||
private byte[] get128BitHash(byte[] byteArrayToHash) throws NoSuchAlgorithmException { | ||
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); | ||
messageDigest.update(byteArrayToHash); | ||
return Arrays.copyOf(messageDigest.digest(), 16); // return 128 bit | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a javadoc as this class might be usefull to others in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.