Connect challenge

O Connect Challenge é o processo de adição de autenticação em dois fatores na API de Transferência do PagBank. Ele envolve a geração de um token e um desafio a serem utilizados como segundo fator de segurança durante a integração com determinadas APIs do PagBank. Esse procedimento envolve o uso de um par de chaves criptografadas, uma pública e outra privada, que oferecem um alto nível de segurança. A utilização das chaves criptografadas garante uma camada adicional de proteção, tornando o sistema mais resiliente a ameaças e violações de segurança.

O processo para a configuração do Connect Challenge é dividido em 4 passos, que serão apresentados na sequência. Entretanto, antes de iniciar é necessário que você tenha uma conta no PagBank Sandbox. Caso ainda não tenha uma conta se registre acessando a página do PagBank Sandbox. Se você já tem uma conta, prossiga para o passo a passo.

1. Gerar as chaves pública e privada

Inicialmente gere um par de chaves, uma pública e uma privada. A chave pública deve ser gerada no formato x.509 (SPKI). Já a chave privada deve ser gerada no formato PKCS8. Ambas precisam ter no mínimo 2048 bits. A seguir são apresentados exemplos de como gerar o par de chaves usando diferentes linguagens de programação.

#> openssl genpkey -algorithm RSA -out private-key -pkeyopt rsa_keygen_bits:2048
#> openssl rsa -pubout -in private-key -out public-key
public static void main(String[] args) throws Exception {
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
    keyPairGenerator.initialize(2048);
    KeyPair keyPair = keyPairGenerator.generateKeyPair();

    System.out.println(Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()));
    System.out.println(Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()));
}
fun main(args: Array<String>) {
    val keyPair = KeyPairGenerator.getInstance("RSA")
        .apply { this.initialize(2048) }.generateKeyPair()
    println(Base64.getEncoder().encodeToString(keyPair.public.encoded))
    println(Base64.getEncoder().encodeToString(keyPair.private.encoded))
}
using System.Security.Cryptography;

var rsa = RSA.Create(2048);
var pubKey = rsa.ExportSubjectPublicKeyInfo();
var privKey = rsa.ExportPkcs8PrivateKeyPem();

Console.WriteLine(Convert.ToBase64String(pubKey));
Console.WriteLine("-------------");
Console.WriteLine(privKey);
var crypto = require('crypto');

crypto.generateKeyPair('rsa',
{
    modulusLength: 2048,
    publicKeyEncoding: {
      type: 'spki',
      format: 'pem'
    },
    privateKeyEncoding: {
      type: 'pkcs8',
      format: 'pem',
    }
  }
, (error, pubKey, pvtKey) => {
    console.log(pubKey);
    console.log(pvtKey);
});

🚧

Proteja sua chave privada

A chave privada é confidencial. Recomendamos não compartilhá-la em ambientes públicos ou com terceiros, além de armazená-la em local seguro.

2. Disponibilize sua chave pública

Você precisa disponibilizar sua chave pública e a data de criação em um endpoint GET. O Content-Type deste endpoint público deve ser do tipo application/json e os dados precisam através no corpo da resposta seguindo o seguinte padrão:

{
  "public_key": "public_key",
  "created_at": 1580237849044
}

O parâmetro public_key deve conter sua chave pública no formato .pem. Já o parâmetro created_at deve ser do tipo long e conter a data em que a chave foi gerada no formato timestamp.

3. Informe a URL da chave pública

Você precisa fornecer a URL do endpoint GETdo passo 2 ao PagBank. Caso esteja utilizando o ambiente Sandbox, abra uma solicitação no Portal PagBank . Nessa página você fornecerá o nome da sua empresa, o e-mail registrado na PagBank e a URL do endpoint criado. O SLA de resposta é de até 2 dias úteis.

Se você está utilizando o ambiente de Produção, a URL deve ser informada de outra forma. Acesse e faça o login na conta. No menu Vendas, acesse Integrações e faça o cadastro da URL. Feito isso, a URL estará cadastrada no ambiente de Produção.

Antes de prosseguir para os passos seguintes, você precisa ter recebido uma devolutiva positiva do chamado aberto para cadastro da URL. Se você está utilizando o ambiente de produção, o resultado da adição é instantâneo.

4. Gere o challenge e o token de acesso

Esse passo só deve ser iniciado caso o passo 3 tenha sido concluído com sucesso. Se a URL de compartilhamento da chave pública não tiver ocorrido com sucesso, o passo atual não será finalizado com sucesso.

Para obter o token de acesso e o challenge você utilizará o endpoint Obter access token. Você precisará definir o tipo da requisição, fornecendo challenge para o parâmetro grand_type e certificate.create para scope. O escopo certificate.create possibilita solicitar a criação de um certificado digital.

A resposta do endpoint fornecerá um Challenge criptografado com a sua chave pública. O desafio estará codificado em base64 e será necessário decodificá-lo. Em seguida, você deve descriptografá-lo utilizando a sua chave privada.

O desafio opera de maneira simples: utilizando a sua chave pública, é aplicado o algoritmo RSA para criptografar uma string. Essa string criptografada só poderá ser descriptografada utilizando a chave privada correspondente, que você possui e mantém de forma segura.

Para descriptografar o desafio, é necessário utilizar a estratégia de Padding do mecanismo OAEP (Optimal Asymmetric Encryption Padding), com a função geradora de máscara MGF1 e o algoritmo de hash SHA-256. Abaixo você encontra exemplos de como realizar a descriptografia em algumas linguagens:

import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;

public class Main {

    public static void main(String[] args) throws Exception {
        String privateKey = Files.readString(Paths.get("<private_key_dir_path>"));
        privateKey = privateKey.replace("-----BEGIN PRIVATE KEY-----", "")
			     .replaceAll(System.lineSeparator(), "")
			     .replace("-----END PRIVATE KEY-----", "");

		byte[] decodedPrivateKey = Base64.getDecoder().decode(privateKey);
		
        var privateKeySpec = new PKCS8EncodedKeySpec(decodedPrivateKey);
        var privateKkeyFactory = KeyFactory.getInstance("RSA");
        PrivateKey pvtKey = privateKkeyFactory.generatePrivate(privateKeySpec);

        
        OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), PSource.PSpecified.DEFAULT);
		
		Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
        cipher.init(Cipher.DECRYPT_MODE, pvtKey, oaepParams);

        byte[] decodedChallenge = Base64.getDecoder().decode("<crypted_challenge>");
        byte[] decipheredChallenge = cipher.doFinal(decodedChallenge);

        System.out.println(new String(decipheredChallenge));
    }
}
var crypto = require('crypto');
var fs = require('fs');

const privateKeyPem = fs.readFileSync('<private_key_dir_path>');
const privateKey = crypto.createPrivateKey({key: privateKeyPem});
const decryptedData = crypto.privateDecrypt(
    {
        key: privateKey,
        padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
        oaepHash: 'sha256'
    }, Buffer.from('<encrypted_challenge>', 'base64'));

console.log(decryptedData.toString());
using System.Security.Cryptography;

var privateKey = "<load_private_key>";
var challenge = "<input_server_generated_challenge>";

var rsa = RSA.Create();
rsa.ImportFromPem(privateKey.ToCharArray());

var decrypted = rsa.Decrypt(Convert.FromBase64String(challenge), RSAEncryptionPadding.OaepSHA256);

Console.WriteLine(System.Text.Encoding.Default.GetString(decrypted));

Uma vez que você tenha descriptografado o desafio com sucesso, poderá utilizar as informações obtidas, juntamente com o token gerado, na sua próxima requisição que exigir essa informação. O token gerado deve ser utilizado na sua próxima requisição e tem uma válidade de 30 segundos. Caso o token expire, você deve repetir o processo para obter um novo token.