I read Bruno Lowagie's white paper: Digital Signatures for PDF documents.
I followed the examples and I was able to sign PDF's with my SwissSign USB token using MSCAPI. This line of code does the trick:
MakeSignature.SignDetached(appearance, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
I am also passing the TSA client with the SwissSign TSA URL: tsa(dot)swisssign(dot)net
When I open the signed PDF in Acrobat Reader DC 2015, I get the error:
Signature is invalid.
There are errors in the formatting or information contained in this signature
Signer's identity has not yet been verified
Signing time is from the clock on the signer's computer.
When signing the PDF with the SwissSign tool everything looks fine: signature is valid.
I have put the PDF's here:
invalid PDF - signed with iTextSharp 5.5.6
valid PDF - signed with SwissSign tool
I have tried different combinations of hash algorithms, but without success. What am I missing?
Any help appreciated.
Best Regards,
Phil
Here is the full code:
private void _sign_Click(object sender, RoutedEventArgs e)
{
X509Store x509Store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
x509Store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificates = x509Store.Certificates;
IList<Org.BouncyCastle.X509.X509Certificate> chain = new List<Org.BouncyCastle.X509.X509Certificate>();
X509Certificate2 pk = null;
if (certificates.Count > 0)
{
for (int i = 0; i < certificates.Count; i++)
{
if (certificates[i].FriendlyName == "Philipp Egger (Qualified Signature) .....") // Phil Egger Signature Certificate
{
pk = certificates[i];
break;
}
}
X509Chain x509chain = new X509Chain();
x509chain.Build(pk);
foreach (X509ChainElement x509ChainElement in x509chain.ChainElements)
{
chain.Add(Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(x509ChainElement.Certificate));
}
}
x509Store.Close();
if (pk != null)
{
#region connect usb token
///////////////////
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)pk.PrivateKey;
CspParameters cspp = new CspParameters();
cspp.KeyContainerName = rsa.CspKeyContainerInfo.KeyContainerName;
cspp.ProviderName = rsa.CspKeyContainerInfo.ProviderName;
cspp.ProviderType = rsa.CspKeyContainerInfo.ProviderType;
cspp.Flags = CspProviderFlags.NoPrompt;
System.Security.SecureString pwstr = new System.Security.SecureString();
pwstr.AppendChar('x');
pwstr.AppendChar('x');
pwstr.AppendChar('x');
cspp.KeyPassword = pwstr;
RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider(cspp);
rsa2.PersistKeyInCsp = true;
// PIN is cached from now on and popup won't appear
///////////////////////
#endregion
IOcspClient ocspClient = new OcspClientBouncyCastle();
ITSAClient tsaClient = null;
for (int i = 0; i < chain.Count; i++)
{
Org.BouncyCastle.X509.X509Certificate cert = chain[i];
String tsaUrl = CertificateUtil.GetTSAURL(cert);
if (tsaUrl != null)
{
tsaClient = new TSAClientBouncyCastle(tsaUrl);
break;
}
}
if (tsaClient == null)
{
tsaClient = new TSAClientBouncyCastle("http://tsa.swisssign.net");
//tsaClient = new MyTSAClientBouncyCastle("http://tsa.swisssign.net"); // set user-agent
}
IList<ICrlClient> crlList = new List<ICrlClient>();
crlList.Add(new CrlClientOnline(chain));
string pathSource = #"C:\Temp\test_to_sign.pdf";
string pathTarget3 = #"C:\Temp\test_to_sign-signed3.pdf";
// this.SignNew(pathSource, pathTarget1, chain, pk, DigestAlgorithms.SHA1, CryptoStandard.CMS, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
// this.SignNew(pathSource, pathTarget2, chain, pk, DigestAlgorithms.SHA1, CryptoStandard.CADES, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
this.SignNew(pathSource, pathTarget3, chain, pk, DigestAlgorithms.SHA256, CryptoStandard.CMS, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
// this.SignNew(pathSource, pathTarget4, chain, pk, DigestAlgorithms.SHA256, CryptoStandard.CADES, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
// this.SignNew(pathSource, pathTarget5, chain, pk, DigestAlgorithms.SHA384, CryptoStandard.CMS, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
// this.SignNew(pathSource, pathTarget6, chain, pk, DigestAlgorithms.SHA384, CryptoStandard.CADES, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
// this.SignNew(pathSource, pathTarget7, chain, pk, DigestAlgorithms.SHA512, CryptoStandard.CMS, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
// this.SignNew(pathSource, pathTarget8, chain, pk, DigestAlgorithms.SHA512, CryptoStandard.CADES, "Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
this._txt.Text = "Signed successfully.";
}
else
{
this._txt.Text = "Certificate not found.";
}
}
public void SignNew(String src, String dest,
ICollection<Org.BouncyCastle.X509.X509Certificate> chain, X509Certificate2 pk,
String digestAlgorithm, CryptoStandard subfilter,
String reason, String location,
ICollection<ICrlClient> crlList,
IOcspClient ocspClient,
ITSAClient tsaClient,
int estimatedSize)
{
// Creating the reader and the stamper
PdfReader reader = null;
PdfStamper stamper = null;
FileStream os = null;
try
{
reader = new PdfReader(src);
os = new FileStream(dest, FileMode.Create);
stamper = PdfStamper.CreateSignature(reader, os, '\0');
// Creating the appearance
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.Reason = reason;
appearance.Location = location;
appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(36, 748, 144, 780), 1, "Signature1");
// Creating the signature
IExternalSignature pks = new X509Certificate2Signature(pk, digestAlgorithm);
MakeSignature.SignDetached(appearance, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
}
catch (Exception e)
{
this._txt.Text = e.Message;
}
finally
{
if (reader != null)
reader.Close();
if (stamper != null)
stamper.Close();
if (os != null)
os.Close();
}
}
The problem is that it's apparently the SwissSign CSP (cryptographic service provider; a layer that provides a bridge between the Windows system stores and the hardware device) which picks the wrong private key when using MSCAPI.
There seems no workaround to pick the correct private key in MSCAPI.
Therefore, I decided to use PKCS11 and NCryptroki library. Here the code:
using Cryptware.NCryptoki;
using iTextSharp.text;
using iTextSharp.text.log;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace _07SignWithPKCS11DLL
{
class Program
{
static void Main(string[] args)
{
LoggerFactory.GetInstance().SetLogger(new SysoLogger());
// Creates a Cryptoki object related to the specific PKCS#11 native library
Cryptoki cryptoki = new Cryptoki("cvP11.dll");
cryptoki.Initialize();
// Reads the set of slots containing a token
SlotList slots = cryptoki.Slots;
if (slots.Count == 0)
{
Console.WriteLine("No slot available");
Console.ReadLine();
return;
}
// Gets the first slot available
Slot slot = slots[0];
if (!slot.IsTokenPresent)
{
Console.WriteLine("No token inserted in the slot: " + slots[0].Info.Description);
Console.ReadLine();
return;
}
// Gets the first token available
Token token = slot.Token;
// Opens a read serial session
Session session = token.OpenSession(Session.CKF_SERIAL_SESSION, null, null);
// Executes the login passing the user PIN
int nRes = session.Login(Session.CKU_USER, "secret");
if (nRes != 0)
{
Console.WriteLine("Wrong PIN");
return;
}
CSignWithPKCS11SC.Smartcardsign(session, "PhilippEggerQualifiedSignature", "SwissSign_nonRep ");
/*
CryptokiCollection template = new CryptokiCollection();
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_CERTIFICATE));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CERTIFICATE_TYPE, Certificate.CKC_X_509));
CryptokiCollection objects = session.Objects.Find(template, 10);
// If the private keys is found continue
if (objects.Count > 0)
{
foreach (Object obj in objects)
{
Cryptware.NCryptoki.X509Certificate cert = (Cryptware.NCryptoki.X509Certificate)obj;
Console.WriteLine(cert.Label + " - " + cert.ID);
}
}
*/
// Logouts and closes the session
session.Logout();
session.Close();
cryptoki.Finalize(IntPtr.Zero);
Console.ReadLine();
}
}
class CryptokiPrivateKeySignature : IExternalSignature
{
private readonly Cryptware.NCryptoki.Session session;
RSAPrivateKey privateKey;
public CryptokiPrivateKeySignature(Session session, String alias)
{
this.session = session;
CryptokiCollection template = new CryptokiCollection();
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_PRIVATE_KEY));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_KEY_TYPE, Key.CKK_RSA));
// "SwissSign_nonRep "
// "SwissSign_digSig "
template.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, alias));
/*
CryptokiCollection objects = session.Objects.Find(template, 10);
if (objects.Count > 0)
{
foreach (Object obj in objects)
{
RSAPrivateKey cert = (RSAPrivateKey)obj;
Console.WriteLine(cert.Label);
}
}
*/
privateKey = (RSAPrivateKey)session.Objects.Find(template);
}
public String GetHashAlgorithm()
{
return "SHA1";
}
public String GetEncryptionAlgorithm()
{
return "RSA";
}
public byte[] Sign(byte[] message)
{
session.SignInit(Mechanism.SHA1_RSA_PKCS, privateKey);
return session.Sign(message);
}
}
class CSignWithPKCS11SC
{
public const String SRC = #"C:\Temp\test_to_sign.pdf";
public const String DEST = #"C:\Temp\test_to_sign-pkcs11.pdf";
//public const String DLL = "c:/windows/system32/beidpkcs11.dll";
public const String DLL = "c:/windows/system32/cvP11.dll";
public void Sign(String src, String dest, ICollection<Org.BouncyCastle.X509.X509Certificate> chain, Session session, String alias,
String digestAlgorithm, CryptoStandard subfilter, String reason, String location,
ICollection<ICrlClient> crlList, IOcspClient ocspClient, ITSAClient tsaClient, int estimatedSize)
{
// Creating the reader and the stamper
PdfReader reader = null;
PdfStamper stamper = null;
FileStream os = null;
try
{
reader = new PdfReader(src);
os = new FileStream(dest, FileMode.Create);
stamper = PdfStamper.CreateSignature(reader, os, '\0');
// Creating the appearance
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.Reason = reason;
appearance.Location = location;
appearance.SetVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
// Creating the signature
IExternalSignature pks = new CryptokiPrivateKeySignature(session, alias);
MakeSignature.SignDetached(appearance, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
}
finally
{
if (reader != null)
reader.Close();
if (stamper != null)
stamper.Close();
if (os != null)
os.Close();
}
}
public static void Smartcardsign(Session session, String alias, String aliasPrivateKey)
{
// Searchs for an RSA certificate object
// Sets the template with its attributes
CryptokiCollection template = new CryptokiCollection();
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_CERTIFICATE));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CERTIFICATE_TYPE, Certificate.CKC_X_509));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, alias));
Cryptware.NCryptoki.X509Certificate nCert = (Cryptware.NCryptoki.X509Certificate)session.Objects.Find(template);
if (nCert != null)
{
X509Certificate2 cert = Utils.ConvertCertificate(nCert);
ICollection<Org.BouncyCastle.X509.X509Certificate> chain = new List<Org.BouncyCastle.X509.X509Certificate>();
X509Chain x509chain = new X509Chain();
x509chain.Build(cert);
foreach (X509ChainElement x509ChainElement in x509chain.ChainElements)
{
chain.Add(DotNetUtilities.FromX509Certificate(x509ChainElement.Certificate));
}
IOcspClient ocspClient = new OcspClientBouncyCastle();
List<ICrlClient> crlList = new List<ICrlClient>();
crlList.Add(new CrlClientOnline(chain));
TSAClientBouncyCastle tsaClient = new TSAClientBouncyCastle("http://tsa.swisssign.net");
CSignWithPKCS11SC app = new CSignWithPKCS11SC();
Console.WriteLine("Logged in? " + session.IsLoggedIn);
app.Sign(SRC, DEST, chain, session, aliasPrivateKey, DigestAlgorithms.SHA256, CryptoStandard.CMS,
"Test", "Rheinau", crlList, ocspClient, tsaClient, 0);
}
else
{
Console.WriteLine("Certificate not found: " + alias);
}
}
}
}
Related
I have a setup where I need to encrypt blob of data in one app and decrypt it in different app.
I built a sample app that creates a named CngKey object. Then create a RSACng using CngKey object. Then use RSACng object to do encryption/decryption. What I found is that the key changes across restarts of the application even though it is loaded using the name it was created with. I am lost trying to understand the relation between CngKey and RSACng objects.
Below is snippet of code that describes what I am trying to do:
using System;
using System.IO;
using System.Security.Cryptography;
namespace TPMCrypto
{
class Program
{
static byte[] data = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
static byte[] privateKey;
private static byte[] encrypted;
private static byte[] decrypted;
static void Main(string[] args)
{
const string MyKey = "MyRSAKey";
CngKey cngKey = null;
string cmd = args.Length > 0 ? args[0] : "";
try
{
CngKeyCreationParameters cng = new CngKeyCreationParameters
{
KeyUsage = CngKeyUsages.AllUsages,
KeyCreationOptions = CngKeyCreationOptions.MachineKey,
Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider
};
if (!CngKey.Exists(MyKey, CngProvider.MicrosoftSoftwareKeyStorageProvider, CngKeyOpenOptions.MachineKey))
{
Console.WriteLine("Creating rsaKey");
cngKey = CngKey.Create(CngAlgorithm.Rsa, MyKey, cng);
}
else
{
Console.WriteLine("Opening rsaKey");
cngKey = CngKey.Open(MyKey, CngProvider.MicrosoftSoftwareKeyStorageProvider, CngKeyOpenOptions.MachineKey);
}
RSACng rsaKey = new RSACng(cngKey)
{
KeySize = 2048
};
privateKey = rsaKey.Key.Export(CngKeyBlobFormat.GenericPrivateBlob);
string prvResult = ByteArrayToHexString(privateKey, 0, privateKey.Length);
Console.WriteLine("\nPrivate key - length = " + privateKey.Length + "\n" + prvResult + "\n");
const string FILE_PATH = #"\temp\tpmtests\encryptedblob.dat";
// Encrypt / decrypt
if (cmd == "readfromfile")
{
Directory.CreateDirectory(Path.GetDirectoryName(FILE_PATH));
encrypted = File.ReadAllBytes(FILE_PATH);
}
else if (cmd == "deletekey")
{
cngKey.Delete();
return;
}
else
{
encrypted = Encrypt(rsaKey, data);
Console.WriteLine("The encrypted blob: ");
Console.WriteLine(ByteArrayToHexString(encrypted, 0, encrypted.Length));
File.WriteAllBytes(FILE_PATH, encrypted);
}
decrypted = Decrypt(rsaKey, encrypted);
bool result = ByteArrayCompare(data, decrypted);
if (result)
Console.WriteLine("Encrypt / decrypt works");
else
Console.WriteLine("Encrypt / decrypt fails");
}
catch (Exception e)
{
Console.WriteLine("Exception " + e.Message);
}
finally
{
if (cngKey != null)
cngKey.Dispose();
}
Console.ReadLine();
}
static bool ByteArrayCompare(byte[] a1, byte[] a2)
{
if (a1.Length != a2.Length)
return false;
for (int i = 0; i < a1.Length; i++)
if (a1[i] != a2[i])
return false;
return true;
}
public static string ByteArrayToHexString(byte[] bytes, int start, int length)
{
string delimitedStringValue = BitConverter.ToString(bytes, start, length);
return delimitedStringValue.Replace("-", "");
}
public static byte[] Sign512(byte[] data, byte[] privateKey)
{
CngKey key = CngKey.Import(privateKey, CngKeyBlobFormat.GenericPrivateBlob);
RSACng crypto = new RSACng(key);
return crypto.SignData(data, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
}
public static bool VerifySignature512(byte[] data, byte[] signature, byte[] publicKey)
{
CngKey key = CngKey.Import(publicKey, CngKeyBlobFormat.GenericPublicBlob);
RSACng crypto = new RSACng(key);
return crypto.VerifyData(data, signature, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
}
public static byte[] Encrypt(byte[] publicKey, byte[] data)
{
CngKey key = CngKey.Import(publicKey, CngKeyBlobFormat.GenericPublicBlob);
RSACng crypto = new RSACng(key);
var result = Encrypt(crypto, data);
return result;
}
public static byte[] Encrypt(RSACng crypto, byte[] data)
{
if (null == crypto)
return null;
var result = crypto.Encrypt(data, RSAEncryptionPadding.OaepSHA512);
return result;
}
public static byte[] Decrypt(byte[] privateKey, byte[] data)
{
CngKey key = CngKey.Import(privateKey, CngKeyBlobFormat.GenericPrivateBlob);
RSACng crypto = new RSACng(key);
var result = Decrypt(crypto, data);
return result;
}
public static byte[] Decrypt(RSACng aKey, byte[] data)
{
if (null == aKey)
return null;
var result = aKey.Decrypt(data, RSAEncryptionPadding.OaepSHA512);
return result;
}
}
}
I am aware of dpapi and how to do this using it. I don't want to use it for this, please don't point me in that direction. I am using CNG flavor of crypto to force C# use NCryptXYZ crypto calls and the desire is to secure the keys in TPM.
Ah, looking at your code again, you've made a goof.
RSACng rsaKey = new RSACng(cngKey)
{
KeySize = 2048
};
Setting the KeySize property on an RSACng does one of two things:
If get_KeySize == value, ignore the input, do nothing.
Else, detach from the current key and the next time the key is used, generate a new key of get_KeySize at the time.
So you're opening an existing key, then discarding it, and generating a new ephemeral key. (Which you could see by checking rsaKey.Key.Name, it won't match your input).
Presumably you did this as a way to create the key with the right size in the first place, but you're too late. The correct way is
CngKeyCreationParameters cng = new CngKeyCreationParameters
{
KeyUsage = CngKeyUsages.AllUsages,
KeyCreationOptions = CngKeyCreationOptions.MachineKey,
Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider,
Parameters =
{
new CngProperty("Length", BitConverter.GetBytes(2048), CngPropertyOptions.Persist),
},
};
public static void keyPairProducing() throws NoSuchAlgorithmException, FileNotFoundException, IOException, SQLException {
File pFile = new File("public.key");
File prFile = new File("private.key");
//ResultSet rs = statement.executeQuery("SELECT * FROM KEYS WHERE SNO=1;");
//rs.next();
//if(rs.getBytes("PUBLICKEY")==null || rs.getBytes("PRIVATEKEY")==null){
if(!pFile.exists() || !prFile.exists()){
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair keypair = keyGen.genKeyPair();
PrivateKey privateKey = keypair.getPrivate();
PublicKey publicKey = keypair.getPublic();
try (FileOutputStream fos = new FileOutputStream("public.key")) {
fos.write(publicKey.getEncoded());
}
try (FileOutputStream fos = new FileOutputStream("private.key")) {
fos.write(privateKey.getEncoded());
}
//PreparedStatement preparedStatement = c.prepareStatement("INSERT INTO KEYS(PUBLICKEY, PRIVATKEY) VALUES(?, ?) WHERE SNO=1;");
//byte[] publicKeyBytes = publicKey.getEncoded();
//preparedStatement.setBytes(1, publicKey.getEncoded());
//preparedStatement.setBytes(2, publicKey.getEncoded());
System.out.println("public.key created");
System.out.println("private.key created");
}
}
public static PrivateKey getPrivateKey() throws IOException, GeneralSecurityException {
File privateKeyFile = new File("private.key");
byte[] privateKeyBytes = Files.readAllBytes(privateKeyFile.toPath());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey prikey = keyFactory.generatePrivate(privateKeySpec);
return prikey;
}
public static PublicKey getPublicKey() throws IOException, GeneralSecurityException, InvalidKeySpecException {
File publicKeyFile = new File("public.key");
byte[] publicKeyBytes = Files.readAllBytes(publicKeyFile.toPath());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
PublicKey pubkey = keyFactory.generatePublic(publicKeySpec);
return pubkey;
}
'can someone please explain instead of into public.key or private.key file how can i store it to postgres database and retrive the key back for encryption and decryption
Thanks in advance'
I am integrating a signed hash in an original PDF, and I still have an error on the validity of the signature. it's say that a pdf has been changed after signing.
below the steps: I calculate the hash then I send it for signature and finally I get the hash sign and I proceed to the integration in the original pdf
package com.example.hashdocument;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.security.*;
import com.lexpersona.commons.utils.ProcessLauncher;
import java.io.*;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.*;
public class Test2 {
private static final String SRC = "B:/Hash-et-Reconstitution/tmp/Doc_test.pdf";
private static final String DST = "B:/Hash-et-Reconstitution/tmp/Doc_test_DST.pdf";
private static final String HASH = "B:/Hash-et-Reconstitution/tmp/Doc_test_hashed.hash";
private static final String PATH_BAT = "C:/Repo_LP7/lpcommand.bat";
private static final String PIN = "123456";
private static final String CERTIFICATE = "C:/lp7command/tools/certificate.p12";
private static final String SIGNED_HASH = "B:/Hash-et-Reconstitution/tmp/doc_signed.hash";
private static byte[] readFileToByteArray(File file){
FileInputStream fis = null;
byte[] bArray = new byte[(int) file.length()];
try{
fis = new FileInputStream(file);
fis.read(bArray);
fis.close();
}catch(IOException ioExp){
ioExp.printStackTrace();
}
return bArray;
}
public static File bytesToFile(byte[] fileByte,String pathFile) {
File file = new File(pathFile);
try {
OutputStream os = new FileOutputStream(file);
os.write(fileByte);
os.close();
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
public static byte[] signDocument() throws IOException {
ProcessLauncher p = new ProcessLauncher(System.out, System.err);
int exec;
exec = p.exec("cmd.exe /c "+PATH_BAT+" <nul "+ SIGNED_HASH +" "+ PIN+" "
+ HASH+" "+CERTIFICATE, null, null);
byte[] signedHash = readFileToByteArray(new File(SIGNED_HASH));
return signedHash;
}
public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
PdfSignatureAppearance appearance = null;
ByteArrayOutputStream os = null;
String hash_document = "";
InputStream data = null;
int contentEstimated = 8192;
PdfReader reader = new PdfReader(SRC);
reader.unethicalreading = true;
reader.setAppendable(true);
int pdfPagenumber = 1;
pdfPagenumber = reader.getNumberOfPages(); // Sign on last page
os = new ByteArrayOutputStream ();
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', null, true);
Calendar cal = Calendar.getInstance();
appearance = stamper.getSignatureAppearance();
appearance.setSignDate(cal);
//appearance.setAcro6Layers(false);
appearance.setReason("Signature de contrat");
appearance.setLocation("MAROC");
appearance.setImage(null);
appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
Rectangle rect = new Rectangle(300, 300, 20, 20);
appearance.setVisibleSignature(rect, pdfPagenumber, null);
HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
exc.put(PdfName.CONTENTS, new Integer(contentEstimated * 2 + 2));
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
dic.setReason(appearance.getReason());
dic.setLocation(appearance.getLocation());
dic.setContact(appearance.getContact());
dic.setDate(new PdfDate(appearance.getSignDate()));
appearance.setCryptoDictionary(dic);
appearance.preClose(exc);
data = appearance.getRangeStream();
MessageDigest messageDigest;
String provider = null;
String hashAlgorithm = DigestAlgorithms.SHA256;
if (provider == null){
messageDigest = MessageDigest.getInstance(hashAlgorithm);
}else {
messageDigest = MessageDigest.getInstance(hashAlgorithm,provider);
}
int read = 0;
byte[] buff = new byte[contentEstimated];
while ((read = data.read(buff, 0, contentEstimated)) > 0)
{
messageDigest.update(buff,0,read);
}
byte[] hashDigest = messageDigest.digest();
byte[] documentHash = org.bouncycastle.util.encoders.Hex.encode(hashDigest);
//eSign Start
hash_document = new String(documentHash, "UTF-8");
System.out.println("Document Hash :"+hash_document);
PrintStream out = new PrintStream(new FileOutputStream(HASH));
out.print(hash_document);
byte[] hashdocumentByte = signDocument();
//////////////////// ADD SIGNED BYTES/HASH TO PDF DOCUMENT.
int contentEstimated2 = 8192;
byte[] paddedSig = new byte[contentEstimated2];
byte[] signedDocByte = hashdocumentByte;
System.arraycopy(signedDocByte, 0, paddedSig, 0, signedDocByte.length);
PdfDictionary dic2 = new PdfDictionary();
dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
appearance.close(dic2);
try(OutputStream outputStream = new FileOutputStream(DST)) {
os.writeTo(outputStream);
}
os.close();
}
}
what do you think abous this code : First i calculate the hash and send to server A for signature
PdfReader reader = new PdfReader(SRC);
FileOutputStream os = new FileOutputStream(TEMP);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
//appearance.setCertificate(chain[0]);
ExternalSignatureContainer external = new
ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.signExternalContainer(appearance, external, 8192);
InputStream inp = appearance.getRangeStream();
BouncyCastleDigest digest = new BouncyCastleDigest();
byte[] hash = DigestAlgorithms.digest(inp, digest.getMessageDigest("SHA256"));
System.out.println("hash to sign : "+ hash);
bytesToFile(hash, HASH);
byte[] hashdocumentByte = TEST.signed_hash(hash);
PdfReader reader2 = new PdfReader(TEMP);
FileOutputStream os2 = new FileOutputStream(DEST);
ExternalSignatureContainer external2 = new
MyExternalSignatureContainer(hashdocumentByte,null);
MakeSignature.signDeferred(reader2, "sig", os2, external2);
And in the server B where i sign the hash :
BouncyCastleProvider providerBC = new BouncyCastleProvider();
Security.addProvider(providerBC);
// we load our private key from the key store
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(CERTIFICATE), PIN);
String alias = (String)ks.aliases().nextElement();
Certificate[] chain = ks.getCertificateChain(alias);
PrivateKey pk = (PrivateKey) ks.getKey(alias, PIN);
PrivateKeySignature signature = new PrivateKeySignature(pk, "SHA256", null);
BouncyCastleDigest digest = new BouncyCastleDigest();
Calendar cal = Calendar.getInstance();
String hashAlgorithm = signature.getHashAlgorithm();
System.out.println(hashAlgorithm);
PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
byte[] extSignature = signature.sign(sh);
System.out.println(signature.getEncryptionAlgorithm());
sgn.setExternalDigest(extSignature, null, signature.getEncryptionAlgorithm());
return sgn.getEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS);
Your signDocument method apparently does not accept a pre-calculated hash value but seems to calculate the hash of the data you give it, in your case the (lower case) hex presentation of the hash value you already calculated.
In your first example document you have these values (all hashes are SHA256 hashes):
Hash of the byte ranges to sign:
91A9F5EBC4F2ECEC819898824E00ECD9194C3E85E4410A3EFCF5193ED7739119
Hash of "91a9f5ebc4f2ecec819898824e00ecd9194c3e85e4410a3efcf5193ed7739119".getBytes():
2F37FE82F4F71770C2B33FB8787DE29627D7319EE77C6B5C48152F6E420A3242
Hash value signed by the embedded signature container:
2F37FE82F4F71770C2B33FB8787DE29627D7319EE77C6B5C48152F6E420A3242
And in your first example document you have these values (all hashes also are SHA256 hashes):
Hash of the byte ranges to sign:
79793C58489EB94A17C365445622B7F7945972A5A0BC4C93B6444BEDFFA5A5BB
Hash of "79793c58489eb94a17c365445622b7f7945972a5a0bc4c93b6444bedffa5a5bb".getBytes():
A8BCBC6F9619ECB950864BFDF41D1B5B7CD33D035AF95570C426CF4B0405949B
Hash value signed by the embedded signature container:
A8BCBC6F9619ECB950864BFDF41D1B5B7CD33D035AF95570C426CF4B0405949B
Thus, you have to correct your signDocument method to interpret the data correctly, or you have to give it a byte array containing the whole range stream to digest.
I am trying to add public key string in MakeSignature.SignExternalContainer but having error,
string sing_test = "MIIFMTCCBBmgAwIBAgICMF8wDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCSU4xKjAoBgNVBAoTIU5TREwgZS1Hb3YgSW5mcmFzdHJ1Y3R1cmUgTGltaXRlZDEdMBsGA1UECxMUQ2VydGlmeWluZyBBdXRob3JpdHkxIjAgBgNVBAMTGU5TRExlR292SXNzdWluZ0NBMjAxNlRlc3QwHhcNMTcwMTI4MDkwOTEzWhcNMTcwMTI4MDkzODEzWjCCARgxCzAJBgNVBAYTAklOMR0wGwYDVQQDExRNQU5JU0ggR0lSSVNIIEJFTkRSRTEpMCcGA1UEQRMgMjUxYjkyYjkxZjllNDBmOGE2YmVlZjZiMDgyMzYyZGYxNjA0BgNVBC0DLQBsbnlOOVVuNzE5S1NKNnpaQVNtUGZaUlJpYTVuTXBLSEV0cs3ZidAmwZQKbBmUKLoeD8nCDIUZZR9Am2pwSnar7WtB2MA74Sz4U2xzifNsh22YPd+ySbGqJtUd9xbhlQIDAQABo4IBHTCCARkwEQYDVR0OBAoECEwFNGCDXdKgMIG7BgNVHSAEgbMwgbAwga0GB2CCZGQCBAIwgaEwQQYIKwYBBQUHAgEWNWh0dHBzOi8vbnNkbC5lZ292LWNhLmNvLmluL3JlcG9zaXRvcnkvbnNkbGVnb3ZjcHMucGRmMFwGCCsGAQUFBwICMFAaTkFhZGhhYXIgZS1LWUMtQmlvbWV0cmljIENsYXNzIENlcnRpZmljYXRlIElzc3VlZCBieSBOU0RMIGUtR292IElzc3VpbmcgQ0EgVGVzdDAhBgNVHREEGjAYgRZtYW5pc2hiZW5kcmVAZ21haWwuY29tMBMGA1UdIwQMMAqACEBuFJI2LqIcMA4GA1UdDwEB/wQEAwIGwDANBgkqhkiG9w0BAQsFAAOCAQEADbuOkgWKquflIrqDsB93L5aa+VxjFHvB914UDIllO4MYTo/UVgDN2iANiJ2HOjFkY0VhdnuJKp0cjDSywP6mTXs0VUf70DEL5sZpjfnoJK++Eb6FlDHHMKflMkG/ja3b6FWK1W/1L0/yjYpjl4E2Uu5tq0T3k4ZOPd/LBD3OeudKZM1IPaT95Zd8JRqwz6LsyYx1SvXqLtrRUb8eIauvAJ92prvovxusvupzolB3AOCkwEr6jqGXOiwssEnqUCuUd3CVXWUxL5TzWW9oCPIDAKbUyyVWtntorVFfKmzvWDCV42jkHrf9J1snbr4DyjNhkOSQr6cDZfg0uK2gKWfBcA==";
byte[] rawData = System.Convert.FromBase64String(sing_test );
public static byte[] GetBytesToSign(string unsignedPdf, string tempPdf, string signatureFieldName)
{
using (PdfReader reader = new PdfReader(unsignedPdf))
{
using (FileStream os = File.OpenWrite(tempPdf))
{
PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0');
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(36, 748, 144, 780), 1, signatureFieldName);
IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKMS, PdfName.ADBE_PKCS7_SHA1);
MakeSignature.SignExternalContainer(appearance, external, 8192);
stamper.Close();
return SHA1Managed.Create().ComputeHash(appearance.GetRangeStream());
}
}
}
public static void EmbedSignature(string tempPdf, string signedPdf, string signatureFieldName, byte[] signedBytes)
{
using (PdfReader reader = new PdfReader(tempPdf))
{
using (FileStream os = File.OpenWrite(signedPdf))
{
PdfStamper st = PdfStamper.CreateSignature(reader, os, '\0', null, true);
PdfSignatureAppearance sap = st.SignatureAppearance;
sap.Reason = "Testing";
sap.Location = "Test";
sap.SetVisibleSignature(new iTextSharp.text.Rectangle(250, 50, 50, 100), 1, null);
IExternalSignatureContainer external = new MyExternalSignatureContainer(signedBytes);
try
{
MakeSignature.SignExternalContainer(sap, external, 8192);
}
catch (Exception ex) { }
st.Close();
}
}
}
private class MyExternalSignatureContainer : IExternalSignatureContainer
{
private readonly byte[] signedBytes;
public MyExternalSignatureContainer(byte[] signedBytes)
{
this.signedBytes = signedBytes;
}
public byte[] Sign(Stream data)
{
return signedBytes;
}
public void ModifySigningDictionary(PdfDictionary signDic)
{
}
}
getting error..
Error during signature verification.
Error encountered while BER decoding:
Thanks...
I am working on iphone push notification. I can able to get my device token. I am using .net for pushing json data. But the issue is i cant get the notification. I just want to know whether .net has to push json data over in hosted machine?
Regards,
sathish
I believe that is related to:
Add iPhone push notification using ASP.NET server
Read through the linked project in there. It is pretty comprehensive. You can actually just use that library... it is pretty good.
Unless I misunderstood the question?
Use following snippet to send Push Notification
public void PendingNotification(string DeviceToken,string message)
{
try
{
int port = 2195;
//Developer
String hostname = "gateway.sandbox.push.apple.com";
//Production
//String hostname = "gateway.push.apple.com";
String certificatePassword = "XXXXXXX";
string certificatePath = Server.MapPath("~/cer.p12");
TcpClient client = new TcpClient(hostname, port);
X509Certificate2 clientCertificate = new X509Certificate2(System.IO.File.ReadAllBytes(certificatePath), certificatePassword);
X509Certificate2Collection certificatesCollection = new X509Certificate2Collection(clientCertificate);
SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
sslStream.AuthenticateAsClient(hostname, certificatesCollection, SslProtocols.Tls, false);
//String DeviceToken = "XXXXXXXXXXXX";
String LoginName = "Name";
int Counter = 1; //Badge Count;
String Message = message;
String UID = "your choice UID";
string payload = "{\"aps\":{\"alert\":\"" + Message + "\",\"badge\":" + Counter + ",\"sound\":\"default\"},\"UID\":\"" + UID + "\",\"LoginName\":\"" + LoginName + "\"}";
MemoryStream memoryStream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(memoryStream);
writer.Write((byte)0);
writer.Write((byte)0);
writer.Write((byte)32);
writer.Write(HexStringToByteArray(DeviceToken.ToUpper()));
writer.Write((byte)0);
writer.Write((byte)payload.Length);
byte[] b1 = System.Text.Encoding.UTF8.GetBytes(payload);
writer.Write(b1);
writer.Flush();
byte[] array = memoryStream.ToArray();
sslStream.Write(array);
}
catch (Exception ex)
{
//Response.Write(ex.Message);
}
}
public static byte[] HexStringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
return false;
}