Crash on a stripped iOS binary when using System.Security.Cryptography

Hi,

The game I’m working on uses several classes from the System.Security.Cryptography package.
If I run it on a normal build it works perfectly, but if I try to strip it using either StrippingLevel.StripAssemblies or StrippingLevel.StripByteCode stripping levels, it crashes with a EXC_BAD_ACCESS.

Here is the mono code that crashes :

PasswordDeriveBytes passwordDeriveBytes = new PasswordDeriveBytes(ENCODING_KEY, new byte[] {some bytes...});
Rijndael alg = Rijndael.Create();
alg.Key = passwordDeriveBytes.GetBytes(32);
alg.IV = passwordDeriveBytes.GetBytes(16);

Here is the assembly code that crashes (on the last ‘.byte’ line) :

System_Security_Cryptography_PasswordDeriveBytes_Reset:

	.byte 13,192,160,225,128,64,45,233,13,112,160,225,0,93,45,233,20,208,77,226,13,176,160,225,0,160,160,225,0,0,160,227
	.byte 24,0,138,229,0,0,160,227,40,0,138,229,0,0,160,227,44,0,138,229,8,0,154,229
bl p_209

	.byte 20,0,138,229,12,0,154,229,0,0,80,227,28,0,0,10,20,192,154,229,28,16,154,229,1,0,160,225,12,48,144,229
	.byte 28,0,154,229,12,32,160,225,8,32,139,229,0,32,160,227,0,0,141,229,0,0,160,227,4,0,141,229,8,0,155,229
	.byte 0,224,156,229
bl Lm_1803

Here is the end of the stack when the application crashes :

#0	0x0040311c in System_Security_Cryptography_PasswordDeriveBytes_Reset at /Users/me/projects/MyGame/iOS/Libraries/mscorlib.dll.s:131226
#1	0x00402df0 in System_Security_Cryptography_PasswordDeriveBytes_GetBytes_int at /Users/me/projects/MyGame/iOS/Libraries/mscorlib.dll.s:131153

So it seems both the PasswordDeriveBytes and Rijndael instances have been created, but that the first (probably) call to GetBytes calls an inner function Reset that is actually causing the crash.

Looking at the IL code of the aforementioned classes, I extracted all dependencies to other classes and added them to the following link.xml file that I put into project’s Resources folder (just to be sure and despite the fact they are all present in the assembly source) :

<linker>
    <assembly fullname="mscorlib">
        <type fullname="System.Security.Cryptography.CipherMode" preseve="all"/>
        <type fullname="System.Security.Cryptography.CryptoConfig" preseve="all"/>
        <type fullname="System.Security.Cryptography.CryptoStream" preseve="all"/>
        <type fullname="System.Security.Cryptography.CryptoStreamMode" preseve="all"/>
        <type fullname="System.Security.Cryptography.CryptographicException" preseve="all"/>
        <type fullname="System.Security.Cryptography.CryptographicUnexpectedOperationException" preseve="all"/>
        <type fullname="System.Security.Cryptography.CspParameters" preseve="all"/>
        <type fullname="System.Security.Cryptography.DeriveBytes" preseve="all"/>
        <type fullname="System.Security.Cryptography.HashAlgorithm" preseve="all"/>
        <type fullname="System.Security.Cryptography.ICryptoTransform" preseve="all"/>
        <type fullname="System.Security.Cryptography.KeySizes" preseve="all"/>
        <type fullname="System.Security.Cryptography.PaddingMode" preseve="all"/>
        <type fullname="System.Security.Cryptography.PasswordDeriveBytes" preseve="all"/>
        <type fullname="System.Security.Cryptography.Rijndael" preseve="all"/>
        <type fullname="System.Security.Cryptography.SHA1" preseve="all"/>
        <type fullname="System.Security.Cryptography.SHA1CryptoServiceProvider" preseve="all"/>
        <type fullname="System.Security.Cryptography.SymmetricAlgorithm" preseve="all"/>
    </assembly>
</linker>

And, to be even more complete, I also tried :

<linker>
    <assembly fullname="mscorlib">
        <type fullname="System.Security.Cryptography" preseve="all"/>
    </assembly>
</linker>

… but the application continues to crash. Off course, if I stop using those classes, the game works perfectly well, just lacking some features !

Edit : As a side note, I use the SHA256Managed class somewhere else in the code, which is also in the System.Security.Cryptography package, and it works perfectly well, so the problem seems tied to the PasswordDeriveBytes class or one of the class it uses…

Does anyone have any idea on what I am missing ?

Avoid the call to Rijndael.Create(); which uses dynamic providers and reflection and instead directly use a concrete provider.

For example, I fixed Uniweb Websockets on iOS AOT by replacing

var sha = System.Security.Cryptography.SHA1.Create ();

with

var sha = new System.Security.Cryptography.SHA1CryptoServiceProvider ();

This looks to be fixed in Mono 3.0.2. Commit notes:

 Make the Crypto stack work with Full AOT.

* System.Security.Cryptography.*cs: To make Crypto work with
	Full AOT we remove the usage of providers and reflection. We hardcode
	the default algorithms for hashing, rng and symmetric cyphers.

Try changing “<type fullname” to “<namespace fullname”

This tripped me up too…

Same thing here, the correct syntax working for me is :

<linker>
	<assembly fullname="mscorlib">
		<namespace fullname="System.Security.Cryptography" preserve="all" />
	</assembly>
</linker>