Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CmsEnvelope decryption ECCP256 / AES128CBC failed #543

Open
TovabbitoJanos opened this issue Jun 10, 2024 · 3 comments
Open

CmsEnvelope decryption ECCP256 / AES128CBC failed #543

TovabbitoJanos opened this issue Jun 10, 2024 · 3 comments

Comments

@TovabbitoJanos
Copy link

HI
The error msg:

checksum failed at Org.BouncyCastle.Crypto.Engines.Rfc3394WrapEngine.Unwrap(Byte[] input, Int32 inOff, Int32 inLen) 
			in BouncyCastle\\crypto\\src\\crypto\\engines\\RFC3394WrapEngine.cs:line 171
  at Org.BouncyCastle.Cms.KeyAgreeRecipientInformation.UnwrapSessionKey(DerObjectIdentifier wrapAlgOid, KeyParameter agreedKey) 
     in BouncyCastle\\crypto\\src\\cms\\KeyAgreeRecipientInformation.cs:line 159 
 at Org.BouncyCastle.Cms.KeyAgreeRecipientInformation.GetSessionKey(AsymmetricKeyParameter receiverPrivateKey) 
    in BouncyCastle\\crypto\\src\\cms\\KeyAgreeRecipientInformation.cs:line 179

when i try to decrypt a cms envelope where the key uese ECC P256
I try to do this:

// My private key
MemoryStream stream = new MemoryStream( certificateRawData );
st.Load( stream, CertPassword.ToCharArray() );
AsymmetricKeyEntry k = st.GetKey( (String) a );

// recipients from msg:
CmsEnvelopedData ced = new CmsEnvelopedData( encryptedData );
RecipientInformationStore rec = ced.GetRecipientInfos();
foreach (RecipientInformation r in rec.GetRecipients())
 {
...
                    byte[] res = r.GetContent( k.Key );

Envelope encrypted with 2.16.840.1.101.3.4.1.2 (Aes128Cbc)
KeyEcryption AlgOid: 1.3.132.1.11.1 (SHA256)
PublicKeyParamSet {1.2.840.10045.3.1.7} 256-bit Elliptic Curve Cryptography

the UnwrapSessionKey(wrapAlgOid, agreedWrapKey);
WrapOID: {2.16.840.1.101.3.4.1.5} AES128 fo wrapping
agreedKey.m_key: 71,240,93,144,182,231,203,68,70,11,69,126,109,174,71,72
calls:
byte[] sKeyBytes = keyCipher.Unwrap(encKeyOctets, 0, encKeyOctets.Length);
in this, at the end:
if (!Arrays.FixedTimeEquals(a, m_iv))
throw new InvalidCipherTextException("checksum failed");
this is failed.
"a" = 46,166,,123,149,177,43,148,153
but m_iv is loaded with 166 , all the 8 bytes.

@heldpeet92
Copy link

I have the same issue, do you have any solution for this yet?

@TovabbitoJanos
Copy link
Author

As I see the 166 (8 times )is the DefaultIV in RFC3394WrapEngine.cs line 51 : Array.Copy(DefaultIV, 0, m_iv, 0, 8); if I modify the contents of m_iv here so that the comparison is good later, I get an error later, when calling the pkcs7 pad block:
throw new InvalidCipherTextException("pad block corrupted");
Stack trace:

BouncyCastle.Cryptography.dll!Org.BouncyCastle.Crypto.Paddings.Pkcs7Padding.PadCount(byte[] input) Line 53	C#
BouncyCastle.Cryptography.dll!Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.DoFinal(byte[] output, int outOff) Line 316	C#
BouncyCastle.Cryptography.dll!Org.BouncyCastle.Crypto.BufferedBlockCipher.DoFinal(byte[] input, int inOff, int inLen) Line 336	C#
BouncyCastle.Cryptography.dll!Org.BouncyCastle.Crypto.IO.CipherStream.ReadAndProcessBlock() Line 360	C#
BouncyCastle.Cryptography.dll!Org.BouncyCastle.Crypto.IO.CipherStream.FillInBuf() Line 332	C#
BouncyCastle.Cryptography.dll!Org.BouncyCastle.Crypto.IO.CipherStream.Read(byte[] buffer, int offset, int count) Line 91	C#
BouncyCastle.Cryptography.dll!Org.BouncyCastle.Utilities.IO.FilterStream.Read(byte[] buffer, int offset, int count) Line 58	C#
BouncyCastle.Cryptography.dll!Org.BouncyCastle.Utilities.IO.Streams.CopyTo(System.IO.Stream source, System.IO.Stream destination, int bufferSize) Line 37	C#
BouncyCastle.Cryptography.dll!Org.BouncyCastle.Utilities.IO.Streams.PipeAll(System.IO.Stream inStr, System.IO.Stream outStr, int bufferSize) Line 100	C#
BouncyCastle.Cryptography.dll!Org.BouncyCastle.Utilities.IO.Streams.PipeAll(System.IO.Stream inStr, System.IO.Stream outStr) Line 90	C#
BouncyCastle.Cryptography.dll!Org.BouncyCastle.Utilities.IO.Streams.ReadAll(System.IO.Stream inStr) Line 133	C#
BouncyCastle.Cryptography.dll!Org.BouncyCastle.Cms.CmsUtilities.StreamToByteArray(System.IO.Stream inStream) Line 111	C#
BouncyCastle.Cryptography.dll!Org.BouncyCastle.Cms.RecipientInformation.GetContent(Org.BouncyCastle.Crypto.ICipherParameters key) Line 96	C#

@lenraven
Copy link

lenraven commented Feb 7, 2025

Hi Everyone!

I have same problem. And I found the reason of the issue.

The input CMS what I want to decrypt was encrypted with the Java version of the Bouncy Castle.

The issue is that the Java and Dotnet implementation is working differently.
The IV in the KdfParameters is different in dotnet.

The Java implementation is this:
Source code

    public ASN1Primitive toASN1Primitive()
    {
        ASN1EncodableVector v = new ASN1EncodableVector(3);

        v.add(keyInfo);

        if (entityUInfo != null)
        {
            v.add(new DERTaggedObject(true, 0, new DEROctetString(entityUInfo)));
        }

        v.add(new DERTaggedObject(true, 2, new DEROctetString(suppPubInfo)));

        return new DERSequence(v);
    }

But the Dotnet implementation is this:
Source Code

        public int GenerateBytes(Span<byte> output)
        {
            // TODO Create an ASN.1 class for this (RFC3278)
            // ECC-CMS-SharedInfo
            DerSequence s = new DerSequence(
                new AlgorithmIdentifier(algorithm, DerNull.Instance),
                new DerTaggedObject(true, 2, new DerOctetString(Pack.UInt32_To_BE((uint)keySize))));

            m_kdf.Init(new KdfParameters(z, s.GetDerEncoded()));

            return m_kdf.GenerateBytes(output);
        }

The problem is that if the entityUInfo is null in that case the Java version will not add it to the IV, but the Dotnet version will add an extra DerNull.Instance to the IV.

For examle:
IV in java:
[ 48, 21, 48, 11, 6, 9, 96, -122, 72, 1, 101, 3, 4, 1, 5, -94, 6, 4, 4, 0, 0, 0, -128 ]
IV in dotnet:
[48, 23, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 1, 5, **5, 0**, 162, 6, 4, 4, 0, 0, 0, 128]
The 5, 0 is the extra part in the dotnet version.

So when the CMS was encrypted in Java, in that case the dotnet version can not read the value, because calculates wrong IV.

I tried it to change the IV in debug mod to this:

new DerSequence(
                new AlgorithmIdentifier(algorithm),
                new DerTaggedObject(true, 2, new DerOctetString(Pack.UInt32_To_BE((uint)keySize))));

And with this change the decryption works fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants