Here are my encryption settings:
public static String encryptionAlgorithm = "AES";
public static short encryptionBitCount = 256;
public static int encryptionMessageLength = 176;
public static String hashingAlgorithm = "PBEWITHSHAAND128BITAES-CBC-BC";
//PBEWithSHA256And256BitAES-CBC-BC"PBEWithMD5AndDES";//"PBKDF2WithHmacSHA1";
public static short hashingCount = 512;
public static String cipherTransformation = "AES/CBC/PKCS5Padding";
Here is my code to decrypt:
public byte[] readMessage () throws Exception
{
byte[] iv = new byte[16];
byte[] message = new byte[EncryptionSettings.encryptionMessageLength];
try
{
// read IV from stream
if (stream.read(iv) != 16)
throw new Exception("Problem receiving full IV from stream");
}
catch (final IOException e)
{
throw new Exception("Unable to read IV from stream");
}
try
{
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
}
catch (final InvalidKeyException e)
{
throw new Exception("Invalid key");
}
catch (final InvalidAlgorithmParameterException e)
{
throw new Exception("Invalid algorithm parameter");
}
try
{
//read message from stream
if (stream.read(message) != EncryptionSettings.encryptionMessageLength)
throw new Exception("Problem receiving full encrypted message from stream");
}
catch (final IOException e)
{
throw new Exception("Unable to read message from stream");
}
try
{
return cipher.doFinal(message); //decipher message and return it.
}
catch (IllegalBlockSizeException e)
{
throw new Exception("Unable to decrypt message due to illegal block size - "
+ e.getMessage());
}
catch (BadPaddingException e)
{
throw new Exception("Unable to decrypt message due to bad padding - "
+ e.getMessage());
}
}
Here is my code to encrypt:
public void writeMessage (final byte[] message) throws Exception
{
try
{
// write iv
byte b[] = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
System.out.println(b.length);
stream.write(b);
}
catch (final InvalidParameterSpecException e)
{
throw new Exception("Unable to write IV to stream due to invalid"+
" parameter specification");
}
catch (final IOException e)
{
throw new Exception("Unable to write IV to stream");
}
try
{
// write cipher text
byte b[] = cipher.doFinal(message);
System.out.println(b.length);
stream.write(b);
}
catch (final IllegalBlockSizeException e)
{
throw new Exception("Unable to write cipher text to stream due to "+
"illegal block size");
}
catch (final BadPaddingException e)
{
throw new Exception("Unable to write cipher text to stream due to " +
"bad padding");
}
catch (final IOException e)
{
throw new Exception("Unable to write cipher text to stream");
}
}
Error: Unable to decrypt message due to bad padding - null.
I am getting a BadPaddingException when decrypting, why? The message is exactly 168 characters which is 176 after padding (divisible by 16)
From my initial comment:
A typical scenario is one where the key is different from the one used at the other side. This is the most probable cause, but you might also want to check the way you handle streams, because you really lack .close() and possibly .flush() statements. You also assume that you always can read all the data into the buffer, which may not be the case.
The key was indeed calculated incorrectly.
BadPaddingException Error in enryption/decryption
I encountered such an error, but this helped me
http://themasterofmagik.wordpress.com/2014/03/19/simple-aes-encryption-and-decryption-in-java-part1/
hope it helps you too.
Related
I am creating a tar.Gzip file using GZIPOutputStream and I have added an another logic in that if any Exception caught while compressing file then, my code will retry three times.
When I am throwing an IOException to test my retry logic it throwing a below Exception:
java.io.IOException: request to write '4096' bytes exceeds size in header of '2644' bytes for entry 'Alldbtypes'
I am getting Exception at line: org.apache.commons.io.IOUtils.copyLarge(inputStream, tarStream);
private class CompressionStream extends GZIPOutputStream {
// Use compression levels from the deflator class
public CompressionStream(OutputStream out, int compressionLevel) throws IOException {
super(out);
def.setLevel(compressionLevel);
}
}
public void createTAR(){
boolean isSuccessful=false;
int count = 0;
int maxTries = 3;
while(!isSuccessful) {
InputStream inputStream =null;
FileOutputStream outputStream =null;
CompressionStream compressionStream=null;
OutputStream md5OutputStream = null;
TarArchiveOutputStream tarStream = null;
try{
inputStream = new BufferedInputStream(new FileInputStream(rawfile));
File stagingPath = new File("C:\\Workarea\\6d22b6a3-564f-42b4-be83-9e1573a718cd\\b88beb62-aa65-4ad5-b46c-4f2e9c892259.tar.gz");
boolean isDeleted = false;
if(stagingPath.exists()){
isDeleted = stagingPath.delete();
if(stagingPath.exists()){
try {
FileUtils.forceDelete(stagingPath);
}catch (IOException ex){
//ignore
}
}
}
outputStream = new FileOutputStream(stagingPath);
if (isCompressionEnabled) {
compressionStream = new
CompressionStream(outputStream, getCompressionLevel(om));
}
final MessageDigest outputDigest = MessageDigest.getInstance("MD5");
md5OutputStream = new DigestOutputStream(isCompressionEnabled ? compressionStream : outputStream, outputDigest);
tarStream = new TarArchiveOutputStream(new BufferedOutputStream(md5OutputStream));
tarStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
tarStream.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_STAR);
TarArchiveEntry entry = new TarArchiveEntry("Alldbtypes");
entry.setSize(getOriginalSize());
entry.setModTime(getLastModified().getMillis());
tarStream.putArchiveEntry(entry);
org.apache.commons.io.IOUtils.copyLarge(inputStream, tarStream);
inputStream.close();
tarStream.closeArchiveEntry();
tarStream.finish();
tarStream.close();
String digest = Hex.encodeHexString(outputDigest.digest());
setChecksum(digest);
setIngested(DateTime.now());
setOriginalSize(FileUtils.sizeOf(stagingPath));
isSuccessful =true;
} catch (IOException e) {
if (++count == maxTries) {
throw new RuntimeException("Exception: " + e.getMessage(), e);
}
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(Exception("MD5 hash algo not installed.");
} catch (Exception e) {
throw new RuntimeException("Exception: " + e.getMessage(), e);
} finally {
org.apache.commons.io.IOUtils.closeQuietly(inputStream);
try {
tarStream.flush();
tarStream.finish();
} catch (IOException e) {
e.printStackTrace();
}
org.apache.commons.io.IOUtils.closeQuietly(tarStream);
org.apache.commons.io.IOUtils.closeQuietly(compressionStream);
org.apache.commons.io.IOUtils.closeQuietly(md5OutputStream);
org.apache.commons.io.IOUtils.closeQuietly(outputStream);
}
}
}
Case solved. This Exception java.io.IOException: request to write '4096' bytes exceeds size in header of '2644' bytes for entry 'Alldbtypes' thrown when the size of the file that going to be zipped is incorrect.
TarArchiveEntry entry = new TarArchiveEntry("Alldbtypes");
entry.setSize(getOriginalSize());
In my code getOriginalSize() is getting updated again at the end so in retry the original size became change and original size is now zipped file size so it was throwing this Exception.
My app prompts the user for the password that was used to encrypt a control file. If the wrong password is entered, the app responds by creating a new control file. Therefore I need to catch a BadPaddingException so I can trigger the appropriate response.
Here's the code snippet that should generate the exception
private void existingHashFile(String file) {
psUI = new passwordUI(new javax.swing.JFrame(), true, "existing");
psUI.setVisible(true);
this.key = passwordUI.key;
try {
hash.decryptHashFile(file, this.key); //this is line 240
} catch (BadPaddingException ex) {
Logger.getLogger(homePage.class.getName()).log(Level.SEVERE, null, ex);
//then the file was not decrypted
System.out.println("BPE 2!");
} catch (Exception ex) {
Logger.getLogger(homePage.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("BPE 3!");
}
For completeness, here's the decryptHashFile method that is called above
public void decryptHashFile(String filename, String key) throws BadPaddingException, UnsupportedEncodingException, Exception {
FileInputStream fis = null;
FileOutputStream fos = null;
CipherInputStream cis = null;
String outFile = filename.replace(".enc", "");
byte[] byteKey = key.getBytes("UTF-8");
Cipher cipher = getCipher(byteKey, "decrypt");
try {
fis = new FileInputStream(filename);
fos = new FileOutputStream(outFile);
cis = new CipherInputStream(fis, cipher);
byte[] buffer = new byte[1024];
int read = cis.read(buffer);
while (read != -1) {
fos.write(buffer, 0, read);
read = cis.read(buffer); //this is line 197
}
} catch (IOException ex) {
Logger.getLogger(hashListClass.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if (fos != null) {
fos.close();
}
if (cis != null) {
cis.close();
}
if (fis != null) {
fis.close();
}
}
}
When I deliberately enter the wrong password, I see this stack trace, but my code (I've used a println in the example) isn't executed:
Dec 02, 2017 2:31:34 PM appwatch.hashListClass decryptHashFile
SEVERE: null
java.io.IOException: javax.crypto.BadPaddingException: Given final block not properly padded
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:121)
at javax.crypto.CipherInputStream.read(CipherInputStream.java:239)
at javax.crypto.CipherInputStream.read(CipherInputStream.java:215)
at appwatch.hashListClass.decryptHashFile(hashListClass.java:197)
at appwatch.homePage.existingHashFile(homePage.java:240)
CipherInputStream.read (your line 197) throws IOException, not BadPaddingException, therefore the exception is caught by the subsequent catch (IOException ex).
After that you are not explicitly throwing other exceptions, so there is nothing else to catch after decryptHashFile.
Here are my encryption settings
public static final String ALGORITHM = "RSA";
public static final String CIPHER = "RSA/ECB/PKCS1Padding";
public static final String HASH_ALGORITHM = "SHA-256";
public static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
public static final int KEY_SIZE = 1048;
Here is my code to encrypt
public byte[] encrypt(byte[] toEncrypt, String keyPath){
int keyLength = KEY_SIZE/8 - 11;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
String toEncryptString = new String(toEncrypt,StandardCharsets.UTF_8);
String[] lines = toEncryptString.split("(?<=\\G.{" + keyLength + "})");
byte[] encryptedData = new byte[0];
try{
inputStream = new ObjectInputStream(new FileInputStream(keyPath));
final PublicKey publicKey = (PublicKey) inputStream.readObject();
final Cipher cipher = Cipher.getInstance(CIPHER);
cipher.init(Cipher.ENCRYPT_MODE,publicKey);
if(toEncrypt.length >= keyLength){
for(String line : lines){
byteArrayOutputStream.write(cipher.doFinal(line.getBytes("UTF-8")));
}
}else{
byteArrayOutputStream.write(cipher.doFinal(toEncrypt));
}
encryptedData = byteArrayOutputStream.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
byte[] cipheredData = base64Encoder(encryptedData);
System.out.println(Arrays.toString(cipheredData));
return cipheredData;
}
Here is my code to decrypt
public byte[] decrypt(byte[] toDecrypt, String keyPath) {
byte[] decypherText = base64Decoder(toDecrypt);
System.out.println(toDecrypt.length);
System.out.println(decypherText.length);
int keyLength = KEY_SIZE/8 - 11;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
String toEncryptString = Arrays.toString(decypherText);
String[] lines = toEncryptString.split("(?<=\\G.{" + keyLength + "})");
byte[] decipheredData = new byte[0];
try{
inputStream = new ObjectInputStream(new FileInputStream(keyPath));
final PrivateKey privateKey = (PrivateKey) inputStream.readObject();
final Cipher cipher = Cipher.getInstance(CIPHER);
cipher.init(Cipher.DECRYPT_MODE,privateKey);
if(decypherText.length >= keyLength){
for(String line : lines){
byteArrayOutputStream.write(cipher.doFinal(line.getBytes("UTF-8")));
}
}else{
byteArrayOutputStream.write(cipher.doFinal(decypherText));
}
decipheredData = byteArrayOutputStream.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
System.out.println(Arrays.toString(decipheredData));
return decipheredData;
}
I'm trying to encrypt a Public Key "A" with the Public Key "B". Encryption is successful, but when I try to decrypt it with the Private Key "B", it gives me that error.
The code looks fine to me, already reviewed it several times, these past 16 hours, already searched through several posts in here, and did not found a suitable answer for my problem.
Also, it already gave me BadPaddingException when decrypting. "Data must not be longer than 131 bytes". However, I'm using a Cipher with padding, so it can only decrypt data with 120 bytes. Why this error, if the Public key ciphered is splitted into blocks of 120 bytes?
Edit: before anyone else says that encrypting a Public Key is a mistery, have in your mind that it's the purpose of the project.. to have a Public Key as an ID and, as such, the need to encrypt so that no one discovers the ID of the user.
Your code doesn't make sense. You're trying to split the ciphertext on a plaintext string. It isn't there. It got removed when you split the string. In any case the data has been encrypted, so searching for a plaintext in it is futile.
You should be base64-decoding, decrypting, reading objects, and then recombining them using "(?<=\\G.{" + keyLength + "})" as a delimiter.
In fact why you're splitting in the first place and then encrypting multiple lines is a mystery.
And why you're serializing is another. Just encrypt the entire thing, without splitting, base64-encode it, and save that. When decrypting, just base64-decode it and decrypt it.
And, finally, why you're encrypting a public key at all is a complete mystery. It's PUBLIC. Not a secret.
When I encrypt and decrypt in the same method, the cipher works perfectly, however as soon as I send an encrypted message to a server, which sends the same message straight back, the decryption throws a "BadPaddingException: Data must start with zero", any ideas as to why?
Here are my decrpytion and encryption methods, including the method they are called from:
public byte[] getServerResponse(byte[] message) throws IOException
{
Log.debug("Getting server response for: " + message.toString());
byte[] encMsg = encrypt(message);
out.write(encMsg);
out.flush();
in = new DataInputStream(s.getInputStream());
byte[] response = new byte[128];
in.readFully(response);
byte[] strResponse = decrypt(response);
Log.debug("Server response: " + response);
return strResponse;
}
private byte[] encrypt(byte[] message) {
byte[] encryptedBytes = new byte[128];
try {
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
encryptedBytes = cipher.doFinal(message);
} catch (GeneralSecurityException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
return encryptedBytes;
}
private byte[] decrypt(byte[] message) {
byte[] cleartext = new byte[128];
try {
cipher.init(Cipher.DECRYPT_MODE, privateKey);
cleartext = cipher.doFinal(message);
} catch (InvalidKeyException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalBlockSizeException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
} catch (BadPaddingException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
return cleartext;
}
The cipher is available to the whole class, and is initialised as follows:
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
Do I need to use the IV? If so, how does one do that?
I'm working on some Java software which entails encrypting and decrypting information on both ends of a network connection using two separate pieces of software. To ease this, I have one class, Cryptographer, that handles the encryption of data. As of right now, the Controller (one side of the connection) and the Agent (the other side) both use this class to generate a SecretKey based on a password shared between the two programs.
The key is generated in this function of the Cryptographer class:
public SecretKey generateKey(String key) {
this._paramSpec = new PBEParameterSpec(this.SALT, this.ITERATION_COUNT);
PBEKeySpec spec = new PBEKeySpec(key.toCharArray());
SecretKeyFactory fac = null;
try {
fac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
System.err.println("[ERR] Cryptographer could not create a SecretKeyFactory due to an unsupported algorithm.");
}
try {
if (fac == null)
return null;
return fac.generateSecret(spec);
} catch (InvalidKeySpecException ex) {
System.err.println("[ERR] Cryptographer could not generate a SecretKey due to an invalid Key Specification.");
ex.printStackTrace();
return null;
}
}
The encryption itself takes place in the encrypt function:
public byte[] encrypt(byte[] message) {
try {
this._cipher.init(Cipher.ENCRYPT_MODE, this._key, this._paramSpec);
} catch (InvalidKeyException ex) {
System.err.println("[ERR] Cryptographer could not encrypt a message because the provided key is invalid.");
ex.printStackTrace();
return new byte[0];
} catch (InvalidAlgorithmParameterException ex) {
System.err.println("[ERR] Cryptographer could not encrypt a message because the parameters are invalid.");
ex.printStackTrace();
return new byte[0];
}
try {
return this._cipher.doFinal(message);
} catch (IllegalBlockSizeException ex) {
System.err.println("[ERR] Cryptographer could not encrypt a message due to an illegal block size.");
ex.printStackTrace();
return new byte[0];
} catch (BadPaddingException ex) {
System.err.println("[ERR] Cryptographer could not encrypt a message due to bad padding.");
ex.printStackTrace();
return new byte[0];
}
}
And it gets decrypted by the decrypt function:
public byte[] decrypt(byte[] message) {
try {
this._cipher.init(Cipher.DECRYPT_MODE, this._key, this._paramSpec);
} catch (InvalidKeyException ex) {
System.err.println("[ERR] Cryptographer could not decrypt a message because the provided key is invalid.");
return new byte[0];
} catch (InvalidAlgorithmParameterException ex) {
System.err.println("[ERR] Cryptographer could not decrypt a message because the parameters are invalid.");
}
try {
return this._cipher.doFinal(message);
} catch (IllegalBlockSizeException ex) {
System.err.println("[ERR] Cryptographer could not decrypt a message due to an illegal block size.");
return new byte[0];
} catch (BadPaddingException ex) {
System.err.println("[ERR] Cryptographer could not decrypt a message due to bad padding.");
return new byte[0];
}
}
Encryption seems to work fine, but when I try to decrypt a serialized object on the receiving end, the InvalidKeyException gets thrown. Comparing the keys independently generated on the Controller and the Agent shows that, although they are sourced in the same password, they are not generating identical keys.
Now, I am new to encryption in Java, so it's entirely possible I'm doing something wrong here. It seems like there is a random element to this that I'm missing. The goal is to get each side of the connection to generate an identical key from identical passwords. So is there anything I'm doing that's obviously wrong? If you need to see more code, let me know. I'll be happy to post it.
The InvalidKeyException being thrown indicates to me that I would look at how the key is being used on the receiving end. Are you storing it in a database or file? Are you sure it is in the same encoding that was used to encrypt the data?