Discussion:
Cipher.getInstance with OID
Daniil Ivanov
2014-07-17 13:59:46 UTC
Permalink
Hi,

I'm puzzled with how I can use OID and cipher parameters in
Cipher.getInstance.
I tried:
Cipher.getInstance("2.16.840.1.101.3.4.1.2", "BC");
This call returns AES with CBC and PKCS#7 padding.

Ok, then I tried this one:
Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding", "BC");
This call return AES with ECB and NoPadding.
I don't quite get how this end up doing ECB.

Any ideas?

Thanks, Daniil
David Hook
2014-07-18 01:53:13 UTC
Permalink
I'll be honest, I'm not really sure either...

What will happen internally is the JCE will find the OID implementation,
then call engineSetMode and engineSetPadding - the base engine will
already have CBC mode on it so XOR'ing the IV twice will remove it (that
probably explains the ECB).

The provider should probably through an exception in the second case -
the OIDs fully describe the algorithm, mode, and padding. From that
point of view the second usage doesn't really make sense.

Regards,

David
Post by Daniil Ivanov
Hi,
I'm puzzled with how I can use OID and cipher parameters in
Cipher.getInstance.
Cipher.getInstance("2.16.840.1.101.3.4.1.2", "BC");
This call returns AES with CBC and PKCS#7 padding.
Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding", "BC");
This call return AES with ECB and NoPadding.
I don't quite get how this end up doing ECB.
Any ideas?
Thanks, Daniil
Tim Whittington
2014-07-18 08:59:32 UTC
Permalink
I'll be honest, I'm not really sure either…
This is a quirk of the way BaseBlockCipher works (helped I guess by the general BlockCipher vs mode vs padding confusion).

The AES$CBC constructor creates :

BaseBlockCipher
-> BufferedGenericBlockCipher
-> PaddedBufferedBlockCipher
-> CBCBlockCipher
+ PKCS7Padding

setMode(“CBC”) replaces that with the same construction (a noop).

setPadding(“NoPadding”) unwraps this and replaces it with:

BaseBlockCipher
-> BufferedGenericBlockCipher
-> BufferedBlockCipher
-> CBCBlockCipher

… which isn’t ECB (I’ve tested, and it’s definitely still doing CBC), but will complain about invalid data lengths if the input isn’t block aligned.
What will happen internally is the JCE will find the OID implementation, then call engineSetMode and engineSetPadding - the base engine will already have CBC mode on it so XOR'ing the IV twice will remove it (that probably explains the ECB).
The provider should probably through an exception in the second case - the OIDs fully describe the algorithm, mode, and padding. From that point of view the second usage doesn't really make sense.
Yeah. Perhaps it'd make more sense if AES$CBC et al specified cipher/mode/padding rather than providing a CBCBlockCipher+relying on the BufferedGenericBlockCipher constructor magic padding assumption, and then BaseBlockCipher errors if the mode/padding is additionally specified?

tim
Hi,
I'm puzzled with how I can use OID and cipher parameters in Cipher.getInstance.
Cipher.getInstance("2.16.840.1.101.3.4.1.2", "BC");
This call returns AES with CBC and PKCS#7 padding.
Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding", "BC");
This call return AES with ECB and NoPadding.
I don't quite get how this end up doing ECB.
Any ideas?
Thanks, Daniil
Daniil Ivanov
2014-07-18 14:10:09 UTC
Permalink
Hi Tim!

I'm using BouncyCastle 1.50 and JDK 1.7. I did the following tests trying
to decrypt results:

/* This test fails - second block of recovered text is corrupted */
@Test
public void testCBC() throws Exception {
BouncyCastleProvider provider = new BouncyCastleProvider();
SecureRandom random = new SecureRandom();

Cipher cipher =
Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding", provider);
byte[] symmetricKey = new byte[cipher.getBlockSize()];
random.nextBytes(symmetricKey);
byte[] data = new byte[2 * cipher.getBlockSize()];
random.nextBytes(data);
byte[] iv = new byte[cipher.getBlockSize()]; // {0} IV
AlgorithmParameterSpec algoSpec = new IvParameterSpec(iv);
SecretKeySpec secretKey = new SecretKeySpec(symmetricKey, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, algoSpec);

byte[] encryptedData = cipher.doFinal(data);

Cipher cipher2 = Cipher.getInstance("AES/CBC/NoPadding", provider);
cipher2.init(Cipher.DECRYPT_MODE, secretKey, algoSpec);
byte[] decryptedData = cipher2.doFinal(encryptedData);

assertEquals(DatatypeConverter.printHexBinary(data),
DatatypeConverter.printHexBinary(decryptedData));
}

/* This test succeeds */
@Test
public void testECB() throws Exception {
BouncyCastleProvider provider = new BouncyCastleProvider();
SecureRandom random = new SecureRandom();

Cipher cipher =
Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding", provider);
byte[] symmetricKey = new byte[cipher.getBlockSize()];
random.nextBytes(symmetricKey);
byte[] data = new byte[2 * cipher.getBlockSize()];
random.nextBytes(data);
byte[] iv = new byte[cipher.getBlockSize()]; // {0} IV
AlgorithmParameterSpec algoSpec = new IvParameterSpec(iv);
SecretKeySpec secretKey = new SecretKeySpec(symmetricKey, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, algoSpec);

byte[] encryptedData = cipher.doFinal(data);

Cipher cipher2 = Cipher.getInstance("AES/ECB/NoPadding", provider);
AlgorithmParameterSpec algoSpec2 = null;
cipher2.init(Cipher.DECRYPT_MODE, secretKey, algoSpec2);
byte[] decryptedData = cipher2.doFinal(encryptedData);

assertEquals(DatatypeConverter.printHexBinary(data),
DatatypeConverter.printHexBinary(decryptedData));
}

So cipher definitely uses ECB chaining mode for me. Which BC and JDK do
you use?

Thanks, Daniil
Post by Tim Whittington
I'll be honest, I'm not really sure either

This is a quirk of the way BaseBlockCipher works (helped I guess by the
general BlockCipher vs mode vs padding confusion).
BaseBlockCipher
-> BufferedGenericBlockCipher
-> PaddedBufferedBlockCipher
-> CBCBlockCipher
+ PKCS7Padding
setMode(“CBC”) replaces that with the same construction (a noop).
BaseBlockCipher
-> BufferedGenericBlockCipher
-> BufferedBlockCipher
-> CBCBlockCipher

 which isn’t ECB (I’ve tested, and it’s definitely still doing CBC), but
will complain about invalid data lengths if the input isn’t block aligned.
What will happen internally is the JCE will find the OID implementation,
then call engineSetMode and engineSetPadding - the base engine will already
have CBC mode on it so XOR'ing the IV twice will remove it (that probably
explains the ECB).
The provider should probably through an exception in the second case -
the OIDs fully describe the algorithm, mode, and padding. From that point
of view the second usage doesn't really make sense.
Yeah. Perhaps it'd make more sense if AES$CBC et al specified
cipher/mode/padding rather than providing a CBCBlockCipher+relying on the
BufferedGenericBlockCipher constructor magic padding assumption, and then
BaseBlockCipher errors if the mode/padding is additionally specified?
tim
Post by Daniil Ivanov
Hi,
I'm puzzled with how I can use OID and cipher parameters in
Cipher.getInstance.
Post by Daniil Ivanov
Cipher.getInstance("2.16.840.1.101.3.4.1.2", "BC");
This call returns AES with CBC and PKCS#7 padding.
Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding", "BC");
This call return AES with ECB and NoPadding.
I don't quite get how this end up doing ECB.
Any ideas?
Thanks, Daniil
Tim Whittington
2014-07-19 08:40:58 UTC
Permalink
Yeah, that was my bad.
It’s doing ECB after the first block (if you use a non-zero IV to encrypt in your example you’ll see the first block change from what ECB would produce).

This is dissecting the exact nature of the brokenness though - what is clear is that OID/Mode/NoPadding should fail and doesn’t in this case.

tim
Post by Daniil Ivanov
Hi Tim!
/* This test fails - second block of recovered text is corrupted */
@Test
public void testCBC() throws Exception {
BouncyCastleProvider provider = new BouncyCastleProvider();
SecureRandom random = new SecureRandom();
Cipher cipher = Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding", provider);
byte[] symmetricKey = new byte[cipher.getBlockSize()];
random.nextBytes(symmetricKey);
byte[] data = new byte[2 * cipher.getBlockSize()];
random.nextBytes(data);
byte[] iv = new byte[cipher.getBlockSize()]; // {0} IV
AlgorithmParameterSpec algoSpec = new IvParameterSpec(iv);
SecretKeySpec secretKey = new SecretKeySpec(symmetricKey, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, algoSpec);
byte[] encryptedData = cipher.doFinal(data);
Cipher cipher2 = Cipher.getInstance("AES/CBC/NoPadding", provider);
cipher2.init(Cipher.DECRYPT_MODE, secretKey, algoSpec);
byte[] decryptedData = cipher2.doFinal(encryptedData);
assertEquals(DatatypeConverter.printHexBinary(data), DatatypeConverter.printHexBinary(decryptedData));
}
/* This test succeeds */
@Test
public void testECB() throws Exception {
BouncyCastleProvider provider = new BouncyCastleProvider();
SecureRandom random = new SecureRandom();
Cipher cipher = Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding", provider);
byte[] symmetricKey = new byte[cipher.getBlockSize()];
random.nextBytes(symmetricKey);
byte[] data = new byte[2 * cipher.getBlockSize()];
random.nextBytes(data);
byte[] iv = new byte[cipher.getBlockSize()]; // {0} IV
AlgorithmParameterSpec algoSpec = new IvParameterSpec(iv);
SecretKeySpec secretKey = new SecretKeySpec(symmetricKey, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, algoSpec);
byte[] encryptedData = cipher.doFinal(data);
Cipher cipher2 = Cipher.getInstance("AES/ECB/NoPadding", provider);
AlgorithmParameterSpec algoSpec2 = null;
cipher2.init(Cipher.DECRYPT_MODE, secretKey, algoSpec2);
byte[] decryptedData = cipher2.doFinal(encryptedData);
assertEquals(DatatypeConverter.printHexBinary(data), DatatypeConverter.printHexBinary(decryptedData));
}
So cipher definitely uses ECB chaining mode for me. Which BC and JDK do you use?
Thanks, Daniil
I'll be honest, I'm not really sure either…
This is a quirk of the way BaseBlockCipher works (helped I guess by the general BlockCipher vs mode vs padding confusion).
BaseBlockCipher
-> BufferedGenericBlockCipher
-> PaddedBufferedBlockCipher
-> CBCBlockCipher
+ PKCS7Padding
setMode(“CBC”) replaces that with the same construction (a noop).
BaseBlockCipher
-> BufferedGenericBlockCipher
-> BufferedBlockCipher
-> CBCBlockCipher
… which isn’t ECB (I’ve tested, and it’s definitely still doing CBC), but will complain about invalid data lengths if the input isn’t block aligned.
What will happen internally is the JCE will find the OID implementation, then call engineSetMode and engineSetPadding - the base engine will already have CBC mode on it so XOR'ing the IV twice will remove it (that probably explains the ECB).
The provider should probably through an exception in the second case - the OIDs fully describe the algorithm, mode, and padding. From that point of view the second usage doesn't really make sense.
Yeah. Perhaps it'd make more sense if AES$CBC et al specified cipher/mode/padding rather than providing a CBCBlockCipher+relying on the BufferedGenericBlockCipher constructor magic padding assumption, and then BaseBlockCipher errors if the mode/padding is additionally specified?
tim
Hi,
I'm puzzled with how I can use OID and cipher parameters in Cipher.getInstance.
Cipher.getInstance("2.16.840.1.101.3.4.1.2", "BC");
This call returns AES with CBC and PKCS#7 padding.
Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding", "BC");
This call return AES with ECB and NoPadding.
I don't quite get how this end up doing ECB.
Any ideas?
Thanks, Daniil
Daniil Ivanov
2014-07-19 10:21:29 UTC
Permalink
Hi,

What I originally wanted to do was to use OID + NoPadding.

Also if I try to see info about AES cipher:

Provider provider = new BouncyCastleProvider();
Service service = provider.getService("Cipher", "2.16.840.1.101.3.4.1.2");
System.out.println(service.toString());

It results in the following:
BC: Cipher.AES -> org.bouncycastle.jcajce.provider.symmetric.AES$ECB
aliases: [2.16.840.1.101.3.4.2, 2.16.840.1.101.3.4.22,
2.16.840.1.101.3.4.42]

First alias is a SHA2 branch OID and second and third are not defined
anywhere.

Thanks, Daniil
Post by Daniil Ivanov
Hi Tim!
I'm using BouncyCastle 1.50 and JDK 1.7. I did the following tests
/* This test fails - second block of recovered text is corrupted */
@Test
public void testCBC() throws Exception {
BouncyCastleProvider provider = new BouncyCastleProvider();
SecureRandom random = new SecureRandom();
Cipher cipher =
Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding", provider);
byte[] symmetricKey = new byte[cipher.getBlockSize()];
random.nextBytes(symmetricKey);
byte[] data = new byte[2 * cipher.getBlockSize()];
random.nextBytes(data);
byte[] iv = new byte[cipher.getBlockSize()]; // {0} IV
AlgorithmParameterSpec algoSpec = new IvParameterSpec(iv);
SecretKeySpec secretKey = new SecretKeySpec(symmetricKey, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, algoSpec);
byte[] encryptedData = cipher.doFinal(data);
Cipher cipher2 = Cipher.getInstance("AES/CBC/NoPadding", provider);
cipher2.init(Cipher.DECRYPT_MODE, secretKey, algoSpec);
byte[] decryptedData = cipher2.doFinal(encryptedData);
assertEquals(DatatypeConverter.printHexBinary(data),
DatatypeConverter.printHexBinary(decryptedData));
}
/* This test succeeds */
@Test
public void testECB() throws Exception {
BouncyCastleProvider provider = new BouncyCastleProvider();
SecureRandom random = new SecureRandom();
Cipher cipher =
Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding", provider);
byte[] symmetricKey = new byte[cipher.getBlockSize()];
random.nextBytes(symmetricKey);
byte[] data = new byte[2 * cipher.getBlockSize()];
random.nextBytes(data);
byte[] iv = new byte[cipher.getBlockSize()]; // {0} IV
AlgorithmParameterSpec algoSpec = new IvParameterSpec(iv);
SecretKeySpec secretKey = new SecretKeySpec(symmetricKey, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, algoSpec);
byte[] encryptedData = cipher.doFinal(data);
Cipher cipher2 = Cipher.getInstance("AES/ECB/NoPadding", provider);
AlgorithmParameterSpec algoSpec2 = null;
cipher2.init(Cipher.DECRYPT_MODE, secretKey, algoSpec2);
byte[] decryptedData = cipher2.doFinal(encryptedData);
assertEquals(DatatypeConverter.printHexBinary(data),
DatatypeConverter.printHexBinary(decryptedData));
}
So cipher definitely uses ECB chaining mode for me. Which BC and JDK
do you use?
Thanks, Daniil
Post by Tim Whittington
I'll be honest, I'm not really sure either

This is a quirk of the way BaseBlockCipher works (helped I guess by the
general BlockCipher vs mode vs padding confusion).
BaseBlockCipher
-> BufferedGenericBlockCipher
-> PaddedBufferedBlockCipher
-> CBCBlockCipher
+ PKCS7Padding
setMode(“CBC”) replaces that with the same construction (a noop).
BaseBlockCipher
-> BufferedGenericBlockCipher
-> BufferedBlockCipher
-> CBCBlockCipher

 which isn’t ECB (I’ve tested, and it’s definitely still doing CBC), but
will complain about invalid data lengths if the input isn’t block aligned.
What will happen internally is the JCE will find the OID
implementation, then call engineSetMode and engineSetPadding - the base
engine will already have CBC mode on it so XOR'ing the IV twice will remove
it (that probably explains the ECB).
The provider should probably through an exception in the second case -
the OIDs fully describe the algorithm, mode, and padding. From that point
of view the second usage doesn't really make sense.
Yeah. Perhaps it'd make more sense if AES$CBC et al specified
cipher/mode/padding rather than providing a CBCBlockCipher+relying on the
BufferedGenericBlockCipher constructor magic padding assumption, and then
BaseBlockCipher errors if the mode/padding is additionally specified?
tim
Post by Daniil Ivanov
Hi,
I'm puzzled with how I can use OID and cipher parameters in
Cipher.getInstance.
Post by Daniil Ivanov
Cipher.getInstance("2.16.840.1.101.3.4.1.2", "BC");
This call returns AES with CBC and PKCS#7 padding.
Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding", "BC");
This call return AES with ECB and NoPadding.
I don't quite get how this end up doing ECB.
Any ideas?
Thanks, Daniil
David Hook
2014-07-22 01:00:44 UTC
Permalink
I'd probably avoid doing this, but you should find:

Cipher.getInstance("2.16.840.1.101.3.4.1.2/ECB/NoPadding", "BC");

will do what you want. It would be better if ECB was NONE but the
provider won't recognise that. ECB for a block cipher is essentially
NONE (i.e. don't modify the mode of whatever engine I've asked for).

The reason I'd advise against doing it, is it's unlikely anyone looking
at this in future will understand what's going on (even with NONE) , and
even if they do this definitely won't work with any other providers that
I'm aware of. You'd be better to map the OID to the transform you want
explicitly. I think I can understand why you're trying to do this, the
NIST OIDs really only mandate the mode - the padding, if any, is left as
an exercise to the reader. So there's nothing wrong with the idea, we
simply use PKCS#7 in this case because it's the most common one and
simplifies operations with standards like CMS.

Regards,

David
Post by Daniil Ivanov
Hi,
What I originally wanted to do was to use OID + NoPadding.
Provider provider = new BouncyCastleProvider();
Service service = provider.getService("Cipher", "2.16.840.1.101.3.4.1.2");
System.out.println(service.toString());
BC: Cipher.AES -> org.bouncycastle.jcajce.provider.symmetric.AES$ECB
aliases: [2.16.840.1.101.3.4.2, 2.16.840.1.101.3.4.22,
2.16.840.1.101.3.4.42]
First alias is a SHA2 branch OID and second and third are not defined
anywhere.
Thanks, Daniil
On Fri, Jul 18, 2014 at 5:10 PM, Daniil Ivanov
Hi Tim!
I'm using BouncyCastle 1.50 and JDK 1.7. I did the following
/* This test fails - second block of recovered text is
corrupted */
@Test
public void testCBC() throws Exception {
BouncyCastleProvider provider = new BouncyCastleProvider();
SecureRandom random = new SecureRandom();
Cipher cipher =
Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding", provider);
byte[] symmetricKey = new byte[cipher.getBlockSize()];
random.nextBytes(symmetricKey);
byte[] data = new byte[2 * cipher.getBlockSize()];
random.nextBytes(data);
byte[] iv = new byte[cipher.getBlockSize()]; // {0} IV
AlgorithmParameterSpec algoSpec = new IvParameterSpec(iv);
SecretKeySpec secretKey = new SecretKeySpec(symmetricKey, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, algoSpec);
byte[] encryptedData = cipher.doFinal(data);
Cipher cipher2 = Cipher.getInstance("AES/CBC/NoPadding", provider);
cipher2.init(Cipher.DECRYPT_MODE, secretKey, algoSpec);
byte[] decryptedData = cipher2.doFinal(encryptedData);
assertEquals(DatatypeConverter.printHexBinary(data),
DatatypeConverter.printHexBinary(decryptedData));
}
/* This test succeeds */
@Test
public void testECB() throws Exception {
BouncyCastleProvider provider = new BouncyCastleProvider();
SecureRandom random = new SecureRandom();
Cipher cipher =
Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding", provider);
byte[] symmetricKey = new byte[cipher.getBlockSize()];
random.nextBytes(symmetricKey);
byte[] data = new byte[2 * cipher.getBlockSize()];
random.nextBytes(data);
byte[] iv = new byte[cipher.getBlockSize()]; // {0} IV
AlgorithmParameterSpec algoSpec = new IvParameterSpec(iv);
SecretKeySpec secretKey = new SecretKeySpec(symmetricKey, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, algoSpec);
byte[] encryptedData = cipher.doFinal(data);
Cipher cipher2 = Cipher.getInstance("AES/ECB/NoPadding", provider);
AlgorithmParameterSpec algoSpec2 = null;
cipher2.init(Cipher.DECRYPT_MODE, secretKey, algoSpec2);
byte[] decryptedData = cipher2.doFinal(encryptedData);
assertEquals(DatatypeConverter.printHexBinary(data),
DatatypeConverter.printHexBinary(decryptedData));
}
So cipher definitely uses ECB chaining mode for me. Which BC
and JDK do you use?
Thanks, Daniil
On Fri, Jul 18, 2014 at 11:59 AM, Tim Whittington
I'll be honest, I'm not really sure either

This is a quirk of the way BaseBlockCipher works (helped I
guess by the general BlockCipher vs mode vs padding confusion).
BaseBlockCipher
-> BufferedGenericBlockCipher
-> PaddedBufferedBlockCipher
-> CBCBlockCipher
+ PKCS7Padding
setMode(“CBC”) replaces that with the same construction (a noop).
BaseBlockCipher
-> BufferedGenericBlockCipher
-> BufferedBlockCipher
-> CBCBlockCipher

 which isn’t ECB (I’ve tested, and it’s definitely still
doing CBC), but will complain about invalid data lengths if
the input isn’t block aligned.
What will happen internally is the JCE will find the OID
implementation, then call engineSetMode and engineSetPadding -
the base engine will already have CBC mode on it so XOR'ing
the IV twice will remove it (that probably explains the ECB).
The provider should probably through an exception in the
second case - the OIDs fully describe the algorithm, mode, and
padding. From that point of view the second usage doesn't
really make sense.
Yeah. Perhaps it'd make more sense if AES$CBC et al specified
cipher/mode/padding rather than providing a
CBCBlockCipher+relying on the BufferedGenericBlockCipher
constructor magic padding assumption, and then BaseBlockCipher
errors if the mode/padding is additionally specified?
tim
Post by Daniil Ivanov
Hi,
I'm puzzled with how I can use OID and cipher parameters
in Cipher.getInstance.
Post by Daniil Ivanov
Cipher.getInstance("2.16.840.1.101.3.4.1.2", "BC");
This call returns AES with CBC and PKCS#7 padding.
Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding",
"BC");
Post by Daniil Ivanov
This call return AES with ECB and NoPadding.
I don't quite get how this end up doing ECB.
Any ideas?
Thanks, Daniil
Tim Whittington
2014-07-28 03:17:56 UTC
Permalink
Hi David

On a separate trip into the JCE implementation, I noticed the following:

http://oss.org.cn/ossdocs/java/se/jdk6/docs/guide/security/jce/HowToImplAJCEProvider.html
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/javax/crypto/Cipher.java?av=f#334

SupportedModes and SupportedPaddings for a Service (e.g. Cipher) can be advertised to the JCE core, e.g for Cipher.DES:
Cipher.DES SupportedModes
Cipher.DES SupportedPaddings

The values for these properties are regular expressions, e.g.: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/com/sun/crypto/provider/SunJCE.java#109

If these properties are present, Cipher.getInstance treats them as authoritative and takes the absence of a mode/padding match by the expression as an explicit NO.
If the properties aren’t there, it tries engineSetMode/engineSetPadding and sees if it blows up.

In this case Cipher.<OID> SupportedModes = “” and Cipher.<OID> SupportedPaddings = “” would block the any attempt at mode/padding switcherooing.

If we just wanted to lock down mode and BaseBlockCipher was sane enough to alter the padding safely, then just the SupportedModes property could be added and Cipher.getInstance(“OID//NoPadding”) would do what the OP wanted (note the double-slash algo//padding form).

… you may already know all this, but it’s news to me :)

cheers
tim
Post by Tim Whittington
BaseBlockCipher
-> BufferedGenericBlockCipher
-> BufferedBlockCipher
-> CBCBlockCipher
-> CBCBlockCipher
engineSetMode assumes the baseCipher is a raw engine - in the the case of the OID it's actually CBCBlockCipher. In that sense it means the code is behaving exactly as expected (i.e. the cipher/blah1/blah2 really mean take cipher and modify it with blah1, etc...) Definitely not an approach that should be encouraged though!
Regards,
David
Post by Tim Whittington
I'll be honest, I'm not really sure either…
This is a quirk of the way BaseBlockCipher works (helped I guess by the general BlockCipher vs mode vs padding confusion).
BaseBlockCipher
-> BufferedGenericBlockCipher
-> PaddedBufferedBlockCipher
-> CBCBlockCipher
+ PKCS7Padding
setMode(“CBC”) replaces that with the same construction (a noop).
BaseBlockCipher
-> BufferedGenericBlockCipher
-> BufferedBlockCipher
-> CBCBlockCipher
… which isn’t ECB (I’ve tested, and it’s definitely still doing CBC), but will complain about invalid data lengths if the input isn’t block aligned.
What will happen internally is the JCE will find the OID implementation, then call engineSetMode and engineSetPadding - the base engine will already have CBC mode on it so XOR'ing the IV twice will remove it (that probably explains the ECB).
The provider should probably through an exception in the second case - the OIDs fully describe the algorithm, mode, and padding. From that point of view the second usage doesn't really make sense.
Yeah. Perhaps it'd make more sense if AES$CBC et al specified cipher/mode/padding rather than providing a CBCBlockCipher+relying on the BufferedGenericBlockCipher constructor magic padding assumption, and then BaseBlockCipher errors if the mode/padding is additionally specified?
tim
Hi,
I'm puzzled with how I can use OID and cipher parameters in Cipher.getInstance.
Cipher.getInstance("2.16.840.1.101.3.4.1.2", "BC");
This call returns AES with CBC and PKCS#7 padding.
Cipher.getInstance("2.16.840.1.101.3.4.1.2/CBC/NoPadding", "BC");
This call return AES with ECB and NoPadding.
I don't quite get how this end up doing ECB.
Any ideas?
Thanks, Daniil
Loading...