Assuming that I'm trying to pull from a RESTful api that uses basic authentication / basic certificates, what would be the best way to store that user name and password in my program? Right now it's just sitting there in plaintext.
UsernamePasswordCredentials creds = new UsernamePasswordCredentials("myName#myserver","myPassword1234");
Is there some way of doing this that is more security minded?
Thanks
Important note:
If you're designing the authentication system as a whole, you shouldn't store passwords, even if they're encrypted. You store a hash, and check if passwords provided during login match the same hash. That way, a security breach on your database avoids getting your users' passwords exposed.
With that said, for situations where you are going to store data as-is (in this case passwords), then with an inner-to-outer mindset, here are some steps to protect your process:
First step, you should change your password-handling from String to character array.
The reason for this is that a String is an immutable object, and so it's data will not be cleansed immediately even if the object is set to null; The data is set for garbage-collection instead, and this poses security problems because malicious programs might gain access to that String (password) data before it is cleaned.
This is the main reason why Swing's JPasswordField's getText() method is deprecated, and why getPassword() uses character arrays.
The second step is to encrypt your credentials, only decrypting them temporarily during the authentication process. Or to hash them server-side, store that hash, and "forget" the original password.
This, similarly to the first step, makes sure your vulnerability-time is as small as possible.
It is recommended that your credentials are not hard-coded, and that instead, you store them in a centralized, configurable and easily-maintainable manner, such as a configuration or properties file, or a database.
You should encrypt your credentials before saving the file, and additionally, you can apply a second encryption to the file itself (2-layer encryption to the credentials, and 1-layer to other file contents).
Note that each of the two encryption processes mentioned above can be multiple-layered themselves. Each encryption can be an individual application of Triple Data Encryption Standard (AKA TDES and 3DES), as a conceptual example.
After your local environment is properly protected (but remember, it's never ever "safe"!), the third step is apply basic protection to your transmission process, by using TLS (Transport Layer Security) or SSL (Secure Sockets Layer).
The forth step is to apply other protection methods.
For example, applying obfuscation techniques to your "to-use" compile, to avoid (even if shortly) the exposure of your security measures in case your program is obtained by Ms. Eve, Mr. Mallory, or someone else (the bad-guys) and decompiled.
UPDATE 1:
By #Damien.Bell 's request, here is an example that covers the first and second steps:
//These will be used as the source of the configuration file's stored attributes.
private static final Map<String, String> COMMON_ATTRIBUTES = new HashMap<String, String>();
private static final Map<String, char[]> SECURE_ATTRIBUTES = new HashMap<String, char[]>();
//Ciphering (encryption and decryption) password/key.
private static final char[] PASSWORD = "Unauthorized_Personel_Is_Unauthorized".toCharArray();
//Cipher salt.
private static final byte[] SALT = {
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,};
//Desktop dir:
private static final File DESKTOP = new File(System.getProperty("user.home") + "/Desktop");
//File names:
private static final String NO_ENCRYPTION = "no_layers.txt";
private static final String SINGLE_LAYER = "single_layer.txt";
private static final String DOUBLE_LAYER = "double_layer.txt";
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws GeneralSecurityException, FileNotFoundException, IOException {
//Set common attributes.
COMMON_ATTRIBUTES.put("Gender", "Male");
COMMON_ATTRIBUTES.put("Age", "21");
COMMON_ATTRIBUTES.put("Name", "Hypot Hetical");
COMMON_ATTRIBUTES.put("Nickname", "HH");
/*
* Set secure attributes.
* NOTE: Ignore the use of Strings here, it's being used for convenience only.
* In real implementations, JPasswordField.getPassword() would send the arrays directly.
*/
SECURE_ATTRIBUTES.put("Username", "Hypothetical".toCharArray());
SECURE_ATTRIBUTES.put("Password", "LetMePass_Word".toCharArray());
/*
* For demosntration purposes, I make the three encryption layer-levels I mention.
* To leave no doubt the code works, I use real file IO.
*/
//File without encryption.
create_EncryptedFile(NO_ENCRYPTION, COMMON_ATTRIBUTES, SECURE_ATTRIBUTES, 0);
//File with encryption to secure attributes only.
create_EncryptedFile(SINGLE_LAYER, COMMON_ATTRIBUTES, SECURE_ATTRIBUTES, 1);
//File completely encrypted, including re-encryption of secure attributes.
create_EncryptedFile(DOUBLE_LAYER, COMMON_ATTRIBUTES, SECURE_ATTRIBUTES, 2);
/*
* Show contents of all three encryption levels, from file.
*/
System.out.println("NO ENCRYPTION: \n" + readFile_NoDecryption(NO_ENCRYPTION) + "\n\n\n");
System.out.println("SINGLE LAYER ENCRYPTION: \n" + readFile_NoDecryption(SINGLE_LAYER) + "\n\n\n");
System.out.println("DOUBLE LAYER ENCRYPTION: \n" + readFile_NoDecryption(DOUBLE_LAYER) + "\n\n\n");
/*
* Decryption is demonstrated with the Double-Layer encryption file.
*/
//Descrypt first layer. (file content) (REMEMBER: Layers are in reverse order from writing).
String decryptedContent = readFile_ApplyDecryption(DOUBLE_LAYER);
System.out.println("READ: [first layer decrypted]\n" + decryptedContent + "\n\n\n");
//Decrypt second layer (secure data).
for (String line : decryptedContent.split("\n")) {
String[] pair = line.split(": ", 2);
if (pair[0].equalsIgnoreCase("Username") || pair[0].equalsIgnoreCase("Password")) {
System.out.println("Decrypted: " + pair[0] + ": " + decrypt(pair[1]));
}
}
}
private static String encrypt(byte[] property) throws GeneralSecurityException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
//Encrypt and save to temporary storage.
String encrypted = Base64.encodeBytes(pbeCipher.doFinal(property));
//Cleanup data-sources - Leave no traces behind.
for (int i = 0; i < property.length; i++) {
property[i] = 0;
}
property = null;
System.gc();
//Return encryption result.
return encrypted;
}
private static String encrypt(char[] property) throws GeneralSecurityException {
//Prepare and encrypt.
byte[] bytes = new byte[property.length];
for (int i = 0; i < property.length; i++) {
bytes[i] = (byte) property[i];
}
String encrypted = encrypt(bytes);
/*
* Cleanup property here. (child data-source 'bytes' is cleaned inside 'encrypt(byte[])').
* It's not being done because the sources are being used multiple times for the different layer samples.
*/
// for (int i = 0; i < property.length; i++) { //cleanup allocated data.
// property[i] = 0;
// }
// property = null; //de-allocate data (set for GC).
// System.gc(); //Attempt triggering garbage-collection.
return encrypted;
}
private static String encrypt(String property) throws GeneralSecurityException {
String encrypted = encrypt(property.getBytes());
/*
* Strings can't really have their allocated data cleaned before CG,
* that's why secure data should be handled with char[] or byte[].
* Still, don't forget to set for GC, even for data of sesser importancy;
* You are making everything safer still, and freeing up memory as bonus.
*/
property = null;
return encrypted;
}
private static String decrypt(String property) throws GeneralSecurityException, IOException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
return new String(pbeCipher.doFinal(Base64.decode(property)));
}
private static void create_EncryptedFile(
String fileName,
Map<String, String> commonAttributes,
Map<String, char[]> secureAttributes,
int layers)
throws GeneralSecurityException, FileNotFoundException, IOException {
StringBuilder sb = new StringBuilder();
for (String k : commonAttributes.keySet()) {
sb.append(k).append(": ").append(commonAttributes.get(k)).append(System.lineSeparator());
}
//First encryption layer. Encrypts secure attribute values only.
for (String k : secureAttributes.keySet()) {
String encryptedValue;
if (layers >= 1) {
encryptedValue = encrypt(secureAttributes.get(k));
} else {
encryptedValue = new String(secureAttributes.get(k));
}
sb.append(k).append(": ").append(encryptedValue).append(System.lineSeparator());
}
//Prepare file and file-writing process.
File f = new File(DESKTOP, fileName);
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
} else if (f.exists()) {
f.delete();
}
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
//Second encryption layer. Encrypts whole file content including previously encrypted stuff.
if (layers >= 2) {
bw.append(encrypt(sb.toString().trim()));
} else {
bw.append(sb.toString().trim());
}
bw.flush();
bw.close();
}
private static String readFile_NoDecryption(String fileName) throws FileNotFoundException, IOException, GeneralSecurityException {
File f = new File(DESKTOP, fileName);
BufferedReader br = new BufferedReader(new FileReader(f));
StringBuilder sb = new StringBuilder();
while (br.ready()) {
sb.append(br.readLine()).append(System.lineSeparator());
}
return sb.toString();
}
private static String readFile_ApplyDecryption(String fileName) throws FileNotFoundException, IOException, GeneralSecurityException {
File f = new File(DESKTOP, fileName);
BufferedReader br = new BufferedReader(new FileReader(f));
StringBuilder sb = new StringBuilder();
while (br.ready()) {
sb.append(br.readLine()).append(System.lineSeparator());
}
return decrypt(sb.toString());
}
A full example, addressing every protection step, would far exceed what I think is reasonable for this question, since it's about "what are the steps", not "how to apply them".
It would far over-size my answer (at last the sampling), while other questions here on S.O. are already directed on the "How to" of those steps, being far more appropriate, and offering far better explanation and sampling on the implementation of each individual step.
If you are using basic auth, you should couple that with SSL to avoid passing your credentials in base64 encoded plain text. You don't want to make it easy for someone sniffing your packets to get your credentials. Also, don't hard code your credentials in your source code. Make them configurable. read them from a config file. You should encrypt the credentials before storing them in a config file and your app should decrypt the credentials once it reads them from the config file.
Why not store credentials in source code
It is generally a good idea to avoid to store credentials in source code.
The issue is, that access to code and who should have access to the credentials often changes over time. Once a project becomes more mature there are usually some developers who do not need to know and hence should not know certain credentials. In addition code may be reused for slightly different purposes or even become open source. Also, as the code base grows more complex, it becomes very tedious to identify credentials being buried somewhere in the middle of the code.
It seems safe to say that hundreds of millions of users have already been affected by issues caused by hard-coded credentials. Here is an article with some examples.
How to provide credentials to your app
If credentials are not part of the code, this raises the question how you can provide credentials to your application. This depends on the platform on which your application runs. For instance if you host your application on some cloud service, this service will have a mechanism to store credentials in a save way and inject them into the operation system environment of your application. To provide a specific example, here is the documentation how to provide credentials for an app hosted on Heroku.
In you application code you can then access them from the environment. E.g. for Java you could use getenv
String apiPassword = getenv("API_PASSWORD");
Here API_PASSWORD needs to be provided in the environment by the hosting mechanism of your app.
Further Reading
I have written a blog article about the topic that covers this topic in more detail: Keep passwords out of source code - why and how.
It's generally not good advice to encrypt credentials. Something that is encrypted can be decrypted. Common best practice is to store passwords as a salted hash.A hash cannot be decrypted. The salt is added to defeat brute force guessing with Rainbow Tables. As long as every userId has its own random salt, an attacker would have to generate a set of tables for every possible value of the salt, quickly making this attack impossible within the lifespan of the universe. This is the reason why websites generally can't send you your password if you have forgotten it, but they can only 'reset' it. They don't have your password stored, only a hash of it.
Password hashing is not very difficult to implement yourself, but it's such a common problem to solve that countless others have done it for you. I've found jBcrypt easy to use.
As an extra protection against brute force guessing of passwords, it is common best practice to force a userId or remote IP to wait a few seconds after a certain number of login attempts with the wrong password. Without this, a brute force attacker can guess as many passwords per second as your server can handle. There is a huge difference between being able to guess 100 passwords per 10 second period or a million.
I get the impression that you have included the username/password combination in your source code. This means that if you ever want to change the password, you'll have to recompile, stop and restart your service, and it also means that anyone who gets a hold of your source code, also has your passwords. Common best practice is never to do this, but to store the credentials (username, password hash, password salt) in your datastore
secure computer that initializes the request (your computer). if that machine is insecure, nothing will protect you. that's completely separate topic (up-to-date software, properly configured, strong passwords, encrypted swap, hardware sniffers, physical security etc)
secure your storage
the medium you use for storing your credentials should be encrypted. decrypted credentials should be stored only in ram of your secured machine
people that maintain that hardware must be trusted (probably the weakest link)
they also should know as few as possible. that's a protection from rubber-hose cryptanalysis
your credentials should fulfil all the security recommendation (proper length, randomness, single purpose etc)
your connection to remote service must be secured (SSL etc)
your remote service must be trusted (see points 1-4). plus it should be hacking prone (if your data/service is insecure then securing your credentials is pointless). plus it should not store your credentials
plus probably thousand things i forgot about :)
If you cannot trust the environment your program is running in, but need to authenticate via plain passwords or certificates, there is nothing you can do to secure your credentials. The most you can do is obfuscate them with the methods described in the other answers.
As a workaround, I'd run all requests to the RESTful api through a proxy that you can trust and do the cleartext password authentication from there.
why are people talking about hashing. OP wants to store his users credentials to access external resource. Hashing his password will not help.
Now that's out of the way. I would just simple best practices for every layer.
1 . Storing your password in java app. : Store it as Char Array. Create a password store class and store the password as hashmap with key as the resource that you want to access and value as some object that contains of username and password. Restrict the entry point to this api with some authentication Ex: accept the logged in users' credential to validate access level of that user for that resource (simply map user to list of passwords they can access. If you've a lot create a group and map passwordmap key to that group) Anything beyond this to store password depends on how paranoid you're about jvm itself to leak it.
to transmit the password ensure you're sending it on secured portocols (Ex: Https is good, http is bad). If you really must transmit over insecure protocol encrypt it and encode it to say base64. Ensure the recipient decodes and can decrypt your password.
Related
I am trying to make a Java program that requires a password. The problem is that a Java class or JAR file can be converted back to source code, so people can see the password by converting the program back to source code. How can I fix this?
You can't.
Even if you encrypt the password, the code to decrypt the password will be available in, and so will not prevent someone decompiling your application.
You have some options:
Put your password in an environment variable (accessible with System.getProperty("variable.name"))
Store the password in a file (still not great, but better than sources)
Access the password from a server, however, you are still required to make the user enter their creds for the server, and now you're left with the same problem.
Make the user enter a password every time they run the application
Probably the best way is to protect the password is to use a one-way hash. I would recommend investigating the Secure Hash Algorithms (SHA). These are one-way hashes (aka cryptographic checksums) that generate, for all practical purposes, a unique hash for some given text or message. Store the hash in the JAR file and the use the same algorithm to hash the entered password. Compare that hash to the stored one for verification.
The down side to this is that it is not easy (or in some cases possible) to change the password.
The odds of generating identical hashes for different inputs is infinitesimal.
Here is one way it could be done using standard Java libraries.
MessageDigest md = MessageDigest.getInstance("SHA-256");
String password = "Password"; // password to be "stored"
byte[] bytes = password.getBytes();
md.update(bytes);
byte[] digest = md.digest();
// store the following string in the jar file
String storedDigest = toHex(digest);
// validation process
String enteredPassword = "Password";
md.update(enteredPassword.getBytes());
System.out.println(toHex(md.digest()).equals(storedDigest) ? "Passed"
: "Failed");
//Convert array of bytes to a long hex string
public static String toHex(byte[] digest) {
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(Integer.toHexString((b >> 4) & 0xF));
sb.append(Integer.toHexString(b & 0xF));
}
return sb.toString();
}
I'm attempting to encrypt data using KMS and the AWS Encryption SDK. Looking at the example provided in the AWS documentation, it appears that there is nowhere to explicitly set the data key.
I've found API documentation for the EncryptionMaterialsRequest class that allows you to set the plaintext key using the associated builder class, EncryptionMaterialsRequest.Builder, and this class has a method that returns an instance of EncryptionMaterials. I can't find anywhere to use the EncryptionMaterials instance when executing the encrypt operation.
Here is the code I have so far. Note that the EncryptionMaterials instance isn't used in the request.
public static void encryptData(String dataToEncrypt, String keyID) {
final KmsMasterKeyProvider prov = new KmsMasterKeyProvider(keyID);
DefaultCryptoMaterialsManager manager = new DefaultCryptoMaterialsManager(prov);
byte[] plaintextKey = generateDataKey(keyID);
EncryptionMaterialsRequest request = EncryptionMaterialsRequest
.newBuilder()
.setPlaintext(plaintextKey)
.build();
EncryptionMaterials materials = manager.getMaterialsForEncrypt(request);
AwsCrypto crypto = new AwsCrypto();
String encryptedString = crypto.encryptString(manager, dataToEncrypt).getResult();
}
public byte[] generateDataKey(String keyID) {
GenerateDataKeyRequest dataKeyRequest = new GenerateDataKeyRequest();
dataKeyRequest.setKeyId(keyID);
dataKeyRequest.setKeySpec(DataKeySpec.AES_256);
GenerateDataKeyResult dataKeyResult = kmsClient.generateDataKey(dataKeyRequest);
ByteBuffer encryptedKey = dataKeyResult.getCiphertextBlob();
byte[] arr = new byte[encryptedKey.remaining()];
encryptedKey.get(arr);
return arr;
}
What is the recommended approach encrypting data using the AWS Encryption SDK with a data key generated by KMS?
#Viccari is correct, but it sounds like some context around the intended use of these constructs would help explain why.
Unless you are building a custom cryptographic materials manager you should not be creating EncryptionMaterials; the client and management components take care of that for you.
The client asks the cryptographic materials manager for encryption materials on every encrypt call. Depending on the cryptographic materials manager, what exactly happens next might be different.
In the case of the DefaulCryptoMaterialsManager, it then asks the provided master key provider for all of the master keys to use, then uses those master keys to generate and encrypt the data key (one is used to generate and encrypt, any additional are used to encrypt).
In the case of the CachingCryptoMaterialsManager, it adds a caching layer between the client and another cryptographic materials manager.
If you want to use the AWS Encryption SDK with AWS KMS, the recommended approach is to simply provide an instance of KmsMasterKey or KmsMasterKeyProvider, or a cryptographic materials manager that ultimately uses one of those, in the encrypt call. All of the details are taken care of by the client.
If you're interested in more details about how these concepts fit together, our concepts documentation[1] would be a good place to start.
[1] https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html
My question for you would be: why not using the DefaultCryptoMaterialsManager, which should generate a new data key from the master key for each encryption operation? Why are you going to reuse the data keys? This does not sound like a sound approach from the security perspective.
But if you want to do that, you need to provide an implementation of the CryptoMaterialsManager interface.
Instead of using DefaultCryptoMaterialsManager, create a new class, let's say, MyCryptoMaterialsManager, that implements the interface above.
Something like this would do it:
public static void encryptData(String dataToEncrypt, String keyID) {
// not sure whether you need this or where you're getting the data key from.
final KmsMasterKeyProvider prov = new KmsMasterKeyProvider(keyID);
MyCryptoMaterialsManager manager = new MyCryptoMaterialsManager(prov);
byte[] plaintextKey = generateDataKey(keyID);
EncryptionMaterialsRequest request = EncryptionMaterialsRequest
.newBuilder()
.setPlaintext(plaintextKey)
.build();
// this, you told you know how to do:
EncryptionMaterials materials = manager.getMaterialsForEncrypt(request);
AwsCrypto crypto = new AwsCrypto();
String encryptedString = crypto.encryptString(manager, dataToEncrypt).getResult();
}
public byte[] generateDataKey(String keyID) {
GenerateDataKeyRequest dataKeyRequest = new GenerateDataKeyRequest();
dataKeyRequest.setKeyId(keyID);
dataKeyRequest.setKeySpec(DataKeySpec.AES_256);
GenerateDataKeyResult dataKeyResult = kmsClient.generateDataKey(dataKeyRequest);
ByteBuffer encryptedKey = dataKeyResult.getCiphertextBlob();
byte[] arr = new byte[encryptedKey.remaining()];
encryptedKey.get(arr);
return arr;
}
If cost or number of calls to KMS is a concern, you could also use the CachingCryptoMaterialsManager instead. It provides guarantees like making sure that a data key is not used an indefinite number of times.
I have a class that stores a password (I'm going to be adding more things than just the password) called Data:
import java.io.Serializable;
public class Data implements Serializable{
public String password = "";
}
As a test I ran these two:
private static File datafile = new File("data.src");
public static void checkDatafile() {
try {
Data data = new Data();
data.password = "Newwww";
if (!datafile.exists()) {
datafile.createNewFile();
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(datafile));
oos.writeObject(data);
oos.flush();
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static Data loadData(Data data) {
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(datafile));
data = (Data) ois.readObject();
ois.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return data;
}
It writes and reads perfectly but when I open the data.src in notepad it's somewhat readable by humans and the password is not secure, this is the output of data.src:
ャ・ sr data.Data克ラ淕6J・ L passwordt Ljava/lang/String;xpt Newwww
The password is easily seen and is not safe, is there a way to encrypt/encode the object when writing to a file so that it's unreadable by humans?
Also, I'd rather stick to the standard Java libs then to download and use others.
It depends on what you mean by "unreadable". If your goal is to prevent a malicious person from extracting the password, even if they have the necessary permissions to run your program, you'll be hard-pressed to do so. After all, if a program can decrypt the password, a person with the same permissions can too. Even without appropriate permissions, a malicious user could potentially inspect raw bytes in memory and extract the password if they have access to the machine.
On the other hand, if you can reasonably trust the user, but just want to avoid having them accidentally see the password in clear-text, any number of simple schemes will work; even just serializing the string as its hex codepoints would be good enough.
If you must store the password itself, i.e. you're accessing a third-party service that requires a password, you essentially have to lock down the machine and limit its access to people you absolutely trust. There's no way around that. There are a number of resources describing encrypting passwords, but they all rely on you being able to lock out users from some part of the system, generally either the encryption key or the cypher-text.
However you likely do not need to, and should not, actually be storing the password at all. The standard way to authenticate a user is to never store their password, and instead store a one-way hash of the password. This is (theoretically) impossible to decipher back into the original password, but by hashing the password the user enters when they log in and comparing it to the hash you have on file you can verify their identity without ever knowing what their password is.
Edit: One more thing about systems which need to store actual passwords. In addition to locking down the machine, you need to create a robust audit trail that records all attempts to access the passwords. Every interaction with that machine and its data should be logged and tracked so that, in the event something goes wrong, you can inspect your audit history and understand the scope of the problem. If you don't have an audit trail you'll have to assume your system is entirely compromised, because you'll have no evidence to the contrary.
not via ObjectOutputStream. you'll have to use a encryption library and either encrypt the complete file, or the password.
You can have the Data class implement the writeObject/readObject methods to encrypt/decrypt the passwords as you read and write the object.
private void writeObject(ObjectOutputStream os) throws IOException{
password = encrypt(password);
os.defaultWriteObject();
}
private void readObject(ObjectOutputStream os) throws IOException{
os.defaultReadObject();
password = decrypt(password);
}
Where encrypt/decrypt define the ecryption/decryption algorithm you wish to use. This being said and as noted in a comment by Gregor Raýman, you might consider just hashing the passwords rather than storing them.
You can try encoding/decoding your content. You can use MD5 hash-functioning. There are pre-written functions and its usage is pretty simple.
The following link can help you understand how to use it in you code.
http://www.asjava.com/core-java/java-md5-example/
i try to find the good way for the best technology/method for hidden password in a file, but without use external jar or library.
Actually i use one object that represent a list of user name and password. Convert my list in a xml (only in memory) and after that, i store in a file with AES.
Use only java 7, no external library.
Is a good/secure method?
If this operation is no good, is possible to create dynamically xml encrypted?
thanks
You can use a FileOutputStream wrapped in a CipherOutputStream.
It's not really secure to save passwords encrypted with AES because:
1) Where do you store the key? If you store it in the server, if an attacker violates the server and finds the key, he will have complete acces to the users information.
2) Do you really need to know the users' passwords? In many application, for security reasons, it's better to keep only the hash of the password. The username can be stored in plaintext and you can also add a salt to the password to enforce it. You can do that with some algorithms offered by Java7 platform. In this way, even if someone enters your server, he can't use users login informations without breaking the hash function.
Here's an example that worked for me:
public byte[] getHash(String password, byte[] salt, String algorithm) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest digest = MessageDigest.getInstance(algorithm);//The String rapresents the alg you want to use: for example "SHA-1" or "SHA-256"
digest.reset();
digest.update(salt);
return digest.digest(password.getBytes("UTF-8"));
}
You can also look at this link for a more complete example: https://www.owasp.org/index.php/Hashing_Java
I am new to encryption.
I have looked at the javax.crypto documentation and got encryption of a file to work using this code ...
File saveFile = new File("Settings.set");
saveFile.delete();
FileOutputStream fout = new FileOutputStream(saveFile);
//Encrypt the settings
//Generate a key
byte key[] = "My Encryption Key98".getBytes();
DESKeySpec desKeySpec = new DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey skey = keyFactory.generateSecret(desKeySpec);
//Prepare the encrypter
Cipher ecipher = Cipher.getInstance("DES");
ecipher.init(Cipher.ENCRYPT_MODE, skey);
// Seal (encrypt) the object
SealedObject so = new SealedObject(this, ecipher);
ObjectOutputStream o = new ObjectOutputStream(fout);
o.writeObject(so);
o.close();
However if you were a clever hacker ( or maybe even amateur since I figured this out), all you would have to do is open the class file that contains this code, and the encryption key (My Encryption Key98) is plainly visible.
How do you encrypt the encryption key? ...LOL... Can you?
Thanks for your help!
If the attacker has access to both the software and the file, it could decrypt it. There are some ways to solve this:
Use asymetric keys. Encrypt the file with the public key, and it can only be decrypted with a private key. This assumes that the software does not need to decrypt the file.
Use Diffie-Hellman exchange. If you want to send an encrypted piece of data over the network, both parties can establish a key without an attacker knowing about it.
If the program needs to both encrypt and decrypt the data, there is nothing you can do. The attacker can simply run the program and look at the decrypted information.
An attacker can always do everything the program can do and usually quite a bit more. The only way to get things secure is the use information not under control of the program. Request the user to enter a password or put information in a store under control of the operating system. The later will not help if an attacker has physical access or maybe even a lot of rights unless special hardware like a Trusted Platform Module (TPM) is involved.
Well if the program can decrypt the data without additional input from the user, you can't really avoid someone else from accessing the file if he has access to the program.
If you are targeting Windows only, you might want to take a look at the Data Protection API (DPAPI). It essentially does the same thing, but the passphrase used for encryption is protected by the operating system on a user (or machine) scope. Simply put: you need the user login (or a program that runs on the given user account) to access the key (or for machine scope the login for any user on the machine).
I don't know how to access the API from Java, but Google brings up some wrapper libraries.
Don't hardcode the key. Assuming you don't have a user on hand to enter the passphrase, configure your code to pull the encryption key from a plain file, then rely on operating system security to keep the file safe. Provide a way to migrate to a new key when the system administrator deems it necessary.
I do not believe that this is possible without having the user entering the key on encryption and decryption.
You could employ some technique to make it harder to view the key without the full source code, but it would not be secure.
If your program can encrypt / decrypt a file on its own, then everything you need to perform the decryption is already built into the program, so a determined troublemaker could decrypt files you encrypted.
If possible, ask the user for a 'password,' and use what they give you as the encryption / decryption key.
Is it important that the user not be able to see his own encryption key? Or merely important that by discovering his won key, the user should not thereby know everyone else's key?
You could prompt the user for a personal key and either store it externally or prompt the user each time you need it. That way each user's key would be his own, and would not be usable to decrypt documents stored by other users on other machines.
the most secure method is not use any encryption, just put your user.properties to your home directory, with following code:
String userhome = System.getProperty("user.home");
String username = system.getProperty("user.name");
String hostname = java.net.InetAddress.getLocalHost().getHostName();
if (hostname.equals("webserver") && username.equals("root")){
ResourceBundle user = ResourceBundle.getBundle(userhome/ "user.properties");
}