Just Code it!
Header

Crypt in C++ and Decrypt in C# (and C++)

February 5th, 2011 | Posted by riccardotramma in .NET | C++ | Cryptography | CSharp | Interop | VS2005 | VS2010

Comment or Leave a Message

Please Comment or Leave a Message if this is what you are looking for or if you have any question/comment/suggestion/request.


So, now you (actually Me) want to encode and crypt something in C++ and then (maybe after a network message), decrypt and decode this info in C#.

Let me explain exactly what I mean with encode/decode, crypt/decrypt.

We use the user’s two public/private key pairs to crypt/decrypt a session key that we will use to encode/decode a message. If all this make sense to you then let’s start.

First of all, let me answer one natural question: “Why all this?”

The reason of the double-step procedure to encode a message is due to two major reason:

  • crypt/decrypt (or signing and verifying) with an algorithm for public-key cryptography such as RSA (the one that I am using), uses a key pair, where one key is used to crypt some data, and the other (asymmetric) key is used to decrypt it. The things can actually work in both ways and in one case we will talk about signing and verifying.
    The protection here is very strong but the cost is resources, especially time. The algorithm is slow compared to others and for this it is not suitable for protecting a large amount of data. Another reason seems to be security itself, where many blocks encrypted with the same RSA key can help an attacker to reach his intent.
  • encode/decode instead is achieved using a symmetric key algorithm that can be very fast and if it is a stream cipher, it works great with streaming data :). I will use RC4 for this.

The Scenario

Two PC, connected through internet, where one behave as a server and the other is the client.

We assume that the server contains (well protected) its private and public keys that it will use to sign and decrypt some data that will go to or will come from the client.
For the client we assume that he knows the server’s public key and that he will use this to verify and crypt the data that he will receive from or that he will send to the server.

More about the Key Pair and Session Key

With Windows you can store/retrieve user keys (key pair) using the Crypto API. With it you can manage machine or user key in a quite simple way.
On the server we will use this API (in C++) to generate/retrieve (and then store) our machine key pair and we will tell the client our public key.

On the client will create a session key (C++) that will be used to encode a message with RC4.
Because the client knows the server public key, he will then use this to encrypt the session key.
Once this is done, the client will proceed to pack the two things together (encrypted session key plus the message) and send the packet to the server.

The Server at this point will save the message in a file, because we want to have more fun later on.

In fact, to make things more interesting then we will create a .NET (C#) project that will retrieve the same key pair previously stored, reads the file, imports the session key and decodes the message. All this in pure .NET.

Does it not seem fun?

To simplify stuff I will not use any network code and I will assume that the data are passed somehow between client and server. This can be network, file, or whatever (DB, mind power,…).
The only storage that I will use will be a file (the encrypted file) to allow a simple code in C# to open it and read and decrypt its content.
To simplify the code and shrink it to the fundamental parts I will provide code snippets that are mostly implemented as simple methods (C style) and I will assume the presence of some globally scoped variable (that should really be class scoped variable in a real environment). This will hopefully simplify the understanding of the concepts without losing the focus tracking the objects relationships.

Let’s start then.

Initial Server Code (C++)

In C++ we can easily use the Crypto API to do all we can (reasonably) think about when we want to protect our data.
This is available including “wincrypt.h” in your code.
The first thing to do is acquire the context where our secret keys are stored. This can be easily done with a code such as:

After this we can retrieve our exchange keys from the container. If the keys doesn’t exist I will create a brand new pair. This code does exactly this:

Happy with the result the next thing to do is to export our public key and give this to our client… or everyone… after all is a public key!
In my sample code I will use a memory buffer. The important thing here is that we are not here to cheat and this buffer will be the only thing that we will give to the client code pretending that it is a completely separate application. The export looks like this:

If everything is fine until now we can temporarily leave our server and switch to our client code.

Client Code (C++)

Because we are still working with Crypto API, the pattern is similar and so the first thing we have to do is acquire the container context in the same way we already did for the server.
The only difference is that we will use a different container to continue simulating a separate environment:

We can then import immediately the server public key:

The initial “handshaking” is completed now! The server is configured with his Key Pair and the client has received the the public part of this pair.

The next move is in client’s hand now. It has the freedom to choose a session key that will be used to encode a secret message.
For this task I am simply generating a brand new session key, especially generated for the algorithm that I will use to encode the message:

With this key I can finally encode my message!

Cool! The message is now protected… well, almost. In order to complete the transmission of the encrypted message, back to the server, we still need to take care of a few more details.
The first one is related to the protection of the session key itself. The server needs it in order to decode the message, but for sure we cannot send it as it is otherwise all this messing around with keys would be just a waste of time (human and cpu).
As already mentioned (and I hope obvious at this point) we will send our session key encrypted with the server public key. The server, and only the server, will then be able to decrypt it.

Enough chatting, let’s go to encrypt the session key then:

In my sample scenario I will simulate the transmission of the encrypted message using a simple file where I will write all the server needs to successfully decrypt the message.

My main focus here is to write a C# server that will be able to do this.
Anyway, just to complete the circle in the C++ world, I will add few more lines that will show how read and decrypt the same message in C++ as well, although I will not follow the same path and I will just continue to use memory buffers, just to avoid to add more details that are not relevant for what I have in mind now. If there is the need I will write another side article for it.

This said, let’s go back to our server (C++).

More Server Code (C++)

Assuming the message as received together with the encrypted key the first thing to do is decrypt the key of course:

As a result we will have another key object that can be used (at last!) to decrypt the message:

Job done! (in C++).

The last (really) thing to do is to create the file that will be used by the C# server.
I will use a single file where I will store both the encrypted key and the encoded message. To keep things a little bit more interesting (and realistic) I will write few bytes at the start of the file to communicate the size of the key.
Because we already have all we need, we can simply create a new file and write this info as described:

If you want to do some cleanup (and you should), remember to release the keys and the context when we don’t need them anymore.
This can be done easily in this way (this assumes that the keys are null if not initialised):

We are ready to switch to C#!

Server Code C#

The server here has to do basically the same things that we already done in C++, but in a slightly different way. In order to retrieve the Key Pair (I am not considering the creation of it in this context) we can use an RSACryptoServiceProvider object specifically configured (with a CspParameters object) to access the same server container we used in the previous app. You can find those classes in System.Security.Cryptography.
I will configure it to use the same RSA algorithm and forcing it to retrieve existing keys without attempting to create a new pair.

This is how we can do it:

We need something to decrypt now. I will use the file that has been created in C++ reading all its content in specific objects:

Once identified the encrypted session key we need to use the RSA service provider to decrypt it.
The only awkward things here is that the .NET encryption algorithm swaps the bytes after encryption (and before decryption) and we will have to take care of this directly, because this key was encrypted by the Crypto API in C++. Another thing to consider is that the encrypted blob doesn’t simply contain the encrypted key but some extra informations about the version, the algorithm to use with that key and the algorithm used to encrypt the key itself. I will not go into any detail for this here and I will instead jump in the session blob, straight to where the encrypted key is stored and use it (we already know what kind of key we generated for this toy app).
The encryption is then as simple as doing:

If everything is correct we will not receive any exception and the original session key is in our hands.

Let’s just use then to decrypt the message… well… no unfortunately.

In .NET there is no implementation of the RC4 algorithm that we used to encode the message.
Although annoying, this is not a big issue because its implementation is not so complex and can be easily hand-crafted.

I will not cover this algorithm in this post (but I will do soon in another one. Update: the post is available here: RC4 Cypher Algorithm in C#) and I will instead assume that you have access to a class/method that takes care of the algorithm details, providing a simple method to decode a message with a specific provided key.
If this is true we can then simply complete the task in this way:

Display the decoded message and jump of joy :).

Final Notes

Wait a second… nice, but… our keys? What if I want to cleanup the keys I generate with this sample code?
Correct. It would be nice to do some housekeeping when we are done with this.
In C++ we can remove out keys from our test container very easily. Sometime it is so easy that risks to be dangerous, but we know what we are doing now :).

The same thing can be done as easily as this in C# (actually it is even easier than C++):

If you try to run the C# server code again after removing the keys you will obtain a CryptographicException “Keyset does not exist” (as expected).
This will give you the knowledge that you correctly did your house-keeping :).

You can follow any responses to this entry through the RSS 2.0 You can leave a response, or trackback.

22 Responses

  • útitárs says:

    This website is mostly a walk-through for all of the info you wished about this and didn’t know who to ask. Glimpse here, and you’ll positively uncover it.

  • Kendall Mcandrews says:

    Wow a really useful article on BW , Whatever next

  • Taki Waston says:

    Great Article! Extremely helpful. Please keep sharing!

  • Drew says:

    I know the article is a year old, but I’m hoping you still check the comments. Is there any chance you could show me how to export a public key from C# and use it in C++?

    • riccardotramma says:

      Hi Drew,
      Yes I still check the comments :).
      I will need to setup the environment to try it properly (it has been some time since I have played with it). I will try to have a go asap.

    • riccardotramma says:

      Hi Drew,
      I manage to find the time to have a go with it.
      Imagining that you have your keys generated in C#, already described in the article, just be sure to remove the “CspProviderFlags.UseExistingKey” flag from the line:

      cspParams.Flags = CspProviderFlags.UseExistingKey | CspProviderFlags.UseMachineKeyStore;

      if you are creating the keys.

      You can easily export the public key (the one you want to share) communicating exponent and modulus to the client. The exponent and modulus are retrieved using something like this:

      RSAParameters par = m_RSACryptoServiceProvider.ExportParameters(false); // export the public key

      Exponent is here: par.Exponent
      Modulus is here: par.Modulus

      I noticed that you need to reverse the modulus when passing this to the C++ client.

      On the client side (C++), once you received those info (and acquired the key context as already explained in the article), you can import the public key using a code similar to this (I assume that the exponent is stored in “dwExponent” and the modulus array is pointed by “pModulus”, with “modulusSize” representing the number of bytes in the “pModulus” array):

      DWORD dwKeyBlobSize = modulusSize + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY);
      BYTE *pBlob = new BYTE[dwKeyBlobSize];

      PUBLICKEYSTRUC *pPublicKey = (PUBLICKEYSTRUC *) pBlob;
      pPublicKey->bType = PUBLICKEYBLOB;
      pPublicKey->bVersion = CUR_BLOB_VERSION;
      pPublicKey->reserved = 0;
      pPublicKey->aiKeyAlg = CALG_RSA_KEYX; // RSA public-key key exchange

      RSAPUBKEY *pRsaPubKey = (RSAPUBKEY *) (pBlob + sizeof(PUBLICKEYSTRUC));
      pRsaPubKey-> magic = 0x31415352; // Set to RSA1 (0x31415352) for public keys and to RSA2 (0x32415352) for private keys
      pRsaPubKey-> bitlen = modulusSize * 8; //Number of bits in the modulus
      pRsaPubKey-> pubexp = dwExponent; //Exponent

      BYTE *pKey = (BYTE *) ((BYTE *)pRsaPubKey + sizeof (RSAPUBKEY));
      memcpy(pKey, pModulus, modulusSize);

      At this point you can use the same method in the article (ClientImportServerPublicKey) to import the public key. The parameters will be “pBlob” and “dwKeyBlobSize” of course :).

      Note that if you want to you can avoid to export the exponent and use directly the value: “0x10001” that is the RSA Exponent.

      Hope this helps.

      • Uwe says:

        Refering to your remark

        “I noticed that you need to reverse the modulus when passing this to the C++ client.”

        Currently I tried to reverse the complete byte array and still am not able to encrypt via CryptEncrypt.

        Could you explain what you mean by “reversing” the modulus? Maybe I just have to swap every two bytes (Big Endian vs. Little Endian)?

        • riccardotramma says:

          Hi Uwe,
          I actually mean reverse the whole byte array:
          So if the original array is for example: 1, 2, 3, 4, 10, 20, …
          Import is in C++ as: … 20, 10, 4, 3, 2, 1
          (each element is a single byte).
          What error do you have and when (what is your scenario)?

          • Uwe says:

            Thanks, Riccardo

            Actual, my scenario is a bit “unusual”; I want to encrypt in C++ and decrypt in C# without transfering anything but the encrypted data.

            I.e. I do not want to use session keys, or transfer keys between the encryption and decryption part. I’ve tried this for hours and I doubt whether this is actually possible to solve with the Crypto API.

            (I’m aware that this is not the highest security, I could get; it is sufficient, though…)

            Do you think this is possible to acchieve?

            • riccardotramma says:

              Hi Uwe,
              If I understand correctly you are trying to use the RSA key to directly encrypt your message and you receive an error when you are trying to execute the CryptEncrypt function.

              The key specified in the CryptEncrypt method should be a handle to the encryption key (obtained by using either the CryptGenKey or the CryptImportKey function).

              You can still use the public key directly to encrypt the data, but there are some problems and limitations:
              One is the security issue as you were saying, the other is the performance, but the third one is that you have some (annoying) limitations with the data you are trying to encrypt.
              One of the error you are most likely to obtain is:

              errorCode = 0x80090004 – NTE_BAD_LEN (Bad Length: The size of the output buffer is too small to hold the generated ciphertext)

              or:

              errorCode = 0x000000EA – ERROR_MORE_DATA (More data is available: the buffer allocated is not large enough to hold the encrypted data)

              The problem is that you can encrypt a buffer no longer than the length of the key modulus, minus eleven bytes (the eleven bytes is the chosen minimum for PKCS #1 padding).
              In this case (modulus 128), you can then encrypt max 117 bytes.

              So, in order to do this kind of encryption you can use a code similar to this:

              DWORD dwLength = 128 - 11;
              res = ::CryptEncrypt( hClientImportedPublicKey, NULL, 1, 0,
              NULL, &dwLength, 0 );

              You can verify that “res” now should be TRUE and “dwLength” should be 128.
              If this is correct you can then allocate your 128 bytes buffer and encrypt your message:

              res = ::CryptEncrypt( hClientImportedPublicKey, NULL, 1, 0,
              (BYTE *)DataToEncrypt, &dwDataBufferLength, dwLength );

              Where “hClientImportedPublicKey” is your RSA (public) key, “DataToEncrypt” is the buffer to encrypt (allocated with the extra space to contain the final encrypted test (then 128 bytes in this case) , “dwDataBufferLength” is the length of the data to encrypt in that buffer (117 in the example), and “dwLength” is total length of the buffer (128 of course).

              To help you in the debugging remember to use the function “GetLastError()” if any of these methods do not work. The error code (even if not very descriptive in some occasions) should tell you what is the main cause of the problem ;).

              Hope this helps. Let me know how it goes.

              • Uwe says:

                Awesome, Riccardo! I’m trying this ASAP to get it working. Thanks a lot for your assistance! If I’m having a working version, I’ll write an article on my blog or on Code Project about it, since it might help others, too.

                • riccardotramma says:

                  Sure. Remember to link back to this article and let me know the link so that I can add it here :).

                  • elmadj says:

                    Hi thanks for your very well written article !
                    I am having the exact same problem Uwe was describing. I have a public/private key pair with a 512 byte modulus. I am allocating a 512 bytes buffer and Encrypting with CryptEncrypt.
                    Then I am using RSACryptoServiceProvider to decrypt the encrypted data which was written in a file in binary mode meanwhile. I made sure to reverse the bytes in my c# code (with Array.Reverse)before trying to decrypt. I am still having a “bad data” error message in a CryptographicException.

                    Any hint on what might be missing ?

                    Here is the exception call stack :

                    à System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
                    à System.Security.Cryptography.RSACryptoServiceProvider.DecryptKey(SafeKeyHandle pKeyContext, Byte[] pbEncryptedKey, Int32 cbEncryptedKey, Boolean fOAEP, ObjectHandleOnStack ohRetDec
                    ryptedKey)
                    à System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP)
                    à GIRO.Licensor.EncryptionContext.Decrypt(Byte[] iData, Byte[]& oData) dans c:\sessions\V2015\V2015_HTOK\src\ogl\prog\GIRO.Licensor.exe\EncryptionContext.cs:ligne 56

  • sarah says:

    maybe you can help me,
    I have a C++ code for encrypting and decrypting with hard coded password.
    When i use c++ code to ancrypt and then decrypt it frm another code (C# which calls C++ code) it works just fine.
    But when i try to decrypt from a third application (also C# calling the c++ code) the result decrypted text comes as garbage.
    what can be the reason? all projects are defined to work with unicode.

    • riccardotramma says:

      Hi Sarah,
      My suggestion is to try to make sure that the Key Container name you are using is the same (correct) one. It sounds like something related to a small error like that one.
      I hope this helps.

  • Larry Smith says:

    Terrific article. Kudos for your efforts! I’ve now spent several painful weeks wrapping my head around all this stuff and largely understand it now (no thanks to MSFT, whose docs on the subject are woeful). I do have one issue maybe you’ld care to weigh in on though. Before you can even begin to decrypt a session key, you need to know the provider that was used for the encryption in the first place (in order to call “CryptAcquireContext()”). It would be much better however to extract that info from the encrypted data itself. You could then decrypt the data from any arbitrary provider without knowing the provider ahead of time. The problem is that to do this, you would need to write the provider name (and its type) to the encrypted file itself. But you would want to encrypt this as well, so that the name of the provider isn’t stored as plain text (since you don’t want anyone to know anything about how the file is encrypted). But how to do this? You can’t encrypt the provider name using the session key itself, since the server would then be facing a chicken/egg situation, i.e., it needs the provider name before it can get access to the session key, but can’t access the provider name until it knows the session key. So maybe the best thing to do is encrypt the provider name using the public key itself, and always with MSFT’s basic or enhanced provider (which may be different than that used by the session key and its data but both client and server need to agree on a common provider used to encrypt the provider name itself). Even if this will work still pondering the situation), the resulting encrypted file will now (usually) contain at least 1 kb or more of overhead (typically 500+ bytes or more for the encrypted session key itself plus another 500+ bytes or more for the encrypted provider name). I find this all problematic, in particular when when a lot of small files (or other sources of data) need to be encrypted (too much overhead involved). Any suggestions or comments? Thanks.

    • riccardotramma says:

      Hi Larry,
      I am glad that you found the article useful and interesting and thanks for the original question.
      While reading your question I thought that the most natural solution is to have both client and server agree upon a common provider to use to encrypt the “main” provider name.
      For the size-overhead problem I was thinking about using a sort of lookup system. You could add a single extra byte to each file. In that way you can identify up to 256 possible alternatives. You can then use an additional set of files that contains (only) the encrypted provider name (one for each file).
      So for example you could name your file in this way:
      provider_000
      provider_001
      provider_002

      provider_255
      When the client receives a file (message.txt) with, for example, the provider byte set to “4”, it will request the file “provider_004” from the server, decrypt it (with the common provider name if this is the solution you go for) and use the decrypted provider name to perform the decryption of the original file (message.txt).
      This will definitely eliminate the overhead for the encrypted provider name.

      You can decide to adopt the same solution for the session key (1, 2 or 4 bytes in this case that reference a set of files with an encrypted key in each one), but this is not really in line with the concept of “session key”, that should not be relative to a file (or a set of files), but should be valid for only a specific session with one client.
      In this case a better solution is therefore to encrypt the files on-the-fly from the server, using a single specific session key (valid only for this session, as it should), and transmitting such key only once to the client before initiating the transmission of the data.
      In this way you will have only one single initial overhead for the encrypted session key and the rest would be pure data.

      Let me know if this helps and covers the scenario you are trying to solve.

      • Larry Smith says:

        HI Riccardo (is that your first name?)

        (Sorry, I know the following is a little long :)

        Thanks for the feedback. It’s appreciated. I’ll give your suggestion some thought. It may work or perhaps some hybrid system but I’ll have to think about it. In the general case though, it would obviously be cleaner for everything to be self-contained in a single file, but it’s likely not doable without incurring the overhead. I had already given some thought however (before you responded), about adding a single byte to the file to identify the provider name. However, I was thinking about mapping it back to the provider name using a hard-coded table in the program itself. It’s hardly ideal, and not nearly as clean as grabbing the provider name from the file (and I’d also be restricted to a predefined collection of providers – not good), but at least no extraneous files would be required. The technique could also be applied to any scenario, not just client/server. I’ve already spent the past several weeks writing some very generic (application independent) classes for encrypting/decrypting any file (or other arbitrary source of data), and it’s not restricted to a client/server scenario (since almost everything I write has a very heavy emphasis on re-use). Clients of my classes can therefore use it in any type of application. I’ll give your idea some thought though and perhaps put something generic together specifically for a client/server environment (built on-top of my other generic routines but leveraging your idea when requested by users of my class). Thanks for the suggestion (didn’t think it).

        On another unrelated issue (while I got you), would you happen to know if it’s safe to open the container for a standard public/private key pair (AT_KEYEXCHANGE) that was originally created using one provider, but using another provider instead. IOW, when calling “CryptAcquireContext()” to access a public/private key pair, I want to pass the container name originally used to create that key, but use a different provider name instead. I know it’s irregular, but the reason I ask is that my generic decryption classes can also handle “.pfx” files meaning they can obtain the private key for decrypting the session key by invoking MSFT’s “PFXImportCertStore()” function. Unfortunately, this function seems to be hardwired to work with MSFT’s enhanced provider, meaning that the private key you end up with is in a container created by the enhanced provider (with no way to change it I could find). If the session key and its encrypted data uses another provider however (say, MSFT’s AES provider), you’re forced to pass the container name created by “PFXImportCertStore()” to “CryptAcquireContext()”, but pass the session key’s provider name instead. IOW, you’re accessing a container originally created by the enhanced provider but using another provider instead (such as the AES provider). This actually works with the AES provider and probably all other mainstream MSFT providers (since public/private key pairs are likely always handled the same way), but I don’t know if it’s safe for a 3rd-party provider. I’m assuming it’s not, since presumably a 3rd-party provider would expect the public/private key pair to be in its own container, not MSFT’s (which it would know nothing about). I know you might just be speculating on this yourself, but any ideas? If not, don’t worry, I’ll just have to live with it (or figure out if it’s possible to safely copy the key created by “PFXImportCertStore()” into a new container under the provider I want).

        Thanks again for your assistance.

        • riccardotramma says:

          Hi Larry,
          (Yep, my name is Riccardo :))

          When you call CryptAcquireContext() and the container doesn’t exist, then you create it adding the flag CRYPT_NEWKEYSET, and it is now generated with that specific provider (PROV_RSA_FULL in the example).
          At this point I would expect that the method returns an error if you try to acquire it with a different provider name.
          This is what should happen (assuming that that’s the case):

          res = ::CryptAcquireContext( &hCryptProvServer, KEY_CONTAINER_SERVER, SERVICE_PROVIDER, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET );

          will probably return false and the same should happen for the following call, when it tries to create a container that exists already:

          res = ::CryptAcquireContext( &hCryptProvServer, KEY_CONTAINER_SERVER, SERVICE_PROVIDER, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET );

          Specifically, the error that I would expect from the first call should be:

          NTE_PROV_TYPE_NO_MATCH (0x8009001BL):
          The provider type specified by dwProvType does not match the provider type found. Note that this error can only occur when pszProvider specifies an actual CSP name.

          If they seems to work as you are saying than it probably means that they are compatible somehow, but I agree that this could not always be the case.

          One thing I can think of is that, in order to transform the provider used for the container created by “PFXImportCertStore()” (that is the MSFT’s enhanced provider), you could try to acquire the context using the same (original) MSFT’s enhanced provider, and then extract the keys and recreate the same container (the same name, removing the previous one), but with the custom provider type you want to use.

          Let me know how it goes with it or if you find an alternative solution :).

  • zkheraj says:

    I am wondering if the code sample would work for the reverse scenario i.e. Server sending an encrypted message to the Client. The Server sends the public key, with the encrypted session key to the client.
    Thanks

  • Zul Kheraj says:

    I’m a bit new to CryptoAPI and I need some help…I suspect I’m approaching things incorrectly.

    What I want to do is:
    – to generate a Session key on the SERVER
    – Encrypt the Session Key

    I’d like to then send this encrypted session key to a client who will then decrypt it using the Public Exchange key previously sent from the server. The conversation will then continue using the session key.
    Does this seem sensible?

    What I am trying to do is reverse scenario of what you have described. Any help ?

    Thanks

  • Kiran Chavan says:

    Hi Riccardo,

    I am facing a difficulty while verifying a digital signature in C# application.

    The signature is created using Win32 Crypto APIs.

    Would you please help me what could be wrong in below snippet.

    RSACryptoServiceProvider rsa;

    const int PROVIDER_RSA_FULL = 1;
    const string SERVICE_PROVIDER = “Microsoft Enhanced Cryptographic Provider v1.0″; //128 bit encryption

    CspParameters cspParams;
    cspParams = new CspParameters(PROVIDER_RSA_FULL);
    //cspParams.KeyContainerName = ” “;

    cspParams.Flags = CspProviderFlags.UseExistingKey | CspProviderFlags.UseMachineKeyStore;
    cspParams.ProviderName = SERVICE_PROVIDER;

    rsa = new RSACryptoServiceProvider(cspParams);

    byte[] PublicKeyBlob;
    using (var fsKeyFile = new FileStream(“..\..\..\Files\pubKey.txt”, FileMode.Open))
    {
    PublicKeyBlob = new byte[fsKeyFile.Length];
    fsKeyFile.Read(PublicKeyBlob, 0, PublicKeyBlob.Length);
    }

    // RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
    // //RSA.FromXmlString(ReadFile(“..\..\..\Files\pub.txt”));
    rsa.ImportCspBlob(PublicKeyBlob);
    RSAPKCS1SignatureDeformatter RSADeformatter = new RSAPKCS1SignatureDeformatter(rsa);
    RSADeformatter.SetHashAlgorithm(“SHA1”);
    SHA1CryptoServiceProvider SHhash = new SHA1CryptoServiceProvider();
    //string signature = ReadFile(“..\..\..\Files\DigiSign.sig”);
    byte[] digitalSign;
    using (var fsSignFile = new FileStream(“..\..\..\Files\DigiSign.sig”, FileMode.Open))
    {
    digitalSign = new byte[fsSignFile.Length];
    fsSignFile.Read(digitalSign, 0, digitalSign.Length);

    // digitalSign = digitalSign.Reverse().ToArray();
    }

    var bytes = new ASCIIEncoding().GetBytes(“HelloWorld”);

    var returnVal = RSADeformatter.VerifySignature(SHhash.ComputeHash(bytes),
    digitalSign);
    if (returnVal)
    {
    Console.WriteLine(“Valid signature”);
    }
    else
    {
    Console.WriteLine(“Wrong sign”);
    }
    }

    The output is: “Wrong sign”

    Whereas the signature is successfully validated in C++ application (where it is generated).

    Would you please help me out in this?



Leave a Reply

Your email address will not be published.