{"title":"Comunica\u00e7\u00f5es locais seguras","category":"default","creationDate":1776961627,"content":"<p>Se sua integra\u00e7\u00e3o usar comunica\u00e7\u00f5es locais, voc\u00ea precisar\u00e1 executar algumas etapas adicionais para ajudar a proteger sua integra\u00e7\u00e3o contra <a href=\"https:\/\/en.wikipedia.org\/wiki\/Man-in-the-middle_attack\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">ataques<\/a>, intercepta\u00e7\u00e3o e adultera\u00e7\u00e3o.<\/p>\n<p>Para proteger as comunica\u00e7\u00f5es entre sua caixa registradora e o terminal, voc\u00ea precisa:<\/p>\n<ul>\n<li><a href=\"#validate-terminal-certificate\">Validar o certificado do terminal<\/a>. Isso confirma que sua caixa registradora est\u00e1 se comunicando diretamente com um terminal da Adyen e n\u00e3o com um impostor.<\/li>\n<li><a href=\"#encrypt-communications\">Criptografar comunica\u00e7\u00f5es <\/a>. Isso impede que os invasores leiam as mensagens transmitidas entre a caixa registradora e o terminal.<\/li>\n<\/ul>\n<h2>Validar certificado do terminal<\/h2>\n<p>Todo terminal da Adyen vem pr\u00e9-instalado com um certificado assinado pela Adyen. Para confirmar que sua caixa registradora est\u00e1 se comunicando diretamente com um terminal da Adyen, \u00e9 necess\u00e1rio:<\/p>\n<ol>\n<li><a href=\"#install\">Instalar o certificado raiz p\u00fablico da Adyen<\/a> trust store.<\/li>\n<li>Autenticar a conex\u00e3o entre a caixa registradora e o terminal, <a href=\"#verify\">verificando o certificado no terminal <\/a>.<\/li>\n<\/ol>\n<h3 id=\"install\">Etapa 1: Instalar o certificado<\/h3>\n<p>Para instalar o certificado raiz p\u00fablico da Adyen em seu trust store:<\/p>\n<ol>\n<li>\n<p>Fa\u00e7a o download dos certificados raiz p\u00fablicos da Adyen em sua caixa registradora:<\/p>\n<ul>\n<li><a href=\"\/pt\/point-of-sale\/design-your-integration\/choose-your-architecture\/local\/adyen-terminalfleet-test.pem\">Certificado do terminal TEST<\/a>: Para validar o certificado nos terminais Adyen <strong>TEST<\/strong>.<\/li>\n<li><a href=\"\/pt\/point-of-sale\/design-your-integration\/choose-your-architecture\/local\/adyen-terminalfleet-live.pem\">Certificado do terminal LIVE<\/a>: FPara validar o certificado nos terminais Adyen <strong>LIVE<\/strong>.<\/li>\n<\/ul>\n<p>Esses certificados podem ser convertidos para formatos como  <strong>.crt<\/strong>, <strong>.cer<\/strong>, ou <strong>.p12<\/strong>, se necess\u00e1rio.<\/p>\n<\/li>\n<li>\n<p>Verifique se a <strong>assinatura SHA-256<\/strong> nos certificados corresponde ao seguinte:<\/p>\n<ul>\n<li>Certificado de terminal <strong>TEST<\/strong>: <code>3A 33 C3 34 C3 0F 69 46 E9 75 4B 6B B1 67 2B 54 6F BA A9 66 FB 6A 4B 58 AA 4E 3A BE 80 A7 EC BE<\/code><\/li>\n<li>\n<p>Certificado de terminal <strong>LIVE<\/strong>: <code>06 D4 86 41 95 4B 95 7D 7A F5 F5 E4 5A 58 D8 61 DB 0D E3 CC ED BB 98 36 60 BB 01 6C E6 14 2D A1<\/code><\/p>\n<!-- list separator -->\n<\/li>\n<\/ul>\n<div class=\"sc-notice note\"><div>\n<p>Em um <strong>ambiente Windows<\/strong> a impress\u00e3o digital SHA-256 pode n\u00e3o estar prontamente dispon\u00edvel por c\u00f3digo ou <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/framework\/wcf\/feature-details\/how-to-view-certificates-with-the-mmc-snap-in\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">MMC<\/a>. Nesse caso, verifique a <strong>assinatura SHA-1<\/strong> nos certificados:<\/p>\n<ul>\n<li>Certificado de terminal <strong>TEST<\/strong>: <code>D5 02 7F A8 B3 93 96 DB 2A 4F B1 86 EF 61 E4 A4 40 A7 30 51<\/code><\/li>\n<li>\n<p>Certificado de terminal <strong>LIVE<\/strong>: <code>62 61 0D 88 27 8E 95 B7 F8 57 9A 9B 5E 07 85 D7 72 87 66 42<\/code><\/p>\n<!-- list separator -->\n<\/li>\n<\/ul>\n<\/div><\/div>\n<\/li>\n<li>\n<p>Instale os certificados no trust store da sua caixa registradora.<\/p>\n<div class=\"sc-notice info\"><div>\n<p>Siga as instru\u00e7\u00f5es do fornecedor para adicionar certificados raiz ao trust store do sistema ou do usu\u00e1rio.<br \/>\nPor exemplo, a documenta\u00e7\u00e3o da <strong>Microsoft<\/strong> para <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/framework\/wcf\/feature-details\/how-to-view-certificates-with-the-mmc-snap-in\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">adicionar certificados usando o snap-in MMC<\/a>, ou <a href=\"https:\/\/docs.microsoft.com\/en-us\/powershell\/module\/pkiclient\/import-certificate\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">importar certificados com o PowerShell<\/a>.<br \/>\nPara <strong>iOS<\/strong>, consulte: <a href=\"https:\/\/support.apple.com\/en-us\/HT204477\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Manipula\u00e7\u00e3o de certificado iOS<\/a>.<\/p>\n<\/div><\/div>\n<\/li>\n<\/ol>\n<p>Depois de instalar os certificados em seu trust store, verifique o certificado no terminal da sua caixa registradora.<\/p>\n<h3 id=\"verify\">Etapa 2: Verificar o certificado<\/h3>\n<p>Quando sua caixa registradora se conecta ao terminal, ela deve:<\/p>\n<ol>\n<li>\n<p>Verificar se o certificado no terminal est\u00e1 assinado pelo certificado raiz confi\u00e1vel que <a href=\"#install\">voc\u00ea instalou<\/a>. Essa verifica\u00e7\u00e3o inclui a verifica\u00e7\u00e3o autom\u00e1tica do certificado intermedi\u00e1rio fornecido pelo terminal no in\u00edcio da conex\u00e3o.<\/p>\n<div class=\"notices yellow\">\n<p>Voc\u00ea ver\u00e1 um <em>erro de incompatibilidade de nome comum<\/em> durante a verifica\u00e7\u00e3o. Isso \u00e9 normal e acontece porque o Nome Comum do certificado n\u00e3o \u00e9 resolvido no DNS.<\/p>\n<\/div>\n<\/li>\n<li>\n<p>Valide o nome comum. O nome comum est\u00e1 em um dos seguintes formatos:<\/p>\n<ul>\n<li>\n<p>Formatos de nome comum do terminal TEST:<\/p>\n<ul>\n<li><strong>legacy-terminal-certificate.test.terminal.adyen.com<\/strong><\/li>\n<li><strong>[POIID].test.terminal.adyen.com<\/strong>\n<div class=\"sc-notice info\"><div>\n<p><strong>[POIID]<\/strong> = <em>[Modelo do terminal]-[N\u00famero de s\u00e9rie]<\/em><br \/>\nPor exemplo, <strong>P400Plus-123456789.test.terminal.adyen.com<\/strong><\/p>\n<\/div><\/div><\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Formatos de nome comum do terminal LIVE:<\/p>\n<ul>\n<li><strong>legacy-terminal-certificate.live.terminal.adyen.com<\/strong><\/li>\n<li><strong>[POIID].live.terminal.adyen.com<\/strong>\n<div class=\"sc-notice info\"><div>\n<p><strong>[POIID]<\/strong> = <em>[Modelo do terminal]-[N\u00famero de s\u00e9rie]<\/em><br \/>\nFor example <strong>P400Plus-123456789.live.terminal.adyen.com<\/strong><\/p>\n<\/div><\/div><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Dependendo do n\u00famero de terminais que voc\u00ea est\u00e1 integrando, conv\u00e9m usar express\u00f5es regulares no seu c\u00f3digo para validar o Nome Comum.<\/p>\n<\/li>\n<\/ol>\n<p>Se o certificado no terminal conectado passar na verifica\u00e7\u00e3o, sua caixa registradora ser\u00e1 conectada a um terminal Adyen.<\/p>\n<h2>Criptografar comunica\u00e7\u00f5es<\/h2>\n<p>Para impedir que outras pessoas possam ler as comunica\u00e7\u00f5es entre sua caixa registradora e o terminal, \u00e9 necess\u00e1rio criptografar as mensagens enviadas entre esses dispositivos. Criptografar essas comunica\u00e7\u00f5es envolve:<\/p>\n<ol>\n<li><a href=\"#step-1-derive-encryption-key\">Derivar uma chave de criptografia<\/a>.<\/li>\n<li><a href=\"#step-2-encrypt-and-decrypt-messages\">Criptografar e descriptografar mensagens<\/a>.<\/li>\n<\/ol>\n<h3 id=\"step-1-derive-encryption-key\">Etapa 1: Derivar chave de criptografia<\/h3>\n<p>Derive uma chave de criptografia para proteger a comunica\u00e7\u00e3o entre dispositivos usando a API do Terminal.<\/p>\n<p>Para derivar uma chave de criptografia, as duas partes devem:<\/p>\n<ol>\n<li>Compartilhar um segredo de comprimento vari\u00e1vel para obter o material principal.<\/li>\n<li>Derivar a chave usando PBKDF2_HMAC_SHA1<\/li>\n<li>\n<p>Incluir os seguintes par\u00e2metros:<\/p>\n<table>\n<thead>\n<tr>\n<th>Par\u00e2metro<\/th>\n<th>Valor<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>salt<\/td>\n<td>AdyenNexoV1Salt<\/td>\n<\/tr>\n<tr>\n<td>salt length<\/td>\n<td>15;<\/td>\n<\/tr>\n<tr>\n<td>rounds<\/td>\n<td>4000;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"sc-notice info\"><div>\n<p>Se o programa salvar a chave derivada resultante, esse c\u00e1lculo ser\u00e1 realizado uma vez para cada segredo compartilhado.<\/p>\n<\/div><\/div>\n<p>O material da chave derivada consiste em 80 bytes: uma chave de cifra de 32 bytes, uma chave HMAC de 32 bytes e um vetor de inicializa\u00e7\u00e3o (IV) de 16 bytes. O IV \u00e9 XORed com um nonce aleat\u00f3rio que \u00e9 gerado por mensagem na criptografia.<\/p>\n<div class=\"sc-notice note\"><div>\n<p>Uma chave derivada \u00e9 identificada por sua  <code>KeyIdentifier<\/code> e sua vers\u00e3o.<\/p>\n<\/div><\/div>\n<\/li>\n<\/ol>\n<p>O exemplo de c\u00f3digo C a seguir demonstra como voc\u00ea usaria o OpenSSL para derivar o material principal:<\/p>\n<pre><code class=\"language-cpp\">\/* The struct to hold the derived keys is defined like so: *\/\n\nstruct nexo_derived_keys {\n    uint8_t hmac_key[NEXO_HMAC_KEY_LENGTH];\n    uint8_t cipher_key[NEXO_CIPHER_KEY_LENGTH];\n    uint8_t iv[NEXO_IV_LENGTH];\n};\n\n\/* Function to derive the keys: *\/\nint nexo_derive_key_material(const char * passphrase, size_t len, struct nexo_derived_keys *dk) {\n    const unsigned char salt[] = \"AdyenNexoV1Salt\";\n    const int saltlen = sizeof(salt) - 1;\n    const int rounds = 4000;\n    return PKCS5_PBKDF2_HMAC_SHA1(passphrase, len, salt, saltlen, rounds,\n             sizeof(struct nexo_derived_keys), (unsigned char *)dk);\n\n}<\/code><\/pre>\n<h3 id=\"step-2-encrypt-and-decrypt-messages\">Etapa 2: Criptografar e descriptografar mensagens<\/h3>\n<p>Configure a criptografia na API do terminal para proteger as mensagens comunicadas entre o terminal e a caixa registradora.<\/p>\n<h4 id=\"encrypt-messages\">Criptografar mensagens<\/h4>\n<p>Para criptografar uma mensagem:<\/p>\n<ol>\n<li>Criptografar o corpo da mensagem usando um vetor de inicializa\u00e7\u00e3o dk.iv (IV) do Nonce XOR, em que dk.iv \u00e9 o IV no material da chave derivada.<br \/>\nO nonce (n\u00famero usado uma vez) \u00e9 uma sequ\u00eancia aleat\u00f3ria de bytes do mesmo tamanho que dk.iv gerado por mensagem.<\/li>\n<li>Coloque o nonce na <code>SecurityTrailer<\/code> como uma cadeia de caracteres codificada Base64.<\/li>\n<\/ol>\n<h4 id=\"decrypt-and-validate-messages\">Descriptografar e validar mensagens<\/h4>\n<p>Para descriptografar e validar uma mensagem:<\/p>\n<ol>\n<li>\n<p>Decomponha a mensagem em suas v\u00e1rias partes.<\/p>\n<\/li>\n<li>\n<p>Verifique o <code>AdyenCryptoVersion<\/code> no <code>SecurityTrailer<\/code>.<\/p>\n<\/li>\n<li>\n<p>Recupere o material principal com base em <code>KeyIdentifier<\/code> e <code>KeyVersion<\/code>.<\/p>\n<\/li>\n<li>\n<p>Descriptografe o blob usando o IV e digite o material da chave e o Nonce no <code>SecurityTrailer<\/code>.<\/p>\n<\/li>\n<li>\n<p>Valide o HMAC computando-o no blob descriptografado.<\/p>\n<div class=\"sc-notice note\"><div>\n<p>N\u00e3o valide no formul\u00e1rio serializado.<\/p>\n<\/div><\/div>\n<\/li>\n<li>\n<p>Compare o resultado ao blob no  <code>SecurityTrailer<\/code>. A mensagem cont\u00e9m uma c\u00f3pia em texto n\u00e3o criptografado <code>MessageHeader<\/code> para fins de roteamento.<\/p>\n<\/li>\n<li>\n<p>Uma vez emparelhado, compare o texto n\u00e3o criptografado MessageHeader<code>com o<\/code>MessageHeader<code>do corpo descriptografado e verifique se eles n\u00e3o s\u00e3o iguais aos<\/code>MessageHeader` da parte descriptografado.<\/p>\n<\/li>\n<\/ol>\n<h4 id=\"configure-a-key-in-the-customer-area\">Configure uma chave na \u00e1rea do cliente<\/h4>\n<p>A chave que o terminal utiliza, recuperada com a configura\u00e7\u00e3o do terminal, \u00e9 definida na <a href=\"https:\/\/ca-live.adyen.com\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Customer Area<\/a>. Atualmente, o software do terminal \u00e9 capaz de usar apenas uma chave. Se v\u00e1rios dispositivos estiverem se comunicando com o mesmo terminal, eles dever\u00e3o compartilhar a mesma chave.<\/p>\n<p>Para configurar a chave:<\/p>\n<ol>\n<li>Abra a <a href=\"https:\/\/ca-test.adyen.com\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Customer Area<\/a> e v\u00e1 para <strong>In-person payments<\/strong> &gt; <strong>Terminals<\/strong>.<\/li>\n<li>Clique na linha do terminal que voc\u00ea deseja configurar. A p\u00e1gina de configura\u00e7\u00e3o desse terminal ser\u00e1 aberta.<\/li>\n<li>Clique em <strong>View decrypted properties<\/strong>.<br \/>\nA p\u00e1gina \u00e9 atualizada e retorna ao menu da API do terminal.<\/li>\n<li>Clique em <strong>Terminal API<\/strong> tab.<\/li>\n<li>Clique em <strong>Edit<\/strong>.<\/li>\n<li>Digite o identificador da chave de criptografia e a senha da chave.<\/li>\n<li>Clique em <strong>Save<\/strong>.<\/li>\n<li>Adicione sua chave no campo <strong>Security Keys<\/strong>.<\/li>\n<\/ol>\n<p>A seguir, \u00e9 apresentado um exemplo da propriedade das Chaves de Seguran\u00e7a:<\/p>\n<pre><code class=\"language-json\">{\n   \"defaultKey\":{\n      \"passphrase\":\"mysupersecretpassphrase\",\n      \"keyIdentifier\":\"mykey\",\n      \"version\":0\n   }\n}<\/code><\/pre>\n<h4 id=\"example\">Exemplo de criptografia<\/h4>\n<p>O c\u00f3digo de exemplo abaixo implementa criptografia de mensagens, computa\u00e7\u00e3o e constru\u00e7\u00e3o do HMAC, al\u00e9m da opera\u00e7\u00e3o reversa: divis\u00e3o, valida\u00e7\u00e3o e descriptografia do HMAC.<\/p>\n<div class=\"sc-notice note\"><div>\n<p>Por padr\u00e3o, o Java tem restri\u00e7\u00e3o AES 128. Pode ser necess\u00e1rio fazer o <a href=\"https:\/\/www.oracle.com\/technetwork\/java\/javase\/downloads\/jce-all-download-5170447.html\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">download de um novo arquivo de pol\u00edticas<\/a> para ativar o AES 256, caso contr\u00e1rio, a exce\u00e7\u00e3o de chave ilegal ser\u00e1 lan\u00e7ada.<\/p>\n<\/div><\/div>\n<pre><code class=\"language-java\">import java.io.*;\nimport java.security.*;\nimport java.security.spec.*;\nimport java.text.ParseException;\nimport java.util.Base64;\nimport java.util.Random;\nimport javax.crypto.*;\nimport javax.crypto.spec.IvParameterSpec;\nimport javax.crypto.spec.PBEKeySpec;\nimport javax.crypto.spec.SecretKeySpec;\nimport javax.json.*;\n\npublic class NexoCrypto {\n\n    public static final int NEXO_HMAC_KEY_LENGTH = 32;\n    public static final int NEXO_CIPHER_KEY_LENGTH = 32;\n    public static final int NEXO_IV_LENGTH = 16;\n\n   \/**\n    * Where to look for pre-derived key files\n    *\/\n   private String keyDirectory;\n\n   \/**\n    * The keys material to use when we are sending\n    *\/\n   private String keyIdentifier;\n   private long keyVersion;\n   private NexoDerivedKeys derivedKeys;\n\n    \/**\n     * A container for Nexo derived keys\n     *\n     * Nexo derived keys is a 80 byte struct containing key data. These 80\n     * bytes are derived from a passsphrase.\n     *\/\n   public class NexoDerivedKeys {\n      public byte hmac_key[];\n      public byte cipher_key[];\n      public byte iv[];\n\n      public NexoDerivedKeys() {\n         hmac_key = new byte[NEXO_HMAC_KEY_LENGTH];\n         cipher_key = new byte[NEXO_CIPHER_KEY_LENGTH];\n         iv = new byte[NEXO_IV_LENGTH];\n      }\n\n      \/**\n       * Read a key material file of 80 bytes, splitting it in the hmac_key, cipher_key and iv\n       *\/\n      public void readKeyData(String keyId, long keyV) throws IOException {\n         String filename = keyDirectory + '\/' + keyId + \".\" + Long.toString(keyV) + \".key\";\n\n         FileInputStream stream = null;\n         try {\n            stream = new FileInputStream(filename);\n            stream.read(this.hmac_key);\n            stream.read(this.cipher_key);\n            stream.read(this.iv);\n         } finally {\n            if (stream != null) {\n               try {\n                  stream.close();\n               }\n               catch (Exception ignored) {\n               }\n            }\n         }\n      }\n\n   };\n\n   \/**\n    * Use this constructor if you want to be able to both encryption and decryption\n    *\/\n   public NexoCrypto(String dir, String keyID, long keyV) throws IOException {\n      keyDirectory = dir;\n      keyIdentifier = keyID;\n      keyVersion = keyV;\n      derivedKeys = new NexoDerivedKeys();\n      derivedKeys.readKeyData(keyIdentifier, keyVersion);\n   }\n\n   \/**\n    * Use this constructor if you a decrypt-only NexoCrypto object\n    *\/\n   public NexoCrypto(String dir) {\n      keyDirectory = dir;\n   }\n\n   \/**\n    * Given a passphrase, compute 80 byte key of key material according to crypto.md\n    *\/\n   public static byte[] deriveKeyMaterial(char[] passphrase) throws NoSuchAlgorithmException, InvalidKeySpecException {\n      byte[] salt = \"AdyenNexoV1Salt\".getBytes();\n      int iterations = 4000;\n      PBEKeySpec spec = new PBEKeySpec(passphrase, salt, iterations, (NEXO_HMAC_KEY_LENGTH +\n            NEXO_CIPHER_KEY_LENGTH + NEXO_IV_LENGTH) * 8);\n      SecretKeyFactory skf = SecretKeyFactory.getInstance(\"PBKDF2WithHmacSHA1\");\n      byte[] keymaterial = skf.generateSecret(spec).getEncoded();\n      return keymaterial;\n   }\n\n   \/**\n    * Encrypt or decrypt data given a iv modifier and using the specified key\n    *\n    * The actual iv is computed by taking the iv from the key material and xoring it with ivmod\n    *\/\n   private byte[] crypt(byte[] bytes, NexoDerivedKeys dk, byte[] ivmod, int mode)\n         throws NoSuchAlgorithmException, NoSuchPaddingException,\n            IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {\n\n      Cipher cipher = Cipher.getInstance(\"AES\/CBC\/PKCS5Padding\");\n      SecretKeySpec s = new SecretKeySpec(dk.cipher_key, \"AES\");\n\n      \/\/ xor dk.iv and the iv modifier\n      byte[] actualIV = new byte[NEXO_IV_LENGTH];\n      for (int i = 0; i &lt; NEXO_IV_LENGTH; i++) {\n         actualIV[i] = (byte) (dk.iv[i] ^ ivmod[i]);\n      }\n\n      IvParameterSpec i = new IvParameterSpec(actualIV);\n      cipher.init(mode, s, i);\n      return cipher.doFinal(bytes);\n   }\n\n   \/**\n    * Compute a hmac using the hmac_key\n    *\/\n   private byte[] hmac(byte[] bytes, NexoDerivedKeys dk) throws NoSuchAlgorithmException, InvalidKeyException {\n      Mac mac = Mac.getInstance(\"HmacSHA256\");\n      SecretKeySpec s = new SecretKeySpec(dk.hmac_key, \"HmacSHA256\");\n\n      mac.init(s);\n      return mac.doFinal(bytes);\n   }\n\n   \/**\n    * Encrypt and compose a secured Nexo message\n    *\n    * This functions takes the original message, encrypts it and converts the encrypted form to Base64 and\n    * names it NexoBlob.\n    * After that, a new message is created with a copy of the header, the NexoBlob and an added SecurityTrailer.\n    *\n    * @param in is the byte representation of the unprotected Nexo message\n    * @returns a byte representation of the secured Nexo message\n    *\/\n   public byte[] encrypt_and_hmac(byte in[]) throws InvalidKeyException, NoSuchAlgorithmException,\n         NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException,\n         InvalidAlgorithmParameterException {\n      Base64.Encoder encb64 = Base64.getEncoder();\n\n      \/\/ parse the json and determined if it is a request or responce\n      JsonReader jsonreader = Json.createReader(new ByteArrayInputStream(in));\n      JsonObject body = jsonreader.readObject();\n      boolean request = true;\n      JsonObject saletopoirequest = body.getJsonObject(\"SaleToPOIRequest\");\n      if (saletopoirequest == null) {\n         request = false;\n         saletopoirequest = body.getJsonObject(\"SaleToPOIResponse\");\n      }\n      \/\/ pick up the MessageHeader\n      JsonObject messageheader = saletopoirequest.getJsonObject(\"MessageHeader\");\n\n      \/\/ Generate a random iv nonce\n      byte[] ivmod = new byte[NEXO_IV_LENGTH];\n      new Random().nextBytes(ivmod);\n\n      \/\/ encrypt taking the original bytes as input\n      byte[] encbytes = crypt(in, this.derivedKeys, ivmod, Cipher.ENCRYPT_MODE);\n\n      \/\/ compute mac over cleartext bytes\n      byte[] hmac = hmac(in, this.derivedKeys);\n\n      \/\/ Construct the inner Json object containing a MessageHeader, a NexoBlob and a SecurityTrailer\n      JsonObject msg = Json.createObjectBuilder()\n            .add(\"MessageHeader\", messageheader)\n            .add(\"NexoBlob\", new String(encb64.encode(encbytes)))\n            .add(\"SecurityTrailer\", Json.createObjectBuilder()\n                  .add(\"Hmac\", new String(encb64.encode(hmac)))\n                  .add(\"KeyIdentifier\", keyIdentifier)\n                  .add(\"KeyVersion\", keyVersion)\n                  .add(\"AdyenCryptoVersion\", 1)\n                  .add(\"Nonce\", new String(encb64.encode(ivmod)))\n                  ).build();\n      \/\/ Wrap the inner message in a SaleToPOIRequest or SaleToPOIResponse object\n      JsonObject total = Json.createObjectBuilder()\n            .add(request ?  \"SaleToPOIRequest\" : \"SaleToPOIResponse\" , msg)\n            .build();\n\n      ByteArrayOutputStream stream = new ByteArrayOutputStream();\n      JsonWriter writer = Json.createWriter(stream);\n      writer.writeObject(total);\n      writer.close();\n      return stream.toByteArray();\n   }\n\n   \/**\n    * A helper class to return a decrypted mesasage and the outer header from the\n    * secured Nexo message\n    *\/\n   public class BytesAndOuterHeader {\n      public byte[] packet;\n      public JsonObject outer_header;\n\n      public BytesAndOuterHeader(byte[] packet, JsonObject outer_header) {\n         this.packet = packet;\n         this.outer_header = outer_header;\n      }\n   }\n\n   \/*\n    * Validate and decrypt a secured Nexo message\n    *\n    * @returns a BytesAndOuterHeader object or null on failure\n    *\/\n   public BytesAndOuterHeader decrypt_and_validate_hmac(byte in[]) throws InvalidKeyException,\n         NoSuchAlgorithmException, IOException, NoSuchPaddingException, IllegalBlockSizeException,\n         BadPaddingException, InvalidAlgorithmParameterException {\n      Base64.Decoder b64dec = Base64.getDecoder();\n\n      \/\/ Parse bytes and retrieve MessageHeader\n      InputStream stream = new ByteArrayInputStream(in);\n      JsonReader jsonreader = Json.createReader(stream);\n      JsonObject total = jsonreader.readObject();\n      if (total == null) {\n         throw new IOException(\"Faulty JSON\");\n      }\n      JsonObject saletopoirequest = total.getJsonObject(\"SaleToPOIRequest\");\n      if (saletopoirequest == null) {\n         saletopoirequest = total.getJsonObject(\"SaleToPOIResponse\");\n      }\n      if (saletopoirequest == null) {\n         throw new IOException(\"No SaleToPOIRequest or SaleToPOIResponse\");\n      }\n      JsonObject messageheader = saletopoirequest.getJsonObject(\"MessageHeader\");\n      if (messageheader == null) {\n         throw new IOException(\"MessageHeader not found\");\n      }\n      \/\/ Get the encrypted actual message and base64 decode it\n      JsonString payload = saletopoirequest.getJsonString(\"NexoBlob\");\n      if (payload == null) {\n         throw new IOException(\"NexoBlob not found\");\n      }\n      byte[] ciphertext = b64dec.decode(payload.getString());\n\n      \/\/ Get the SecurityTrailer and its values\n      JsonObject jsonTrailer = saletopoirequest.getJsonObject(\"SecurityTrailer\");\n      if (jsonTrailer == null) {\n         throw new IOException(\"SecurityTrailer not found\");\n      }\n      JsonNumber version = jsonTrailer.getJsonNumber(\"AdyenCryptoVersion\");\n      if (version == null || version.intValue() != 1) {\n         throw new IOException(\"AdyenCryptoVersion version not found or not supported\");\n      }\n      JsonString nonce = jsonTrailer.getJsonString(\"Nonce\");\n      if (nonce == null) {\n         throw new IOException(\"Nonce not found\");\n      }\n\n      JsonString keyId = jsonTrailer.getJsonString(\"KeyIdentifier\");\n      if (keyId == null) {\n         throw new IOException(\"KeyIdentifier not found\");\n      }\n      JsonNumber kversion = jsonTrailer.getJsonNumber(\"KeyVersion\");\n      if (kversion == null) {\n         throw new IOException(\"KeyVersion not found\");\n      }\n      JsonString b64 = jsonTrailer.getJsonString(\"Hmac\");\n      if (b64 == null) {\n         throw new IOException(\"Hmac not found\");\n      }\n\n      \/\/ Read the key from disk\n      NexoDerivedKeys dk = new NexoDerivedKeys();\n      dk.readKeyData(keyId.getString(), kversion.longValue());\n\n      \/\/ Decrypt the actual message with the base64 decoded ivmod as found in the securitytrailer\n      byte[] ivmod = b64dec.decode(nonce.getString());\n      byte[] ret = crypt(ciphertext, dk, ivmod, Cipher.DECRYPT_MODE);\n\n      \/\/ Base64 decode the received HMAC and compare it to a computed hmac\n      \/\/ Use a timing safe compare, this is to mitigate a (theoretical) timing based attack\n      byte[] receivedmac = b64dec.decode(b64.getString());\n      byte[] hmac = hmac(ret, dk);\n      if (receivedmac.length != hmac.length) {\n         throw new IOException(\"Validation failed\");\n      }\n      boolean equal = true;\n      for (int i = 0; i &lt; hmac.length; i++) {\n         if (receivedmac[i] != hmac[i]) {\n            equal = false;\n         }\n      }\n      if (!equal) {\n         throw new IOException(\"Validation failed\");\n      }\n\n      \/\/ Return decrypted message and outer header\n      return new BytesAndOuterHeader(ret, messageheader);\n   }\n\n   \/**\n    * Compare an inner and outer MessageHeader\n    * @param the inner  MessageHeader\n    * @param outer the outer MessageHeader\n    * @return\n    *\/\n   public boolean validateInnerAndOuterHeader(JsonObject inner, JsonObject outer) {\n      if (inner == null || outer == null) {\n         return false;\n      }\n      String[] fields = {\n            \"DeviceID\",\n            \"MessageCategory\",\n            \"MessageClass\",\n            \"MessageType\",\n            \"SaleID\",\n            \"ServiceID\",\n            \"POIID\",\n            \"ProtocolVersion\",\n      };\n      for (String field : fields) {\n\n         try {\n            JsonString a = inner.getJsonString(field);\n            JsonString b = outer.getJsonString(field);\n            if (a == null &amp;&amp; b == null) {\n               continue;\n            }\n            if (a == null || !a.equals(b)) {\n               return false;\n            }\n         }\n         catch (ClassCastException ex) {\n            return false;\n         }\n      }\n      return true;\n   }\n\n}<\/code><\/pre>\n<h2>Veja tamb\u00e9m<\/h2>\n<div class=\"see-also-links output-inline\" id=\"see-also\">\n<ul><li><a href=\"\/point-of-sale\"\n                        target=\"_self\"\n                        >\n                    Integra\u00e7\u00e3o da API de terminais\n                <\/a><\/li><li><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/framework\/wcf\/feature-details\/how-to-view-certificates-with-the-mmc-snap-in\"\n                        target=\"_blank\"\n                         class=\"external\">\n                     Como exibir certificados com o snap-in MMC\n                <\/a><\/li><li><a href=\"https:\/\/docs.microsoft.com\/en-us\/powershell\/module\/pkiclient\/import-certificate\"\n                        target=\"_blank\"\n                         class=\"external\">\n                     Importando certificados com o PowerShell\n                <\/a><\/li><\/ul><\/div>\n","url":"https:\/\/docs.adyen.com\/pt\/point-of-sale\/design-your-integration\/choose-your-architecture\/local\/protect","articleFields":{"description":"Valide e criptografe as comunica\u00e7\u00f5es locais entre sua caixa registradora e o terminal.","id":"47489964","type":"page","_expandable":{"operations":""},"status":"current","last_edit_on":"28-05-2020 17:18"},"algolia":{"url":"https:\/\/docs.adyen.com\/pt\/point-of-sale\/design-your-integration\/choose-your-architecture\/local\/protect","title":"Comunica\u00e7\u00f5es locais seguras","content":"Se sua integra\u00e7\u00e3o usar comunica\u00e7\u00f5es locais, voc\u00ea precisar\u00e1 executar algumas etapas adicionais para ajudar a proteger sua integra\u00e7\u00e3o contra ataques, intercepta\u00e7\u00e3o e adultera\u00e7\u00e3o.\nPara proteger as comunica\u00e7\u00f5es entre sua caixa registradora e o terminal, voc\u00ea precisa:\n\nValidar o certificado do terminal. Isso confirma que sua caixa registradora est\u00e1 se comunicando diretamente com um terminal da Adyen e n\u00e3o com um impostor.\nCriptografar comunica\u00e7\u00f5es . Isso impede que os invasores leiam as mensagens transmitidas entre a caixa registradora e o terminal.\n\nValidar certificado do terminal\nTodo terminal da Adyen vem pr\u00e9-instalado com um certificado assinado pela Adyen. Para confirmar que sua caixa registradora est\u00e1 se comunicando diretamente com um terminal da Adyen, \u00e9 necess\u00e1rio:\n\nInstalar o certificado raiz p\u00fablico da Adyen trust store.\nAutenticar a conex\u00e3o entre a caixa registradora e o terminal, verificando o certificado no terminal .\n\nEtapa 1: Instalar o certificado\nPara instalar o certificado raiz p\u00fablico da Adyen em seu trust store:\n\n\nFa\u00e7a o download dos certificados raiz p\u00fablicos da Adyen em sua caixa registradora:\n\nCertificado do terminal TEST: Para validar o certificado nos terminais Adyen TEST.\nCertificado do terminal LIVE: FPara validar o certificado nos terminais Adyen LIVE.\n\nEsses certificados podem ser convertidos para formatos como  .crt, .cer, ou .p12, se necess\u00e1rio.\n\n\nVerifique se a assinatura SHA-256 nos certificados corresponde ao seguinte:\n\nCertificado de terminal TEST: 3A 33 C3 34 C3 0F 69 46 E9 75 4B 6B B1 67 2B 54 6F BA A9 66 FB 6A 4B 58 AA 4E 3A BE 80 A7 EC BE\n\nCertificado de terminal LIVE: 06 D4 86 41 95 4B 95 7D 7A F5 F5 E4 5A 58 D8 61 DB 0D E3 CC ED BB 98 36 60 BB 01 6C E6 14 2D A1\n\n\n\n\nEm um ambiente Windows a impress\u00e3o digital SHA-256 pode n\u00e3o estar prontamente dispon\u00edvel por c\u00f3digo ou MMC. Nesse caso, verifique a assinatura SHA-1 nos certificados:\n\nCertificado de terminal TEST: D5 02 7F A8 B3 93 96 DB 2A 4F B1 86 EF 61 E4 A4 40 A7 30 51\n\nCertificado de terminal LIVE: 62 61 0D 88 27 8E 95 B7 F8 57 9A 9B 5E 07 85 D7 72 87 66 42\n\n\n\n\n\n\nInstale os certificados no trust store da sua caixa registradora.\n\nSiga as instru\u00e7\u00f5es do fornecedor para adicionar certificados raiz ao trust store do sistema ou do usu\u00e1rio.\nPor exemplo, a documenta\u00e7\u00e3o da Microsoft para adicionar certificados usando o snap-in MMC, ou importar certificados com o PowerShell.\nPara iOS, consulte: Manipula\u00e7\u00e3o de certificado iOS.\n\n\n\nDepois de instalar os certificados em seu trust store, verifique o certificado no terminal da sua caixa registradora.\nEtapa 2: Verificar o certificado\nQuando sua caixa registradora se conecta ao terminal, ela deve:\n\n\nVerificar se o certificado no terminal est\u00e1 assinado pelo certificado raiz confi\u00e1vel que voc\u00ea instalou. Essa verifica\u00e7\u00e3o inclui a verifica\u00e7\u00e3o autom\u00e1tica do certificado intermedi\u00e1rio fornecido pelo terminal no in\u00edcio da conex\u00e3o.\n\nVoc\u00ea ver\u00e1 um erro de incompatibilidade de nome comum durante a verifica\u00e7\u00e3o. Isso \u00e9 normal e acontece porque o Nome Comum do certificado n\u00e3o \u00e9 resolvido no DNS.\n\n\n\nValide o nome comum. O nome comum est\u00e1 em um dos seguintes formatos:\n\n\nFormatos de nome comum do terminal TEST:\n\nlegacy-terminal-certificate.test.terminal.adyen.com\n[POIID].test.terminal.adyen.com\n\n[POIID] = [Modelo do terminal]-[N\u00famero de s\u00e9rie]\nPor exemplo, P400Plus-123456789.test.terminal.adyen.com\n\n\n\n\nFormatos de nome comum do terminal LIVE:\n\nlegacy-terminal-certificate.live.terminal.adyen.com\n[POIID].live.terminal.adyen.com\n\n[POIID] = [Modelo do terminal]-[N\u00famero de s\u00e9rie]\nFor example P400Plus-123456789.live.terminal.adyen.com\n\n\n\n\nDependendo do n\u00famero de terminais que voc\u00ea est\u00e1 integrando, conv\u00e9m usar express\u00f5es regulares no seu c\u00f3digo para validar o Nome Comum.\n\n\nSe o certificado no terminal conectado passar na verifica\u00e7\u00e3o, sua caixa registradora ser\u00e1 conectada a um terminal Adyen.\nCriptografar comunica\u00e7\u00f5es\nPara impedir que outras pessoas possam ler as comunica\u00e7\u00f5es entre sua caixa registradora e o terminal, \u00e9 necess\u00e1rio criptografar as mensagens enviadas entre esses dispositivos. Criptografar essas comunica\u00e7\u00f5es envolve:\n\nDerivar uma chave de criptografia.\nCriptografar e descriptografar mensagens.\n\nEtapa 1: Derivar chave de criptografia\nDerive uma chave de criptografia para proteger a comunica\u00e7\u00e3o entre dispositivos usando a API do Terminal.\nPara derivar uma chave de criptografia, as duas partes devem:\n\nCompartilhar um segredo de comprimento vari\u00e1vel para obter o material principal.\nDerivar a chave usando PBKDF2_HMAC_SHA1\n\nIncluir os seguintes par\u00e2metros:\n\n\n\nPar\u00e2metro\nValor\n\n\n\n\nsalt\nAdyenNexoV1Salt\n\n\nsalt length\n15;\n\n\nrounds\n4000;\n\n\n\n\nSe o programa salvar a chave derivada resultante, esse c\u00e1lculo ser\u00e1 realizado uma vez para cada segredo compartilhado.\n\nO material da chave derivada consiste em 80 bytes: uma chave de cifra de 32 bytes, uma chave HMAC de 32 bytes e um vetor de inicializa\u00e7\u00e3o (IV) de 16 bytes. O IV \u00e9 XORed com um nonce aleat\u00f3rio que \u00e9 gerado por mensagem na criptografia.\n\nUma chave derivada \u00e9 identificada por sua  KeyIdentifier e sua vers\u00e3o.\n\n\n\nO exemplo de c\u00f3digo C a seguir demonstra como voc\u00ea usaria o OpenSSL para derivar o material principal:\n\/* The struct to hold the derived keys is defined like so: *\/\n\nstruct nexo_derived_keys {\n    uint8_t hmac_key[NEXO_HMAC_KEY_LENGTH];\n    uint8_t cipher_key[NEXO_CIPHER_KEY_LENGTH];\n    uint8_t iv[NEXO_IV_LENGTH];\n};\n\n\/* Function to derive the keys: *\/\nint nexo_derive_key_material(const char * passphrase, size_t len, struct nexo_derived_keys *dk) {\n    const unsigned char salt[] = \"AdyenNexoV1Salt\";\n    const int saltlen = sizeof(salt) - 1;\n    const int rounds = 4000;\n    return PKCS5_PBKDF2_HMAC_SHA1(passphrase, len, salt, saltlen, rounds,\n             sizeof(struct nexo_derived_keys), (unsigned char *)dk);\n\n}\nEtapa 2: Criptografar e descriptografar mensagens\nConfigure a criptografia na API do terminal para proteger as mensagens comunicadas entre o terminal e a caixa registradora.\nCriptografar mensagens\nPara criptografar uma mensagem:\n\nCriptografar o corpo da mensagem usando um vetor de inicializa\u00e7\u00e3o dk.iv (IV) do Nonce XOR, em que dk.iv \u00e9 o IV no material da chave derivada.\nO nonce (n\u00famero usado uma vez) \u00e9 uma sequ\u00eancia aleat\u00f3ria de bytes do mesmo tamanho que dk.iv gerado por mensagem.\nColoque o nonce na SecurityTrailer como uma cadeia de caracteres codificada Base64.\n\nDescriptografar e validar mensagens\nPara descriptografar e validar uma mensagem:\n\n\nDecomponha a mensagem em suas v\u00e1rias partes.\n\n\nVerifique o AdyenCryptoVersion no SecurityTrailer.\n\n\nRecupere o material principal com base em KeyIdentifier e KeyVersion.\n\n\nDescriptografe o blob usando o IV e digite o material da chave e o Nonce no SecurityTrailer.\n\n\nValide o HMAC computando-o no blob descriptografado.\n\nN\u00e3o valide no formul\u00e1rio serializado.\n\n\n\nCompare o resultado ao blob no  SecurityTrailer. A mensagem cont\u00e9m uma c\u00f3pia em texto n\u00e3o criptografado MessageHeader para fins de roteamento.\n\n\nUma vez emparelhado, compare o texto n\u00e3o criptografado MessageHeadercom oMessageHeaderdo corpo descriptografado e verifique se eles n\u00e3o s\u00e3o iguais aosMessageHeader` da parte descriptografado.\n\n\nConfigure uma chave na \u00e1rea do cliente\nA chave que o terminal utiliza, recuperada com a configura\u00e7\u00e3o do terminal, \u00e9 definida na Customer Area. Atualmente, o software do terminal \u00e9 capaz de usar apenas uma chave. Se v\u00e1rios dispositivos estiverem se comunicando com o mesmo terminal, eles dever\u00e3o compartilhar a mesma chave.\nPara configurar a chave:\n\nAbra a Customer Area e v\u00e1 para In-person payments &gt; Terminals.\nClique na linha do terminal que voc\u00ea deseja configurar. A p\u00e1gina de configura\u00e7\u00e3o desse terminal ser\u00e1 aberta.\nClique em View decrypted properties.\nA p\u00e1gina \u00e9 atualizada e retorna ao menu da API do terminal.\nClique em Terminal API tab.\nClique em Edit.\nDigite o identificador da chave de criptografia e a senha da chave.\nClique em Save.\nAdicione sua chave no campo Security Keys.\n\nA seguir, \u00e9 apresentado um exemplo da propriedade das Chaves de Seguran\u00e7a:\n{\n   \"defaultKey\":{\n      \"passphrase\":\"mysupersecretpassphrase\",\n      \"keyIdentifier\":\"mykey\",\n      \"version\":0\n   }\n}\nExemplo de criptografia\nO c\u00f3digo de exemplo abaixo implementa criptografia de mensagens, computa\u00e7\u00e3o e constru\u00e7\u00e3o do HMAC, al\u00e9m da opera\u00e7\u00e3o reversa: divis\u00e3o, valida\u00e7\u00e3o e descriptografia do HMAC.\n\nPor padr\u00e3o, o Java tem restri\u00e7\u00e3o AES 128. Pode ser necess\u00e1rio fazer o download de um novo arquivo de pol\u00edticas para ativar o AES 256, caso contr\u00e1rio, a exce\u00e7\u00e3o de chave ilegal ser\u00e1 lan\u00e7ada.\n\nimport java.io.*;\nimport java.security.*;\nimport java.security.spec.*;\nimport java.text.ParseException;\nimport java.util.Base64;\nimport java.util.Random;\nimport javax.crypto.*;\nimport javax.crypto.spec.IvParameterSpec;\nimport javax.crypto.spec.PBEKeySpec;\nimport javax.crypto.spec.SecretKeySpec;\nimport javax.json.*;\n\npublic class NexoCrypto {\n\n    public static final int NEXO_HMAC_KEY_LENGTH = 32;\n    public static final int NEXO_CIPHER_KEY_LENGTH = 32;\n    public static final int NEXO_IV_LENGTH = 16;\n\n   \/**\n    * Where to look for pre-derived key files\n    *\/\n   private String keyDirectory;\n\n   \/**\n    * The keys material to use when we are sending\n    *\/\n   private String keyIdentifier;\n   private long keyVersion;\n   private NexoDerivedKeys derivedKeys;\n\n    \/**\n     * A container for Nexo derived keys\n     *\n     * Nexo derived keys is a 80 byte struct containing key data. These 80\n     * bytes are derived from a passsphrase.\n     *\/\n   public class NexoDerivedKeys {\n      public byte hmac_key[];\n      public byte cipher_key[];\n      public byte iv[];\n\n      public NexoDerivedKeys() {\n         hmac_key = new byte[NEXO_HMAC_KEY_LENGTH];\n         cipher_key = new byte[NEXO_CIPHER_KEY_LENGTH];\n         iv = new byte[NEXO_IV_LENGTH];\n      }\n\n      \/**\n       * Read a key material file of 80 bytes, splitting it in the hmac_key, cipher_key and iv\n       *\/\n      public void readKeyData(String keyId, long keyV) throws IOException {\n         String filename = keyDirectory + '\/' + keyId + \".\" + Long.toString(keyV) + \".key\";\n\n         FileInputStream stream = null;\n         try {\n            stream = new FileInputStream(filename);\n            stream.read(this.hmac_key);\n            stream.read(this.cipher_key);\n            stream.read(this.iv);\n         } finally {\n            if (stream != null) {\n               try {\n                  stream.close();\n               }\n               catch (Exception ignored) {\n               }\n            }\n         }\n      }\n\n   };\n\n   \/**\n    * Use this constructor if you want to be able to both encryption and decryption\n    *\/\n   public NexoCrypto(String dir, String keyID, long keyV) throws IOException {\n      keyDirectory = dir;\n      keyIdentifier = keyID;\n      keyVersion = keyV;\n      derivedKeys = new NexoDerivedKeys();\n      derivedKeys.readKeyData(keyIdentifier, keyVersion);\n   }\n\n   \/**\n    * Use this constructor if you a decrypt-only NexoCrypto object\n    *\/\n   public NexoCrypto(String dir) {\n      keyDirectory = dir;\n   }\n\n   \/**\n    * Given a passphrase, compute 80 byte key of key material according to crypto.md\n    *\/\n   public static byte[] deriveKeyMaterial(char[] passphrase) throws NoSuchAlgorithmException, InvalidKeySpecException {\n      byte[] salt = \"AdyenNexoV1Salt\".getBytes();\n      int iterations = 4000;\n      PBEKeySpec spec = new PBEKeySpec(passphrase, salt, iterations, (NEXO_HMAC_KEY_LENGTH +\n            NEXO_CIPHER_KEY_LENGTH + NEXO_IV_LENGTH) * 8);\n      SecretKeyFactory skf = SecretKeyFactory.getInstance(\"PBKDF2WithHmacSHA1\");\n      byte[] keymaterial = skf.generateSecret(spec).getEncoded();\n      return keymaterial;\n   }\n\n   \/**\n    * Encrypt or decrypt data given a iv modifier and using the specified key\n    *\n    * The actual iv is computed by taking the iv from the key material and xoring it with ivmod\n    *\/\n   private byte[] crypt(byte[] bytes, NexoDerivedKeys dk, byte[] ivmod, int mode)\n         throws NoSuchAlgorithmException, NoSuchPaddingException,\n            IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {\n\n      Cipher cipher = Cipher.getInstance(\"AES\/CBC\/PKCS5Padding\");\n      SecretKeySpec s = new SecretKeySpec(dk.cipher_key, \"AES\");\n\n      \/\/ xor dk.iv and the iv modifier\n      byte[] actualIV = new byte[NEXO_IV_LENGTH];\n      for (int i = 0; i &lt; NEXO_IV_LENGTH; i++) {\n         actualIV[i] = (byte) (dk.iv[i] ^ ivmod[i]);\n      }\n\n      IvParameterSpec i = new IvParameterSpec(actualIV);\n      cipher.init(mode, s, i);\n      return cipher.doFinal(bytes);\n   }\n\n   \/**\n    * Compute a hmac using the hmac_key\n    *\/\n   private byte[] hmac(byte[] bytes, NexoDerivedKeys dk) throws NoSuchAlgorithmException, InvalidKeyException {\n      Mac mac = Mac.getInstance(\"HmacSHA256\");\n      SecretKeySpec s = new SecretKeySpec(dk.hmac_key, \"HmacSHA256\");\n\n      mac.init(s);\n      return mac.doFinal(bytes);\n   }\n\n   \/**\n    * Encrypt and compose a secured Nexo message\n    *\n    * This functions takes the original message, encrypts it and converts the encrypted form to Base64 and\n    * names it NexoBlob.\n    * After that, a new message is created with a copy of the header, the NexoBlob and an added SecurityTrailer.\n    *\n    * @param in is the byte representation of the unprotected Nexo message\n    * @returns a byte representation of the secured Nexo message\n    *\/\n   public byte[] encrypt_and_hmac(byte in[]) throws InvalidKeyException, NoSuchAlgorithmException,\n         NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException,\n         InvalidAlgorithmParameterException {\n      Base64.Encoder encb64 = Base64.getEncoder();\n\n      \/\/ parse the json and determined if it is a request or responce\n      JsonReader jsonreader = Json.createReader(new ByteArrayInputStream(in));\n      JsonObject body = jsonreader.readObject();\n      boolean request = true;\n      JsonObject saletopoirequest = body.getJsonObject(\"SaleToPOIRequest\");\n      if (saletopoirequest == null) {\n         request = false;\n         saletopoirequest = body.getJsonObject(\"SaleToPOIResponse\");\n      }\n      \/\/ pick up the MessageHeader\n      JsonObject messageheader = saletopoirequest.getJsonObject(\"MessageHeader\");\n\n      \/\/ Generate a random iv nonce\n      byte[] ivmod = new byte[NEXO_IV_LENGTH];\n      new Random().nextBytes(ivmod);\n\n      \/\/ encrypt taking the original bytes as input\n      byte[] encbytes = crypt(in, this.derivedKeys, ivmod, Cipher.ENCRYPT_MODE);\n\n      \/\/ compute mac over cleartext bytes\n      byte[] hmac = hmac(in, this.derivedKeys);\n\n      \/\/ Construct the inner Json object containing a MessageHeader, a NexoBlob and a SecurityTrailer\n      JsonObject msg = Json.createObjectBuilder()\n            .add(\"MessageHeader\", messageheader)\n            .add(\"NexoBlob\", new String(encb64.encode(encbytes)))\n            .add(\"SecurityTrailer\", Json.createObjectBuilder()\n                  .add(\"Hmac\", new String(encb64.encode(hmac)))\n                  .add(\"KeyIdentifier\", keyIdentifier)\n                  .add(\"KeyVersion\", keyVersion)\n                  .add(\"AdyenCryptoVersion\", 1)\n                  .add(\"Nonce\", new String(encb64.encode(ivmod)))\n                  ).build();\n      \/\/ Wrap the inner message in a SaleToPOIRequest or SaleToPOIResponse object\n      JsonObject total = Json.createObjectBuilder()\n            .add(request ?  \"SaleToPOIRequest\" : \"SaleToPOIResponse\" , msg)\n            .build();\n\n      ByteArrayOutputStream stream = new ByteArrayOutputStream();\n      JsonWriter writer = Json.createWriter(stream);\n      writer.writeObject(total);\n      writer.close();\n      return stream.toByteArray();\n   }\n\n   \/**\n    * A helper class to return a decrypted mesasage and the outer header from the\n    * secured Nexo message\n    *\/\n   public class BytesAndOuterHeader {\n      public byte[] packet;\n      public JsonObject outer_header;\n\n      public BytesAndOuterHeader(byte[] packet, JsonObject outer_header) {\n         this.packet = packet;\n         this.outer_header = outer_header;\n      }\n   }\n\n   \/*\n    * Validate and decrypt a secured Nexo message\n    *\n    * @returns a BytesAndOuterHeader object or null on failure\n    *\/\n   public BytesAndOuterHeader decrypt_and_validate_hmac(byte in[]) throws InvalidKeyException,\n         NoSuchAlgorithmException, IOException, NoSuchPaddingException, IllegalBlockSizeException,\n         BadPaddingException, InvalidAlgorithmParameterException {\n      Base64.Decoder b64dec = Base64.getDecoder();\n\n      \/\/ Parse bytes and retrieve MessageHeader\n      InputStream stream = new ByteArrayInputStream(in);\n      JsonReader jsonreader = Json.createReader(stream);\n      JsonObject total = jsonreader.readObject();\n      if (total == null) {\n         throw new IOException(\"Faulty JSON\");\n      }\n      JsonObject saletopoirequest = total.getJsonObject(\"SaleToPOIRequest\");\n      if (saletopoirequest == null) {\n         saletopoirequest = total.getJsonObject(\"SaleToPOIResponse\");\n      }\n      if (saletopoirequest == null) {\n         throw new IOException(\"No SaleToPOIRequest or SaleToPOIResponse\");\n      }\n      JsonObject messageheader = saletopoirequest.getJsonObject(\"MessageHeader\");\n      if (messageheader == null) {\n         throw new IOException(\"MessageHeader not found\");\n      }\n      \/\/ Get the encrypted actual message and base64 decode it\n      JsonString payload = saletopoirequest.getJsonString(\"NexoBlob\");\n      if (payload == null) {\n         throw new IOException(\"NexoBlob not found\");\n      }\n      byte[] ciphertext = b64dec.decode(payload.getString());\n\n      \/\/ Get the SecurityTrailer and its values\n      JsonObject jsonTrailer = saletopoirequest.getJsonObject(\"SecurityTrailer\");\n      if (jsonTrailer == null) {\n         throw new IOException(\"SecurityTrailer not found\");\n      }\n      JsonNumber version = jsonTrailer.getJsonNumber(\"AdyenCryptoVersion\");\n      if (version == null || version.intValue() != 1) {\n         throw new IOException(\"AdyenCryptoVersion version not found or not supported\");\n      }\n      JsonString nonce = jsonTrailer.getJsonString(\"Nonce\");\n      if (nonce == null) {\n         throw new IOException(\"Nonce not found\");\n      }\n\n      JsonString keyId = jsonTrailer.getJsonString(\"KeyIdentifier\");\n      if (keyId == null) {\n         throw new IOException(\"KeyIdentifier not found\");\n      }\n      JsonNumber kversion = jsonTrailer.getJsonNumber(\"KeyVersion\");\n      if (kversion == null) {\n         throw new IOException(\"KeyVersion not found\");\n      }\n      JsonString b64 = jsonTrailer.getJsonString(\"Hmac\");\n      if (b64 == null) {\n         throw new IOException(\"Hmac not found\");\n      }\n\n      \/\/ Read the key from disk\n      NexoDerivedKeys dk = new NexoDerivedKeys();\n      dk.readKeyData(keyId.getString(), kversion.longValue());\n\n      \/\/ Decrypt the actual message with the base64 decoded ivmod as found in the securitytrailer\n      byte[] ivmod = b64dec.decode(nonce.getString());\n      byte[] ret = crypt(ciphertext, dk, ivmod, Cipher.DECRYPT_MODE);\n\n      \/\/ Base64 decode the received HMAC and compare it to a computed hmac\n      \/\/ Use a timing safe compare, this is to mitigate a (theoretical) timing based attack\n      byte[] receivedmac = b64dec.decode(b64.getString());\n      byte[] hmac = hmac(ret, dk);\n      if (receivedmac.length != hmac.length) {\n         throw new IOException(\"Validation failed\");\n      }\n      boolean equal = true;\n      for (int i = 0; i &lt; hmac.length; i++) {\n         if (receivedmac[i] != hmac[i]) {\n            equal = false;\n         }\n      }\n      if (!equal) {\n         throw new IOException(\"Validation failed\");\n      }\n\n      \/\/ Return decrypted message and outer header\n      return new BytesAndOuterHeader(ret, messageheader);\n   }\n\n   \/**\n    * Compare an inner and outer MessageHeader\n    * @param the inner  MessageHeader\n    * @param outer the outer MessageHeader\n    * @return\n    *\/\n   public boolean validateInnerAndOuterHeader(JsonObject inner, JsonObject outer) {\n      if (inner == null || outer == null) {\n         return false;\n      }\n      String[] fields = {\n            \"DeviceID\",\n            \"MessageCategory\",\n            \"MessageClass\",\n            \"MessageType\",\n            \"SaleID\",\n            \"ServiceID\",\n            \"POIID\",\n            \"ProtocolVersion\",\n      };\n      for (String field : fields) {\n\n         try {\n            JsonString a = inner.getJsonString(field);\n            JsonString b = outer.getJsonString(field);\n            if (a == null &amp;&amp; b == null) {\n               continue;\n            }\n            if (a == null || !a.equals(b)) {\n               return false;\n            }\n         }\n         catch (ClassCastException ex) {\n            return false;\n         }\n      }\n      return true;\n   }\n\n}\nVeja tamb\u00e9m\n\n\n                    Integra\u00e7\u00e3o da API de terminais\n                \n                     Como exibir certificados com o snap-in MMC\n                \n                     Importando certificados com o PowerShell\n                \n","type":"page","locale":"pt","boost":15,"hierarchy":{"lvl0":"Home","lvl1":"Terminais","lvl2":"Design your integration","lvl3":"Escolha uma arquitetura de integra\u00e7\u00e3o para seus terminais","lvl4":"Construindo uma integra\u00e7\u00e3o local","lvl5":"Comunica\u00e7\u00f5es locais seguras"},"hierarchy_url":{"lvl0":"https:\/\/docs.adyen.com\/pt","lvl1":"https:\/\/docs.adyen.com\/pt\/point-of-sale","lvl2":"https:\/\/docs.adyen.com\/pt\/point-of-sale\/design-your-integration","lvl3":"https:\/\/docs.adyen.com\/pt\/point-of-sale\/design-your-integration\/choose-your-architecture","lvl4":"https:\/\/docs.adyen.com\/pt\/point-of-sale\/design-your-integration\/choose-your-architecture\/local","lvl5":"\/pt\/point-of-sale\/design-your-integration\/choose-your-architecture\/local\/protect"},"levels":6,"category":"In-person payments","category_color":"green","tags":["Comunica\u00e7\u00f5es","locais","seguras"]},"articleFiles":{"encryption-decryption.js":"<p alt=\"\">encryption-decryption.js<\/p>"}}
