DES encryption error in Java (Illegal base64 character 20) - java

I am trying to make a little encryption/decryption software for my APCS-A final project. I have most of it done with various text ciphers and such, but I am trying to get DES encryption to work as like the big thing. I couldn't get it working in the main program so I created its own little thing to try to learn and test it first. I think I've gotten decently far, but I am getting stuck on an error that I can't figure out.
import java.util.Scanner;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.*;
import java.util.Base64;
public class BigETest
{
public static void main(String[]args) throws NoSuchAlgorithmException,NoSuchPaddingException,InvalidKeyException,IllegalBlockSizeException,BadPaddingException
{
Scanner kbd = new Scanner(System.in);
System.out.print("Enter text: ");
String t = kbd.nextLine();
String[] rets = en(t);
System.out.println("Encrypted: "+ rets[0]);
System.out.println("Key: " + rets[1]);
String dec = de(rets[0],rets[1]);
System.out.println("Decrypted: "+dec);
}
public static String[] en(String inText) throws BadPaddingException,IllegalBlockSizeException,InvalidKeyException,NoSuchPaddingException,NoSuchAlgorithmException
{
KeyGenerator keyGen = KeyGenerator.getInstance("DES");
SecretKey key = keyGen.generateKey();
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] text = Base64.getUrlDecoder().decode(inText);
byte[] encryptedBytes = cipher.doFinal(text);
String encrypted = new String(Base64.getUrlEncoder().encodeToString(encryptedBytes));
byte[] rawKey = key.getEncoded();
String stringKey = new String(Base64.getUrlEncoder().encodeToString(rawKey));
String[] ret = {encrypted,stringKey};
return ret;
}
public static String de(String inText, String inKey) throws BadPaddingException,IllegalBlockSizeException,InvalidKeyException,NoSuchPaddingException,NoSuchAlgorithmException
{
byte[] keyB = Base64.getUrlDecoder().decode(inKey);
SecretKey key = new SecretKeySpec(keyB, "DES");
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] text = Base64.getUrlDecoder().decode(inText);
byte[] fin = cipher.doFinal(text);
String dec = new String(Base64.getUrlEncoder().encodeToString(fin));
return dec;
}
}
The code works sometimes if the input is short and doesn't have spaces in it
Enter text: test
Encrypted: BOM9tFOUfWc=
Key: bq2ooSbc1n8=
Decrypted: test
but falls apart if the input is a bit longer
Enter text: BigTest
Encrypted: jme0nIAHXyA=
Key: 90UxVwetj2g=
Decrypted: BigTess=
And then gives me an error if there are any spaces
Enter text: bigger test
java.lang.IllegalArgumentException: Illegal base64 character 20
at java.base/java.util.Base64$Decoder.decode0(Base64.java:746)
at java.base/java.util.Base64$Decoder.decode(Base64.java:538)
at java.base/java.util.Base64$Decoder.decode(Base64.java:561)
at BigETest.en(BigETest.java:34)
at BigETest.main(BigETest.java:20)
I have tried changing things up and looked around both on here and just around anyplace I could find on Google for some answers, but nothing seems to be working. Any help would be greatly appreciated.

Related

Does this smali class decrypt data? what encryption is it using?

Q: Does this smali class decrypt data? what encryption is it using?
I need help finding out what this code uses to decrypt the file text it receives?
the encrypted text prints out as expected in a jumbled mess, is there a way to manually decrypt the text using the information I need help understanding?
package utils;
import android.util.Log;
import com.crashlytics.android.Crashlytics;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.io.FileUtils;
public class EFileIO {
private static byte[] df(byte[] var0, byte[] var1) throws Exception {
SecretKeySpec var2 = new SecretKeySpec(var0, "AES");
Cipher var3 = Cipher.getInstance("AES");
var3.init(2, var2);
return var3.doFinal(var1);
}
private static byte[] ef(byte[] var0, byte[] var1) throws Exception {
SecretKeySpec var2 = new SecretKeySpec(var0, "AES");
Cipher var3 = Cipher.getInstance("AES");
var3.init(1, var2);
return var3.doFinal(var1);
}
private static byte[] gk(String var0) throws Exception {
byte[] var1 = var0.getBytes("UTF-8");
KeyGenerator var2 = KeyGenerator.getInstance("AES");
SecureRandom var3 = SecureRandom.getInstance("SHA1PRNG", "Crypto");
var3.setSeed(var1);
var2.init(128, var3);
return var2.generateKey().getEncoded();
}
public static String rf(File var0) {
String var1 = "";
String var3;
String var5;
try {
byte[] var2 = df(gk("AIzaSyDVQJ323-Th1pPJIcDrSt0KYFMTuLJR7Vw"), FileUtils.readFileToByteArray(var0));
var3 = new String(var2, "UTF-8");
} catch (Exception var4) {
Crashlytics.log(6, "EFILEIO.java", "rf, mf.getName(): " + var0.getName());
Crashlytics.logException(var4);
var4.printStackTrace();
var5 = var1;
return var5;
}
var5 = var3;
return var5;
}
public static void wr(StringBuilder var0, File var1) {
try {
FileOutputStream var3 = new FileOutputStream(var1);
BufferedOutputStream var2 = new BufferedOutputStream(var3);
byte[] var5 = ef(gk("AIzaSyDVQJ323-Th1pPJIcDrSt0KYFMTuLJR7Vw"), var0.toString().trim().getBytes("UTF-8"));
StringBuilder var6 = new StringBuilder();
Log.e("FileIo", var6.append("wr: content ").append(var5).toString());
var2.write(var5);
var2.flush();
var2.close();
} catch (Exception var4) {
Crashlytics.log(6, "EFILEIO.java", "wr, mf.getName(): " + var1.getName());
Crashlytics.logException(var4);
var4.printStackTrace();
}
The (short) answer to your question is YES.
Your class (method wr) is encrypting a String (wrapped in a StringBuilder) with a fixed key and saves the ciphertext to a file on the disc. Another method (rf) is reading the file with the ciphertext, decrypts it with the fixed key and prints the
decrypted / plaintext to the console.
These are the 5 methods in your class with a short description:
gk = generates a fixed 16 byte (128 bit) long key for AES en-/decryption
ef = encrypts a byte array with the generated key
df = decrypts a byte array with the generated key
wr = writes the encrypted byte array (using method ef) to a file on the disc
rf = reads the contents of a file to a byte array, decrypts it with method df and shows the decrypted text
The class uses the AES/ECB/PKCS5PADDING mode for encryption (I done the decryption manually on OpenJDK 11, so maybe the mode has another name with your crypto service provider on Android). The initialisation in methods ef + df with
"Cipher.getInstance("AES")" results in the "standard" ECB-PKCS5PADDING mode which is insecure and should be no longer used.
If you created a ciphertextfile "cipher.dat" you can use this simple program to decrypt the content and show it on the console (there is no proper exception handling...):
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class SimpleDecryption {
public static void main(String[] args) throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, IOException, BadPaddingException, IllegalBlockSizeException {
System.out.println("Simple decryption method for\n" +
"https://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java");
String filename = "cipher.dat";
byte[] fixedKey = hexStringToByteArray("e409c02fb48745a14f5e1c03e3c6f0ca");
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
SecretKeySpec secretKeySpec = new SecretKeySpec(fixedKey, "AES");
aesCipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
System.out.println("decrypted text: " + new String(aesCipher.doFinal(Files.readAllBytes(Paths.get(filename))),"UTF-8"));
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}
}
Sample output:
Simple decryption method for
https://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java
decrypted text: This text needs to get encrypted

Decrypting a string with RSA returns additional zeros at the beginning

I'm trying to generate an AES key, encrypt it and decrypt it using RSA.
It kind of works, except that after decrypting the data and encoding with Base64 I get a pile of "A" letters before my actual string(the base64-encoded AES key). I guess these were zeros in byte.
The "RSA/ECB/NoPadding" parameters are mandatory. What am I doing wrong ? I need it to return the original string/bytes.
package szyfrator;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.tools.bzip2.CBZip2OutputStream;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;
import com.sun.org.apache.xml.internal.security.utils.Base64;
public class Cryptography {
private static byte[] aesKey;
private static String base64AESKey;
private static byte[] encryptedAESKey;
private static String base64AESEncryptedKey;
private static byte[] aesKeyTransformed;
public static void main(String args[]){
Cryptography.generateAESkey();
Cryptography.encryptAESKey(new File("G:\\HASHBABYHASH\\public.txt"));
Cryptography.decryptAESKey(new File("G:\\HASHBABYHASH\\private.txt"));
System.out.println("String: " + Base64.encode(Cryptography.getAesKey()) + "\r\n");
System.out.println("Encrypted string: " + Cryptography.getBase64EncryptedKey() + "\r\n");
System.out.println("Decrypted String: " + Base64.encode(Cryptography.getAesKeyTransformed()) + "\r\n");
}
public static void generateAESkey(){
try {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
SecretKey secretKey = keyGen.generateKey();
byte[] keyBytes = secretKey.getEncoded();
base64AESKey = Base64.encode(keyBytes);
aesKey = keyBytes;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public static void encryptAESKey(File publicKeyFile){
try {
FileInputStream input = new FileInputStream(publicKeyFile);
byte[] decoded = Base64.decode(IOUtils.toByteArray(input));
X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(decoded);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(publicSpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
encryptedAESKey = cipher.doFinal(aesKey);
base64AESEncryptedKey = Base64.encode(encryptedAESKey);
input.close();
}catch (Exception e) {
e.printStackTrace();
}
}
public static void decryptAESKey(File privateKeyFile){
try {
FileInputStream input = new FileInputStream(privateKeyFile);
byte[] decoded = Base64.decode(IOUtils.toByteArray(input));
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decoded);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
aesKeyTransformed = cipher.doFinal(encryptedAESKey);
input.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
Here is the result:
String: xVwH7Nbz84emVoH0J31sRHC+B669T9wCUVlTDhYgXiI=
Encrypted string: INTA8rx46hX6bZbDIl4iiWsUGO4ywCW0Aee1reqQ3wR5X7He5ztLHvyZoa0WZmUGYbYwprNGffRI
OVJFxczMHkxUfHU1WWCTzcfNylD+sWObIYrbyc13aZi9OL/r1GXuaGtkIgTJyqv0QPHfIri7iaH3
Lr/F4EIcyphJM3E2reQ=
Decrypted String: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxVwH7Nbz84emVoH0J31sRHC+
B669T9wCUVlTDhYgXiI=
In RSA some data is encoded into a large number and calculated upon. NoPadding (unpadded or textbook RSA) means that you're fully responsible for the proper encoding of the message. All of the calculations are done against a large modulus (should be at least 2048 bit nowadays). Since Java assumes big-endian numbers, your message is encoded into the least significant bytes automatically, but the decryption returns the decoded message in the same size of the modulus, because it cannot know whether the leading zero-bytes where intentional or not.
In order to make this calculation correct and secure it is necessary to apply padding. The old-style PKCS#1 v1.5 padding is not considered secure nowadays, but it only has 11 bytes of overhead (only 2048/8-11=245 bytes can be encrypted with a key of 2048 bit). The newer PKCS#1 v2.1 padding (OAEP) is considered secure and should be used here. It does have an overhead of 42 bytes if SHA-1 is used.
The "RSA/ECB/NoPadding" parameters are mandatory.
This is really bad, because it is very insecure: Which attacks are possible against raw/textbook RSA?
If you're not willing to simply change the cipher string to Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");, you will have to remove the leading zeros yourself. The problem is of course that this "zero-padding" mode is ambiguous and if the plaintext begins with a 0x00 byte, you will not be able to distinguish it from a padding byte and will have to remove it, thus breaking your plaintext. If the plaintext is an AES key as in your case, there is a 0.3% chance that it begins with a 0x00 byte and thus breaks the key. You will have to make sure that the key is actually correct and fill up with zero bytes if it has not the correct length.
Here is how you can remove leading zero bytes:
byte[] unpadZeros(byte[] in) {
int i = 0;
while(in[i] == 0) i++;
return Arrays.copyOfRange(in, i, in.length);
}
If you know that you're decrypting an AES key, then it's possible to make the unpadding no produce wrong data:
byte[] unpadZerosToGetAesKey(byte[] in) {
int i = 0;
while(in[i] == 0) i++;
int len = in.length - i;
if (len <= 16) len = 16;
else if (len <= 24) len = 24;
else len = 32;
return Arrays.copyOfRange(in, in.length - len, in.length);
}

AES-128 Encrypted String not properly padded

I'm having trouble creating an encrypted string using AES/CBC/PKCS5Padding with a 128-bit key. I have code to decrypt an encrypted string. I have an example encrypted string from another system that decrypts successfully, but when I try to create my own encrypted string it is not padded properly for some reason. When I decrypt my encrypted string it only shows the characters after the 16 byte.
All of the examples I find either assume the encryption happens first then decryption happens right after that with variables set during encryption or they are randomly generating a key, but in my case i want to use a known key.
I am really stuck so any help would be greatly appreciated, thank you very much for your time and efforts!
Example:
Original Text: 01234567891234565
Encrypted: zmb16qyYrdoW6akBdcJv7DXCzlw0qU7A2ea5q4YQWUo=
Key length: 16
Decrypted: 5 (this is the last digit in the Original Text String)
Sample Code:
package com.company.encrypt.tests;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class TestEncryptDecrypt {
private static final String characterEncoding = "UTF-8";
private static final String cipherTransformation = "AES/CBC/PKCS5Padding";
private static final String aesEncryptionAlgorithm = "AES";
public static void main(String[] args) throws Exception {
String key1 = "1234567812345678";
String text = "01234567891234565";
System.out.println("Original Text: " + text);
String encrypted = encrypt(text, key1);
System.out.println("Encrypted: " + encrypted);
String decrypted = decrypt(encrypted, key1);
System.out.println("Decrypted: " + decrypted);
}
public static String decrypt(String encryptedText, String key) throws Exception {
String plainText = null;
int keyLength = key.length();
System.out.println("Key length: " + String.valueOf(keyLength));
byte[] encryptedTextBytes = Base64.decodeBase64(encryptedText.getBytes());
byte[] keyBytes = key.getBytes();
byte[] initialVector = Arrays.copyOfRange(encryptedTextBytes, 0, keyLength);
byte[] trimmedCipherText = Arrays.copyOfRange(encryptedTextBytes, keyLength, encryptedTextBytes.length);
try {
Cipher cipher = Cipher.getInstance(cipherTransformation);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, aesEncryptionAlgorithm);
IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] clearText;
clearText = cipher.doFinal(trimmedCipherText);
plainText = new String(clearText, characterEncoding);
} catch(NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException
| InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return plainText;
}
public static String encrypt(String plainText, String encryptionKey) throws Exception {
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), aesEncryptionAlgorithm);
Cipher cipher = Cipher.getInstance(cipherTransformation);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainTextBytes = plainText.getBytes("UTF-8");
byte[] encrypted = cipher.doFinal(plainTextBytes);
return new String(Base64.encodeBase64(encrypted));
}
}
I've noticed that in the decrypt() function, you separated the encrypted array into two parts: first 16 bytes, and the rest. You used the first 16 bytes as the IV for decryption, however, you did not prepend the 16 byte IV to the beginning of the encrypted message in encrypt(). This results in the first 16 bytes of the plaintext to be lost. I presume you assumed that doFinal() automatically does that for you, but it doesn't.
To fix this, before returning the encrypted message, prepend the IV, which can be retrieved using cipher.getIV(). You can accomplish this using the ArrayUtils.addAll() from Apache Commons Lang library, or simply write your own function to do it. Another thing to note is that the IV will always be the block size, which is 16 bytes for AES, no matter the key size.
Hope this answer helps!

Java BouncyCastle Cast6Engine (CAST-256) encrypting

I'm trying to implement a function that receives a string and returns the encoded values of the String in CAST-256. The following code is what i implement following the example on BoncyCastle official web page (http://www.bouncycastle.org/specifications.html , point 4.1).
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.engines.CAST6Engine;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
public class Test {
static{
Security.addProvider(new BouncyCastleProvider());
}
public static final String UTF8 = "utf-8";
public static final String KEY = "CLp4j13gADa9AmRsqsXGJ";
public static byte[] encrypt(String inputString) throws UnsupportedEncodingException {
final BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CAST6Engine());
byte[] key = KEY.getBytes(UTF8);
byte[] input = inputString.getBytes(UTF8);
cipher.init(true, new KeyParameter(key));
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int outputLen = cipher.processBytes(input, 0, input.length, cipherText, 0);
try {
cipher.doFinal(cipherText, outputLen);
} catch (CryptoException ce) {
System.err.println(ce);
System.exit(1);
}
return cipherText;
}
public static void main(String[] args) throws UnsupportedEncodingException {
final String toEncrypt = "hola";
final String encrypted = new String(Base64.encode(test(toEncrypt)),UTF8);
System.out.println(encrypted);
}
}
But , when i run my code i get
QUrYzMVlbx3OK6IKXWq1ng==
and if you encode hola in CAST-256 with the same key ( try here if you want http://www.tools4noobs.com/online_tools/encrypt/) i should get
w5nZSYEyA8HuPL5V0J29Yg==.
What is happening? Why im getting a wront encrypted string?
I'm tired of find that on internet and didnt find a answer.
Bouncy Castle uses PKCS #7 padding by default, while PHP's mcrypt (and the web site you linked) uses zero padding by default. This causes the different ciphertexts.
Please note that the ECB mode used here is not secure for almost any use. Additionally, I hope the secret key you posted is not the real key, because now that it's not secret anymore, all this encryption is useless.
This doesn't really answer your question, but it does provide some pointers.
You need to do a little digging to ensure you are decrypting in exactly the same way as PHP's mcrypt(). You need to make sure your key generation, encoding/decoding and cipher algorithm match exactly.
Keys
"CLp4j13gADa9AmRsqsXGJ".getBytes("UTF-8");
is probably not the right way to create the key source bytes. The docs seem to indicate that mcrypt() pads the key and data with \0 if it isn't the right size. Note that your method produces a 168 bit key, which is not a valid key size and I'm not sure what java is going to do about it.
Algorithm
Make sure the cipher mode and padding are the same. Does mcrypt() use ECB, CBC, something else?
Encoding
Ciphers work on bytes, not Strings. Make sure your conversion between the two is the same in java and PHP.
Here is a reference test for CAST6 using test vectors from https://www.rfc-editor.org/rfc/rfc2612#page-10. Note the key, ciphertext and plaintext are hex encoded.
import java.security.Provider;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class Cast6 {
static final String KEY_ALGO = "CAST6";
static final String CIPHER_ALGO = "CAST6/ECB/NOPADDING";
static String keytext = "2342bb9efa38542c0af75647f29f615d";
static String plaintext = "00000000000000000000000000000000";
static String ciphertext = "c842a08972b43d20836c91d1b7530f6b";
static Provider bc = new BouncyCastleProvider();
public static void main(String[] args) throws Exception {
System.out.println("encrypting");
String actual = encrypt();
System.out.println("actual: " + actual);
System.out.println("expect: " + ciphertext);
System.out.println("decrypting");
actual = decrypt();
System.out.println("actual: " + actual);
System.out.println("expect: " + plaintext);
}
static String encrypt() throws Exception {
Cipher cipher = Cipher.getInstance(CIPHER_ALGO, bc);
byte[] keyBytes = Hex.decodeHex(keytext.toCharArray());
SecretKeySpec key = new SecretKeySpec(keyBytes, KEY_ALGO);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] input = Hex.decodeHex(plaintext.toCharArray());
byte[] output = cipher.doFinal(input);
String actual = Hex.encodeHexString(output);
return actual;
}
static String decrypt() throws Exception {
Cipher cipher = Cipher.getInstance(CIPHER_ALGO, bc);
byte[] keyBytes = Hex.decodeHex(keytext.toCharArray());
SecretKeySpec key = new SecretKeySpec(keyBytes, KEY_ALGO);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] output = cipher.doFinal(Hex.decodeHex(ciphertext.toCharArray()));
String actual = Hex.encodeHexString(output);
return actual;
}
}

JAVA Decryption error: Needs Input to be multiple of 16

I'm trying to develop a simple encryption/decryption program. The problem I am running into is when I attempt to decrypt the encrypted message, I get an error message stating that the Input length must be multiple of 16 when decrypting with cipher. I read somewhere that the encrypted message might need to be encoded before converting it to a string. I'm not sure how to do this? Or if there is an alternative way can someone please help me out?
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
public class Cryption {
public static void cryption(String[] args, String message) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
byte[] encodedKey = "ADBSJHJS12547896".getBytes();
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
Key aesKey = keyGen.generateKey();
System.out.println("CheckType: "+ Global.checkType);
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] input = Global.message.getBytes();
// Check if clicked Encrypted
if(Global.checkType==true) {
// Encrypt
byte[] messageEncrypted = cipher.doFinal(input);
System.out.println("Encrypted Text: " + messageEncrypted);
Global.encValue = messageEncrypted.toString();
}
// Check if clicked Decrypted
if(Global.checkType==false) {
//String mes = message;
System.out.println(Global.message);
System.out.println("Char lenght " + Global.message.length());
byte[] mesByte = Global.message.getBytes();
// Decrypt
cipher.init(Cipher.DECRYPT_MODE, aesKey);
byte[] messageDecrypted = cipher.doFinal(mesByte);
System.out.println("Text Decrypted: " + new String(messageDecrypted));
}
}
}
Global.encValue = messageEncrypted.toString();
This is completely wrong, as it just calls byte[].toString(), which doesn't give you the contents, just a thing with a classname and a hashcode in it. It is also wrong semantically, as String is not a container for binary data in the first place. Don't turn encrypted text into a String. Use the byte[] array that the API gave you.
Have a look at http://docs.oracle.com/javase/tutorial/i18n/text/string.html
It probably means that it doesn't know if it is ASCII or UTF8 or some other byte encoding...

Categories