javac#code-conversion

How to Create Digital Signature and Verify it in C# using PKCS 7 and SHA algorithm


I am trying to digitally sign xml document and verify the signature with the original xml file with public key and signed document. I have a java code for reference. I need to convert java code to C# where I have java code like this:

   certList = new ArrayList<X509Certificate>();
   certList.add(signerCert);
   certStore = new JcaCertStore(certList);
   signedDataGenerator = new CMSSignedDataGenerator();
   ContentSigner sha2Signer = new JcaContentSignerBuilder("SHA512with" + privateKey.getAlgorithm()).build(privateKey);

   ignedDataGenerator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()).setDirectSignature(true).build(sha2Signer, signerCert));
   signedDataGenerator.addCertificates(certStore);
   CMSSignedData sigData = signedDataGenerator.generate(new CMSProcessableFile(inputXmlFile), false);
   signedBytes = sigData.getEncoded();

I have converted java code to C# like this:

        X509Store my = new X509Store(StoreName.My, StoreLocation.LocalMachine);
        my.Open(OpenFlags.ReadOnly);
        // Find the certificate we’ll use to sign
        RSACryptoServiceProvider csp = null;
        foreach (X509Certificate2 cert in my.Certificates)
        {
            if (cert.Subject.Contains(certSubject))
            {
                // We found it.
                // Get its associated CSP and private key
                csp = (RSACryptoServiceProvider)cert.PrivateKey;                  
            }
        }
        if (csp == null)
        {
            throw new Exception("oppose no valid application was found");
        }
        // Hash the data
        SHA512Managed sha1 = new SHA512Managed();
        UnicodeEncoding encoding = new UnicodeEncoding();
        byte[] data = encoding.GetBytes(text);
        byte[] hash = sha1.ComputeHash(data);
        // Sign the hash
        return csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));

I am trying to convert it since two days, It is generating sign byte array but not been able to verify. While verifying it is throwing bad hash\r\n error I shall be highly grateful for any assistance. I know I am somewhere wrong in converting the java code to C#. I am able to verify the code but not been able to sign the document


Solution

  • I have generated Signature using System.Security.Cryptography.Pkcs library like this

        public static byte[] Sign(byte[] data, X509Certificate2 certificate)
        {
            if (data == null)
                throw new ArgumentNullException("data");
            if (certificate == null)
                throw new ArgumentNullException("certificate");
    
            // setup the data to sign
            ContentInfo content = new ContentInfo(data);
            SignedCms signedCms = new SignedCms(content, false);
            CmsSigner signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, certificate);
            // create the signature
            signedCms.ComputeSignature(signer);
            return signedCms.Encode();
        }
    

    and verify the signature like this

      private static bool VerifySignatures(FileInfo contentFile, Stream signedDataStream)
        {
            CmsProcessable signedContent = null;
            CmsSignedData cmsSignedData = null;
            Org.BouncyCastle.X509.Store.IX509Store store = null;
            ICollection signers = null;
            bool verifiedStatus = false;
            try
            {
                //Org.BouncyCastle.Security.addProvider(new BouncyCastleProvider());
                signedContent = new CmsProcessableFile(contentFile);
                cmsSignedData = new CmsSignedData(signedContent, signedDataStream);
                store = cmsSignedData.GetCertificates("Collection");//.getCertificates();
                IX509Store certStore = cmsSignedData.GetCertificates("Collection");
                signers = cmsSignedData.GetSignerInfos().GetSigners();
                foreach (var item in signers)
                {
                    SignerInformation signer = (SignerInformation)item;
                    var certCollection = certStore.GetMatches(signer.SignerID);
                    IEnumerator iter = certCollection.GetEnumerator();
                    iter.MoveNext();
                    var cert = (Org.BouncyCastle.X509.X509Certificate)iter.Current;
                    verifiedStatus = signer.Verify(cert.GetPublicKey());
                }
    
            }
            catch (Exception e)
            {
                throw e;
            }
    
            return verifiedStatus;
        }
    

    It is working for me