Java - Saving values availiable in whole application - java

I'm writing an Server/Client application with encrypted communication in Java (Client is on Android).
What is the best way to save the SecretKeySpec, so I don't have to generate it each time I want to encode/decode a message?
I'm using this method, taken from this site (german):
String keyStr = "secret";
byte[] key = (keyStr).getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("MD5");
key = sha.digest(key);
key = Arrays.copyOf(key, 16);
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
String text = "Some text"
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] encrypted = cipher.doFinal(text.getBytes());
Should I store it in a static variable? Or should I try a completely different approach?
EDIT: To clarify my question, my main problem is with the server program, how should I do it in the server program?

to permanently save those little things I would recommend to use the Shared Preferences.
But if you want to you could use the Internal Storage.
The main different is that the Shared Preferences only save primitive datatypes (such as int, byte, String) and in the Internal Storage you can wirte whole files (like savegames or temp files)
With both types the user can't access the data.
To easily access the saved information you could write a class that handels that for you, so you don't have to instantiate the whole Classes from the ADK.
Greetings

Related

Why can I still decrypt parts of my data after flipping a bit in the ciphertext?

I am using in my application AES algorithm to encrypt my data. My key is of 256 bit. The encrypted token formed is of this sort:
pRplOI4vTs41FICGeQ5mlWUoq5F3bcviHcTZ2hN
Now if I change one bit of the token alphabet from upper case to lower case say some thing like this:
prplOI4vTs41FICGeQ5mlWUoq5F3bcviHcTZ2hN
Some part of the token is getting decrypted along with junk value. My concern is why even some part of the data is getting visible when as such one bit is changed.My code for encryption is as follows:
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
Key secretKeySpecification = secretKeyData.getKey();
cipher.init(
Cipher.ENCRYPT_MODE,
secretKeySpecification,
new IvParameterSpec(secretKeyData.getIV().getBytes("UTF-8")));
byte[] bytesdata = cipher.doFinal(data.getBytes());
String encodedData = new BASE64Encoder().encode(bytesdata)
My code for decryption is:
Key secretKeySpecification = decryptionKeyDetails.getKey();
cipher.init(Cipher.DECRYPT_MODE, secretKeySpecification,
new IvParameterSpec(decryptionKeyDetails.getIV()
.getBytes("UTF-8")));
byte[] bytesdata;
byte[] tempStr = new BASE64Decoder()
.decodeBuffer(splitedData[0]);
bytesdata = cipher.doFinal(tempStr);
return new String(bytesdata);
Ciphertext modes of operation have specific forms of error propagation. There is such as thing as Bi-IGE (Bi-directional Infinite Garble Extension, that does change the whole plaintext if any error is introduced. However, it requires more than one pass, and it still won't protect you from getting random data if a bit was changed.
In the end, listen to Oleg and Codes (and Wikipedia and even me) and add an authentication tag to your ciphertext. Validate the authentication tag (e.g. HMAC) before decryption. Don't forget to include other data in your protocol such as the IV, or you may have a plaintext for which the first block has been changed.

Create a file protected by a password in java

I would like to create a file protected by a password in JAVA.
What I mean is, once I launch the program, one file created by my program would be directly protected by previously determined password.
Is there an easy way to do it ?
Once again, my aim is not to create a file and then add it a password, but right during the creation protecting the file by a password.
Actually, I want the current runner program not having access in reading/editing the created file EXCEPT if he/she has the password previously set.
So anyway, if some of you know an easy way to protect files when writing them thanks to java, I would be most grateful.
Have a nice day!
You want to encrypt your file('s content) with a password. Here is a pretty well known library to do it: http://www.jasypt.org/
From their site:
..encrypting and decrypting a text...
BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
textEncryptor.setPassword(myEncryptionPassword);
String myEncryptedText = textEncryptor.encrypt(myText);
...
String plainText = textEncryptor.decrypt(myEncryptedText);
You can read/write the encrypted content to your file.
When you want to encrypt files, strings, etc there are 2 main approaches.
You should start by building a class or method to convert ur string/file to an array of bytes. Build another method to convert the array of bytes back to the string/file.
You may encrypt a file using 2 approaches:
1 - Symmetric key - A secret word (usually a huge string of chars or a password set by the user) will encrypt your file and password, and the same password will be used to decrypt.
2 - Asymmetric key - You generate a pair of keys. One is called the public key and the other is called a private key. Public keys are used to encrypt files, private keys to decrypt.
This would be the more 'professional' approach.
If you want a really safe approach, you should download GnuPG. GnuPG is an executable that manages assymmetric encryption, you may build a class to work with GnuPG and let GnuPG manage ur encryption/decryption process.
Theres an unsafe approach that is 'native' to java (symmetric key) that may work out for you:
Encryption:
byte[] key = //... password converted to an array of bytes
byte[] dataToSend = ...
Cipher c = Cipher.getInstance("AES");
SecretKeySpec k =
new SecretKeySpec(key, "AES");
c.init(Cipher.ENCRYPT_MODE, k);
byte[] encryptedData = c.doFinal(dataToSend);
Decryption:
byte[] key = //
byte[] encryptedData = //
Cipher c = Cipher.getInstance("AES");
SecretKeySpec k =
new SecretKeySpec(key, "AES");
c.init(Cipher.DECRYPT_MODE, k);
byte[] data = c.doFinal(encryptedData);
Hope this helps.
If the file is a plain text file, then not giving the user access to the file without a password in your program does not really password-protect the data, because the user can just open the file with some other program. So IF the file is a text file, then I think you must use encryption.
You can use the comment by #mazaneicha to help you get started in this direction. If you want to dive more into it, you can look at the Java Cryptography architectre and the javax.crypto java docs.
If your file is not human-readable, and only your program understands it, then I would make the first line or first n Bytes of the file a password. If you prefer, you could save another password file in the same directory and use that to authenticate the user before deciding if the user has the right to view the file. A common way to encrypt a password is with an MD5 hash function. The user enters a password, you compute the hash of it, then compare the computed hash with the hash value read from the file:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Use to encrypt passwords using MD5 algorithm
* #param password should be a plain text password.
* #return a hex String that results from encrypting the given password.
*/
static String encryptPassword(String password) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(password.getBytes());
byte byteData[] = md.digest();
StringBuilder hexString = new StringBuilder();
for (int i=0;i<byteData.length;i++) {
String hex=Integer.toHexString(0xff & byteData[i]);
if(hex.length()==1)
hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
catch(java.security.NoSuchAlgorithmException missing) {
return password;
}
}

Java encryption issue with data type conversion

I have web services implemented that comunicate between client and server with strings. The problem I'm getting is with the conversion of the encripted byte array to string since I can't convert it back to the original content on server side.
KeyPairGenerator keyGen;
keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair key = keyGen.generateKeyPair();
String publicKeyPath = new String("publicKeys.txt");
publickey = key.getPublic()
byte[] pubEncoded = key.getPublic().getEncoded();
FileOutputStream fout = new FileOutputStream(publicKeyPath);
fout.write(pubEncoded);
fout.flush();
fout.close();
String privateKeyPath = new String("privateKeys.txt");
byte[] privEncoded = key.getPrivate().getEncoded();
fout = new FileOutputStream(privateKeyPath);
fout.write(privEncoded);
fout.flush();
fout.close();
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
And on each method in client:
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publickey);
byte[] cipherText = cipher.doFinal(str.getBytes());
port.callX(chiperText.toString());
On server side:
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] newPlainText = cipher.doFinal(arg.getBytes());
This gives the padding problem of "Data must start with a zero"
There is only one KeyPair generated, for debug, I tried to encrypt and decript on the same function, and the problem relies on the conversions from byte[] to String.
I don't really wan't to change the passing of arguments to other type since operations are auto generated and all code is to strings. I've tried with different "UTF-8" and "UTF-16Le" but none works :S
Any idea?
Encrypting data directly with asymmetric keys isnt a good idea and it does not work. RSA keys cannot encrypt data bigger than its key length. So, the right way of doing that would be to generate a symmetric key and encrypt the data with the symmetric key and inturn encrypt the symmetric key with the asymmetric key. So, you need to send the encrypted data and the encrypted key both to the other party.
If you try encrypting the data directly with the asymmetric key then your byte[] may not contain the correct data or it may contain nothing at all. This happens if your data is bigger than the key length. For data smaller the key length it works fine but not with bigger data.

Problems encoding/decoding using AES-128-CBC

So basically I have these snippets of code and would like them to produce the same output:
require 'openssl'
aes = OpenSSL::Cipher::Cipher.new("AES-128-CBC")
aes.key = "aaaaaaaaaaaaaaaa"
aes.iv = "aaaaaaaaaaaaaaaa"
aes.encrypt
encrypted = aes.update("1234567890123456") << aes.final
puts encrypted.unpack('H*').join
This prints:
8d3bbffade308f8e4e80cb77ecb8df19ee933f75438cec1315c4a491bd1b83f4
And this Java code:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
String key = "aaaaaaaaaaaaaaaa";
String textToEncryptpt = "1234567890123456";
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(key.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(textToEncryptpt.getBytes());
System.out.println(Crypto.bytesToHex(encrypted));
Prints:
2d3760f53b8b3dee722aed83224f418f9dd70e089ecfe9dc689147cfe0927ddb
Annoying thing is that it was working a couple of days ago... so I am not sure what happened. What's wrong with this code? Do you see anything unusual?
Ruby script is wrong. You have to first call the encrypt method, and then set the key and iv:
require 'openssl'
aes = OpenSSL::Cipher::Cipher.new("AES-128-CBC")
aes.encrypt
aes.key = "aaaaaaaaaaaaaaaa"
aes.iv = "aaaaaaaaaaaaaaaa"
encrypted = aes.update("1234567890123456") << aes.final
puts encrypted.unpack('H*').join
I figured out because when trying to decode an encrypted string I got:
aescrypt.rb:13:in `final': bad decrypt (OpenSSL::Cipher::CipherError)
from aescrypt.rb:13:in `<main>'
Seems you found already the reason that your script does give different results.
Some more things to consider:
Don't ever hardcode the key in the program - that way you can't easily change it, and if someone gets access to your program code, she also gets to see the key.
Don't ever use a constant initialization vector. Instead, generate a random one and send it together with the ciphertext. Alternatively, if you generate the key from a password and some salt, you can also generate the IV from the same ... but don't use the key directly as IV.
Your key/IV values are strings, not bytes. String.getBytes() (in Java) converts the string to bytes using some encoding. The encoding used is system-dependent, and none of the usual String encodings (UTF-8, Latin-1, ...) can represent all bytes as printable (and typeable) characters. Preferably use something like Base64 or hex-encoding, if you have to store your key as string.
And whenever you transform a string to bytes, specify an encoding (and use the same encoding later for retrieving it).
#Cristian, For key and initial vector, you can create a function by using today's date plus the secure fixed keyword.
Eg: key = January 8, 2012 + Key
And for initial vector,
Eg: iv = January 8, 2012 + IV
Then enter that data(key and iv) to MD5 it will produce the output 16 bytes that you can use for the Key and IV. Every day, key and iv will change randomly.
Make sure both systems use the same date format and setup on the same date.

Duplicate Oracle DES encrypting in Java

I recently asked a question about Oracle Encryption. Along the way to finding a solution for myself I decided to move the encryption (well, obfuscation) to the application side for certain tasks.
My problem is that the database is already encrypting data a certain way and I need Java code to duplicate that functionality, so that text encrypted by one system can be decrypted by the other and vice versa.
I want the encryption to be compatible with what the DB was already doing but couldn't find the documentation that describes exactly what Oracle is doing. How do I replicate this in Java?
dbms_obfuscation_toolkit.DESEncrypt(
input_string => v_string,
key_string => key_string,
encrypted_string => encrypted_string );
RETURN UTL_RAW.CAST_TO_RAW(encrypted_string);
No matter what I try, it seems as if the Java DES encryption is different than Oracle's.
I found this works:
KeySpec ks = new DESKeySpec(new byte[] {'s','e','c','r','e','t','!','!'});
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
SecretKey sk = skf.generateSecret(ks);
Cipher c = Cipher.getInstance("DES/CBC/NoPadding");
IvParameterSpec ips = new IvParameterSpec(new byte[] {0,0,0,0,0,0,0,0});
c.init(Cipher.ENCRYPT, sk, ips);
// or
c.init(Cipher.DECRYPT, sk, ips);
The missing piece was the Initialization Vector (ips) which must be 8 zeros. When you use null in Java you get something different.
Using Java in the database would have been another approach that would (should!) have guarenteed that the code (and hence results) would be identical.

Categories

Resources