AES -256 decryption - java

I have an encrypted email id for unsubscribing from abcde.test.com.
for ex : https://abcde.test.com/Forms/unSubscribe.jsp?n=2&rid=00028e7353d9c4eca480a579e10ef09b&eid=588876054d458e62779be9345f399252cac7346ad8c464b8ed0bdfbff3512dd96a5b4190c5d71c30c90c34ff39e544aa
This is encrypted in aes-256.where eid="encrypted message" and rid when combined with keysize,and keystr (like "6a6b663472346c38736873346569727538346234333534376635333962353666") forms the encoded key.
Now I want to decrypt this message.
can any one help me decrypting it?

Try the following using Java SE and Apache Commons. Please note that you haven't indicated the mode or padding for your cipher (just "AES"), so you might need to make some adjustments.
// decode the key string into bytes (using Apache Commons)
byte[] keyBytes = Hex.decodeHex(keystr.toCharArray());
// create a representation of the key
SecretKeySpec spec = new SecretKeySpec(keyBytes, "AES");
// turn the key spec into a usable key
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("AES");
SecretKey key = keyFactory.generateSecret(spec);
// use a cipher to decrypt the eid
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = cipher.doFinal(hex.decodeHex(eid.toCharArray())); // decode from Hex again
I don't know what type eid represents, so turning that into something concrete is up to you, but here's an example:
String eid = new String(plainText, "ASCII");

Related

How to decrypt an AES encrypted string while having only the secret key

I am consuming a SOAP API that sends a response that is encrypted with AES. I too have the secret key from the API provider. However I am a bit confused on how to decrypt the response.
All guides that describe how I can decrypt the message tell me I need SecretKeySpec when using javax.crypto.Cipher. However I have no idea what is actually expected there?
Here is an example what I am trying to do:
final String encryptedResponse = "F9nwhTquiEcRY3wfwCGVH1yvZ1fl28VnBXQ3vo6fyCzdV0MnOmeeHg8ea/7c/9ZT0AeEywnR06r5eUoeq4Swf/bFIixc9JJEYB7/fJ0h6I7blQbiOuks7QOUBoSMNaAum1NYTgTm0MHbM3GYLHDPlb8PkBFTL0XxZalKqcqRuhr3BQxPfITeSXjqSvPvy5Wt1Jq";
final String secretKey = "ijsdfgDJJff42h3412";
BASE64Decoder myDecoder = new BASE64Decoder();
byte[] crypted = myDecoder.decodeBuffer(secretKey);
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] cipherData = cipher.doFinal(crypted);
String decryptedResponse = new String(cipherData);
here I receive the following error
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
The key length should be 16,get the true key first;
mayby the key length should be 16,get the true key first;

AES cypher in GCM mode with null byte IV in java

I have to encrypt a json payload using AES cypher in GCM mode with null byte IV.
When i tried using the secret key and the json payload, i am getting a different result than expected. It only mismatches with AES GCM MAC part.
These are the parameters and my source code:
GCM_TAG_LENGTH= 16,
Symmetric key In Hex: 083080D3D0C521C02CD3AE2134363D09EA50DFF914677FAB9E22F18F9C28A3B9
jsonPayload:{"Parameter1":"Value1","Parameter2":"Value2","Parameter3":"Value3"}
OutPut (Expected): EF6BA2FFA05B6985FE129E3CB6845C4EA1E94AE98D31A538A4E24906FB720D764D640894CD9 DE7CEC00114396651A1CCAEDCF480C57A959E925C04492B9CF85FC711FAB3CBED10DC2BA99A2B B063CEFF8DE1
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(secretkey, "AES");
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(Integer.valueOf(WalletStaticTypes.GCM_TAG_LENGTH.getType()) * 8,newbyte[12]);
cipher.init(Cipher.ENCRYPT_MODE, keySpec,gcmParameterSpec);
byte[] encryptedPayLoad = cipher.doFinal(jsonPayload.getBytes("UTF-8"));
Hex.encodeHexString(encryptedPayLoad,false);
I noticed that this is about the Apple Pay integration, I managed to achieve the same results from the test documentation using
GCMParameterSpec(128, ByteArray(12))
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.ENCRYPT_MODE, finalKey, GCMParameterSpec(128, ByteArray(12)))
// AES Key
083080D3D0C521C02CD3AE2134363D09EA50DFF914677FAB9E22F18F9C28A3B9
// JSON Payload (67 bytes), UTF-8 encoded: {"Parameter1":"Value1","Parameter2":"Value2","Parameter3":"Value3"}
Output:
E3EF6BA2FFA05B6985FE129E3CB6845C4EA1E94AE98D31A538A4E24906FB720D764D640894CD9DE7CEC00114396651A1CCAEDCF480C57A959E925C04492B9CF85FC711FAB3CBED10DC2BA99A2BB063CEFF8DE1

iOS CryptoKit in Java

I am looking for settings/parameters of CryptoKit which will allow me to share data between iOS App and a Java Application. The flow would be something like below:
- Use CryptoKit to encrypt a text using a fixed key and random initialization vector (IV).
- In the Java application use standard javax libraries to perform the decryption using the same fixed key. The random IV will be transported/shared with the application along with the encrypted text.
Similarly, the reverse is also required, where text is encrypted using JavaX libraries using a fixed key and random IV. The random IV and encrypted text is shared with the iOS app where it should use CryptoKit to decrypt it.
Below is the code for Encrypt and Decrypt in Java
public static byte[] encrypt(byte[] plaintext, byte[] key, byte[] IV) throws Exception
{
// Get Cipher Instance
Cipher cipher = Cipher.getInstance("AES_256/GCM/NoPadding");
// Create SecretKeySpec
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
// Create GCMParameterSpec
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, IV);
// Initialize Cipher for ENCRYPT_MODE
cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec);
// Perform Encryption
byte[] cipherText = cipher.doFinal(plaintext);
return cipherText;
}
public static String decrypt(byte[] cipherText, byte[] key, byte[] IV) throws Exception
{
// Get Cipher Instance
Cipher cipher = Cipher.getInstance("AES_256/GCM/NoPadding");
// Create SecretKeySpec
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
// Create GCMParameterSpec
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, IV);
// Initialize Cipher for DECRYPT_MODE
cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);
// Perform Decryption
byte[] decryptedText = cipher.doFinal(cipherText);
return new String(decryptedText);
}
The CryptoKit commands as below:
let mykey = SymmetricKey(data: passhash)
let myiv = try AES.GCM.Nonce()
let mySealedBox = try AES.GCM.seal(source.data(using: .utf8)!, using: mykey, nonce: myiv)
let myNewSealedBox = try AES.GCM.SealedBox(nonce: myiv, ciphertext: mySealedBox.ciphertext, tag: mySealedBox.tag)
let myText = try String(decoding: AES.GCM.open(myNewSealedBox, using: mykey), as: UTF8.self)
Below are the steps to generate an encrypted text in Java:
int GCM_IV_LENGTH = 12;
//Generate Key
MessageDigest md = MessageDigest.getInstance("SHA265");
byte[] key = md.digest("pass".getBytes(StandardCharsets.UTF_8));
// Generate IV
SecureRandom sr = new SecureRandom(pass.getBytes(StandardCharsets.UTF_8));
byte[] IV = new byte[GCM_IV_LENGTH];
sr.nextBytes(IV);
//Encrypt
byte[] cipherText = encrypt("Text to encrypt".getBytes(), key, IV);
//Base64 Encoded CipherText
String cipherTextBase64 = Base64.getEncoder().encodeToString(cipherText);
To Decrypt this in SWIFT CryptoKit, I first need to create a sealed box with this CipherText however, the CryptoKit API to create a sealed box requires the following:
Nonce/IV (Available above)
CipherText (Available above)
Tag (NO IDEA FROM WHERE TO GET THIS????)
AES.GCM.SealedBox(nonce: , ciphertext: , tag: )
The other way, lets first encrypt data in CryptoKit
let mykey = SymmetricKey(data: SHA256.hash(data: "12345".data(using: .utf8)!))
let myiv = AES.GCM.Nonce()
let mySealedBox = try AES.GCM.seal("Text to encrypt".data(using: .utf8)!, using: mykey, nonce: myiv)
let cipherText = mySealedBox.cipherText.base64EncodedString()
let iv = myiv.withUnsafeBytes{
return Data(Array($0)).base64EncodedString()
}
If i pass this IV and CipherText to Java Decrypt function along with key (SHA265 hash of "12345" string), i get a TAG mismatch error.
This is the final set of code in SWIFT:
let pass = “Password”
let data = “Text to encrypt”.data(using: .utf8)!
let key = SymmetricKey(data: SHA256.hash(data: pass.datat(using: .utf8)!))
let iv = AES.GCM.Nonce()
let mySealedBox = try AES.GCM.seal(data, using: key, nonce: iv)
dataToShare = mySealedBox.combined?.base64EncodedData()
Write this data to a file (I am using google APIs to write this data to a file on google drive)
Read this data from the file in java and pass it to the functions as defined in the question using the below code:
byte[] iv = Base64.getDecoder().decode(text.substring(0,16));
cipher[] = Base64.getDecoder().decode(text.substring(16));
byte[] key = md.digest(pass.getBytes(StandardCharsets.UTF_8));
String plainText = decrypt(cipher, key, iv);

AES encryp-decrypt is not working properly --Android

I want to encrypt an arbitrary text with RSA, but as I read, RSA dont allow to long texts, so firsts, I need to encrypt with AES-256 (for example), then encrypt the AES key with RSA public, add the encrypted text(with AES), and send the message.
At this moment, I'm doing the AES enc-dec. But I'm doing something wrong because is not decrypting the message properly:
First I generate the AES Key:
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(KEY_SIZE_AES);
this.secretKey_AES = keyGenerator.generateKey();
return this.secretKey_AES;
then I encrypt the message:
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey_AES);
byte[] encrypted = cipher.doFinal(message.getBytes("UTF-8"));
String encryptedMessage = Base64.encodeToString(encrypted, Base64.DEFAULT);
return encryptedMessage;
and finally I decrypt it:
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey_AES);
byte[] decrypted = cipher.doFinal(Base64.decode(message,Base64.DEFAULT));
String decryptedMessage = new String(Base64.encode(decrypted, Base64.DEFAULT));
return decryptedMessage;
But the decrypted text is not the same as the original. I'm missing somthing?
Or I forget some step?
Example:
Your code is working properly, but you are encoding the result in BASE64. ("Elias" is "RWxpYXM" in base64). Just change
String decryptedMessage = new String(Base64.encode(decrypted, Base64.DEFAULT));
with
String decryptedMessage = new String(decrypted, "UTF-8");
Note that this method will only work for text strings

Does AES/CBC really require IV parameter?

I am writing a simple app to encrypt my message using AES / CBC (mode). As my understanding CBC mode requires IV parameter but I don't know why my code work without IV parameter used. Anyone can explain why? Thanks.
The encrypted message printed: T9KdWxVZ5xStaisXn6llfg== without exception.
public class TestAES {
public static void main(String[] args) {
try {
byte[] salt = new byte[8];
new SecureRandom().nextBytes(salt);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec("myPassword".toCharArray(), salt, 100, 128);
SecretKey tmp = keyFactory.generateSecret(keySpec);
SecretKeySpec key = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher enCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
enCipher.init(Cipher.ENCRYPT_MODE, key);
// enCipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
byte[] cipherBytes = enCipher.doFinal("myMessage".getBytes());
String cipherMsg = BaseEncoding.base64().encode(cipherBytes);
System.out.println("Encrypted message: " + cipherMsg);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
When it is used without an IV, for certain types of ciphers including AES, it implicitly uses 0 IV. See Cipher class documentation.
The disadvantage of a null IV (or a deterministic IV) is that it is vulnerable to dictionary attacks. The requirement for IV is to prevent the same plain text block producing the same cipher text every time.
Like other users have said, it depends on the JCE provider. Java SE generates a random IV for you if you specify none.
Only Android1 and Javacard API use a blank IV, which is non-conforming to the Java Crypto spec, which states:
If this cipher requires any algorithm parameters that cannot be derived from the given key, the underlying cipher implementation is supposed to generate the required parameters itself (using provider-specific default or random values) if it is being initialized for encryption or key wrapping, and raise an InvalidKeyException if it is being initialized for decryption or key unwrapping. The generated parameters can be retrieved using getParameters or getIV (if the parameter is an IV).
If you do not specify the IV, in Java SE you get a random one, and will need to retrieve it with cipher.getIV() and store it, as it will be needed for decryption.
But better yet, generate a random IV yourself and provide it via IvParameterSpec.
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecureRandom rnd = new SecureRandom();
byte[] iv = new byte[cipher.getBlockSize()];
rnd.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), ivParams);
byte[] ciphertext = cipher.doFinal(input.getBytes());
1 That could be because Android is Java-esque, like the Eminem-esque ad. Just guessing, that's all.

Categories