4

Anyone successfully bound SpongyCastle to Xamarin.Android? I bump into a bunch of warnings with my Metadata.xml in the binding project.

So far I have:

<remove-node path="/api/package[@name='org.spongycastle.x509']" />
<remove-node path="/api/package[@name='org.spongycastle.crypto']" />
<remove-node path="/api/package[@name='org.spongycastle.crypto.tls']" />
<remove-node path="/api/package[@name='org.spongycastle.cms']" />
<remove-node path="/api/package[@name='org.spongycastle.crypto.prng']" />
<remove-node path="/api/package[@name='org.spongycastle.openpgp']" />
<remove-node path="/api/package[@name='org.spongycastle.openssl']" />
<remove-node path="/api/package[@name='org.spongycastle.cert.ocsp']" />

<remove-node path="/api/package[@name='org.spongycastle.jcajce']" />
<remove-node path="/api/package[@name='org.spongycastle.jcajce.provider.asymmetric.dh']" />
<remove-node path="/api/package[@name='org.spongycastle.jcajce.provider.asymmetric.ec']" />
<remove-node path="/api/package[@name='org.spongycastle.jcajce.provider.digest']" />
<remove-node path="/api/package[@name='org.spongycastle.jcajce.provider.keystore.bc']" />
<remove-node path="/api/package[@name='org.spongycastle.jcajce.provider.symmetric']" />

<remove-node path="/api/package[@name='org.spongycastle.jcajce.provider.asymmetric.dsa']" />
<remove-node path="/api/package[@name='org.spongycastle.jcajce.provider.asymmetric.util']" />
<remove-node path="/api/package[@name='org.spongycastle.jcajce.provider.symmetric.util']" />
<remove-node path="/api/package[@name='org.spongycastle.jcajce.provider.asymmetric.gost']" />
<remove-node path="/api/package[@name='org.spongycastle.jcajce.provider.asymmetric.ies']" />
<remove-node path="/api/package[@name='org.spongycastle.jcajce.provider.asymmetric.rsa']" />
<remove-node path="/api/package[@name='org.spongycastle.jcajce.provider.asymmetric.x509']" />

<remove-node path="/api/package[@name='org.spongycastle.jce.provider']/class[@name='CertStoreCollectionSpi']" />
<remove-node path="/api/package[@name='org.spongycastle.jce.provider']/class[@name='MultiCertStoreSpi']" />
<remove-node path="/api/package[@name='org.spongycastle.jce.provider']/class[@name='X509CRLEntryObject']" />
<remove-node path="/api/package[@name='org.spongycastle.jce.provider']/class[@name='X509CRLObject']" />
<remove-node path="/api/package[@name='org.spongycastle.jce.provider']/class[@name='X509CertificateObject']" />
<remove-node path="/api/package[@name='org.spongycastle.jce.provider']/class[@name='X509LDAPCertStoreSpi']"/>
<remove-node path="/api/package[@name='org.spongycastle.jce.provider']/class[@name='PKIXPolicyNode']" />

<remove-node path="/api/package[@name='org.spongycastle.pqc.jcajce.provider.rainbow']" />
<remove-node path="/api/package[@name='org.spongycastle.pqc.jcajce.provider.mceliece']"/>
<remove-node path="/api/package[@name='org.spongycastle.pqc.jcajce.provider.util']" />
<remove-node path="/api/package[@name='org.spongycastle.pqc.crypto.ntru']" />
<remove-node path="/api/package[@name='org.spongycastle.pqc.math.ntru.polynomial']" />

So it compiles, but when using the binding project in the Xamarin.Android project it takes several mins. to compile and then it fails complaining about the HEAP size of Java.

When I set the heap size to 1GB, it completes, but debugging is then broken when running the app in debug mode on device.

Is there a way to just use the ARRs without a binding library? I just need to invoke a wrapper method that I made in this ARR and get the output from that. I don't need to access the full library through C#. Or is there a better way?

Update: And when I build the CPU looks like this (Look at Java): enter image description here

chrisva
  • 625
  • 9
  • 17
  • Why don't use Bouncy Castle? – jzeferino Jul 01 '16 at 17:08
  • I'm not a crypto expert, but when so many people on various forums states: "The android platform unfortunately ships a incomplete and outdated version of Bouncy Castle for Android which also makes hard to install an updated version of the library. That said, we had to stick with Spongy Castle, a version of Bouncy Castle repackaged to make it work on Android." - the I choose Spongy Castle. ref: https://aerogear.org/docs/specs/aerogear-crypto/ – chrisva Jul 01 '16 at 22:09
  • Recently i used bouncy castle in pcl with Android. Had no problem. – jzeferino Jul 01 '16 at 22:10
  • It probably depends on what you need to do. I have a dependency to several libraries doing quite some neat stuff with NFC. So, it is recommended to use SpongyCastle by the libraries I have dependencies to. Anyway, this is more about solving binding / calls to Java from Xamarin and not what kind of libraries that is needed. – chrisva Jul 01 '16 at 22:16

2 Answers2

2

By ARR, do you mean AAR? In the case of only using some items, you can directly use the JNI: https://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/working_with_jni/

Easiest way would be to <remove-node> of all the items you don't wish to keep and work on the ones you do want to keep. However you may need to make sure that you keep the dependencies so they bind correctly. This can get nasty pretty quickly.

I have a general guide that might help in certain areas with this binding:

https://github.com/JonDouglas/xamarin-support-docs/blob/master/Android/android-bindings-troubleshooting.md

As mentioned by @jzeferino you could always go the route of using something that's a bit more battle-proven than roll your own binding.

BouncyCastle-PCL: https://github.com/onovotny/BouncyCastle-PCL

PCL Crypto: https://github.com/AArnott/PCLCrypto

Both of these provide respective cryptographic methods to accomplish your task. In the case of PCLCrypto, they are either provided by Mono's implementation or the platform's implementation.

Jon Douglas
  • 13,006
  • 4
  • 38
  • 51
  • @chrisva I think this is the best path to choose, and thats why I said to move to Bouncy Castle. – jzeferino Jul 02 '16 at 08:10
  • Yes, it is AAR i mean. Thanks for pointing me in the direction to the PCL's that is already out there. I know them quite well. My 3rd party library has dependencies to Spongy Castle, so I am not looking for an easy way around it. I want to learn how to do binding in the most optimized way because what we build will require a few binding projects in the future with various complexity. So JNI seems like a very interesting approach for us in this case. I'll dive into it and give an update on how it goes. Thanks. – chrisva Jul 03 '16 at 10:10
  • And that guide is great by the way @jon-douglas – chrisva Jul 03 '16 at 10:11
0

I ended up removing almost everything related to BouncyCastle and SpongyCastle in my metadata.xml file in the binding project. Then I copied parts of the generated BouncyCastleProvider from the generated files folder in the Binding Project. So I created my own JNI wrapper only for the parts I needed to call.

It works great. Now compile time is reduced to a few seconds and deployment is fast during debugging. And I enjoy the third party libraries.

My take from this was to generate C# classes first and then choose to implement parts of the JNI in my own library and add/remove nodes in Metadata.xml.

using System;
using System.Collections.Generic;
using Android.Runtime;
namespace Org.Spongycastle.Jce.Provider
{

// Metadata.xml XPath class reference: path="/api/package[@name='org.spongycastle.jce.provider']/class[@name='BouncyCastleProvider']"
[global::Android.Runtime.Register("org/spongycastle/jce/provider/BouncyCastleProvider", DoNotGenerateAcw = true)]
public sealed partial class BouncyCastleProvider : global::Java.Security.Provider
{
    // Metadata.xml XPath field reference: path="/api/package[@name='org.spongycastle.jce.provider']/class[@name='BouncyCastleProvider']/field[@name='PROVIDER_NAME']"
    [Register("PROVIDER_NAME")]
    public const string ProviderName = (string)"SC";

    internal static IntPtr java_class_handle;
    internal static IntPtr class_ref
    {
        get
        {
            return JNIEnv.FindClass("org/spongycastle/jce/provider/BouncyCastleProvider", ref java_class_handle);
        }
    }

    protected override IntPtr ThresholdClass
    {
        get { return class_ref; }
    }

    protected override global::System.Type ThresholdType
    {
        get { return typeof(BouncyCastleProvider); }
    }

    internal BouncyCastleProvider(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) { }

    static IntPtr id_ctor;
    // Metadata.xml XPath constructor reference: path="/api/package[@name='org.spongycastle.jce.provider']/class[@name='BouncyCastleProvider']/constructor[@name='BouncyCastleProvider' and count(parameter)=0]"
    [Register(".ctor", "()V", "")]
    public unsafe BouncyCastleProvider()
        : base(IntPtr.Zero, JniHandleOwnership.DoNotTransfer)
    {
        if (Handle != IntPtr.Zero)
            return;

        try
        {
            if (GetType() != typeof(BouncyCastleProvider))
            {
                SetHandle(
                        global::Android.Runtime.JNIEnv.StartCreateInstance(GetType(), "()V"),
                        JniHandleOwnership.TransferLocalRef);
                global::Android.Runtime.JNIEnv.FinishCreateInstance(Handle, "()V");
                return;
            }

            if (id_ctor == IntPtr.Zero)
                id_ctor = JNIEnv.GetMethodID(class_ref, "<init>", "()V");
            SetHandle(
                    global::Android.Runtime.JNIEnv.StartCreateInstance(class_ref, id_ctor),
                    JniHandleOwnership.TransferLocalRef);
            JNIEnv.FinishCreateInstance(Handle, class_ref, id_ctor);
        }
        finally
        {
        }
    }
}
}
chrisva
  • 625
  • 9
  • 17