bc-csharp icon indicating copy to clipboard operation
bc-csharp copied to clipboard

CmsEnvelope decryption ECCP256 / AES128CBC failed

Open TovabbitoJanos opened this issue 1 year ago • 3 comments

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.

TovabbitoJanos avatar Jun 10 '24 11:06 TovabbitoJanos

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

heldpeet92 avatar Jun 10 '24 12:06 heldpeet92

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#

TovabbitoJanos avatar Jun 11 '24 10:06 TovabbitoJanos

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.

lenraven avatar Feb 07 '25 13:02 lenraven