EUROPEAN COMMISSION DIRECTORATE-GENERAL FOR HEALTH AND FOOD SAFETY General Affairs Information systems EUCEG: Encryption process
Document Control Information Settings Document Title: Project Title: Document Author: Value EUCEG: Encryption process EUCEG EC Doc. Version: 1.0 Sensitivity: public Date: 13/05/2016 Document history: The Document Author is authorized to make the following types of changes to the document without requiring that the document be re-approved: Editorial, formatting, and spelling Clarification To request a change to this document, contact the Document Author or Owner. Changes to this document are summarized in the following table in reverse chronological order (latest version first). Revision Date Created by Short Description of Changes 1.0 13/05/2016 EC Creation of the document 1.1 10/06/2016 EC Update 1.2 22/09/2016 EC Code sample update
Table of Contents 1. AS4 MESSAGE... 4 1.1. AS4 Message structure... 4 2. ENCRYPTION... 4 2.1. At AS4 communication level... 4 2.1.1. Principle... 4 2.2. At Payload container level... 5 2.2.1. Principle of sending encrypted message to EU-CEG... 5 2.2.2. How to encrypt messages to send to EUCEG... 6 2.2.3. How to decrypt the messages received from EUCEG... 7 3. TECHNICAL CONTACT... 7 4. ANNEX... 8 4.1. Payload example... 8 4.2. Java code... 9
Payload container EUCEG XML message AS4 message 1. AS4 MESSAGE Information about AS4 message can be found here: https://ec.europa.eu/cefdigital/wiki/display/cefdigital/access+point 1.1. AS4 Message structure 2. ENCRYPTION 2.1. At AS4 communication level 2.1.1. Principle This encryption should be done automatically in your AS4 access point for the AS4 message. Note: The encryption at AS4 level is only done automatically if it is configured correctly in your AS4 access point according to the PMode details document (EU- CEG PMode Configuration v1.02.docx) that you can find here: a. For tobacco product : https://circabc.europa.eu/w/browse/f41a02bf-7fe6-459d-a1cf-92ca4fe625a3 b. For e-cigarettes : https://circabc.europa.eu/w/browse/44a30101-4d59-410e- 9475-9b009a160066 Please be aware that if your AS4 access point is not configured to encrypt AS4 messages this message will fail to arrive.
2.2. At Payload container level 2.2.1. Principle of sending encrypted message to EU-CEG As the AS4 communication level encryption does not cover all the message transport to EU-CEG, another encryption is therefore needed for the payload container which contains the EUCEG XML message (XML submitter, XML product, or XML attachment) in order to meet the end to end encryption requirement. The principle of the used encryption for the payload is to encrypt it with a symmetric encryption and to use asymmetric encryption (PKI) to encrypt the symmetric key used. The used asymmetric key is the public key of EU-CEG. The encrypted payload and encrypted symmetric key are sent to EU-CEG. The EU- CEG decrypts the encrypted symmetric key with its private key then it decrypts the payload with the decrypted symmetric key. The figure below presents the steps of encryption. 1 - Hash the file with the hashing algorithm SHA_512 2 - Generate an AES 256 key 3 - Symmetric encryption of file with the AES 256 key 4 - Asymmetric encryption of the AES 256 key with the EC public key 5 - Send the hash value, the encrypted file and the encrypted key
2.2.2. How to encrypt messages to send to EUCEG As described in 2.2.1, these are the steps to follow in order to send an encrypted message: 1) Perform a checksum of the xml document (submitter_detail.xml, attachement.xml, submission.xml) with the method. 2) Generate an AES 256 key. Encryptions algorithm AES 256: https://en.wikipedia.org/wiki/advanced_encryption_standard 3) Encrypt the xml document (submitter_detail.xml, attachement.xml, submission.xml) with the generated key 4) Encrypt the generated key with the EUCEG public key using the algorithm RSA/ ECB/PKCS1Padding The EC certificate containing the public key can be found in CIRCABC (EUCEG_AP_EUROPEAN_COMMISSION.cer): a. For tobacco product : https://circabc.europa.eu/w/browse/15ac2779-867f-471fae39-06dcb815c5d0 b. For e-cigarettes : https://circabc.europa.eu/w/browse/fe86d3f5-d4e1-42d2-8434- 70e768dff38a 5) Create the payload according to the XSD schema (AS4EncryptedPayload.xsd). The payload must include the following information: a. the encrypted XML document encoded in base 64,. b. the checksum value of the XML document to ensure the integrity of the content. c. the encrypted key encoded in base 64. In the annex you will find an example of the payload that should be included in the AS4 message. The XSD schema (AS4EncryptedPayload.xsd) can be found in CIRCABC: c. For tobacco product : https://circabc.europa.eu/w/browse/b62c5975-245e- 4372-9967-7488be96e313 d. For e-cigarettes : https://circabc.europa.eu/w/browse/30c8bfc3-956a-4f59- bf74-c8838489a3a3 Once the message is ready, you can submit it through your AS4 access point. Note: You can find a simple Java code example to encrypt one file in the annexe
2.2.3. How to decrypt the messages received from EUCEG The message response received from EC AS4 Access point will respect the same XSD schema as the one used to send messages. These are the steps to follow in order to decrypt the message: 1) Extract from the payload received: a. The Content of the XML document <Content> </content> b. The Hash of the XML document <DocumentHash> </DocumentHash> c. The Key (Symmetric key) <Key> </Key> 2) Decode from base 64 the content and the key. 3) Decrypt the key using the private key provided by EC PKI service. 4) Decrypt the content using the decrypted key (step 3) Note: The checksum of the decrypted file has to be equal to the Document Hash value. 3. TECHNICAL CONTACT If you have any questions regarding the encryption please send an email to EUCEG- SUPPORT-IT@ec.europa.eu. For a better support please specify in your email your Submitter identifier.
4. ANNEX 4.1. Payload example <?xml version="1.0" encoding="utf-8"?> <AS4Payload xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:nonamespaceschemalocation="as4payload.xsd"> <Content>4MNhDT0Vh6ylZKeaHyPs4GBMghQx1zZPz5IbzCPXW3nggw/eGGvcx3D khjfpjt7bpsnb+uxztxdgdtdn/qeddo7zuysrfy59dqxqwdlzbflm8kpc1bpuhaf RcEBPlHyJW9oR8/Kd5SZ4zHvqPvHtdQcLUp+zYi7bf/cfXteSulMQm0BKQ1oxzXCp NnX5OBG6R/cHOfIFZyg5KPRTQo3xihRevzNnwK4USAHcvUQTMNFL8+E6jNHgy e5zsevdcb+f4hsiywzzncckxurfyujkvvtjfhej6lng5/p0yslla4cvnew6ybpyxugprs NqiTnJdsfV1NDkhnuEbUYatIiLTbMtKV92/+b//U7PCSNDBDND8BJNwio9b8SYvZE NuF3nplI5cggnrq3Y4PY66LhPCox/0WZj2B6BOKQYI7VRRG9b8VPTwTc47EnxKZI pqgduaorh8vfbsdxvpm82secf9waaaaaaaaaaaaaaaaaa</content> <DocumentHash>ff2d8a916ab1cfce03957a3d160a6a6862ad7d6bd28445b62eff5165e78 813fa5638a672f8f42f25a6c1b71909c69d44f5fe28669f539c3947ac38684ca8e5a1</Docu menthash> <Key>d9aAVK1ByWos3oZxXC2pZYvTC9q9WqNYWvFK1YXSCyQ3b6aflTeB5qR2 kn7mlm68roohwaoosixius+fbo2jotukej6327be8b7cy0hl/w2ozsa3h9fruq2b 3lbCvwzsM7aixBCZlKFeA7QtJkvzscLKqyZPu8FGEruXRKnT/9Tss6w76BmyLAupPp 6ngc6lwPy8RAAxQSSPjwepYhCuIJw87JRoe3UzPbVyhRb4kM77W0cT3SPpKIf2eLO be6bdoueoqpr/yf5lygzqgxrelttyhfkkkuq1g7ovruawzqxflp1v3f+csotpiw MPFLePLuyqzX9RBcCTPyzztbV/qw==</Key> </AS4Payload>
4.2. Java code package eu.europa.ec.sante.tobir.gateway.security; import java.io.file; import java.io.fileinputstream; import java.io.filenotfoundexception; import java.io.fileoutputstream; import java.io.ioexception; import java.io.inputstream; import java.io.outputstream; import java.security.keystore; import java.security.keystoreexception; import java.security.nosuchalgorithmexception; import java.security.privatekey; import java.security.publickey; import java.security.unrecoverablekeyexception; import java.security.cert.certificateexception; import javax.crypto.cipher; import javax.crypto.keygenerator; import javax.crypto.secretkey; import org.apache.commons.io.fileutils; import org.apache.commons.io.ioutils; import org.bouncycastle.crypto.blockcipher; import org.bouncycastle.crypto.bufferedblockcipher; import org.bouncycastle.crypto.cipherparameters; import org.bouncycastle.crypto.engines.aesengine; import org.bouncycastle.crypto.io.cipherinputstream; import org.bouncycastle.crypto.io.cipheroutputstream; import org.bouncycastle.crypto.modes.cbcblockcipher; import org.bouncycastle.crypto.paddings.blockcipherpadding; import org.bouncycastle.crypto.paddings.pkcs7padding; import org.bouncycastle.crypto.paddings.paddedbufferedblockcipher; import org.bouncycastle.crypto.params.keyparameter; public class EncryptionExample { private PublicKey publickey; private PrivateKey privatekey; private byte[] AESKey; private byte[] encryptedaeskey; private byte[] decryptedaeskey; public static void main(string[] args) throws Exception { EncryptionExample encryptioexample = new EncryptionExample(); // get the public key from the truststore (the trustore is put at the classpath root) encryptioexample.extractkeyfromtruststore("/truststore.jks", "certificatealiasname", "truststorepassword"); // generate a symmetric key for the encryption of the xml content encryptioexample.genaes256key(); // encrypt the xml file in a txt file ( xml file is put at the classpath root) encryptioexample.encryptfilewithaeskey("filetoencode.xml", "encodedfile.txt"); // encrypt the symmetric key with the public key (asymmetric key extract from the truststore) encryptioexample.encryptaeskey(); "keypassword"); // get the private key from the keystore (the keystore is put at the classpath root) encryptioexample.extractkeyfromkeystore("/keystore.jks", "keyalias", "keystorepassword", // decrypt the symetric key with the private key encryptioexample.decryptaeskey(); // decrypt the file with the decrypted symmetric key and put in a new file encryptioexample.decryptfile( "encodedfile.txt", "decryptedfile.xml");
public void extractkeyfromtruststore(string keystorepath, String alias, String password) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException { InputStream fis = this.getclass().getresourceasstream(keystorepath); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(fis, password.tochararray()); publickey = ks.getcertificate(alias).getpublickey(); public void extractkeyfromkeystore(string keystorepath, String alias, String password, String passwordkey) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException { InputStream fis = this.getclass().getresourceasstream(keystorepath); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(fis, password.tochararray()); privatekey = (PrivateKey) ks.getkey(alias, passwordkey.tochararray()); public void genaes256key() throws NoSuchAlgorithmException { KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(256); // Generate the secret key specs. SecretKey skey = kgen.generatekey(); AESKey = skey.getencoded(); /** * asymmetric encryption * */ public void encryptaeskey() throws Exception { Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm() + "/ECB/PKCS1Padding"); cipher.init(cipher.encrypt_mode, publickey); encryptedaeskey = cipher.dofinal(aeskey); /** * asymmetric decryption * */ public void decryptaeskey() throws Exception { Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm() + "/ECB/PKCS1Padding"); cipher.init(cipher.decrypt_mode, privatekey); decryptedaeskey = cipher.dofinal(encryptedaeskey); public void encryptfilewithaeskey(string relativefilepath, String destpath) { byte[] filetoencrypt = convertfiletoencryptedbytearray(relativefilepath); copybytearray(filetoencrypt, destpath); public void decryptfile(string encryptedfilepath, String decryptedfilepath) throws FileNotFoundException { InputStream is = getclass().getclassloader().getresourceasstream(encryptedfilepath); File file = new File(decryptedFilePath); OutputStream os = null; int i; try { os = FileUtils.openOutputStream(file); //wrap the output stream into an output stream with decryption capabilities //the data will be decrypted as they are written os = getcipheroutputstream(os, decryptedaeskey, false); while ((i = is.read())!= -1) { os.write(i); catch (Exception e) { e.printstacktrace(); finally { IOUtils.closeQuietly(os); IOUtils.closeQuietly(is);
private byte[] convertfiletoencryptedbytearray(string relativefilepath) { InputStream inputstream=null; File xmlfile = new File(getClass().getClassLoader().getResource(relativeFilePath).getFile()); try { //convert file into encrypted array of bytes //the data will be encrypted as they are read inputstream = getcipherinputstream(new FileInputStream(xmlFile), AESKey, true) ; byte[] bfile = IOUtils.toByteArray(inputStream); inputstream.close(); return bfile; catch(exception e) { e.printstacktrace(); return null; public InputStream getcipherinputstream(inputstream inputstream, byte[] aes256key, boolean forencryption) { BufferedBlockCipher bufferedblockcipher = buildaesbufferedblockcipher(aes256key, forencryption); return new CipherInputStream(inputStream, bufferedblockcipher); public OutputStream getcipheroutputstream(outputstream outputstream, byte[] aes256key, boolean forencryption) { BufferedBlockCipher bufferedblockcipher = buildaesbufferedblockcipher(aes256key, forencryption); return new CipherOutputStream(outputStream, bufferedblockcipher); public void copybytearray( byte[] bfile, String path ) { try { //convert array of bytes into file FileOutputStream fileouputstream = new FileOutputStream(path); fileouputstream.write(bfile); fileouputstream.close(); catch(exception e){ e.printstacktrace(); private BufferedBlockCipher buildaesbufferedblockcipher(byte[] key, boolean forencryption) { /* * A full list of BlockCiphers can be found at http://www.bouncycastle.org/docs/docs1.6/org/bouncycastle/crypto/blockcipher.html */ BlockCipher blockcipher = new AESEngine(); CBCBlockCipher cbcblockcipher = new CBCBlockCipher(blockCipher); /* * Paddings available (http://www.bouncycastle.org/docs/docs1.6/org/bouncycastle/crypto/paddings/blockcipherpadding.html): * - ISO10126d2Padding * - ISO7816d4Padding * - PKCS7Padding * - TBCPadding * - X923Padding * - ZeroBytePadding */ BlockCipherPadding blockcipherpadding = new PKCS7Padding(); BufferedBlockCipher bufferedblockcipher = new PaddedBufferedBlockCipher(cbcBlockCipher, blockcipherpadding);
CipherParameters cipherparameters = new KeyParameter(key); bufferedblockcipher.init(forencryption, cipherparameters); return bufferedblockcipher;