Sign file with SHA-256 Algorithm - c#

I have a function that signing an XML file with a X509Certificate2 certificate. My problem is that the signature is inserted as SHA-1 and SHA-256 instead. What did I do wrong in my code?
CmsSigner cms = new CmsSigner(oCert);
//if apply this row receive unknow error!
//cms.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1");
ContentInfo ci = new ContentInfo(File.ReadAllBytes(cFileXml));
SignedCms cmssigned = new SignedCms(ci);
cmssigned.ComputeSignature(cms);
byte[] encodedmessage = cmssigned.Encode();
File.WriteAllBytes(cFile + ".p7m", encodedmessage);

I say to myself. This is the simply solution:
string PIN = Leo.LeggiFirmacert();
System.Security.SecureString SecurePIN = new System.Security.SecureString();
foreach (char ch in PIN)
{ SecurePIN.AppendChar(ch); }
var rsa = (RSACryptoServiceProvider)cert.PrivateKey;
string ContinerName = rsa.CspKeyContainerInfo.KeyContainerName;
string CspName = rsa.CspKeyContainerInfo.ProviderName;
int CspType = rsa.CspKeyContainerInfo.ProviderType;
CspParameters csp = new CspParameters(CspType, CspName, ContinerName, new System.Security.AccessControl.CryptoKeySecurity(), SecurePIN);
SHA256Managed hashSha256 = new SHA256Managed();
byte[] certHash = hashSha256.ComputeHash(cert.RawData);
EssCertIDv2 essCert1 = new EssCertIDv2(new Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier("2.16.840.1.101.3.4.2.1"), certHash);
SigningCertificateV2 scv2 = new SigningCertificateV2(new EssCertIDv2[] { essCert1 });
Org.BouncyCastle.Asn1.Cms.Attribute CertHAttribute = new Org.BouncyCastle.Asn1.Cms.Attribute(Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.IdAASigningCertificateV2, new DerSet(scv2));
Asn1EncodableVector v = new Asn1EncodableVector();
v.Add(CertHAttribute);
Org.BouncyCastle.Asn1.Cms.AttributeTable AT = new Org.BouncyCastle.Asn1.Cms.AttributeTable(v);
CmsSignedDataGenWithRsaCsp cms = new CmsSignedDataGenWithRsaCsp();
Org.BouncyCastle.Crypto.AsymmetricKeyParameter keyParameter = null;
Org.BouncyCastle.X509.X509Certificate certCopy = DotNetUtilities.FromX509Certificate(cert);
cms.MyAddSigner(rsa, certCopy, keyParameter, "1.2.840.113549.1.1.1", "2.16.840.1.101.3.4.2.1", AT, null);
ArrayList certList = new ArrayList();
certList.Add(certCopy);
Org.BouncyCastle.X509.Store.X509CollectionStoreParameters PP = new Org.BouncyCastle.X509.Store.X509CollectionStoreParameters(certList);
Org.BouncyCastle.X509.Store.IX509Store st1 = Org.BouncyCastle.X509.Store.X509StoreFactory.Create("CERTIFICATE/COLLECTION", PP);
cms.AddCertificates(st1);
FileInfo File__1 = new FileInfo(NomeFile);
CmsProcessableFile file__2 = new CmsProcessableFile(File__1);
CmsSignedData Firmato = cms.Generate(file__2, true);
byte[] Encoded = Firmato.GetEncoded();
RisFirma = "";
return Encoded;

Related

C# cms.ComputeSignature(signer) without prompting a PIN code (smart card)

I am trying to get a certificate signature using CMS/Pkcs, it keeps prompting me a PIN code. How to disable this pin code pop-up or include it within the code (Note it is a fixed pin and it does not change)
Encoding utf8 = Encoding.UTF8;
byte[] bytes = utf8.GetBytes(serializedJson);
Pkcs11InteropFactories factories = new Pkcs11InteropFactories();
using (IPkcs11Library library = factories.Pkcs11LibraryFactory.LoadPkcs11Library(factories, this.DllLibPath, AppType.MultiThreaded))
{
ISlot slot = ((IEnumerable<ISlot>)library.GetSlotList(SlotsType.WithTokenPresent)).FirstOrDefault<ISlot>();
if (slot == null)
{
str = "No slots found";
}
else
{
ITokenInfo tokenInfo = slot.GetTokenInfo();
ISlotInfo slotInfo = slot.GetSlotInfo();
using (ISession session = slot.OpenSession(SessionType.ReadWrite))
{
session.Login(CKU.CKU_USER, utf8.GetBytes(this.TokenPin));
List<IObjectAttribute> list1 = new List<IObjectAttribute>();
list1.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_CERTIFICATE));
list1.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true));
list1.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CERTIFICATE_TYPE, CKC.CKC_X_509));
if (((IEnumerable<IObjectHandle>)session.FindAllObjects(list1)).FirstOrDefault<IObjectHandle>() == null)
{
str = "Certificate not found";
}
else
{
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.MaxAllowed);
X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByIssuerName, "Egypt Trust Sealing CA", true);
if (certificates.Count == 0)
{
str = "no device detected";
}
else
{
X509Certificate2 certificate = certificates[0];
store.Close();
SignedCms cms = new SignedCms(new ContentInfo(new Oid("1.2.840.113549.1.7.5"), bytes), true);
EssCertIDv2 dv = new EssCertIDv2(new Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier(new DerObjectIdentifier("1.2.840.113549.1.9.16.2.47")), this.HashBytes(certificate.RawData));
EssCertIDv2[] certs = new EssCertIDv2[] { dv };
SigningCertificateV2 ev = new SigningCertificateV2(certs);
CmsSigner signer = new CmsSigner(certificate)
{
DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1"),
SignedAttributes = {
new Pkcs9SigningTime(DateTime.UtcNow),
new AsnEncodedData(new Oid("1.2.840.113549.1.9.16.2.47"), ev.GetEncoded())
}
};
cms.ComputeSignature(signer);
Thank you in advance.

Unable to cast object of type 'Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair' to type 'Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters'

Here is the code which is working fine when reading file from the txt but when i read it from the string i am getting the error here
public string encrypt(string plainText,string PrivateKey)
{
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
string filepath = path + "\\rsakeys\\pem_public.pem";
string localPath = new Uri(filepath).LocalPath;
PemReader pr = new PemReader(
(StreamReader)File.OpenText(localPath)
);
var reader = new StringReader(PrivateKey);
var pre = new PemReader(reader);
var o = pr.ReadObject();
var os = pre.ReadObject();
RsaKeyParameters keys = (RsaKeyParameters)os; >>> Here i am getting the error where os is the object readed from the string
This solve my problem
var o = pr.ReadObject();
AsymmetricCipherKeyPair keyPair=(AsymmetricCipherKeyPair)o;
//As Keypair.public is RsaParamterKey
Pkcs1Encoding eng = new Pkcs1Encoding(new RsaEngine());
eng.Init(true, keyPair.Public);

SignedCms.ComputeSignature throws "The object identifier is poorly formatted"

This exception starts to be thrown recently, the code was working fine:
public byte[] Sign(CmsMessage cmsMessage, CspKeyInfo keyInfo)
{
ContentInfo contentInfo = new ContentInfo(new Oid(cmsMessage.ContentTypeOid), cmsMessage.Content);
var cspObj = new CspParameters()
{
ProviderName = keyInfo.ProviderName,
ProviderType = keyInfo.ProviderType,
KeyNumber = (int)KeyNumber.Signature,
Flags = CspProviderFlags.UseExistingKey,
KeyContainerName = keyInfo.ContainerName
};
var signer = new CmsSigner(cspObj)
{
DigestAlgorithm = new Oid(cmsMessage.SignerHashAlgorithmOid)
};
signer.SignedAttributes.Add(new Pkcs9SigningTime());
var signedCms = new SignedCms(contentInfo, cmsMessage.Detached);
signedCms.ComputeSignature(signer);
var encodeByteBlock = (ByteBlock)signedCms.Encode();
return encodeByteBlock;
}
The signer's SignerIdentifierType is SubjectKeyIdentifier
but it throws: CryptographicException at ComputeSignature
The object identifier is poorly formatted
The dummy certificate has a private key (HasPrivateKey is true)

RSA encryption using modulus and exponent in PHP

I want to encrypt password using modulus and exponent. I'm using .NET RSACryptoServiceProvider and in PHP I'm using seclib.
I have this piece of C# code and I want to do the exact same thing in PHP.
string exponent = "010001";
string modulus = "A1DFE8C5D4140E46610A4B2B0E0B77F7048A9386F50D5CF0B02C983C0138392F60C5B20C67285A37FABD2E270CB32FDBCB0DB1902EC74A0ADF41C623B3CF250EC4287BF9C3A0477BAEFD5803C07401C3E013BABEE8EE528EF765EB8EA4A82034DF7B0AC2BA9CDA6B0D6B87999D2AF0CA851C4FD6D62EF538EF73F1183658E0D810132DE2F7814C73A14E31B6472027A682EFD938EA6CC7C6E48DFD7F5145A870595E4B9A63909AF3AABD75C5148E276D1D329531CB2F27E45E0F09B076B08D56A310DE5BD2BF1EFD04D9A88BF1A1C0B74C60E04CE2EAB96E9B5BE7F6C42CA72E9D2970031550EB515C4F7EB5C245B3EF141E67864C536D54D3DA10CED3DF63F1";
string password = "testing";
byte[] encryptedPasswordBytes;
using (var rsaEncryptor = new RSACryptoServiceProvider())
{
var passwordBytes = Encoding.ASCII.GetBytes(password);
var rsaParameters = rsaEncryptor.ExportParameters(false);
rsaParameters.Exponent = HexStringToByteArray(exponent);
rsaParameters.Modulus = HexStringToByteArray(modulus);
rsaEncryptor.ImportParameters(rsaParameters);
encryptedPasswordBytes = rsaEncryptor.Encrypt(passwordBytes, false);
}
string encryptedPassword = Convert.ToBase64String(encryptedPasswordBytes);
Console.WriteLine(WebUtility.UrlEncode(encryptedPassword));
Console.ReadLine();
HexStringToByteArray method source code:
public static byte[] HexStringToByteArray(string hex)
{
int hexLen = hex.Length;
byte[] ret = new byte[hexLen / 2];
for (int i = 0; i < hexLen; i += 2)
ret[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return ret;
}
I'm trying to get same results in PHP using seclib and I think I'm not successfull.
$exponent = '010001';
$modulus = 'A1DFE8C5D4140E46610A4B2B0E0B77F7048A9386F50D5CF0B02C983C0138392F60C5B20C67285A37FABD2E270CB32FDBCB0DB1902EC74A0ADF41C623B3CF250EC4287BF9C3A0477BAEFD5803C07401C3E013BABEE8EE528EF765EB8EA4A82034DF7B0AC2BA9CDA6B0D6B87999D2AF0CA851C4FD6D62EF538EF73F1183658E0D810132DE2F7814C73A14E31B6472027A682EFD938EA6CC7C6E48DFD7F5145A870595E4B9A63909AF3AABD75C5148E276D1D329531CB2F27E45E0F09B076B08D56A310DE5BD2BF1EFD04D9A88BF1A1C0B74C60E04CE2EAB96E9B5BE7F6C42CA72E9D2970031550EB515C4F7EB5C245B3EF141E67864C536D54D3DA10CED3DF63F1';
$password = 'testing';
$rsa = new Crypt_RSA();
$rsa->loadKey(
array(
'e' => new Math_BigInteger($exponent,16),
'n' => new Math_BigInteger($modulus,16)
)
);
$encryptedPassword = urlencode(base64_encode($rsa->encrypt($password)));
$exponent = '010001';
$modulus = 'A1DFE8C5D4140E46610A4B2B0E0B77F7048A9386F50D5CF0B02C983C0138392F60C5B20C67285A37FABD2E270CB32FDBCB0DB1902EC74A0ADF41C623B3CF250EC4287BF9C3A0477BAEFD5803C07401C3E013BABEE8EE528EF765EB8EA4A82034DF7B0AC2BA9CDA6B0D6B87999D2AF0CA851C4FD6D62EF538EF73F1183658E0D810132DE2F7814C73A14E31B6472027A682EFD938EA6CC7C6E48DFD7F5145A870595E4B9A63909AF3AABD75C5148E276D1D329531CB2F27E45E0F09B076B08D56A310DE5BD2BF1EFD04D9A88BF1A1C0B74C60E04CE2EAB96E9B5BE7F6C42CA72E9D2970031550EB515C4F7EB5C245B3EF141E67864C536D54D3DA10CED3DF63F1';
$password = 'testing';
$rsa = new Crypt_RSA();
$modulus = new Math_BigInteger(($modulus), 16);
$exponent = new Math_BigInteger(($exponent), 16);
$rsa->loadKey(array('n' => $modulus, 'e' => $exponent));
$rsa->setPublicKey(array('n' => $modulus, 'e' => $exponent));
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$encryptedPassword = $rsa->encrypt($password);

Create a X509Certificate2 from RSACryptoServiceProvider fails with Cannot find the requested object

Sample code:
CspParameters cspParameters = new CspParameters();
cspParameters.ProviderType = 1; // PROV_RSA_FULL
// Create the crypto service provider, generating a new
// key.
mRsaCSP = new RSACryptoServiceProvider(mDefaultKeyLength, cspParameters);
mRsaCSP.PersistKeyInCsp = true;
RSAParameters privateKey = mRsaCSP.ExportParameters(true);
byte[] rsaBytes = mRsaCSP.ExportCspBlob(true);
try
{
X509Certificate2 cert = new X509Certificate2(rsaBytes);
mKeyDataPfx = Convert.ToBase64String(cert.Export(X509ContentType.Pkcs12, password));
}
catch (Exception ce)
{
string error = ce.Message;
}
Here is my solution, using the BouncyCastle library.
// create the RSA key from an XML string
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
key.FromXmlString(keyTextBox.Text);
// convert to BouncyCastle key object
var keypair = DotNetUtilities.GetRsaKeyPair(key);
var gen = new X509V3CertificateGenerator();
string certName = Path.GetFileNameWithoutExtension(fileName);
var name = new X509Name("CN=" + certName);
var serial = BigInteger.ProbablePrime(120, new Random());
gen.SetSerialNumber(serial);
gen.SetSubjectDN(name);
gen.SetIssuerDN(name);
gen.SetNotAfter(DateTime.Now.AddYears(10));
gen.SetNotBefore(DateTime.Now);
gen.SetSignatureAlgorithm("MD5WithRSA");
gen.SetPublicKey(keypair.Public);
// generate the certificate
var newCert = gen.Generate(keypair.Private);
// convert back to .NET certificate
var cert = DotNetUtilities.ToX509Certificate(newCert);
// export as byte array
byte[] certData = cert.Export(X509ContentType.Pfx);
File.WriteAllBytes(fileName, certData);

Categories

Resources