glcjr

I have created a dll in c# using this class found on the PayPal developer board:

http://www.pdncommunity.com/pdn/board/message board.id=ewp&message.id=17

using System;
using System.Text;

namespace com.paypal.demo
{
  // Requires modified CAPICOM Interop assembly. See http://www.codeproject.com/dotnet/CapicomUTF8.asp.

  public class ButtonEncryption
  {
    private Encoding _encoding = Encoding.Default;
    private string _recipientPublicCertPath;

    private CAPICOM.Certificate _signerCert;
    private CAPICOM.Certificate _recipientCert;

    public ButtonEncryption()
    {
    }

    #region Properties

    /// <summary>
    /// Character encoding, e.g. UTF-8, Windows-1252
    /// </summary>
    public string Charset
    {
      get { return _encoding.WebName; }
      set
      {
        if (value != null && value != "")
        {
          _encoding = Encoding.GetEncoding(value);
        }
      }
    }

    /// <summary>
    /// Path to the recipient's public certificate in PEM format
    /// </summary>
    public string RecipientPublicCertPath
    {
      get { return _recipientPublicCertPath; }
      set 
      { 
        _recipientPublicCertPath = value;
        _recipientCert = new CAPICOM.CertificateClass();
        _recipientCert.Load(_recipientPublicCertPath, null, 
                  CAPICOM.CAPICOM_KEY_STORAGE_FLAG.CAPICOM_KEY_STORAGE_DEFAULT, 
                  CAPICOM.CAPICOM_KEY_LOCATION.CAPICOM_CURRENT_USER_KEY);
      }
    }

    #endregion

    /// <summary>
    /// 
    /// </summary>
    /// <param name="signerPfxCertPath">File path to the signer's public certificate plus private key in PFX (P12) format</param>
    /// <param name="signerPfxCertPassword">Password for signer's private key</param>
    public void LoadSignerCredential(string signerPfxCertPath, string signerPfxCertPassword)
    {
      _signerCert = new CAPICOM.CertificateClass();
      _signerCert.Load(signerPfxCertPath, signerPfxCertPassword, 
               CAPICOM.CAPICOM_KEY_STORAGE_FLAG.CAPICOM_KEY_STORAGE_DEFAULT, 
               CAPICOM.CAPICOM_KEY_LOCATION.CAPICOM_CURRENT_USER_KEY);
    }

    /// <summary>
    /// Sign a message and encrypt it for the recipient.
    /// </summary>
    /// <param name="clearText">Name value pairs must be separated by \n (vbLf or Chr(10)), for example "cmd=_xclick\nbusiness=..."</param>
    /// <returns></returns>
    public string SignAndEncrypt(string clearText)
    {
      string result = null;

      IntPtr bstr = UnicodeStringToBinaryString(clearText);
      string signed = Sign(bstr);
      string enveloped = Envelope(signed);

      result = FormatForTransport(enveloped);

      return result;
    }

    private string Sign(IntPtr bstr)
    {
      CAPICOM.ISigner signer = new CAPICOM.SignerClass();
      signer.Certificate = _signerCert;
      CAPICOM.SignedData signed = new CAPICOM.SignedDataClass();
      signed.set_Content(bstr);
      string result = signed.Sign(signer, false, CAPICOM.CAPICOM_ENCODING_TYPE.CAPICOM_ENCODE_BINARY);

      return result;
    }

    private string Envelope(string bstr)
    {
      CAPICOM.EnvelopedData enveloped = new CAPICOM.EnvelopedDataClass();
      enveloped.Content = bstr;
      enveloped.Recipients.Add(_recipientCert);
      string result = enveloped.Encrypt(CAPICOM.CAPICOM_ENCODING_TYPE.CAPICOM_ENCODE_BINARY);

      return result;
    }

    private string FormatForTransport(string bstr)
    {
      const string PKCS7_HEADER = "-----BEGIN PKCS7-----";
      const string PKCS7_FOOTER = "-----END PKCS7-----";

      CAPICOM.Utilities utils = new CAPICOM.UtilitiesClass();
      string base64 = utils.Base64Encode(bstr);
      StringBuilder formatted = new StringBuilder();
      formatted.Append(PKCS7_HEADER);
      formatted.Append(base64.Replace("\r\n", ""));
      formatted.Append(PKCS7_FOOTER);

      return formatted.ToString();
    }
  
    private IntPtr UnicodeStringToBinaryString(string ustr)
    {
      byte[] bytes = _encoding.GetBytes(ustr);
      CAPICOM.Utilities utils = new CAPICOM.UtilitiesClass();
      IntPtr bstr = utils.ByteArrayToBinaryString(bytes);
 
      return bstr;
    }  
  }
}

It needs a modified capicom.dll found at the code project here:

http://www.codeproject.com/dotnet/CapicomUTF8.asp

Now I use my dll in a c++ program. But when it comes time to run code from the dll, the program throws an exception when its on a computer other than my development system. Any ideas on what is needed to deploy this modified capicom.dll I've tried it in the System32 directory and the application directory . And it always throws the exception that seems to indicate it can't find the capicom.dll. And I tried registering the capicom.dll but regsvr32 doesn't recognize it as registerable

Here's the error:

Retrieving the COM class factory for component with CLSID P9171C115-7DD9-46BA-B1E6-OED50AFFC1B8} failed due to the following error: 80040154




Re: ClickOnce and Setup & Deployment Projects Modified Capicom.dll deployment

william13

Hi glcjr ;-)

It's just because you don't have registered the new CAPICOM.DLL (the one which is provided by codeproject).

Use "regsvr32 CAPICOM.DLL" in a DOS window to register this new DLL.

This DLL doesn't use the same CLSID than the original one provided by Microsoft.

It's normal because a change has been made in its interface (int in place of BSTR).

Remark 1:

Use Visual C++ Error Lookup (MS tool provided in the Visual Studio package, available in Visual Studio .NET Tools menu) to find the corresponding error message.

In your case, 0x80040154 is "Class not registered"... which is more understandable ! ;-)

Remark 2:

the CLSID you give in your post is wrong...

The good one is 9171C115-7DD9-46BA-B1E5-0ED50AFFC1B8...