Lua Requires Chilkat v11.0.0+
Lua
Create JPK VAT metadata XML
See more RSA Examples
Demonstrates how to create the JPK VAT metadata XML (InitUpload) that will be signed using XADES.Chilkat Lua Downloads
local chilkat = require("chilkat")
-- This example requires the Chilkat API to have been previously unlocked.
-- See Global Unlock Sample for sample code.
-- First build an InitUpload XML template
-- Use this online tool to generate the code from the sample XML below:
-- Generate Code to Create XML
-- <InitUpload xmlns="http://e-dokumenty.mf.gov.pl">
-- <DocumentType>JPK</DocumentType>
-- <Version>01.02.01.20160617</Version>
-- <EncryptionKey algorithm="RSA" encoding="Base64" mode="ECB" padding="PKCS#1">F9EhKFec...uWqAWUIg==</EncryptionKey>
-- <DocumentList>
-- <Document>
-- <FormCode schemaVersion="1-1" systemCode="JPK_VAT (3)">JPK_VAT</FormCode>
-- <FileName>JPK_VAT_3_v1-1_20181201.xml</FileName>
-- <ContentLength>8736</ContentLength>
-- <HashValue algorithm="SHA-256" encoding="Base64">JFDI1pItwh6dj/Xe1uts/x61qnjZ4DLHpkZMhmf1oKQ=</HashValue>
-- <FileSignatureList filesNumber="1">
-- <Packaging>
-- <SplitZip mode="zip" type="split"/>
-- </Packaging>
-- <Encryption>
-- <AES block="16" mode="CBC" padding="PKCS#7" size="256">
-- <IV bytes="16" encoding="Base64">z64oN9zXHt1+S3XACRSCYw==</IV>
-- </AES>
-- </Encryption>
-- <FileSignature>
-- <OrdinalNumber>1</OrdinalNumber>
-- <FileName>JPK_VAT_3_v1-1_20181201-000.xml.zip.aes</FileName>
-- <ContentLength>16</ContentLength>
-- <HashValue algorithm="MD5" encoding="Base64">5NX0q1935fvMjLFV7E1yDw==</HashValue>
-- </FileSignature>
-- </FileSignatureList>
-- </Document>
-- </DocumentList>
-- </InitUpload>
local xml = chilkat.Xml.new()
xml.tag = "InitUpload"
xml:add_attribute("xmlns", "http://e-dokumenty.mf.gov.pl")
xml:update_child_content("DocumentType", "JPK")
xml:update_child_content("Version", "01.02.01.20160617")
xml:update_attr_at("EncryptionKey", true, "algorithm", "RSA")
xml:update_attr_at("EncryptionKey", true, "encoding", "Base64")
xml:update_attr_at("EncryptionKey", true, "mode", "ECB")
xml:update_attr_at("EncryptionKey", true, "padding", "PKCS#1")
xml:update_child_content("EncryptionKey", "TO BE DETERMINED")
xml:update_attr_at("DocumentList|Document|FormCode", true, "schemaVersion", "1-1")
xml:update_attr_at("DocumentList|Document|FormCode", true, "systemCode", "JPK_VAT (3)")
xml:update_child_content("DocumentList|Document|FormCode", "JPK_VAT")
xml:update_child_content("DocumentList|Document|FileName", "JPK_VAT_3_v1-1_20181201.xml")
xml:update_child_content("DocumentList|Document|ContentLength", "9999")
xml:update_attr_at("DocumentList|Document|HashValue", true, "algorithm", "SHA-256")
xml:update_attr_at("DocumentList|Document|HashValue", true, "encoding", "Base64")
xml:update_child_content("DocumentList|Document|HashValue", "TO BE DETERMINED")
xml:update_attr_at("DocumentList|Document|FileSignatureList", true, "filesNumber", "1")
xml:update_attr_at("DocumentList|Document|FileSignatureList|Packaging|SplitZip", true, "mode", "zip")
xml:update_attr_at("DocumentList|Document|FileSignatureList|Packaging|SplitZip", true, "type", "split")
xml:update_attr_at("DocumentList|Document|FileSignatureList|Encryption|AES", true, "block", "16")
xml:update_attr_at("DocumentList|Document|FileSignatureList|Encryption|AES", true, "mode", "CBC")
xml:update_attr_at("DocumentList|Document|FileSignatureList|Encryption|AES", true, "padding", "PKCS#7")
xml:update_attr_at("DocumentList|Document|FileSignatureList|Encryption|AES", true, "size", "256")
xml:update_attr_at("DocumentList|Document|FileSignatureList|Encryption|AES|IV", true, "bytes", "16")
xml:update_attr_at("DocumentList|Document|FileSignatureList|Encryption|AES|IV", true, "encoding", "Base64")
xml:update_child_content("DocumentList|Document|FileSignatureList|Encryption|AES|IV", "TO BE DETERMINED")
xml:update_child_content("DocumentList|Document|FileSignatureList|FileSignature|OrdinalNumber", "1")
xml:update_child_content("DocumentList|Document|FileSignatureList|FileSignature|FileName", "JPK_VAT_3_v1-1_20181201-000.xml.zip.aes")
xml:update_child_content("DocumentList|Document|FileSignatureList|FileSignature|ContentLength", "9999")
xml:update_attr_at("DocumentList|Document|FileSignatureList|FileSignature|HashValue", true, "algorithm", "MD5")
xml:update_attr_at("DocumentList|Document|FileSignatureList|FileSignature|HashValue", true, "encoding", "Base64")
xml:update_child_content("DocumentList|Document|FileSignatureList|FileSignature|HashValue", "TO BE DETERMINED")
-- ------------------------------------------------------------
-- Step 1: Load our JPK_VAT XML and update the DocumentList|Document|HashValue
-- and DocumentList|Document|ContentLength
local bdXml = chilkat.BinData.new()
local success = bdXml:load_file("qa_data/xml_dsig/jpk_vat/JPK_VAT_3_v1-1_20181201-000.xml")
if not success then
print("Failed to load XML file.")
return
end
xml:update_child_content_int("DocumentList|Document|ContentLength", bdXml.num_bytes)
local crypt = chilkat.Crypt2.new()
crypt.hash_algorithm = "sha256"
crypt.encoding_mode = "base64"
xml:update_child_content("DocumentList|Document|HashValue", crypt:hash_bd_enc(bdXml))
-- ------------------------------------------------------------
-- Step 2: Create a Zip archive containing the XML.
local zip = chilkat.Zip.new()
-- The filename we pass here doesn't matter because we won't actually be creating a .zip file.
zip:new_zip("anything.zip")
zip:add_bd("JPK_VAT_3_v1-1_20181201-000.xml", bdXml)
-- Write the .zip file to a BinData object.
local bdZip = chilkat.BinData.new()
zip:write_bd(bdZip)
-- ------------------------------------------------------------
-- Step 3: Generate a random 256-bit AES key (32-bytes)
local prng = chilkat.Prng.new()
local bdAesKey = chilkat.BinData.new()
prng:gen_random_bd(32, bdAesKey)
local ivBytes = prng:gen_random(16, "base64")
-- Store the IV (base64 string) in the XML.
xml:update_child_content("DocumentList|Document|FileSignatureList|Encryption|AES|IV", ivBytes)
-- ------------------------------------------------------------
-- Step 4: AES encrypt our zip archive (the contents of bdZip)
crypt.cipher_mode = "cbc"
crypt.key_length = 256
crypt.crypt_algorithm = "aes"
crypt.padding_scheme = 0
crypt:set_encoded_iv(ivBytes, "base64")
crypt:set_encoded_key(bdAesKey:get_encoded("base64"), "base64")
-- AES by definition has a block size of 16.
crypt:encrypt_bd(bdZip)
-- bdZip now contains the AES encrypted data.
-- Note: This is NOT the same as a zip where the contents are AES encrypted.
-- In that case, we have an unencrypted zip structure with AES encrypted files within.
-- In our case, the entire zip file image is encrypted.
-- Save the bdZip to a file. This is what will get sent to e-dokumenty.mf.gov.pl
success = bdZip:write_file("qa_output/JPK_VAT_3_v1-1_20181201-000.xml.zip.aes")
xml:update_child_content_int("DocumentList|Document|FileSignatureList|FileSignature|ContentLength", bdZip.num_bytes)
-- ------------------------------------------------------------
-- Step 4: RSA Encrypt the AES key using the public key certificate provided by the Ministry of Finance
local cert = chilkat.Cert.new()
success = cert:load_from_file("qa_data/pem/mf_public_rsa.pem")
if not success then
print(cert.last_error_text)
return
end
local pubKey = chilkat.PublicKey.new()
cert:get_public_key(pubKey)
local rsa = chilkat.Rsa.new()
rsa:use_public_key(pubKey)
rsa.encoding_mode = "base64"
rsa.little_endian = false
-- in-place RSA encrypt the contents of bdAesKey.
rsa:encrypt_bd(bdAesKey, false)
xml:update_child_content("EncryptionKey", bdAesKey:get_encoded("base64"))
-- Step 5: We forgot to get the MD5 hash of the AES encrypted zip.
-- (I'm assuming we need the MD5 of the encrypted zip as opposed to the MD5 of the pre-encrypted zip..)
crypt.hash_algorithm = "md5"
xml:update_child_content("DocumentList|Document|FileSignatureList|FileSignature|HashValue", crypt:hash_bd_enc(bdZip))
-- At this point, the XML is prepared and the AES encrypted image of the zip file is written
-- to a file (and also in bdZip).
local finalXml = xml:get_xml()
print(finalXml)
xml:save_xml("qa_output/jpk_vat.xml")
print("Finished.")