I have a swift function to encrypt a string.
When I give it "abc" it creates a ciphertext without padding.
When I give it "a" it creates a ciphertext with padding "==".
This behavior is understood. The problem is I need to decrypt the string in java.
Java code decryptes the ciphertext of "abc" fine, but not of "a".
It throws error "input byte array has incorrect ending byte at...".
Obviously it is not able to decrypt the padding bytes.
How do I solve this issue in java code? I tried instantiating Cipher with AES/GCM/PKCS5Padding but it says cannot find any provider supporting this padding
SWIFT ENCRYPTOR
static func encrypt() {
let plain = "a" // another string "abc"
static let secret = "my-xxx-bit-secret-my-secret-my-s"
static let nonceString = "fv1nixTVoYpSvpdA"
static let nonce = try! AES.GCM.Nonce(data: Data(base64Encoded: nonceString)!)
static let symKey = SymmetricKey(data: secret.data(using: .utf8)!)
let sealedBox = try! AES.GCM.seal(plain.data(using: .utf8)!, using: symKey, nonce: nonce)
let ciphertext = sealedBox.ciphertext.base64EncodedString()
let tag = sealedBox.tag
print("ciphertext: .\(ciphertext).")
print("tag: \(tag.base64EncodedString())")
}
JAVA DECRYPTOR
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
public class StringDecryptor {
public static void main(String[] args) throws Exception {
String actualText1 = "abc";
String cipherText1 = "UoRs";
String tag1 = "7VhlWAPpKka0CkmpshyOjw==";
decryptSimpleString(cipherText1, tag1);
String actualText2 = "a";
String cipherText2 = "Ug==";
String tag2 = "hkjeGS301OgQyGqdGDuHAA==";
decryptSimpleString(cipherText2, tag2);
}
public static void decryptSimpleString(String cipherText, String tag) throws Exception {
String secret = "my-xxx-bit-secret-my-secret-my-s";
byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
String nonce = "fv1nixTVoYpSvpdA";
byte[] nonceBytes = Base64.getDecoder().decode(nonce);
byte[] tagBytes = Base64.getDecoder().decode(tag);
String ciphterTextWithTag = cipherText + tag;
byte[] ciphertextBytes = Base64.getDecoder().decode(ciphterTextWithTag);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, nonceBytes);
cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmSpec);
byte[] plaintextBytes = cipher.doFinal(ciphertextBytes);
String plaintext = new String(plaintextBytes, StandardCharsets.UTF_8);
System.out.println("plain text was "+plaintext);
}
}
Output of Java code
plain text was abc
Exception in thread "main" java.lang.IllegalArgumentException: Input byte array has incorrect ending byte at 4
at java.base/java.util.Base64$Decoder.decode0(Base64.java:875)
at java.base/java.util.Base64$Decoder.decode(Base64.java:566)
at java.base/java.util.Base64$Decoder.decode(Base64.java:589)
at com.mydomain.crypto.StringDecryptor.decryptSimpleString(StringDecryptor.java:34)
at com.mydomain.crypto.StringDecryptor.main(StringDecryptor.java:21)
When in doubt, check the documentation.
The documentation for Base64 starts out with:
If we follow that first link, we see the Internet standard for Base64 encoding (and some other encodings). Section 4 says:
And a little lower down, it says:
Hopefully, this makes it clear that the
=
character may only appear at the end of Base64 encoded bytes.Your code has this:
which means the first argument to decryptSimpleString,
cipherText
, is "Ug==", and the second argument to decyptSimpleString,tag
, is a longer sequence of Base64 encoded bytes.The decryptSimpleString method contains this:
Oops.
cipherText
contains=
characters, and since the Base64 specification clearly states that=
can only appear at the end of Base64 encoded content,cipherText + tag
is not a valid Base64 sequence.In summary, you cannot just concatenate two Base64 sequences and assume the result is itself a valid Base64 sequence.
If you have two Base64 sequences and you want to create a single sequence of bytes from them, decode each of them separately: