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")).
Related
I'm working on a security application using my own customized cryptography method, and having a problem on message decryption.
Here is an my Code
private static void myCryptography(){
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
byte[] input = "Hitesh Dhamshaniya".getBytes();
byte[] keyBytes = "ABCD657865BHNKKK".getBytes();
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
// encryption pass
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
Log.e("==> ", " == > Encode " + Base64.encodeToString(cipherText, Base64.DEFAULT));
String encodedStr = Base64.encodeToString(cipherText, Base64.DEFAULT);
// decryption pass
cipherText = Base64.decode(encodedStr, Base64.DEFAULT);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = new byte[cipher.getOutputSize(ctLength)];
int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);
ptLength += cipher.doFinal(plainText, ptLength);
Log.e("==> ", " == > Decoded " + new String(plainText, "UTF-8"));
}
Getting below output
== > Encode TteNmufoa5AWWmEPBmQ3N8fdqRpahvwUR7CSclAcsjM=
== > Decoded Hitesh Dhamshaniya���������������������
How to remove unwanted character like '��' from decode string.
The cipher removes the padding automatically. What you see here comes from the conversion of the byte array plainText to the string. You should only use the first ptLength bytes instead of the whole array:
new String(plainText, 0, ptLength, "UTF-8")
I need to use PublicKey to encrypt session key but I have public key as Base64 encoded string so I tried to convert it as :
KeyFactory kf = KeyFactory.getInstance("RSA"); // or "EC" or whatever
byte[] keyBytes = _publicKey.getBytes();
byte[] publicKeyBytes = Base64.decode(keyBytes, Base64.DEFAULT);
X509EncodedKeySpec publicKeySpecs = new X509EncodedKeySpec(publicKeyBytes);
Log.v("", "X509 KS" + publicKeySpecs);
publicKey = kf.generatePublic(publicKeySpecs);
But I am getting public key as null value and getting exception as :
java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag
If anyone has idea how to do it or have working code then please help me.
Thanks in Advance
Hi guys I generated Public Key from Base64 encoded String .
after wondering for few days this code worked for me.
String _publicKey= base64encoded_publickey;
// InputStream fileInputStream = null;
try {
// Receiving side
byte[] decodedBytes = Base64.decode(_publicKey, Base64.DEFAULT);
fileInputStream = new ByteArrayInputStream(decodedBytes);
// Print the decoded string
String decodedString = new String(decodedBytes);
CertificateFactory certFactory = CertificateFactory
.getInstance(CERTIFICATE_TYPE);
// certFactory.
X509Certificate cert = (X509Certificate) certFactory
.generateCertificate(fileInputStream);
publicKey = cert.getPublicKey();
Log.d("TAG", "Public key of the certificate:" + publicKey);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Could not intialize encryption module",
e);
} finally {
if (keyStream != null) {
try {
keyStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Hope it will help you...Thanks...
well, last time it worked for me (I used bouncyCastle library..), you might need to modify it if it doesn't suit your need..
KeyPairGenerator keyGen = null;
KeyPair kp = null;
keyGen = KeyPairGenerator.getInstance("ECDSA", "BC");
ECGenParameterSpec ecSpec = new ECGenParameterSpec("brainpoolp160r1");
keyGen.initialize(ecSpec, new SecureRandom());
kp = keyGen.generateKeyPair();
EDIT:
(oops my bad, that's for initial generation..)
at that time I stored them as one..
and I need to convert the Base64 string back to array of byte first, and split them into part 1 and part 2..
private void splitKeyPair (byte[] thekeypair, byte[] part1, byte[] part2)
{
System.arraycopy(thekeypair, 0, part1, 0, 68);
System.arraycopy(thekeypair, 68, part2, 0, 115);
}
byte[] part1 = new byte[68];
byte[] part2 = new byte[115];
splitKeyPair(inputBuffer, part1, part2);
fact = KeyFactory.getInstance("ECDSA", "BC");
kp = new KeyPair(fact.generatePublic(new X509EncodedKeySpec(part1)),
fact.generatePrivate(new PKCS8EncodedKeySpec(part2)));
hope it helps..
*note: the size might vary, depending on the spec..
I am encrypting images in assets folder with following code and trying to decrypt in apk. (I am doing this just to avoid easy copying of images with just unzip of apk file). I know i will have the key as part of apk.
I used and tested below code for encrypting the images with stand alone java program. (I tested them by decrpyting and it is working fine in stand alone java program.
Encryption
byte[] incrept = simpleCrypto.encrypt(KEY, simpleCrypto.getImageFile("E:/aeroplane.png"));
//Store encrypted file in SD card of your mobile with name vincent.mp3.
FileOutputStream fos = new FileOutputStream(new File("E:/out-aeroplane.png"));
fos.write(incrept);
fos.close();
Decryption
byte[] decrpt = simpleCrypto.decrypt(KEY, simpleCrypto.getImageFile("E:/out-aeroplane.png"));
//Store encrypted file in SD card of your mobile with name vincent.mp3.
FileOutputStream fosdecrypt = new FileOutputStream(new File("E:/outdecrypt-aeroplane.png"));
fosdecrypt.write(decrpt);
fosdecrypt.close();
Encrypt Decrypt logic
public byte[] getImageFile(String fileName) throws FileNotFoundException
{
byte[] Image_data = null;
byte[] inarry = null;
try {
File file = new File(fileName);
#SuppressWarnings("resource")
FileInputStream is = new FileInputStream (file); // use recorded file instead of getting file from assets folder.
int length = is.available();
Image_data = new byte[length];
int bytesRead;
ByteArrayOutputStream output = new ByteArrayOutputStream();
while ((bytesRead = is.read(Image_data)) != -1)
{
output.write(Image_data, 0, bytesRead);
}
inarry = output.toByteArray();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return inarry;
}
public byte[] encrypt(String seed, byte[] cleartext) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext);
// return toHex(result);
return result;
}
public byte[] decrypt(String seed, byte[] encrypted) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = encrypted;
byte[] result = decrypt(rawKey, enc);
return result;
}
//done
private byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr);
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
private byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
private byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
In my apk file after getting the image as InputStream, I am decrypting them after converting them as byte array. Again I am converting the decrypted byte array to input stream for BitmapFactory.decode. I tried both decodeByteArray and decodeStream. Both not working.
Image is encrypted with stand alone java program and it is decrypted in apk. (If i decrypt in stand alone java program, it is working fine.)
I am getting error saying Failed to decode Stream javax.crypto.BadPaddingException: pad block corrupted
public static Bitmap readBitmap(InputStream input) {
if (input == null)
return null;
try {
String KEY = "kumar";
byte[] inarry =IOUtils.toByteArray(input);
byte[] decrpt = SquarksCryptUtil.decrypt(KEY, inarry);
InputStream cleanStream = null;
cleanStream = new ByteArrayInputStream(decrpt);
// return BitmapFactory.decodeStream(cleanStream);
return BitmapFactory.decodeByteArray(decrpt, 0, decrpt.length);
// return BitmapFactory.decodeStream(input);
} catch (Exception e) {
Log.e(FILE_NAME, "Failed to decode Stream " + e);
return null;
} finally {
close(input);
}
}
The problem that you are facing is because you are assuming that the random number generates the same key on each platform. This issue is due to the fact that there is a very bad example on the internet that uses SecureRandom as a key derivation function, which it is not. SecureRandom is not even well defined if the seed is set directly. You can use PBKDF2 instead of the incorrect key derivation function on both sides, there should be enough pointers on stackoverflow on how to perform PBKDF2 key derivation using Java.
The best thing to do is to decrypt the images on the SE platform and then re-encrypt them correctly using PBKDF2. Currently, the way the key is derived is only specified in the source code of the Sun implementation of "SHA1PRNG". That's not a good foundation at all.
Furthermore you need to assure that there are no platform dependencies during encryption/decryption, as others already have pointed out.
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..
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).