Le forum (ô combien francophone) des utilisateurs de Powerbuilder.
Bonjour,
Je cherche à signer les pdf dans powerbuilder.
Pour ce faire , je suis partie sur la piste de ItextSharp (http://sourceforge.net/projects/itextsharp/)
J'ai récupéré une application en C#, j'en ai extrait le code qui m'intéresse et j'ai compilé le tout en com assembly que j'ai enregistré avec regsam.
Mon problème est que le connecttonewobject me retourne toujours -3
J'ai mis le code c#, je tiens à préciser que je suis une bille en C#
J'ai du louper un truc a moins que Pb 11.5 ne fonctionne pas avec les assembly donet
Quelqu'un a-t-il déjà signer un pdf avec PB ?
Code PB
oleobject loo integer li_rc string ls_orgfilename, ls_encfilename string ls_orgpathname, ls_encpathname string ls_extension = "PDF" string ls_filter = "PDF files (*.pdf),*.pdf" IF GetFileOpenName ( "Select PDF file to encrypt", ls_orgpathname, ls_orgfilename, ls_extension, ls_filter ) = 1 THEN IF GetFileSaveName ( "Specify filename for encrypted file", ls_encpathname, ls_encfilename, ls_extension, ls_filter ) = 1 THEN loo = create oleobject li_rc = loo.ConnectToNewObject ( "ItextWrapper2.ItextWrapper2" ) Messagebox('test',string(li_rc)) // loo.encrypt ( ls_orgpathname, ls_encpathname ) // loo.DisconnectObject() destroy loo END IF END IF
Code c#
using System; using System.Collections.Generic; using System.IO; using iTextSharp.text; using iTextSharp.text.pdf; using iTextSharp.text.pdf.security; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.Security; using Org.BouncyCastle.X509; namespace ItextWrapper2 { public class ItextWrapper2 { public string KEYSTORE = @"C:\Users\ydulondel\AppData\Roaming\Adobe\Acrobat\11.0\Security\narval.pfx"; public string KEYSTORE_PUB = @"D:\test\pub\CertExchangenarval.fdf"; // public const String KEYSTORE = @"..\..\resources\text\pdf\signature\ds-ks\cert2.pfx"; public string PASSWORD = "password"; // public const String Src = @"..\..\resources\text\pdf\signature\xfa.pdf"; public string Src; public string Dst; public const string HashAlg = "SHA1"; public const string SignAlg = "SHA-1withRSA"; private class SignatureDTO { public byte[] Hash { get; set; } public PdfSignatureAppearance SignatureAppearance { get; set; } public PdfPKCS7 Sign { get; set; } public DateTime Now { get; set; } public Stream Stream { get; set; } } private AsymmetricKeyEntry LoadCertificateChainFromKeyStorage() { MemoryStream ks = new MemoryStream(); using (FileStream reader = new FileStream(KEYSTORE, FileMode.Open)) { byte[] buffer = new byte[reader.Length]; reader.Read(buffer, 0, (int)reader.Length); ks.Write(buffer, 0, buffer.Length); ks.Position = 0; } Pkcs12Store store = new Pkcs12Store(ks, PASSWORD.ToCharArray()); String alias = ""; List<X509Certificate> chain = new List<X509Certificate>(); // searching for private key foreach (string al in store.Aliases) { if (store.IsKeyEntry(al) && store.GetKey(al).Key.IsPrivate) { alias = al; break; } } foreach (X509CertificateEntry c in store.GetCertificateChain(alias)) // may be return too chain.Add(c.Certificate); AsymmetricKeyEntry pk = store.GetKey(alias); return pk; //return chain; } public void SignTest(String pKeyStore, String pKeyStorePub, String pPassword, String pPdf, String pSignPdf) { this.KEYSTORE = pKeyStore; this.KEYSTORE_PUB = pKeyStorePub; this.PASSWORD = pPassword; this.Src = pPdf; this.Dst = pSignPdf; SignatureDTO result = ServerSidePrepare(); byte[] signedData = ClientSideSign(result.Hash); SaveSignedDocumentOnServer(result, signedData); } private SignatureDTO ServerSidePrepare() { // get public key chain X509Certificate cert = new X509CertificateParser().ReadCertificate( File.ReadAllBytes(KEYSTORE_PUB)); // сервер у нас и так имеет публичный ключ пользователя PdfReader reader = new PdfReader(Src); // считаем что файл перед подписью есть на сервере // MemoryStream ms = new MemoryStream(); // var ms = File.Create(Dst); FileStream os = new FileStream(Dst, FileMode.Create); PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0'); PdfSignatureAppearance sap = stamper.SignatureAppearance; sap.Reason = "reason"; sap.Location = "location"; sap.Certificate = cert; sap.SetVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig"); PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED); dic.Reason = sap.Reason; dic.Location = sap.Location; dic.Contact = sap.Contact; // dic.Date = new PdfDate(sap.SignDate); dic.Date = new PdfDate(new DateTime(2015, 7, 26, 17, 5, 25)); sap.CryptoDictionary = dic; Dictionary<PdfName, int> exc = new Dictionary<PdfName, int> { { PdfName.CONTENTS, 8192 * 2 + 2 } // не подписываемые данные (исключения). Зависит от того, внедрены ли CRL и ответы OCSP в документе. // PdfName.CONTENTS здесь должен быть обязательно }; sap.PreClose(exc); var sgn = new PdfPKCS7(null, new[] { cert }, HashAlg, false); Stream data = sap.GetRangeStream(); // byte[] hash = DigestAlgorithms.Digest(data, externalDigest.getMessageDigest("SHA256")); byte[] messageHash = DigestAlgorithms.Digest(data, HashAlg); // hash calculated. Sending it to client. var now = DateTime.Now; return new SignatureDTO { Hash = sgn.getAuthenticatedAttributeBytes(messageHash, now, null, null, CryptoStandard.CMS), Now = now, SignatureAppearance = sap, Sign = sgn, Stream = os }; } private byte[] ClientSideSign(byte[] hash) { AsymmetricKeyEntry pk = LoadCertificateChainFromKeyStorage(); // we sign the hash received from the server ISigner sig = SignerUtilities.GetSigner(SignAlg); sig.Init(true, pk.Key); sig.BlockUpdate(hash, 0, hash.Length); return sig.GenerateSignature(); } private void SaveSignedDocumentOnServer(SignatureDTO result, byte[] signature) { result.Sign.SetExternalDigest(signature, null, "RSA"); byte[] encodedSig = result.Sign.GetEncodedPKCS7(result.Hash, result.Now, null, null, null, CryptoStandard.CMS); byte[] paddedSig = new byte[8192]; Array.Copy(encodedSig, 0, paddedSig, 0, encodedSig.Length); PdfDictionary pdfDic = new PdfDictionary(); pdfDic.Put(PdfName.CONTENTS, new PdfString(paddedSig).SetHexWriting(true)); result.SignatureAppearance.Close(pdfDic); // use try/catch in real app } } }
Dernière modification par ydl (30-07-2015 09:45:34)
Hors ligne
Pour que ta dll soit disponible en objet com tu doit déclarer des interfaces pour chacunes de tes methodes public disponible en com via ton objet.
Il manque aussi un [ComVisible(true)] avant le début de ta classItextWrapper2 que doit récupérer le contrat d'interface.
Tu dois aussi utiliser une clé dans un fichier .snk (je ne me rappel plus trop la façon de faire car je l'ai utilisé qu'une seule fois en début d'année).
Tu peux regarder le dépôt github de ma dll com pour web services. J'ai utiliser visual studio 2012 et j'utilise la dll via une appli PB12.6 mais ça doit pas poser de problème de l'utiliser via PB 11.5.
Bref y'a encore un peu de boulot mais ça reste gentil. Une fois que ce sera fait tu pourra utiliser ta Dll via l'objet COM.
Hors ligne
est-ce que tu as bien toutes les dll des dépendances (bouncycastle etc.) à ton assembly .net accessibles par ton assembly ?
Hors ligne
En fouillant un peu , j'ai trouvé
En modifiant le code
using System; using System.Collections.Generic; using System.IO; using iTextSharp.text; using iTextSharp.text.pdf; using iTextSharp.text.pdf.security; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.Security; using Org.BouncyCastle.X509; using System.Runtime.InteropServices; namespace ItextWrapper2 { [Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")] public interface ComClass1Interface { } [Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA71"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface ComClass1Events { } [Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938"), ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(typeof(ComClass1Events))] public class ItextWrapper2 : ComClass1Interface { public string KEYSTORE =
J'ai un retour a 0 maintenant
Hors ligne
Je n'avais pas vu vos réponses.
Merci
Hors ligne