Dear @aymannagy
No need of generating hash using hashing function ?
No if You Did That it Will Give u Same Hash. You Can Test it . Just Try what i told you and u Will See but tell me if it fixed
But using the hash from signing process i am getting error âThe invoice hash API body does not match the (calculated) Hash of the XMLâ
i tried it but getting the same error
Just Try What i told you u will see
ok tell me the Steps How You Sign it ? and What you Did after Sign it
Dear i m trying this
SignResult signresult = new SignResult();
EInvoiceSigner Sign = new EInvoiceSigner();
signresult = Sign.SignDocument(xDoc, certificateContent, privateKeyContent);
List lstStepResults = new List();
lstStepResults = signresult.Steps;
xDoc = new XmlDocument();
xDoc = signresult.SignedEInvoice;;
string Invoicehash= lstStepResults[1].ResultedValue;
QRResult QRresult = new QRResult();
EInvoiceQRGenerator QRGen = new EInvoiceQRGenerator();
QRresult = QRGen.GenerateEInvoiceQRCode(xDoc);
string strNamespace_cbc = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2";
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xDoc.NameTable);
nsmgr.AddNamespace("cbc", strNamespace_cbc);
XmlNode NodeQR = xDoc.SelectSingleNode("*[local-name()='Invoice']//*[local-name()='AdditionalDocumentReference'][cbc:ID='QR']//*[local-name()='Attachment']//*[local-name()='EmbeddedDocumentBinaryObject']", nsmgr);
NodeQR.InnerText = QRresult.QR;
FinalJSON Final = new FinalJSON();
Final.invoiceHash = Invoicehash;
Final.uuid = UUID;
Final.invoice = Convert.ToBase64String(Encoding.UTF8.GetBytes(xDoc.OuterXml));
var strJson = JsonConvert.SerializeObject(Final);
Please check and advice
XmlDocument xmlDocument = new XmlDocument(); string invoice = Base64Decode(requestSignInvoiceB2B.XmlInvoice); invoice = invoice.Replace(" />", "/>"); xmlDocument.LoadXml(invoice); Zatca.EInvoice.SDK.EInvoiceSigner invoiceSigner = new Zatca.EInvoice.SDK.EInvoiceSigner(); SignResult signResult = invoiceSigner.SignDocument(xmlDocument, Base64Decode(requestSignInvoiceB2B.BinaryToken), Base64Decode(requestSignInvoiceB2B.PrivateKey)); xmlDocument.LoadXml(signResult.SignedEInvoice.InnerXml.Replace(" />", "/>")); Zatca.EInvoice.SDK.EInvoiceQRGenerator eInvoiceQRGenerator = new Zatca.EInvoice.SDK.EInvoiceQRGenerator(); string qRResult = GenerateQRCode(xmlDocument); string ReplaceString = GetNodeInnerText(xmlDocument, "//*[local-name()='AdditionalDocumentReference'][cbc:ID[normalize-space(text())='QR']]"); string FixedXML = signResult.SignedEInvoice.InnerXml; FixedXML = FixedXML.Replace(ReplaceString, qRResult); xmlDocument.LoadXml(FixedXML); Zatca.EInvoice.SDK.EInvoiceHashGenerator invoiceHashGenerator = new Zatca.EInvoice.SDK.EInvoiceHashGenerator(); HashResult hashResult = invoiceHashGenerator.GenerateEInvoiceHashing(xmlDocument); //var t = signResult.Steps.Where(x => x.StepName == "Generate EInvoice Hash").FirstOrDefault(); // FixedXML = FixedXML.Replace(t.ResultedValue, hashResult.Hash); xmlDocument.LoadXml(FixedXML); Models.ReciveSingDocument reciveSingDocument = new Models.ReciveSingDocument(); reciveSingDocument.Hash = hashResult.Hash; reciveSingDocument.SignDocumentBase64 = Base64Encode(xmlDocument.InnerXml); reciveSingDocument.QR = qRResult; reciveSingDocument.SignDocument = xmlDocument.InnerXml; //System.IO.File.WriteAllText(@"D:\AYman\Output\InoviceSingied.txt", xmlDocument.InnerXml); //System.IO.File.WriteAllText(@"D:\AYman\Output\InoviceBase64Singied.txt", reciveSingDocument.SignDocumentBase64); //System.IO.File.WriteAllText(@"D:\AYman\Output\Hash.txt", reciveSingDocument.Hash); //System.IO.File.WriteAllText(@"D:\AYman\Output\QR.txt", reciveSingDocument.QR); return JsonConvert.SerializeObject(reciveSingDocument);
Here you are generating hash separately in your code right ?
Zatca.EInvoice.SDK.EInvoiceHashGenerator invoiceHashGenerator = new Zatca.EInvoice.SDK.EInvoiceHashGenerator();
HashResult hashResult = invoiceHashGenerator.GenerateEInvoiceHashing(xmlDocument);
Can you please share the code of QR code generation ?
its Just to Save Hash but im not replace it
private static readonly string XpathSellerName = â/[local-name() = âInvoiceâ]/[local-name() = âAccountingSupplierPartyâ]/[local-name() = âPartyâ]/[local-name() = âPartyLegalEntityâ]//*[local-name() = âRegistrationNameâ]â;
private static readonly string XpathVatRegisteration = â/[local-name() = âInvoiceâ]/[local-name() = âAccountingSupplierPartyâ]/[local-name() = âPartyâ]/[local-name() = âPartyTaxSchemeâ]/*[local-name() = âCompanyIDâ]â;
private static readonly string XpathInvoiceTotal = â/[local-name() = âInvoiceâ]/[local-name() = âLegalMonetaryTotalâ]/*[local-name() = âTaxInclusiveAmountâ]â;
private static readonly string XpathPayableAmount = â/[local-name() = âInvoiceâ]/[local-name() = âLegalMonetaryTotalâ]/*[local-name() = âPayableAmountâ]â;
private static readonly string XpathVatTotal = â/[local-name() = âInvoiceâ]/[local-name() = âTaxTotalâ]/*[local-name() = âTaxAmountâ]â;
private static readonly string CERTIFICATE_XPATH = â/[local-name() = âInvoiceâ]/[local-name() = âUBLExtensionsâ]/[local-name() = âUBLExtensionâ]/[local-name() = âExtensionContentâ]/[local-name() = âUBLDocumentSignaturesâ]/[local-name() = âSignatureInformationâ]/[local-name() = âSignatureâ]/[local-name() = âKeyInfoâ]/[local-name() = âX509Dataâ]/[local-name() = âX509Certificateâ]â;
private static readonly string XpathSignature = â/[local-name() = âInvoiceâ]/[local-name() = âUBLExtensionsâ]/[local-name() = âUBLExtensionâ]/[local-name() = âExtensionContentâ]/[local-name() = âUBLDocumentSignaturesâ]/[local-name() = âSignatureInformationâ]/[local-name() = âSignatureâ]/[local-name() = âSignatureValueâ]â;private static readonly string XpathQR = â/[local-name() = âInvoiceâ]/[local-name() = âAdditionalDocumentReferenceâ and [local-name()=âIDâ and .=âQRâ]]/[local-name() = âAttachmentâ]/*[local-name() = âEmbeddedDocumentBinaryObjectâ]â;
private static readonly string XpathHash = â/[local-name() = âInvoiceâ]/[local-name() = âUBLExtensionsâ]/[local-name() = âUBLExtensionâ]/[local-name() = âExtensionContentâ]/[local-name() = âUBLDocumentSignaturesâ]/[local-name() = âSignatureInformationâ]/[local-name() = âSignatureâ]/[local-name() = âSignedInfoâ]/[local-name() = âReferenceâ and @Id=âinvoiceSignedDataâ]/[local-name() = âDigestValueâ]â;
private static readonly string XpathUuid = â//[local-name()=âInvoiceâ]//[local-name()=âUUIDâ]â;
private static readonly string XpathPih = â/[local-name() = âInvoiceâ]/[local-name() = âAdditionalDocumentReferenceâ and [local-name()=âIDâ and .=âPIHâ]]/[local-name() = âAttachmentâ]/[local-name() = âEmbeddedDocumentBinaryObjectâ]";
private static readonly string ISSUE_DATE_XPATH = "/[local-name() = âInvoiceâ]/*[local-name() = âIssueDateâ]â;private static readonly string ISSUE_TIME_XPATH = â/[local-name() = âInvoiceâ]/[local-name() = âIssueTimeâ]â;
private static SortedDictionary<int, byte> GetInvoiceDetails(XmlDocument Invoice)
{
return new SortedDictionary<int, byte>
{
{
1,
Encoding.UTF8.GetBytes(GetNodeInnerText(Invoice,XpathSellerName))
},
{
2,
Encoding.UTF8.GetBytes(GetNodeInnerText(Invoice,XpathVatRegisteration))
},
{
3,
Encoding.UTF8.GetBytes( GetDateTime(GetNodeInnerText(Invoice,ISSUE_DATE_XPATH),GetNodeInnerText(Invoice,ISSUE_TIME_XPATH)))
},
{
4,
Encoding.UTF8.GetBytes(GetNodeInnerText(Invoice,XpathPayableAmount))
},
{
5,
Encoding.UTF8.GetBytes(GetNodeInnerText(Invoice,XpathVatTotal))
},
{
6,
Encoding.UTF8.GetBytes(GetNodeInnerText(Invoice,XpathHash))
},
{
7,
Encoding.UTF8.GetBytes(GetNodeInnerText(Invoice,XpathSignature))
}
};
}
private static void TryGetPublicKeySByteArray(string certificate, out byte publicKey, out byte certificateSignature)
{Org.BouncyCastle.X509.X509Certificate certificate2 = Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(new X509Certificate2(Convert.FromBase64String(certificate))); publicKey = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(certificate2.GetPublicKey()).GetEncoded(); certificateSignature = certificate2.GetSignature();
}
private static void WriteLength(MemoryStream stream, int? length)
{
if (!length.HasValue)
{
stream.WriteByte(0x80);
}
else
{
int? nullable = length;
int num2 = 0;
if (!(nullable.GetValueOrDefault() < num2 & nullable.HasValue))
{
nullable = length;
long? nullable2 = nullable.HasValue ? new long?(nullable.GetValueOrDefault()) : null;
long num3 = 0xffff_ffff;
if (!(nullable2.GetValueOrDefault() > num3 & nullable2.HasValue))
{
nullable = length;
num2 = 0x7f;
if (nullable.GetValueOrDefault() <= num2 & nullable.HasValue)
{
stream.WriteByte((byte)length.Value);
}
else
{
byte num;
nullable = length;
num2 = 0xff;
if (nullable.GetValueOrDefault() <= num2 & nullable.HasValue)
{
num = 1;
}
else
{
nullable = length;
num2 = 0xffff;
if (nullable.GetValueOrDefault() <= num2 & nullable.HasValue)
{
num = 2;
}
else
{
nullable = length;
num2 = 0xff_ffff;
if (nullable.GetValueOrDefault() <= num2 & nullable.HasValue)
{
num = 3;
}
else
{
nullable = length;
nullable2 = nullable.HasValue ? new long?(nullable.GetValueOrDefault()) : null;
num3 = 0xffff_ffff;
if (!(nullable2.GetValueOrDefault() <= num3 & nullable2.HasValue))
{
throw new Exception($â[Error] Length value too big: {length}â);
}
num = 4;
}
}
}
stream.WriteByte((byte)(num | 0x80));
for (int i = num - 1; i >= 0; iâ)
{
nullable = length;
num2 = 8 * i;
int? nullable4 = nullable.HasValue ? new int?(nullable.GetValueOrDefault() >> (num2 & 0x1f)) : null;
byte num5 = (byte)nullable4.Value;
stream.WriteByte(num5);
}
}
return;
}
}
throw new Exception($â[Error] Invalid length value: {length}â);
}
}
private static void WriteTag(MemoryStream stream, uint tag)
{
bool flag = true;
for (int i = 3; i >= 0; iâ)
{
byte num2 = (byte)(tag >> 8 * i);
if (!(num2 == 0 & flag) || i <= 0)
{
if (flag)
{
if (i != 0)
{
if ((num2 & 0x1f) != 0x1f)
{
throw new Exception(â[Error] Invalid tag value: first octet indicates no subsequent octets, but subsequent octets foundâ);
}
}
else if ((num2 & 0x1f) == 0x1f)
{
throw new Exception(â[Error] Invalid tag value: first octet indicates subsequent octets, but no subsequent octets foundâ);
}
}
else if (i == 0)
{
if ((num2 & 0x80) == 0x80)
{
throw new Exception(â[Error] Invalid tag value: last octet indicates subsequent octetsâ);
}
}
else if ((num2 & 0x80) != 0x80)
{
throw new Exception(â[Error] Invalid tag value: non-last octet indicates no subsequent octetsâ);
}
stream.WriteByte(num2);
flag = false;
}
}
}private static byte WriteTlv(uint tag, byte value)
{
if (value == null)
{
throw new Exception(â[Error] Please provide a value!â);
}
using MemoryStream stream = new();
WriteTag(stream, tag);
int num = value != null ? value.Length : 0;
WriteLength(stream, new int?(num));
stream.Write(value, 0, num);
return stream.ToArray();
}private static string GetDateTime(string Date, string Time)
{
if (Time.EndsWith(âZâ))
{
DateTime dateTime = DateTime.ParseExact(Date + âTâ + Time, âyyyy-MM-ddTHH:mm:ssZâ, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);
TimeZoneInfo destinationTimeZone = TimeZoneInfo.FindSystemTimeZoneById(âArab Standard Timeâ);
return TimeZoneInfo.ConvertTimeFromUtc(dateTime, destinationTimeZone).ToString(âyyyy-MM-ddTHH:mm:ssâ);
}
else
{
return DateTime.ParseExact(Date + âTâ + Time, âyyyy-MM-ddTHH:mm:ssâ, null).ToString(âyyyy-MM-ddTHH:mm:ssâ);
}}
private static string GenerateQRCodeFromValues(SortedDictionary<int, byte> invoiceDetails)
{
List data = ;
foreach (var item in invoiceDetails)
{
data.AddRange(WriteTlv((uint)item.Key, item.Value));
}
return Convert.ToBase64String(data.ToArray());
}private static string GenerateQRCode(XmlDocument invoiceObject)
{
try
{
SortedDictionary<int, byte> invoiceDetails = GetInvoiceDetails(invoiceObject);
var stringCertificate = GetNodeInnerText(invoiceObject, CERTIFICATE_XPATH);
TryGetPublicKeySByteArray(stringCertificate, out byte publicKey, out byte certificateSignature);invoiceDetails.Add(8, publicKey); invoiceDetails.Add(9, certificateSignature); return GenerateQRCodeFromValues(invoiceDetails); } catch (Exception exception) { throw new Exception("Error generating EInvoice QR Code", exception); }
}
private static string GetNodeInnerText(XmlDocument doc, string xPath)
{
XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(doc.NameTable);
xmlNamespaceManager.AddNamespace(âcacâ, âurn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2â);
xmlNamespaceManager.AddNamespace(âcbcâ, âurn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2â);
xmlNamespaceManager.AddNamespace(âextâ, âurn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2â);
XmlNode xmlNode = doc.SelectSingleNode(xPath, xmlNamespaceManager);
if (xmlNode == null)
{
return ââ;
}return xmlNode.InnerText;
}
but you are sending that hash to ZATCA right ?
The Hash That Generates From Sign.
Both of them is same
iâm getting different one
its B2C ?? replace the old Hash With New one
yes B2C invoice. Ok let me try . thank you
Dear @aymannagy
Thank you for your previous supports. I followed your instructions and checked in simulation environment now i am getting âInvalid signed properties hashing, SignedProperties with id='xadesSignedPropertiesâ as error. Please advise on this .
Did u resolve this issue of Invalid signed properties hashing, SignedProperties with id='xadesSignedProperties @anusv