Archived Forum Post

Index of archived forum posts

Question:

RSA Sign on iOS and Verify w/ C# on .NET?

Oct 01 '12 at 11:08

We are a happy consumer of your chilkat software.

I need your help. I'm trying to sign some data using your library on the iPad. Later I have to verify this Data using plain DotNet Crypto API.

I did tried many things, but nothing worked.

This is my iOS Code:

-(CkoRsa*)signData
{
    if (_signData == nil)
    {
        _signData = [[CkoRsa alloc] init];
        if( [self unlockRsaComponent:_signData] == NO )
        {
            return nil;
        }

_signData.EncodingMode = @"base64";
        _signData.LittleEndian = YES;
        [_signData setCharset:@"utf-8"];
        [_signData setOaepPadding:YES];

}
    return _signData;
}

-(NSString*)signData:(NSString*)data
{
    return [self.signData SignBytesENC:[data dataUsingEncoding:NSUTF8StringEncoding] hashAlg:@"sha-1"];
}

Later on, I tried to verify the Data on the DotNet Side:

RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
provider.FromXmlString(publicKey);
bool bc1 = provider.VerifyData(Encoding.UTF8.GetBytes(data), "SHA1", System.Convert.FromBase64String(signature));

I'm using Version 9.3.2 of you library. Do you have any hint for me ? How I should set the Property for CkoRsa to get a compatible Signature to DotNet ?


Answer

There are two immediate issues w/ your iOS code that I can see.

1) The LittleEndian property should be set to NO. Microsoft's Crypto API (i.e. the native Platform SDK) uses little endian byte ordering. However, the Microsoft .NET crypto implementation uses big endian to conform to what is used by all other implementations, such as OpenSSL, Java, etc.

2) You may simplify your iOS code by calling SignStringENC (instead of SignBytesENC). Given that you set the Charset property equal to "utf-8" (via _signData.setUtf8), you may pass the NSString directly to SignStringENC instead of doing the conversion to utf-8 bytes via dataUsingEncoding:NSUTF8StringEncoding.

I wrote a simple C# test program that uses Chilkat to create the signature, and then uses .NET to verify the signature. The equivalent Chilkat calls in any programming language (such as Objective-C) and on any operating system will produce the same results.

Also notice that "SHA1" is not passed directly to VerifyData. Instead you should pass this: CryptoConfig.MapNameToOID("SHA1")

    Chilkat.PrivateKey privKey = new Chilkat.PrivateKey();

bool success = privKey.LoadXmlFile("c:/aaworkarea/privKey.xml");
if (!success)
{
    textBox1.Text = privKey.LastErrorText;
    return;
}

string privKeyXml = privKey.GetXml();

Chilkat.Rsa rsa = new Chilkat.Rsa();

success = rsa.UnlockComponent("30-day trial");
if (success != true)
{
    textBox1.Text = rsa.LastErrorText;
    return;
}

//  Import the private key into the RSA component:
success = rsa.ImportPrivateKey(privKeyXml);
if (success != true)
{
    textBox1.Text = rsa.LastErrorText;
    return;
}

rsa.EncodingMode = "base64";
rsa.LittleEndian = false;

string strData;
strData = "This is the string to be signed.";

//  Sign the string using the sha-1 hash algorithm.
//  Other valid choices are "md2", "sha256", "sha384", "sha512",  and "md5".
string base64Sig;
base64Sig = rsa.SignStringENC(strData, "sha-1");

textBox1.Text = base64Sig;

RSACryptoServiceProvider provider = new RSACryptoServiceProvider();

string publicKey = System.IO.File.ReadAllText("c:/aaworkarea/pubKey.xml");
provider.FromXmlString(publicKey);

bool bVerified = provider.VerifyData(Encoding.UTF8.GetBytes(strData), 
    CryptoConfig.MapNameToOID("SHA1"), 
    System.Convert.FromBase64String(base64Sig));

if (bVerified)
{
    MessageBox.Show("Verified.");
}
else
{
    MessageBox.Show("Not Verified.");
}