Hi I have problem in my android application. I wrote client which used tcp and udp. Data are encrypt by AES. BUT my application return exception when i try to receive datagram.
this is my code:
protected Void doInBackground(Void... params)
{
try
{
udp = new DatagramSocket(2500);
boolean flagaBYE = true;
String w = "";
while(flagaBYE)
{
byte[] receiveData= new byte[1024];
DatagramPacket pakiet = new DatagramPacket(receiveData, receiveData.length);
udp.receive(pakiet);
String wiadomosc = new String(pakiet.getData(),"utf-8");
publishProgress(wiadomosc);
String szyfr = main.preferences.getString("SZYFR_TCP", "");
if(!szyfr.equals("1"))
{
Encryptor enc = new Encryptor(getKeyBytes(key), getCode());
wiadomosc = enc.decrypt(wiadomosc);
}
My exception is pad block corrupted
I generate key like this:
String key = "tojestkluczwlasnie";
And next parse string to byte[]
public static byte[] getKeyBytes(String key) throws UnsupportedEncodingException{
byte[] keyBytes= new byte[16];
byte[] parameterKeyBytes= key.getBytes("UTF-8");
System.arraycopy(parameterKeyBytes, 0, keyBytes, 0, Math.min(parameterKeyBytes.length, keyBytes.length));
return keyBytes;
}
You should not treat bytes as being UTF-8 strings, and you should not treat passwords if they are keys. Its likely that you lose information during the transformations between the data formats (encoding/decoding).
Related
We are currently trying to port the Laravel encryption/decryption to Objective C and Android.
We have achieved the port to Android, the code looks like this;
public static String encrypt(byte[] keyValue, String plaintext) throws Exception {
Key key = new SecretKeySpec(keyValue, "AES");
//serialize
String serializedPlaintext = "s:" + plaintext.length() + ":\"" + plaintext + "\";";
byte[] plaintextBytes = serializedPlaintext.getBytes("UTF-8");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = c.getIV();
byte[] encVal = c.doFinal(plaintextBytes);
String encryptedData = Base64.encodeToString(encVal, Base64.NO_WRAP);
SecretKeySpec macKey = new SecretKeySpec(keyValue, "HmacSHA256");
Mac hmacSha256 = Mac.getInstance("HmacSHA256");
hmacSha256.init(macKey);
hmacSha256.update(Base64.encode(iv, Base64.NO_WRAP));
byte[] calcMac = hmacSha256.doFinal(encryptedData.getBytes("UTF-8"));
String mac = new String(Hex.encodeHex(calcMac));
//Log.d("MAC",mac);
AesEncryptedData aesData = new AesEncryptedData(
Base64.encodeToString(iv, Base64.NO_WRAP),
encryptedData,
mac);
String aesDataJson = new Gson().toJson(aesData);
return Base64.encodeToString(aesDataJson.getBytes("UTF-8"), Base64.DEFAULT);
}
But the Objective C part is troubling us the most, we are not able to replicate Laravel's encryption mechanism. The mac generation part seems to be hardest one. If anyone has some idea, on how the port could look like in objective c that would be really helpful.
I need to encrypt the username and password and encode them and send it via SOAP header.
I used DES algorithm to encrypt the plainText `
String key = "qwer1234qwetr123wqw";
String x = "sadgsagd:%%^%ghsagdh";
byte[] keyBytes = new byte[1024];
byte[] plaintext = x.getBytes();
byte[] tdesKeyData = key.getBytes();
Cipher c3des = Cipher.getInstance("DESede/CBC/PKCS5Padding");
SecretKeySpec myKey = new SecretKeySpec(tdesKeyData, "DESede");
IvParameterSpec ivspec = new IvParameterSpec(keyBytes);
c3des.init(Cipher.ENCRYPT_MODE, myKey, ivspec);
byte[] cipherText = c3des.doFinal(plaintext);
int hash = Base64.encode(cipherText).hashCode();
return Base64.encode(cipherText);`
At runtime i am getting an Exception:
javax.crypto.BadPaddingException: Given
if you are using byte buffer of 64,i probably is too long change it to 32,
or use the length of file like this byte[] buffer = new byte[(int)new File("data").length()];
my problem get solved after doing this..
I have a Serialized class that I need to send as an object via Bluetooth, and also implements Runnable. As such, I set a few variables first, then send it as an object to be executed by another Android device, which will then set its result into a variable, and send back the same object with the result in one of the variables. I have been using the following two methods to serialize my object and get a ByteArray before sending them through the OutputStream of my BluetoothSocket, and to deserialize that ByteArray to get back my object.
public static byte[] serializeObject(Object o) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = new ObjectOutputStream(bos);
out.writeObject(o);
out.flush();
out.close();
// Get the bytes of the serialized object
byte[] buf = bos.toByteArray();
return buf;
}
public static Object deserializeObject(byte[] b) throws OptionalDataException, ClassNotFoundException, IOException {
ByteArrayInputStream bis = new ByteArrayInputStream(b);
ObjectInputStream in = new ObjectInputStream(bis);
Object object = in.readObject();
in.close();
return object;
}
I still got the same error from these two methods, so I tried to merge it with the methods I use to send my ByteArray via BluetoothSocket's OutputStream, as shown below.
public void sendObject(Object obj) throws IOException{
ByteArrayOutputStream bos = new ByteArrayOutputStream() ;
ObjectOutputStream out = new ObjectOutputStream( bos );
out.writeObject(obj);
out.flush();
out.close();
byte[] buf = bos.toByteArray();
sendByteArray(buf);
}
public void sendByteArray(byte[] buffer, int offset, int count) throws IOException{
bluetoothSocket.getOutputStream().write(buffer, offset, count);
}
public Object getObject() throws IOException, ClassNotFoundException{
byte[] buffer = new byte[10240];
Object obj = null;
if(bluetoothSocket.getInputStream().available() > 0){
bluetoothSocket.getInputStream().read(buffer);
ByteArrayInputStream b = new ByteArrayInputStream(buffer);
ObjectInputStream o = new ObjectInputStream(b);
obj = o.readObject();
}
return obj;
}
In the end, I get the same error when deserializing the object at the receiving device, as shown below.
java.io.StreamCorruptedException
at java.io.ObjectInputStream.readStreamHeader (ObjectInputStream.java:2102)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:372)
and so on...
Can anybody please help? I'm desperate, this has been killing me for weeks, and I need this to work in a few days. :S
According to this and this thread :
You should use single ObjectOutputStream and ObjectInputStream for the life of the socket, and don't use any other streams on the socket.
Secondly, use ObjectOutputStream.reset() to clear previous values.
Let me know if this works !
I am using code to Base-64 encode and encrypt data in c#, then I ship the file over to my Android app where I attempt to decrypt it.
Problem is, I get an "Length of Base64 encoded input string is not a multiple of 4." error when decrypting:
(Java code for Android):
try
{
Boolean inEvent = false;
// read encrypted file to string
BufferedInputStream fin = new BufferedInputStream(new FileInputStream(filename));
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte buffer[] = new byte[8192];
int read = fin.read(buffer);
while(read != -1) {
bout.write(buffer, 0, read);
read = fin.read(buffer);
}
fin.close();
String encryptedText = bout.toByteArray().toString();
String unencryptedText = "";
// decrypt string
try
{
unencryptedText = Decrypt(encryptedText, sKey); <-- error occurs here
}
catch ( Exception e)
{
alert(e.getMessage());
return sched;
}
Decrypt method:
protected String Decrypt(String text, String key) throws Exception
{
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
byte[] keyBytes= new byte[16];
byte[] b= key.getBytes("UTF-8");
int len= b.length;
if (len > keyBytes.length) len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.DECRYPT_MODE,keySpec,ivSpec);
byte [] results = cipher.doFinal(Base64Coder.decode(text));
return new String(results,"UTF-8");
}
Finally, here is the c# code I am encrypting with:
(c# code):
string Encrypt(string textToEncrypt, string key)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.PKCS7;
rijndaelCipher.KeySize = 0x80;
rijndaelCipher.BlockSize = 0x80;
byte[] pwdBytes = Encoding.UTF8.GetBytes(key);
byte[] keyBytes = new byte[0x10];
int len = pwdBytes.Length;
if (len > keyBytes.Length)
{
len = keyBytes.Length;
}
Array.Copy(pwdBytes, keyBytes, len);
rijndaelCipher.Key = keyBytes;
rijndaelCipher.IV = keyBytes;
ICryptoTransform transform = rijndaelCipher.CreateEncryptor();
byte[] plainText = Encoding.UTF8.GetBytes(textToEncrypt);
return Convert.ToBase64String(transform.TransformFinalBlock(plainText, 0, plainText.Length));
}
Not sure what's wrong. Does the length of the key have to be some specific number of bytes long?
The comment has already identified the problem, and you'd see it immediately if you debugged the key item here: the base 64 string you think you are reading.
You collect your bytes from the file in bout. But your attempt to convert it to a string representation is not doing anything like what you imagine. It's going to be something like "[B#2352544e]", just Java's internal default toString() from the array. Instead, try new String(bout.toByteArray(), Charset.forName("US-ASCII")).
So I've seen a lot of examples, and done a lot of googling, and looked at examples on Stack Overflow... and I need help. I've got an Android application and I'm storing username and passwords on the device, and I need to encrypt them AES 256. From looking at examples, this is what I have so far:
public class Security {
Cipher ecipher;
Cipher dcipher;
// 8-byte Salt
byte[] salt = {
(byte)0xA9, (byte)0x9B, (byte)0xC8, (byte)0x32,
(byte)0x56, (byte)0x35, (byte)0xE3, (byte)0x03
};
// Iteration count
int iterationCount = 19;
public Security (String passPhrase) {
try {
// Create the key
KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount);
SecretKey key = SecretKeyFactory.getInstance(
"PBEWithSHAAndAES").generateSecret(keySpec);
ecipher = Cipher.getInstance(key.getAlgorithm());
dcipher = Cipher.getInstance(key.getAlgorithm());
// Prepare the parameter to the ciphers
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
// Create the ciphers
ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
} catch (Exception e) {
e.printStackTrace();
}
}
public String encrypt(String str) {
try {
// Encode the string into bytes using utf-8
byte[] utf8 = str.getBytes("UTF8");
// Encrypt
byte[] enc = ecipher.doFinal(utf8);
// Encode bytes to base64 to get a string
return Base64.encodeToString(enc, Base64.DEFAULT);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public String decrypt(String str) {
try {
// Decode base64 to get bytes
byte[] dec = Base64.decode(str, Base64.DEFAULT);
// Decrypt
byte[] utf8 = dcipher.doFinal(dec);
// Decode using utf-8
return new String(utf8, "UTF8");
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
I'm trying to make it password based, so a user will create an account the first time using the username and password needed to communicate back to the server, and create a PIN that will be used as the key for these credentials stored in the database.
What I'm mainly concerned about is does this look secure? I know a fixed salt is bad, how do I fix that?
I know there's been like a billion questions about this, but I want someone to just come out and say "THIS IS SECURE" or "THIS IS NOT SECURE, CHANGE THIS"
Thanks!
EDIT:
So this is the code I have so far, and it seems to be working...
public class Security {
Cipher ecipher;
Cipher dcipher;
byte[] salt = new byte[8];
int iterationCount = 200;
public Security(String passPhrase) {
try {
// generate a random salt
SecureRandom random = new SecureRandom();
random.nextBytes(salt);
// Create the key
KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount);
SecretKey key = SecretKeyFactory.getInstance(
"PBEWithSHA256And256BitAES-CBC-BC").generateSecret(keySpec);
ecipher = Cipher.getInstance(key.getAlgorithm());
dcipher = Cipher.getInstance(key.getAlgorithm());
// Prepare the parameter to the ciphers
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
// Create the ciphers
ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
} catch (Exception e) {
e.printStackTrace();
}
}
public String encrypt(String str) {
try {
// Encode the string into bytes using utf-8
byte[] utf8 = str.getBytes("UTF8");
// Encrypt
byte[] enc = ecipher.doFinal(utf8);
// Encode bytes to base64 to get a string
return Base64.encodeToString(enc, Base64.DEFAULT);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public String decrypt(String str) {
try {
// Decode base64 to get bytes
byte[] dec = Base64.decode(str, Base64.DEFAULT);
// Decrypt
byte[] utf8 = dcipher.doFinal(dec);
// Decode using utf-8
return new String(utf8, "UTF8");
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public int getIterationCount() {
return iterationCount;
}
public String getSalt() {
return Base64.encodeToString(salt, Base64.DEFAULT);
}
}
I used this code to test it:
Security s = new Security(pinBox.getText().toString());
String encrypted = s.encrypt(passwordBox.getText().toString());
String decrypted = s.decrypt(encrypted);
builder.setMessage("pin: " + pinBox.getText().toString() + "\n" +
"password: " + passwordBox.getText().toString() + "\n" +
"encrypted: " + encrypted + "\n" +
"decrypted: " + decrypted + "\n" +
"salt: " + s.getSalt());
So I don't need to worry about an initialization vector? Or specifically hardcode a Cipher algorithm?
Thanks again!
EDIT: While the code below is correct, what you have is doing basically the same thing, with the IV derived from the password, so you don't have to store it separately.
Does your code work as expected? For the actual encryption/decryption you would want to use AES, most probably in CBC mode. Then you would need an IV, so it becomes something like this:
ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = new byte[IV_LENGTH];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
ecipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(iv));
byte[] enc = ecipher.doFinal(utf8);
Whether it is secure depends on what you are using this for. The purpose of the salt is to make it harder to brute force the passphrase: if it's random the attacker cannot use pre-generated passphrase tables (passphrase->key). If you are not too worried about this sort of attack, you might leave it fixed. If you decide to make it random, just store it with the encrypted data. Same with the IV.