Sample code for 30+ languages & platforms
Go Requires Chilkat v11.0.0+

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 Go Downloads

Go
    success := false

    //  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>

    xml := chilkat.NewXml()
    xml.SetTag("InitUpload")
    xml.AddAttribute("xmlns","http://e-dokumenty.mf.gov.pl")
    xml.UpdateChildContent("DocumentType","JPK")
    xml.UpdateChildContent("Version","01.02.01.20160617")
    xml.UpdateAttrAt("EncryptionKey",true,"algorithm","RSA")
    xml.UpdateAttrAt("EncryptionKey",true,"encoding","Base64")
    xml.UpdateAttrAt("EncryptionKey",true,"mode","ECB")
    xml.UpdateAttrAt("EncryptionKey",true,"padding","PKCS#1")
    xml.UpdateChildContent("EncryptionKey","TO BE DETERMINED")
    xml.UpdateAttrAt("DocumentList|Document|FormCode",true,"schemaVersion","1-1")
    xml.UpdateAttrAt("DocumentList|Document|FormCode",true,"systemCode","JPK_VAT (3)")
    xml.UpdateChildContent("DocumentList|Document|FormCode","JPK_VAT")
    xml.UpdateChildContent("DocumentList|Document|FileName","JPK_VAT_3_v1-1_20181201.xml")
    xml.UpdateChildContent("DocumentList|Document|ContentLength","9999")
    xml.UpdateAttrAt("DocumentList|Document|HashValue",true,"algorithm","SHA-256")
    xml.UpdateAttrAt("DocumentList|Document|HashValue",true,"encoding","Base64")
    xml.UpdateChildContent("DocumentList|Document|HashValue","TO BE DETERMINED")
    xml.UpdateAttrAt("DocumentList|Document|FileSignatureList",true,"filesNumber","1")
    xml.UpdateAttrAt("DocumentList|Document|FileSignatureList|Packaging|SplitZip",true,"mode","zip")
    xml.UpdateAttrAt("DocumentList|Document|FileSignatureList|Packaging|SplitZip",true,"type","split")
    xml.UpdateAttrAt("DocumentList|Document|FileSignatureList|Encryption|AES",true,"block","16")
    xml.UpdateAttrAt("DocumentList|Document|FileSignatureList|Encryption|AES",true,"mode","CBC")
    xml.UpdateAttrAt("DocumentList|Document|FileSignatureList|Encryption|AES",true,"padding","PKCS#7")
    xml.UpdateAttrAt("DocumentList|Document|FileSignatureList|Encryption|AES",true,"size","256")
    xml.UpdateAttrAt("DocumentList|Document|FileSignatureList|Encryption|AES|IV",true,"bytes","16")
    xml.UpdateAttrAt("DocumentList|Document|FileSignatureList|Encryption|AES|IV",true,"encoding","Base64")
    xml.UpdateChildContent("DocumentList|Document|FileSignatureList|Encryption|AES|IV","TO BE DETERMINED")
    xml.UpdateChildContent("DocumentList|Document|FileSignatureList|FileSignature|OrdinalNumber","1")
    xml.UpdateChildContent("DocumentList|Document|FileSignatureList|FileSignature|FileName","JPK_VAT_3_v1-1_20181201-000.xml.zip.aes")
    xml.UpdateChildContent("DocumentList|Document|FileSignatureList|FileSignature|ContentLength","9999")
    xml.UpdateAttrAt("DocumentList|Document|FileSignatureList|FileSignature|HashValue",true,"algorithm","MD5")
    xml.UpdateAttrAt("DocumentList|Document|FileSignatureList|FileSignature|HashValue",true,"encoding","Base64")
    xml.UpdateChildContent("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
    bdXml := chilkat.NewBinData()
    success = bdXml.LoadFile("qa_data/xml_dsig/jpk_vat/JPK_VAT_3_v1-1_20181201-000.xml")
    if success != true {
        fmt.Println("Failed to load XML file.")
        xml.DisposeXml()
        bdXml.DisposeBinData()
        return
    }

    xml.UpdateChildContentInt("DocumentList|Document|ContentLength",bdXml.NumBytes())

    crypt := chilkat.NewCrypt2()
    crypt.SetHashAlgorithm("sha256")
    crypt.SetEncodingMode("base64")
    xml.UpdateChildContent("DocumentList|Document|HashValue",*crypt.HashBdENC(bdXml))

    //  ------------------------------------------------------------
    //  Step 2: Create a Zip archive containing the XML.
    zip := chilkat.NewZip()
    //  The filename we pass here doesn't matter because we won't actually be creating a .zip file.
    zip.NewZip("anything.zip")
    zip.AddBd("JPK_VAT_3_v1-1_20181201-000.xml",bdXml)
    //  Write the .zip file to a BinData object.
    bdZip := chilkat.NewBinData()
    zip.WriteBd(bdZip)

    //  ------------------------------------------------------------
    //  Step 3: Generate a random 256-bit AES key (32-bytes)
    prng := chilkat.NewPrng()
    bdAesKey := chilkat.NewBinData()
    prng.GenRandomBd(32,bdAesKey)
    ivBytes := prng.GenRandom(16,"base64")

    //  Store the IV (base64 string) in the XML.
    xml.UpdateChildContent("DocumentList|Document|FileSignatureList|Encryption|AES|IV",*ivBytes)

    //  ------------------------------------------------------------
    //  Step 4: AES encrypt our zip archive (the contents of bdZip)
    crypt.SetCipherMode("cbc")
    crypt.SetKeyLength(256)
    crypt.SetCryptAlgorithm("aes")
    crypt.SetPaddingScheme(0)
    crypt.SetEncodedIV(*ivBytes,"base64")
    crypt.SetEncodedKey(*bdAesKey.GetEncoded("base64"),"base64")
    //  AES by definition has a block size of 16.
    crypt.EncryptBd(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.WriteFile("qa_output/JPK_VAT_3_v1-1_20181201-000.xml.zip.aes")
    xml.UpdateChildContentInt("DocumentList|Document|FileSignatureList|FileSignature|ContentLength",bdZip.NumBytes())

    //  ------------------------------------------------------------
    //  Step 4: RSA Encrypt the AES key using the public key certificate provided by the Ministry of Finance
    cert := chilkat.NewCert()
    success = cert.LoadFromFile("qa_data/pem/mf_public_rsa.pem")
    if success == false {
        fmt.Println(cert.LastErrorText())
        xml.DisposeXml()
        bdXml.DisposeBinData()
        crypt.DisposeCrypt2()
        zip.DisposeZip()
        bdZip.DisposeBinData()
        prng.DisposePrng()
        bdAesKey.DisposeBinData()
        cert.DisposeCert()
        return
    }

    pubKey := chilkat.NewPublicKey()
    cert.GetPublicKey(pubKey)

    rsa := chilkat.NewRsa()
    rsa.UsePublicKey(pubKey)

    rsa.SetEncodingMode("base64")
    rsa.SetLittleEndian(false)
    //  in-place RSA encrypt the contents of bdAesKey.
    rsa.EncryptBd(bdAesKey,false)
    xml.UpdateChildContent("EncryptionKey",*bdAesKey.GetEncoded("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.SetHashAlgorithm("md5")
    xml.UpdateChildContent("DocumentList|Document|FileSignatureList|FileSignature|HashValue",*crypt.HashBdENC(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).
    finalXml := xml.GetXml()
    fmt.Println(*finalXml)

    xml.SaveXml("qa_output/jpk_vat.xml")

    fmt.Println("Finished.")

    xml.DisposeXml()
    bdXml.DisposeBinData()
    crypt.DisposeCrypt2()
    zip.DisposeZip()
    bdZip.DisposeBinData()
    prng.DisposePrng()
    bdAesKey.DisposeBinData()
    cert.DisposeCert()
    pubKey.DisposePublicKey()
    rsa.DisposeRsa()