Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Estrarre fattura da p7m con CryptDecodeMessage

584 views
Skip to first unread message

Davide La Mantia

unread,
Jan 10, 2022, 10:05:51 AM1/10/22
to
Ciao a tutti,
per acquisire automaticamente le fatture elettroniche ho scritto una funzione VBA che esegue l'estrazione.
La cosa funziona perfettamente, ma occasionalmente (ogni 6-12 mesi circa) salta fuori un nuovo flag della firma che non mi era ancora capitato e devo aggiornare la lista dei flag da rimuovere per l'estrazione.
Potrei continuare così, tanto finiranno prima o poi, tuttavia sto indagando altri metodi e ho trovato la funzione in oggetto che pare si possa usare allo scopo (link: https://resch.pro/p/vba-da-p7m-a-xml/ nb: attenzione che alla fine nel codice c'è un piccolo errore di sintassi da correggere, si vede subito).
Tuttavia l'estrazione fallisce e non ho trovato un modo per farla funzionare.

Qualcuno ha mai provato con questa funzione?

Ciao
Davide

BFS

unread,
Jan 10, 2022, 10:51:18 AM1/10/22
to
l'ho provato e funziona, anche con allegati

basta aggiungere questa funziona che in quel sorgente manca :


Function Stream_BinaryToString(sFullNameFile As String) As String
'Funzione per convertire un file da dati binari a dati di testo
'Necessario per inserire un "allegato" alla fattura elettronica
'Reperita alla seguente URL:
'https://stackoverflow.com/questions/496751/base64-encode-string-in-vbscript
Const adTypeBinary = 1 ' Binary file is encoded
' Variables for encoding
Dim objXML
Dim objDocElem
' Variable for reading binary picture
Dim objStream
' Open data stream from picture
Set objStream = CreateObject("ADODB.Stream")
objStream.Type = adTypeBinary
objStream.Open
objStream.LoadFromFile sFullNameFile
' Create XML Document object and root node
' that will contain the data
Set objXML = CreateObject("MSXml2.DOMDocument")
Set objDocElem = objXML.createElement("Base64Data")
objDocElem.DataType = "bin.base64"
' Set binary value
objDocElem.nodeTypedValue = objStream.Read()
Stream_BinaryToString = objDocElem.Text
' Clean all
Set objXML = Nothing
Set objDocElem = Nothing
Set objStream = Nothing
End Function


bfs

Davide La Mantia

unread,
Jan 10, 2022, 3:14:42 PM1/10/22
to
Il giorno lunedì 10 gennaio 2022 alle 16:51:18 UTC+1 BFS ha scritto:
> Il 10/01/2022 16:05, Davide La Mantia ha scritto:
CUT
> >ho trovato la funzione in oggetto che pare si possa usare allo scopo (link: https://resch.pro/p/vba-da-p7m-a-xml/ nb: attenzione che alla fine nel codice c'è un piccolo errore di sintassi da correggere, si vede subito).
> > Tuttavia l'estrazione fallisce e non ho trovato un modo per farla funzionare.
> >
> > Qualcuno ha mai provato con questa funzione?
> >
> > Ciao
> > Davide
> l'ho provato e funziona, anche con allegati
>
> basta aggiungere questa funziona che in quel sorgente manca :
>
>
> Function Stream_BinaryToString(sFullNameFile As String) As String
> 'Funzione per convertire un file da dati binari a dati di testo
CUT
> bfs

Grazie per la risposta!
Intendi dire che la funzione CryptDecodeMessage vuole passata la fattura codificata in Base 64?
Perchè avevo fatto attenzione a passargliela non codificata...

Comunque non funziona ancora...

Ciao
Davide

Davide La Mantia

unread,
Jan 10, 2022, 4:13:58 PM1/10/22
to
OK, confermo che non va.
la variabile che dovrebbe contenere l'output rimane tutta fatta di null

ciao

BFS

unread,
Jan 11, 2022, 1:24:28 AM1/11/22
to
creati una form chiamata maschera1

metti un pulsante comando0
metti una textbox chiamata testo1

sul click del tuo bottone metti
leggiFileFirmato "c:\blablabla\test.p7m" 'il percorso del tuo p7m

su un modulo incolla tutto questo

Option Compare Database

Const CMSG_DATA_FLAG = 2 ' Raw data with no
particular formatting
Const CMSG_SIGNED_FLAG = 4 ' Signed message
Const CMSG_ENVELOPED_FLAG = 8 ' Enveloped (encrypted) message
Const CMSG_SIGNED_AND_ENVELOPED_FLAG = 16 ' Signed and encrypted message
Const CMSG_HASHED_FLAG = 32 ' Hashed message
Const CMSG_ENCRYPTED_FLAG = 64 ' Encrypted message
Const CMSG_DATA = 1 ' Raw data with no
particular formatting
Const CMSG_SIGNED = 2 ' Signed message
Const CMSG_ENVELOPED = 3 ' Enveloped (encrypted) message
Const CMSG_SIGNED_AND_ENVELOPED = 4 ' Signed and encrypted message
Const CMSG_HASHED = 5 ' Hashed message
Const CMSG_ENCRYPTED = 6 ' Encrypted message

Const CERT_FIND_ANY = 0
Const CERT_FIND_EXISTING = &HD0000
Const CERT_FIND_ISSUER_OF = &HC0000
Const CERT_FIND_ISSUER_STR = &H70004
Const CERT_FIND_KEY_SPEC = &H90000
Const CERT_FIND_PROPERTY = &H50000
Const CERT_FIND_SUBJECT_STR = &H70007
Const X509_ASN_ENCODING = &H1 ' X.509 Encoding
Const PKCS_7_ASN_ENCODING = &H10000 ' PKCS #7 Message Formatting

Public Type CRYPT_DECRYPT_MESSAGE_PARA
cbSize As Long
dwMsgAndCertEncodingType As Long
cCertStore As Long ' hCryptProv As Long
pfnGetSignerCertificate As Long ' Pointer to callback
function HCERTSTORE *rghCertStore;
dwFlags As Long ' pvGetArg As Long ' void
Pointer
End Type

Public Type CRYPT_VERIFY_MESSAGE_PARA
cbSize As Long
dwMsgAndCertEncodingType As Long
hCryptProv As Long ' HCRYPTPROV_LEGACY hCryptProv;
pfnGetSignerCertificate As Long ' Pointer to callback
function PFN_CRYPT_GET_SIGNER_CERTIFICATE pfnGetSignerCertificate;
pvGetArg As Long ' void Pointer
End Type

Public Declare Function CryptDecodeMessage Lib "Crypt32.dll" (ByVal
dwMsgTypeFlags As Long, _
pDecryptPara As
CRYPT_DECRYPT_MESSAGE_PARA, _
pVerifyPara As
CRYPT_VERIFY_MESSAGE_PARA, _
ByVal dwSignerIndex As
Long, ByVal pbEncodedBlob As String, _
ByVal cbEncodedBlob As
Long, ByVal dwPrevInnerContentType As Long, _
pdwMsgType As Long,
pdwInnerContentType As Long, _
ByVal pbDecoded As String,
pcbDecoded As Long, _
ppXchgCert As Long,
ppSignerCert As Long) As Long

Public Function leggiFileFirmato(ByVal NomeFile As String) As String
' Funzione per leggere il contenuto di un file firmato p7m
' [NomeFile] nome del file da leggere completo di percorso
' Restituisce il contenuto del file firmato

On Error Resume Next
Dim dwMsgTypeFlags As Long, i As Long
Dim pDecryptPara As CRYPT_DECRYPT_MESSAGE_PARA
Dim pVerifyPara As CRYPT_VERIFY_MESSAGE_PARA
Dim dwSignerIndex As Long
Dim dwPrevInnerContentType As Long
Dim pdwMsgType As Long, pdwInnerContentType As Long
Dim ppXchgCert As Long, ppSignerCert As Long
Dim m_lHCryptProv As Long ' Handle for the
cryptographic service provider (CSP)

Dim messaggioFirmato As String
Dim messaggioFirmato_L As Long ' Lunghezza messaggio
Dim messaggioDecodificato As String
Dim messaggioDecodificato_L As Long

Dim iFile As Integer
iFile = FreeFile
Open NomeFile For Binary Access Read As #iFile
messaggioFirmato = Input(LOF(iFile), iFile)
Close #iFile

messaggioDecodificato = Base64Decode(messaggioFirmato) ' Verifica
codifica base64
If Err.Number <> 0 Then ' = -2147467259 "Errore durante
l'analisi di "..." come tipo di dati bin.base64."
Err.Clear
Else
messaggioFirmato = messaggioDecodificato
End If
messaggioFirmato_L = Len(messaggioFirmato) ' Lunghezza
messaggioDecodificato = String(messaggioFirmato_L, vbNullChar)
messaggioDecodificato_L = 0 'Len(messaggioDecodificato)

' strutture dati
pVerifyPara.cbSize = 20
pVerifyPara.dwMsgAndCertEncodingType = X509_ASN_ENCODING Or
PKCS_7_ASN_ENCODING '--- The encoding type
pVerifyPara.hCryptProv = m_lHCryptProv '--- The CSP handle
' -
pDecryptPara.cbSize = 16
pDecryptPara.dwMsgAndCertEncodingType =
pVerifyPara.dwMsgAndCertEncodingType 'X509_ASN_ENCODING Or
PKCS_7_ASN_ENCODING
'pDecryptPara.cCertStore = 0 '1000
pDecryptPara.dwFlags = CMSG_SIGNED_AND_ENVELOPED
pdwMsgType = CMSG_DATA_FLAG
dwMsgTypeFlags = CMSG_SIGNED_FLAG ' CMSG_DATA_FLAG
pdwInnerContentType = 0

i = CryptDecodeMessage(dwMsgTypeFlags, pDecryptPara, _
pVerifyPara, dwSignerIndex, _
messaggioFirmato, messaggioFirmato_L, _
dwPrevInnerContentType, pdwMsgType, _
pdwInnerContentType, messaggioDecodificato, _
messaggioDecodificato_L, ppXchgCert,
ppSignerCert)
i = CryptDecodeMessage(dwMsgTypeFlags, pDecryptPara, _
pVerifyPara, dwSignerIndex, _
messaggioFirmato, messaggioFirmato_L, _
dwPrevInnerContentType, pdwMsgType, _
pdwInnerContentType, messaggioDecodificato, _
messaggioDecodificato_L, ppXchgCert,
ppSignerCert)

Form_Maschera1.Testo1 = messaggioDecodificato

If Err.Number = 0 Then
leggiFileFirmato = messaggioDecodificato
End If

End Function

Function Base64Decode(ByVal vCode)
On Error Resume Next
Dim oXML, oNode
Set oXML = CreateObject(lb_XML_DOM)
Set oNode = oXML.createElement("base64")
oNode.DataType = "bin.base64"
oNode.Text = vCode
If Err.Number = 0 Then
Base64Decode = Stream_BinaryToString(oNode.nodeTypedValue)
End If
Set oNode = Nothing: Set oXML = Nothing
End Function



Function Stream_BinaryToString(sFullNameFile As String) As String
'Funzione per convertire un file da dati binari a dati di testo
premi il pulsante e vedrai che nel testo1 troverai il contenuto del tuo xml
provato con una decina di fatture con allegati e no
e funziona

BFS

Davide La Mantia

unread,
Jan 11, 2022, 8:52:44 AM1/11/22
to
CUT
> premi il pulsante e vedrai che nel testo1 troverai il contenuto del tuo xml
> provato con una decina di fatture con allegati e no
> e funziona
>
> BFS

Intanto ti ringrazio molto per la risposta completa ed esaustiva!

Controllando ho visto che sostanzialmente era lo stesso codice che già avevo, nondimeno, per evitare che mi fosse sfuggito qualcosa ho preso il tuo codice e l'ho sostituito al mio.

Il parametro lb_XML_DOM non viene riconosciuto, quindi l'ho sostituito con la stringa "MSXML2.DOMDocument"

Ad ogni modo, la fattura che sto usando per test non è codificata base64 quindi non dovrebbe avere bisogno di conversione.

Detto questo, purtroppo il risultato è lo stesso, viene restituita una stringa tutta di null (equivalente alla stringa di partenza), paro paro come se la doppia chiamata di funzione non eseguisse alcuna elaborazione, la variabile i resta uguale a zero.

La fattura in questione è una delle fatture da me ricevute che ho già importato con la mia routine, quindi è sicuramente ben formattata.

Ciao
Davide

BFS

unread,
Jan 11, 2022, 9:10:28 AM1/11/22
to
non so che dirti
io ho fatto copia incolla da quella pagina e ho aggiunto quello che ti
ho detto
e il risultato è questo


https://ibb.co/ZgkQWxv

fattura di un mio fornitore in p7m prelevata dal portale aruba estratta
perfettamente

anche con altre fatture nessun problema

BFS






Message has been deleted

Davide La Mantia

unread,
Jan 11, 2022, 9:50:04 AM1/11/22
to
Il giorno martedì 11 gennaio 2022 alle 15:10:28 UTC+1 BFS ha scritto:
> Il 11/01/2022 14:52, Davide La Mantia ha scritto:
> > Il giorno martedì 11 gennaio 2022 alle 07:24:28 UTC+1 BFS ha scritto:
> >> Il 10/01/2022 22:13, Davide La Mantia ha scritto:
> >>> Il giorno lunedì 10 gennaio 2022 alle 21:14:42 UTC+1 Davide La Mantia ha scritto:
> >>>> Il giorno lunedì 10 gennaio 2022 alle 16:51:18 UTC+1 BFS ha scritto:
> >>>>> Il 10/01/2022 16:05, Davide La Mantia ha scritto:
CUT
> > Detto questo, purtroppo il risultato è lo stesso, viene restituita una stringa tutta di null (equivalente alla stringa di partenza), paro paro come se la doppia chiamata di funzione non eseguisse alcuna elaborazione, la variabile i resta uguale a zero.
> >
> > La fattura in questione è una delle fatture da me ricevute che ho già importato con la mia routine, quindi è sicuramente ben formattata.
> >
> > Ciao
> > Davide
> non so che dirti
> io ho fatto copia incolla da quella pagina e ho aggiunto quello che ti
> ho detto
> e il risultato è questo
>
>
> https://ibb.co/ZgkQWxv
>
> fattura di un mio fornitore in p7m prelevata dal portale aruba estratta
> perfettamente
>
> anche con altre fatture nessun problema
>
> BFS

Secondo me c'è qualcosa che non va nel codice, visto che Stream_BinaryToString apre un file e lo legge, non può funzionare all'interno della funzione Base64Decode nel modo in cui è inserita.

Ti chiedo un paio di cose: la funzione Base64Decode nel codice della tua applicazione riceve come input il percorso del file o il contenuto del file?

Il parametro lb_XML_DOM da te viene riconosciuto?

La funzione CryptDecodeMessage prende come input messaggioFirmato il file in chiaro o il file codificato in base64?

Il file in chiaro se lo visualizzi contiene fondamentalmente tutti i caratteri del file xml condito con tutti i marcatori della firma, quello in base 64 è una sequenza indistinta di lettere e numeri...

Ciao
Davide

BFS

unread,
Jan 11, 2022, 10:43:48 AM1/11/22
to
fai finta che non abbia scritto nulla
leggevo un file che non centrava nulla
ti confermo che il codice riportato nel sito non funziona

BFS

Davide La Mantia

unread,
Jan 11, 2022, 11:51:27 AM1/11/22
to
Nessun problema, mi è servito come spunto di riflessione...
Il fatto è anche che trovo documentazione piuttosto vaga sulla funzione Cryptdecodemessage, quindi non posso neanche vedere se i parametri di input siano corretti.

Ciao
Davide

RobertoA

unread,
Jan 11, 2022, 12:18:58 PM1/11/22
to
Hai provato a scrivere all'autore di quell'articolo chiedendo informazioni?
Magari la soluzione dell'inghippo e' dietro l'angolo

Simone Calligaris

unread,
Jan 11, 2022, 12:34:56 PM1/11/22
to
Certo: è la soluzione che adotto da anni e funziona perfettamente!

Saluti

P:S: Scherzavo ... confermo che non va: un vero peccato.




Message has been deleted

shado gps

unread,
Jan 11, 2022, 2:02:08 PM1/11/22
to
I

funziona perfettamente.

es : https://shadoware.it/test/fatt_p7m.zip

Davide La Mantia

unread,
Jan 11, 2022, 5:19:23 PM1/11/22
to
No, non funziona.
Anche la tua funzione, che poi è identica alla mia, restituisce una stringa di null.

Ciao

Davide La Mantia

unread,
Jan 11, 2022, 5:21:52 PM1/11/22
to
Non ho trovato email sul sito, solo un link a linkedin.

Ciao

RobertoA

unread,
Jan 12, 2022, 4:15:51 AM1/12/22
to
Io ho provato il file FATT_P7M.ZIP e coi p7m che ho a disposizione
funziona perfettamente, ho provato sia file vecchi del 2019 che roba
recente del 2021
Dove per 'funziona' intendo dire che dentro la testo1 vengono
visualizzate le righe dell'xml scelto

Davide La Mantia

unread,
Jan 12, 2022, 8:25:47 AM1/12/22
to
Ciao Roberto,
visto che a me continua a dare una stringa di null (non poteva essere diversamente visto che la funzione dell'esempio è identica a lla mia che avevo già testato), puoi dirmi che configurazione hai?
Che versione di Access, SO, ecc
Le fatture che importi, sono codificate Base64?

Ciao

RobertoA

unread,
Jan 12, 2022, 10:20:22 AM1/12/22
to
Win10 64bit, Office 2013 32 bit
Le fatture sono i file che ricevo via sdi Agenzia Entrate
Per a codifica file Base64 non saprei, sono i file ricevuti direttamente
dallo sdi Agenzia Entrate, se mi indichi come capirlo posso confermare o
negare
Ho provato con almeno una ventina di questi file, di date diverse, e la
procedura non ha sbagliato un colpo, nel senso che me le ha visualizzate
tutte nella textbox
Quando parlo di 'procedura' intendo il file contenuto in
https://shadoware.it/test/fatt_p7m.zip

Davide La Mantia

unread,
Jan 12, 2022, 1:25:42 PM1/12/22
to
Non vorrei che fosse perchè sto usanto Access a 64 Bit...
Ora provo su access a 32

Comunque verificare se è codificata base 64 è facilissimo: apri la fattura col notepad, se è una sequenza continua di lettere apparentemente alla rinfusa allora è codificata base64.

Ciao

RobertoA

unread,
Jan 12, 2022, 2:10:14 PM1/12/22
to
Questo e' il formato p7m che mi arrivano
Aperto con Notepad++

https://ibb.co/ZJZmrF5

Inizia con vari caratteri di controllo, poi si vede il testo come un xml
classico

Davide La Mantia

unread,
Jan 12, 2022, 2:23:56 PM1/12/22
to
Il giorno mercoledì 12 gennaio 2022 alle 20:10:14 UTC+1 RobertoA ha scritto:
> Il 12/01/2022 19:25, Davide La Mantia ha scritto:
CUT
> > Non vorrei che fosse perchè sto usanto Access a 64 Bit...
> > Ora provo su access a 32
> >
> > Comunque verificare se è codificata base 64 è facilissimo: apri la fattura col notepad, se è una sequenza continua di lettere apparentemente alla rinfusa allora è codificata base64.
> >
> > Ciao
> Questo e' il formato p7m che mi arrivano
> Aperto con Notepad++
>
> https://ibb.co/ZJZmrF5
>
> Inizia con vari caratteri di controllo, poi si vede il testo come un xml
> classico

Il file che mostri non è codificato base64, avresti una cosa tipo:

agHFSDHWRJWErhHFJFDgsdfhsgfJSDFHERHTERJEWRHOWEHJJdfrbteuer

e così via

Ad ogni modo ho verificato che su access 32 bit la funzione funziona ;-) e quindi la cosa diventa interessante.

Resta da capire come farla funzionare su Access a 64 bit

Ciao

Simone Calligaris

unread,
Jan 12, 2022, 3:24:25 PM1/12/22
to

> Ad ogni modo ho verificato che su access 32 bit la funzione funziona ;-) e quindi la cosa diventa interessante.
>
> Resta da capire come farla funzionare su Access a 64 bit


Premetto che ho testato solo la versione da te recuperata (coincidente con quella di Shado?).
Esiti:

Access 64 bit ----> Null
Access2003 ----> Null (l'unica versione che ho su questo PC).

Quindi, pare che non vada su tutte le release a 32 bit, pur tenendo conto dell'antichità di A '2003.
Su quale versione l'hai provato?

Saluti

Davide La Mantia

unread,
Jan 12, 2022, 3:29:21 PM1/12/22
to
Access 365 (2019) 32 bit e ha funzionato
Access 365 (2019) 64 bit, restituisce stringa di null

Sto cercando informazioni sull'adattamento delle api a VBA 64 bit, sto provando con LongPtr al posto dei Long, ma ancora niente


Ciao

@Alex

unread,
Jan 14, 2022, 7:49:20 AM1/14/22
to
Vedi se questo ti aiuta:

https://stackoverflow.com/questions/40748130/adapt-crypto-api-vba-to-use-with-access-2010-64-bit

Ovviamente se gestisci in compilazione condizionale devi rendere condizionale anche i TypeStructure ecc... ma il codice esposto mi pare già estremamente chiaro.

Ciao
@Alex

Davide La Mantia

unread,
Feb 3, 2022, 8:12:13 PM2/3/22
to
Grazie del suggerimento.
Purtroppo ho già fatto ogni possibile modifica per adattarlo alla versione 64 bit (PtrSafe, LongPtr, ecc) ma continua a funzionare perfettamente su 32 bit e a non funzionare su access 64 bit...

Ciao

Antonino Accardo

unread,
Mar 9, 2023, 6:20:06 PM3/9/23
to
Buonasera, ho il tuo stesso problema, tu hai risolto in qualche modo?

Ciao

Davide La Mantia

unread,
Mar 12, 2023, 1:38:04 PM3/12/23
to
Il giorno venerdì 10 marzo 2023 alle 00:20:06 UTC+1 Antonino Accardo ha scritto:
CUT
> >
> > Ciao
> Buonasera, ho il tuo stesso problema, tu hai risolto in qualche modo?

Ciao Antonio,
in effetti no, quel codice non ne vuole sapere di funzionare su Access a 64 bit, mi sembra un grosso limite ma al momento non ho novità.
Vado col mio personale estrattore che finora ha funzionato benissimo.

Ciao

Antonino Accardo

unread,
Mar 23, 2023, 7:05:05 PM3/23/23
to
Cosa usi? Estrae anche le fatture firmate il cui file xml è codificato base64? Io ho riscontrato alcune fatture che sono così e con la funzione CryptDecodeMessage a 32bit e qualche modifica al codice, sono riuscito ad estrarre il file xml corretto.
Ora che a 64bit non funziona più niente, non riesco a trovare alternativa in VBA, quindi penso di utilizzare openssl.
Consigli?
Ciao
0 new messages