antacerod
antacerod

Reputation: 1420

Decrypt with jasypt after retrieving the encrypted value in Http Request

I am having problem to make work jaspyt in this scenario:

StrongTextEncryptor textEncryptor = new StrongTextEncryptor();      
textEncryptor.setPassword("myPassword");
String myEncryptedParam = textEncryptor.encrypt("myClearMessage");

myObject.setCallbackUrl("http://myhost/notification?myparam="+myEncryptedParam);

When I receive the callback url and try to decrypt the param 'myParam' provided in the url WITH THE SAME STRONGTEXTENCRYPTOR used in the request, it raises an exception:

org.jasypt.exceptions.EncryptionOperationNotPossibleException
at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.decrypt(StandardPBEByteEncryptor.java:1055)
at org.jasypt.encryption.pbe.StandardPBEStringEncryptor.decrypt(StandardPBEStringEncryptor.java:725)
at org.jasypt.util.text.StrongTextEncryptor.decrypt(StrongTextEncryptor.java:118)
at com.softlysoftware.caligraph.util.Util.decryptMessage(Util.java:30)

Digging a bit more in the exception I get:

BadPaddingException: Given final block not properly padded

If I test the encryption/decryption process without httprequest, works ok.

Upvotes: 1

Views: 3317

Answers (2)

ThomasRS
ThomasRS

Reputation: 8287

Building on Artjom's answer, here is a Jasypt text encryptor wrapper

import org.jasypt.util.text.TextEncryptor;

public class UrlSafeTextEncryptor implements TextEncryptor {

    private TextEncryptor textEncryptor; // thread safe

    public UrlSafeTextEncryptor(TextEncryptor textEncryptor) {
        this.textEncryptor = textEncryptor;
    }

    public String encrypt(String string) {
        String encrypted = textEncryptor.encrypt(string);

        return encrypted.replaceAll("/", "_").replaceAll("\\+", "-");
    }

    public String decrypt(String encrypted) {

        encrypted = encrypted.replaceAll("_", "/").replaceAll("-", "\\+");

        return textEncryptor.decrypt(encrypted);
    }
}

and corresponding test case

import org.jasypt.util.text.StrongTextEncryptor;
import org.jasypt.util.text.TextEncryptor;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class UrlSafeTextEncryptorTest {

    private String password = "12345678";

    protected TextEncryptor encryptor;
    protected UrlSafeTextEncryptor urlSafeEncryptor;

    @Before
    public void init() {
        StrongTextEncryptor encryptor = new StrongTextEncryptor(); // your implementation here
        encryptor.setPassword(password);

        this.encryptor = encryptor;

        this.urlSafeEncryptor = new UrlSafeTextEncryptor(encryptor);
    }

    @Test
    public void scramble_roundtrip_urlSafe() {

        int i = 0;
        while(true) {
            String key = Integer.toString(i);

            String urlSafeEncrypted = urlSafeEncryptor.encrypt(key);

            Assert.assertFalse(urlSafeEncrypted, urlSafeEncrypted.contains("/"));

            Assert.assertEquals(key, urlSafeEncryptor.decrypt(urlSafeEncrypted));

            if(urlSafeEncrypted.contains("_")) {
                break;
            }

            i++;
        }

    }
}

Upvotes: 0

Artjom B.
Artjom B.

Reputation: 61902

The problem is that StrongTextEncryptor uses StandardPBEStringEncryptor which in turn uses Base64 to encode the ciphertexts. The problem is that Base64 has a / character which is not URL-safe. When you try to decrypt, the parameter parser that you use probably drops those / characters which makes the ciphertext incomplete.

The easiest solution is probably to change the offending characters with replace all:

myEncryptedParam.replaceAll("/", "_").replaceAll("\\+", "-");

and back again before you try to decrypt:

receivedParam.replaceAll("_", "/").replaceAll("-", "\\+");

This transforms the encoding from the normal Base64 encoding to the "URL and Filename safe" Base 64 alphabet.

Upvotes: 4

Related Questions