This specific case is coming whenever i tried to encrypt single char strings in application. When i tried to encrypt the same string with main method then i was able to encrypt it. But when i run with the application then this specific issue is coming. I felt this is strange because it is working with the main method.
My encryption code will be as follows.
public static String encryptWithAES256(String strToEncrypt) throws Exception
{
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] encodedhash = digest.digest(KEY.getBytes(StandardCharsets.UTF_8));
IvParameterSpec ivspec = new IvParameterSpec(Arrays.copyOf(KEY.getBytes(),16));
SecretKeySpec secretKey = new SecretKeySpec(encodedhash, AES_ENCRYPTION_ALGORITHM);
Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
return new String(Base64.encodeBase64(cipher.doFinal(strToEncrypt.getBytes(CHARACTER_ENCODING))));
}
Related
I have a Java code to encrypt(AES encryption with key) a JSON and store it in Oracle database LONG RAW column.
I have a python code to read the data from that column and decrypt. Below is the code i am using for decryption.
The code is running fine but i am not able to see the JSON after decryption instead some unreadable string is getting printed.
c = conn.cursor()
c.execute(u'select KEY_VALUE from TEST1')
encoded = "";
for row in c:
encoded = base64.b64encode(row[0])
print(encoded)
key = 'F50D518354690A8630BCE683B7AC8F55'
aes = AES.new(key, AES.MODE_CBC, 16 * b'\0')
print(aes.decrypt(encoded))
conn.close()
Can you please point where am i wrong.
Also the Encoded String is getting printed fine and matches the value in Oracle database.
I tried using AES.MODE_ECB since the java code was not iv to encrypt but still the same issue
Below is the Encryption and Decryption Code in java. I want to replicate the decrypt in python.
decrypt
public static String decryptText(byte[] byteCipherText, SecretKey secKey) throws Exception {
// AES defaults to AES/ECB/PKCS5Padding in Java 7
System.out.println(secKey.toString());
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.DECRYPT_MODE, secKey);
byte[] bytePlainText = aesCipher.doFinal(byteCipherText);
return new String(bytePlainText);
}
encrypt
public static byte[] encryptText(String plainText, String key) throws Exception {
// AES defaults to AES/ECB/PKCS5Padding in Java 7
System.out.println("key is "+key);
SecretKey secKey=decodeKeyFromString(key);
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.ENCRYPT_MODE, secKey);
byte[] byteCipherText = aesCipher.doFinal(plainText.getBytes());
return byteCipherText;
}
The decodeKeyFromString method has just the below line :
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
I Even tried writing the encrypted value as blob in oracle and then doing decryption but still the same garbage values.
for row in c:
encoded=row[0]
encrypted= open(blobpath,'wb')
encrypted.write(encoded.read())
encrypted.close()
with open('encrypted.txt', 'r') as myfile:
data=myfile.read().replace('\n', '')
key='F50D518354690A8630BCE683B7AC8F55'
aes = AES.new(key, AES.MODE_ECB)
e=unpad(aes.decrypt(base64.b64encode(data)))
Please excuse the hackjob! Still new at coding and was utilizing a lot of sys outs to troubleshoot, and this is my first post at StackOverflow. Thank you for the help!
So I've been working on trying to encrypt String objects using the javax.crypto.Cipher API, and I have found some success, but only when it is using the same instance of the Cipher object. However, for the purposes of my project, I am encrypting text (String) to and decrypting text from a text file, and will not be accessing the same Cipher object every time.
I believe the issue is not from converting between the byte arrays and Strings, since the Base64 encoder seems to have taken care of that problem. The output of the byte arrays are identical pre-encoding and post-decoding, so that should isolate it as an issue during the decryption phase. What can be done so that my decryptPW method can use a different Cipher instance (with the same arguments passed) and not trigger a BadPaddingException?
private static String encryptPW(String pw){
byte[] pwBytes = pw.getBytes();
byte[] keyBytes = "0123456789abcdef".getBytes();
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
try {
Cipher ciph = Cipher.getInstance("AES/CBC/PKCS5Padding");
ciph.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encryptedBytes = ciph.doFinal(pwBytes);
pw = Base64.getEncoder().encodeToString(ciph.doFinal(pwBytes));
for (byte b : encryptedBytes){
System.out.print(b);
}
System.out.println();
} catch (Exception e){
e.printStackTrace();
}
return pw;
}
private static String decryptPW(String pw){
byte[] pwBytes = Base64.getDecoder().decode(pw.getBytes());
for (byte b : pwBytes){
System.out.print(b);
}
System.out.println();
byte[] keyBytes = "0123456789abcdef".getBytes();
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
try {
Cipher ciph = Cipher.getInstance("AES/CBC/PKCS5Padding");
ciph.init(Cipher.DECRYPT_MODE, keySpec, ciph.getParameters());
pw = new String(ciph.doFinal(pwBytes));
} catch (Exception e){
e.printStackTrace();
}
return pw;
}
Again, thank you!
As you use CBC mode, you need to save the random Initialization Vector (IV) from the encryption cipher and provide it to the decryption cipher.
You can get it from the encryption cipher after init like:
ciph.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] iv = ciph.getIV();
And provide it to the decrypt cipher with something like:
ciph.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(iv));
You need to come up with a method of saving the IV. A common way is to prefix the encrypted data with the IV, so it's available when you need to initialize your decrypt cipher. It don't need to be secret.
I have a problem with decrypting a message using AES. At the end when I expect a message, e.g.
ala123
Instead of that I receive sth like:
...6�b}\7�k�8�vFP�8~%��_zժF��FW��O_e���ó������������ala123
The message I pass to encryption is built as:
cipher key is SHA-256 from AES_TOKEN
cipher IV is some characters, which are then stored in the message (at the beginnig)
decrypted message is wrapped up into Base64
The question is why at the end I eventually receive my expected message, but with a lot of rubbish chars at the beggining?
My encryption code is:
private static final String AES_TOKEN = "my_very_secret_token";
// encrypted is base64 string
public String decrypt(String encrypted) throws Exception {
byte[] decrypted = Base64.getDecoder().decode(encrypted);
return new String(aesDecrypt(decrypted), "UTF-8");
}
private byte[] aesDecrypt(byte[] message) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] token = MessageDigest.getInstance("SHA-256").digest(AES_TOKEN.getBytes());
SecretKeySpec secretKey = new SecretKeySpec(token, "AES");
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOf(message, 16));
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
return cipher.doFinal(message);
}
It looks like you aren't removing the IV from the beginning of message after reading it in to iv. That would explain the garbage being at the start of the decrypted message.
I did a simple encrypt/decrypt string class in java and tested it. It workes fine, now im trying to use it in an android device to encrypt a string, send it to my server and there decrypt it. All using the same custom class. Why is this not working? Is it simply not supported? what else can i do to easily encrypt/decrypt a string for this purpose? Base64 is not accepted:)
package crypto;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class Crypto {
public static byte[] encrypt(String message) throws Exception
{
String symmetricKey = "25Ae1f1711%z1 )1";
SecretKeySpec aesKey = new SecretKeySpec(symmetricKey.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "SunJCE");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(message.getBytes());
}
public static String decrypt(byte[] encryptedMessage) throws Exception
{
String symmetricKey = "25Ae1f1711%z1 )1";
SecretKeySpec aesKey = new SecretKeySpec(symmetricKey.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "SunJCE");
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(encryptedMessage));
}
}
In logcat i can see the following exception pop up: java.security.NoSuchProviderException: Provider not avalible: SunJCE
I deleted the specified provider "SunJCE" from the line.
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "SunJCE");
i found the solution to this over here
now i get this error at the serverside instead:
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:750)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:317)
at javax.crypto.Cipher.doFinal(Cipher.java:1813)
at crypto.Crypto.decrypt(Crypto.java:20)
at io.network.UDPServer.run(UDPServer.java:37
tried with BC but i still have the same error
Try this code:
Call encrypt method like this: encrypt_text = Encrypt(Text,"avs3qt");
Encrypt function definition:
String Encrypt(String text, String key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
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.ENCRYPT_MODE, keySpec, ivSpec);
byte[] results = cipher.doFinal(text.getBytes("UTF-8"));
BASE64Decoder encoder = new BASE64Decoder();
return encoder.encodeBytes(results);
}
call Decrypt method like this:
decrypt_text = Decrypt(Text, "avs3qt");
Function definition:
String Decrypt(String text, String key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
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);
BASE64Decoder decoder = new BASE64Decoder();
byte[] results = cipher.doFinal(decoder.decode(text));
return new String(results, "UTF-8");
}
It depends on the security provider. On Android and in JVM are different defaults and not all Sun/Oracle Algorithm exist on android, too.
I had nearly the same problem and was solving it by switching to bounce castle (BC). It exist on both sides and are working in exactly the same metter.
I'm using "RSA/ECB/PKCS1Padding" as Transformation on both sides. And its working.
Your code won't run on any Java VM except Oracle's. The reason is that you request a specific cryptography provider called "SunJCE", which is the reference implementation of the JCE API from Oracle (previously Sun).
Just change your code to accept any provider capable of handling the requested algorithm:
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
Yo Brother,
I have just made an App on android which uses encryption
Have a look at this following question
Java 256-bit AES Password-Based Encryption
Check out the reply given by wufoo (the one having 14 pts)
Just omit use of import org.apache.commons.codec.binary.Hex; and its methods (As the method used in by Hex class are from new version of the apache api and android have built in apache of older version, Plus in android native api is given preference over external library/api )
and download plus reference the org.apache.common from this link http://commons.apache.org/proper/commons-codec/
I hope it helps
Devel
I have Perl code that decrypts a String and I want to do the same in Java. This is the Perl code:
my $c = Crypt::CBC->new( -key => $keyString, -cipher => 'Blowfish', -header => 'randomiv');
return $c->decrypt_hex($config->{encrypted_password})
This is my attempt at the Java code:
Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
// setup an IV (initialization vector) that should be
// randomly generated for each input that's encrypted
byte[] iv = new byte[cipher.getBlockSize()];
new SecureRandom().nextBytes(iv);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
// decrypt
SecretKey secretKey = new SecretKeySpec(Base64.decodeBase64(keyString), "Blowfish");
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
byte[] decrypted = cipher.doFinal(Base64.decodeBase64(input));
return Hex.encodeHexString(decrypted);
I'm getting:javax.crypto.BadPaddingException: Given final block not properly padded. But according to this, the Crypt CBC library uses PKCS5 as the default padding.
Also, am I doing the hex encoding at the end right?
One of the problems you have is that you generate a random IV instead of importing the one used for encryption. Do you have access to the IV used at encryption? Could it be at the start of the ciphertext?
I don't do Perl, so I'm not quite sure if my response is valid. Base64 is probably not the right decoding you're looking for.
For creating your SecretKeySpec, try doing something like:
SecretKey secretKey = new SecretKeySpec(keyString.getBytes("ASCII"), "Blowfish");
For decoding the text, check out Hex.decodeHex(char[]) which can be found at http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Hex.html ... so your code might look something like this:
byte[] decrypted = cipher.doFinal(Hex.decodeHex(input.toCharArray()));
String unencryptedStuff = new String(decrypted);