Forum > General

[Solved] AES Decrypt

(1/2) > >>

OwlOfTime:
Hi, I'm using CryptoJS to encrypt a JSON with AES in the browser.

Now I need to decrypt that with FPC.

I know there is TDPC_Rijndael with Dcpcrypt package, but I don't know how to use it to decrypt.

I have this code working in Java:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---package ...; import android.os.Build; import androidx.annotation.RequiresApi; import java.nio.charset.StandardCharsets;import java.security.DigestException;import java.security.InvalidAlgorithmParameterException;import java.security.InvalidKeyException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.Arrays;import java.util.Base64; 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; public class DecryptAES {     public static String decrypt(String secret, String cipherText) throws NoSuchAlgorithmException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException {         byte[] cipherData = android.util.Base64.decode(cipherText, 0);        byte[] saltData = Arrays.copyOfRange(cipherData, 8, 16);         MessageDigest md5 = MessageDigest.getInstance("MD5");        final byte[][] keyAndIV = GenerateKeyAndIV(32, 16, 1, saltData, secret.getBytes(StandardCharsets.UTF_8), md5);        SecretKeySpec key = new SecretKeySpec(keyAndIV[0], "AES");        IvParameterSpec iv = new IvParameterSpec(keyAndIV[1]);         byte[] encrypted = Arrays.copyOfRange(cipherData, 16, cipherData.length);        Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");        aesCBC.init(Cipher.DECRYPT_MODE, key, iv);        byte[] decryptedData = aesCBC.doFinal(encrypted);        String decryptedText = new String(decryptedData, StandardCharsets.UTF_8);         return decryptedText;    }     /**     * Generates a key and an initialization vector (IV) with the given salt and password.     * <p>     * This method is equivalent to OpenSSL's EVP_BytesToKey function     * (see https://github.com/openssl/openssl/blob/master/crypto/evp/evp_key.c).     * By default, OpenSSL uses a single iteration, MD5 as the algorithm and UTF-8 encoded password data.     * </p>     * @param keyLength the length of the generated key (in bytes)     * @param ivLength the length of the generated IV (in bytes)     * @param iterations the number of digestion rounds     * @param salt the salt data (8 bytes of data or <code>null</code>)     * @param password the password data (optional)     * @param md the message digest algorithm to use     * @return an two-element array with the generated key and IV     */    public static byte[][] GenerateKeyAndIV(int keyLength, int ivLength, int iterations, byte[] salt, byte[] password, MessageDigest md) {         int digestLength = md.getDigestLength();        int requiredLength = (keyLength + ivLength + digestLength - 1) / digestLength * digestLength;        byte[] generatedData = new byte[requiredLength];        int generatedLength = 0;         try {            md.reset();             // Repeat process until sufficient data has been generated            while (generatedLength < keyLength + ivLength) {                 // Digest data (last digest if available, password data, salt if available)                if (generatedLength > 0)                    md.update(generatedData, generatedLength - digestLength, digestLength);                md.update(password);                if (salt != null)                    md.update(salt, 0, 8);                md.digest(generatedData, generatedLength, digestLength);                 // additional rounds                for (int i = 1; i < iterations; i++) {                    md.update(generatedData, generatedLength, digestLength);                    md.digest(generatedData, generatedLength, digestLength);                }                 generatedLength += digestLength;            }             // Copy key and IV into separate byte arrays            byte[][] result = new byte[2][];            result[0] = Arrays.copyOfRange(generatedData, 0, keyLength);            if (ivLength > 0)                result[1] = Arrays.copyOfRange(generatedData, keyLength, keyLength + ivLength);             return result;         } catch (DigestException e) {            throw new RuntimeException(e);         } finally {            // Clean out temporary data            Arrays.fill(generatedData, (byte)0);        }    }     public static void main(String[] args) {     }}
As well I have this example on how to use Rijndael:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---var  Cipher : TDCP_rijndael;  Key    : AnsiString;  IV     : AnsiString;   CBC    : AnsiString;  Buffer : AnsiString;begin  Result := '';  Key  := ??;  IV   := ??;  CBC :=DecodeStringBase64(sText);  Cipher := TDCP_rijndael.Create(nil);  try    Cipher.Init(Key[1], 128, @IV[1]);    SetLength(Buffer, Length(CBC));    Cipher.DecryptCBC(CBC[1], Buffer[1], 16);    Result := Buffer;  finally    Cipher.Free;  end;
Here the problem is how to fill the Key and IV, and use the salt as well like is done with the Java code.

Test data:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---text: 'hello world'pass: 'o0t878'encrypted: 'U2FsdGVkX1/YzdOqaSV3F1JhH/80gyk7qK5VtJdpj5Y='
Any help is appreciated.

xinyiman:
Look https://forum.lazarus.freepascal.org/index.php/topic,47639.msg396061.html#msg396061

loaded:
In the webbrowser you use in fpc;
- Display an html that you can create by yourself, containing an 'input' object. (Alternatively, alert can also be used, but the above method is better for me)
- Run Javascript used by CryptoJS for encryption and decryption with execScript in the browser.
Write a javascript method that passes the -decrypt result to the input object and run it in the browser with execScript.
The solution will be in the palm of your hand.

PierceNg:

--- Quote from: lainz on May 11, 2021, 05:20:25 pm ---
--- Code: Java  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---final byte[][] keyAndIV = GenerateKeyAndIV(32, 16, 1, saltData, secret.getBytes(StandardCharsets.UTF_8), md5);
--- End quote ---

This is how the Java code is generating IV (initialization vector) and cipher key. The code requires secret (password 'o0t878' in your post presumably, passed in as a UTF8 string) and saltData. On the encrypting side, salt is usually randomly generated. The decrypting side must know what the salt is to be able to decrypt.


--- Quote from: lainz on May 11, 2021, 05:20:25 pm ---
--- Code: Java  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---byte[] saltData = Arrays.copyOfRange(cipherData, 8, 16);
--- End quote ---

Ok, for decrypting, saltData is included in the ciphertext.

However, (without attempting to decode), looks like your cipher text  'U2FsdGVkX1/YzdOqaSV3F1JhH/80gyk7qK5VtJdpj5Y=' is base64- or something-encoded, so you'll need to decode it into a byte array.


--- Quote from: lainz on May 11, 2021, 05:20:25 pm ---
--- Code: Java  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
--- End quote ---

And in the Java code the cipher used is AES/CBC/PKCS5Padding. CBC means cipher block chaining and is a standard cipher mode. PKCS5 is a padding mechanism. Does the Dcpcrypt package support this cipher combo?

For generating IV and key, you could port the Java code since it shows how it's done, but for PKCS5 padding, the crypto library needs to support.

If any of ciphertext format (usually byte array, and the string you posted looks encoded), salt, cipher IV and key, cipher mode, padding is wrong, then decryption will fail.

OwlOfTime:
Hi, I think I must learn first the basics of cryptography, else this can be done wrong.

I change the goal of this thread, still at cryptography: How I can start to learn cryptography? Any online documentation you recommend?

Navigation

[0] Message Index

[#] Next page

Go to full version