Search code examples
javaswiftencryptionbadpaddingexception

BadPadding: Encryption Error when I decrypt my encrypted string at java


I use SwiftyRSA to encrypt string with public key with PKCS1 padding. Unfortunately, I've found BadPadding: Encryption Error when I decrypt my encrypted string at Java. So far, I found Java use Mode to encrypt/decrypt string but there is no Mode in iOS/Swift. Please let me know which algorithm should I use to encrypt/decrypt between Swift & Java.

Here is Public & Private Key to encrypt/decrypt

https://github.com/ppshein/Encrypt-Decrypt

Swift to encrypt

let publicKey = try PublicKey(pemNamed: "public")
let clear = try ClearMessage(string: inString, using: .utf8)
let encrypted = try clear.encrypted(with: publicKey, padding: .init(rawValue: 0))
let base64 = encrypted.data.base64EncodedString()

Java to decrypt

public class CryptographyUsingKeystore {
    private static final String ALGORITHM = "RSA";
    public static byte[] encrypt(PublicKey publicKey, byte[] inputData)
            throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.PUBLIC_KEY, publicKey);
        byte[] encryptedBytes = cipher.doFinal(inputData);
        return encryptedBytes;
    }
    public static byte[] decrypt(PrivateKey privateKey, byte[] inputData)
            throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.PRIVATE_KEY, privateKey);
        byte[] decryptedBytes = cipher.doFinal(inputData);
        return decryptedBytes;
    }
    public static void main(String[] args) throws Exception {
        KeyProvider keyProvider = new KeyProvider();

        PublicKey publicKey = myKey.getPemPublicKey();
        //PrivateKey privateKey = (PrivateKey) keyProvider.getPrivateKey();

        byte[] encryptedData = encrypt(publicKey,
                "Hello".getBytes());

        System.out.println("Encrypted Key.... ");
        System.out.println(new String(Base64.getEncoder().encode(encryptedData)));

      byte[] decryptedData = decrypt(privateKey, encryptedData);

        System.out.println("Decrypted key.... ");
        System.out.println(new String(decryptedData));
    }
}

Solution

  • Java crypto (JCA) uses the syntax algorithm/mode/padding called a transformation (or just transform) to specify all ciphers. If you specify only an algorithm, mode and padding are defaulted. For RSA there are no actual modes of operation, and the mode in the transform (ECB) is just a placeholder to conform to the fixed syntax. But there are significantly different padding schemes.

    I'm not a Swift person, but it appears to me from the doc that 0 is actually sigRaw, and PKCS1 is 1. If so you are encrypting with 'raw' = no padding which corresponds to Java's NoPadding so decrypting with Java default PKCS1Padding will fail as you found. Try "RSA/ECB/NoPadding". Or better, encrypt with PKCS1 and decrypt with PKCS1 (explicitly or by default) because ...

    Warning: RSA encryption with no padding is always semantically insecure, and depending on how you use it often totally insecure (as in, an attacker can quickly decrypt all your data). This is precisely why it is not the default and not recommended. However, security is not the topic of stackoverflow; it is the topic of crypto.SX and security.SX where there are alreadying numerous Qs and As explaining the dangers of unpadded aka 'textbook' or 'naive' RSA encryption.