OpenSSLCipher: adjust expected length with padding in decrypt mode
- Consider the |final| buffer when computing the expected length
- Should not expect an extra block when using padding in decrypting
mode
Bug: 19186852
Change-Id: I206442d45c4cf68363201738ba9d0b035f19c436
diff --git a/src/main/java/org/conscrypt/NativeCrypto.java b/src/main/java/org/conscrypt/NativeCrypto.java
index 4045a57..55465cb 100644
--- a/src/main/java/org/conscrypt/NativeCrypto.java
+++ b/src/main/java/org/conscrypt/NativeCrypto.java
@@ -300,6 +300,8 @@
public static native int get_EVP_CIPHER_CTX_buf_len(NativeRef.EVP_CIPHER_CTX ctx);
+ public static native boolean get_EVP_CIPHER_CTX_final_used(NativeRef.EVP_CIPHER_CTX ctx);
+
public static native void EVP_CIPHER_CTX_set_padding(NativeRef.EVP_CIPHER_CTX ctx,
boolean enablePadding);
diff --git a/src/main/java/org/conscrypt/OpenSSLCipher.java b/src/main/java/org/conscrypt/OpenSSLCipher.java
index 591915d..47de94a 100644
--- a/src/main/java/org/conscrypt/OpenSSLCipher.java
+++ b/src/main/java/org/conscrypt/OpenSSLCipher.java
@@ -589,10 +589,19 @@
return inputLen;
} else {
final int buffered = NativeCrypto.get_EVP_CIPHER_CTX_buf_len(cipherCtx);
+
if (getPadding() == Padding.NOPADDING) {
return buffered + inputLen;
} else {
- final int totalLen = inputLen + buffered + modeBlockSize;
+ final boolean finalUsed = NativeCrypto.get_EVP_CIPHER_CTX_final_used(cipherCtx);
+ // There is an additional buffer containing the possible final block.
+ int totalLen = inputLen + buffered + (finalUsed ? modeBlockSize : 0);
+ // Extra block for remainder bytes plus padding.
+ // In case it's encrypting and there are no remainder bytes, add an extra block
+ // consisting only of padding.
+ totalLen += ((totalLen % modeBlockSize != 0) || isEncrypting())
+ ? modeBlockSize : 0;
+ // The minimum multiple of {@code modeBlockSize} that can hold all the bytes.
return totalLen - (totalLen % modeBlockSize);
}
}
diff --git a/src/main/native/org_conscrypt_NativeCrypto.cpp b/src/main/native/org_conscrypt_NativeCrypto.cpp
index 07db712..6026f2c 100644
--- a/src/main/native/org_conscrypt_NativeCrypto.cpp
+++ b/src/main/native/org_conscrypt_NativeCrypto.cpp
@@ -4867,6 +4867,20 @@
return buf_len;
}
+static jboolean NativeCrypto_get_EVP_CIPHER_CTX_final_used(JNIEnv* env, jclass, jobject ctxRef) {
+ EVP_CIPHER_CTX* ctx = fromContextObject<EVP_CIPHER_CTX>(env, ctxRef);
+ JNI_TRACE("get_EVP_CIPHER_CTX_final_used(%p)", ctx);
+
+ if (ctx == NULL) {
+ JNI_TRACE("ctx=%p get_EVP_CIPHER_CTX_final_used => ctx == null", ctx);
+ return 0;
+ }
+
+ bool final_used = ctx->final_used != 0;
+ JNI_TRACE("get_EVP_CIPHER_CTX_final_used(%p) => %d", ctx, final_used);
+ return final_used;
+}
+
static void NativeCrypto_EVP_CIPHER_CTX_set_padding(JNIEnv* env, jclass, jobject ctxRef,
jboolean enablePaddingBool) {
EVP_CIPHER_CTX* ctx = fromContextObject<EVP_CIPHER_CTX>(env, ctxRef);
@@ -10540,6 +10554,7 @@
NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_new, "()J"),
NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_block_size, "(" REF_EVP_CIPHER_CTX ")I"),
NATIVE_METHOD(NativeCrypto, get_EVP_CIPHER_CTX_buf_len, "(" REF_EVP_CIPHER_CTX ")I"),
+ NATIVE_METHOD(NativeCrypto, get_EVP_CIPHER_CTX_final_used, "(" REF_EVP_CIPHER_CTX ")Z"),
NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_set_padding, "(" REF_EVP_CIPHER_CTX "Z)V"),
NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_set_key_length, "(" REF_EVP_CIPHER_CTX "I)V"),
NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_free, "(J)V"),