Pular para o conteúdo principal
ℹ️ Conteúdo em atualização

Estamos revisando estes procedimentos. Pessoas técnicas podem encontrar ajustes em códigos de erro ou mapeamentos de payload; valide com os logs e o OpenAPI mais recente. Pessoas não técnicas podem continuar usando o passo a passo e acionar o time de suporte caso algo pareça diferente do descrito.

🔐 Geração de Pinblock ISO-0

Este documento descreve o processo completo para gerar um Pinblock no formato ISO-0 (ISO 9564-1 Format 0), necessário para realizar transações de venda com senha criptografada.

🎯 O que é Pinblock?

O Pinblock (PIN Block) é um método padrão de criptografia de senha (PIN) usado em transações financeiras. Ele combina o PIN do cliente com o número do cartão (PAN) e aplica criptografia 3DES para garantir a segurança da transação.

Características

  • Formato: ISO-0 (ISO 9564-1 Format 0)
  • Padding: Caractere F
  • Criptografia: 3DES ECB
  • Tamanho: 16 bytes (32 caracteres hexadecimais)

🔄 Processo de Geração

A geração do Pinblock envolve 3 passos principais:

📝 Passo a Passo

Dados de Entrada

Para o exemplo, vamos usar:

  • PAN (Número do Cartão): 9357229116678858
  • Senha (PIN): 8374
  • Working Key: BF21C1AB96E97E1CF2D9EFAE4A9086F6458B9E6118B1AF8C (obtida via API)

Passo 1: Formatação do PIN

Concatene os seguintes elementos para formar uma string de 16 caracteres hexadecimais:

  1. 04 - Prefixo fixo indicando o formato ISO-0
  2. Tamanho do PIN - Número de dígitos do PIN (4 neste exemplo)
  3. PIN - A senha do cliente
  4. Padding F - Preencha o restante com F até completar 16 caracteres

Exemplo:

Prefixo: 04
Tamanho: 4
PIN: 8374
Padding: FFFFFFFFFFF

Resultado Passo 1: 04 8374 FFFFFFFFFFF

Formatado: 04 83 74 FF FF FF FF FF

Em hexadecimal: 0 4 8 3 7 4 F F F F F F F F F F

Passo 2: Formatação do PAN

Extraia os 12 dígitos centrais do PAN (posições 4 a 15, desconsiderando os dígitos de controle) e formate:

  1. 0000 - Prefixo fixo
  2. 12 dígitos do PAN - Posições 4 até 15 do número do cartão

Exemplo:

PAN completo: 9357229116678858
Posições 4-15: 722911667885

Prefixo: 0000
PAN parcial: 722911667885

Resultado Passo 2: 0000722911667885

Em hexadecimal: 0 0 0 0 7 2 2 9 1 1 6 6 7 8 8 5

Passo 3: Operação XOR

Aplique a operação XOR bit a bit entre os resultados do Passo 1 e Passo 2:

Passo 1:  0 4 8 3 7 4 F F F F F F F F F F
Passo 2: 0 0 0 0 7 2 2 9 1 1 6 6 7 8 8 5
─────────────────────────────────
XOR: 0 4 8 3 0 6 D 6 E E 9 9 8 7 7 A

Resultado (Pinblock em Claro): 048306D6EE99877A

Validando o XOR

Você pode validar o XOR usando a Calculadora do Windows no modo Programador:

Exemplo: F XOR 6 = 9

F (hex) = 1111 (binário)
6 (hex) = 0110 (binário)
────
XOR 1001 (binário) = 9 (hex)

Passo 4: Criptografia 3DES

Aplique criptografia 3DES no modo ECB usando a Working Key obtida através da API:

Exemplo:

Pinblock em Claro: 048306D6EE99877A
Working Key: BF21C1AB96E97E1CF2D9EFAE4A9086F6458B9E6118B1AF8C

Algoritmo: 3DES ECB (sem padding adicional)

Resultado: a760654cfeeffd24

Pinblock Criptografado Final: a760654cfeeffd24

💻 Implementação

JavaScript/Node.js

const crypto = require('crypto');

/**
* Gera um Pinblock ISO-0 criptografado
* @param {string} pin - Senha do cliente (4-12 dígitos)
* @param {string} pan - Número do cartão (PAN)
* @param {string} workingKey - Chave de trabalho (hex string)
* @returns {string} Pinblock criptografado em hexadecimal
*/
function gerarPinblockISO0(pin, pan, workingKey) {
// Validações
if (!pin || pin.length < 4 || pin.length > 12) {
throw new Error('PIN deve ter entre 4 e 12 dígitos');
}
if (!pan || pan.length < 13) {
throw new Error('PAN inválido');
}

// Passo 1: Formatar PIN
const pinLength = pin.length.toString(16).padStart(2, '0');
const passo1 = ('04' + pin + 'F'.repeat(14 - pin.length)).toUpperCase();

// Passo 2: Formatar PAN (posições 4 a 15)
const panPart = pan.substring(pan.length - 13, pan.length - 1);
const passo2 = ('0000' + panPart).substring(0, 16);

// Passo 3: XOR
let pinblockClaro = '';
for (let i = 0; i < 16; i++) {
const xor = parseInt(passo1[i], 16) ^ parseInt(passo2[i], 16);
pinblockClaro += xor.toString(16).toUpperCase();
}

console.log('Passo 1 (PIN formatado):', passo1);
console.log('Passo 2 (PAN formatado):', passo2);
console.log('Passo 3 (XOR - Pinblock em claro):', pinblockClaro);

// Passo 4: Criptografar com 3DES
const key = Buffer.from(workingKey, 'hex');
const cipher = crypto.createCipheriv('des-ede3', key, null);
cipher.setAutoPadding(false);

const pinblockBuffer = Buffer.from(pinblockClaro, 'hex');
let encrypted = cipher.update(pinblockBuffer);
encrypted = Buffer.concat([encrypted, cipher.final()]);

const pinblockCriptografado = encrypted.toString('hex');

console.log('Pinblock Criptografado:', pinblockCriptografado);

return pinblockCriptografado;
}

// Exemplo de uso
const pin = '8374';
const pan = '9357229116678858';
const workingKey = 'BF21C1AB96E97E1CF2D9EFAE4A9086F6458B9E6118B1AF8C';

const pinblock = gerarPinblockISO0(pin, pan, workingKey);
console.log('\nPinblock Final:', pinblock);
// Resultado esperado: a760654cfeeffd24

Python

from Crypto.Cipher import DES3
import binascii

def gerar_pinblock_iso0(pin, pan, working_key):
"""
Gera um Pinblock ISO-0 criptografado

Args:
pin (str): Senha do cliente (4-12 dígitos)
pan (str): Número do cartão (PAN)
working_key (str): Chave de trabalho (hex string)

Returns:
str: Pinblock criptografado em hexadecimal
"""
# Validações
if not pin or len(pin) < 4 or len(pin) > 12:
raise ValueError('PIN deve ter entre 4 e 12 dígitos')
if not pan or len(pan) < 13:
raise ValueError('PAN inválido')

# Passo 1: Formatar PIN
passo1 = f"04{pin}{'F' * (14 - len(pin))}"

# Passo 2: Formatar PAN (posições 4 a 15)
pan_part = pan[-13:-1]
passo2 = f"0000{pan_part}"[:16]

# Passo 3: XOR
pinblock_claro = ''
for i in range(16):
xor = int(passo1[i], 16) ^ int(passo2[i], 16)
pinblock_claro += format(xor, 'X')

print(f'Passo 1 (PIN formatado): {passo1}')
print(f'Passo 2 (PAN formatado): {passo2}')
print(f'Passo 3 (XOR - Pinblock em claro): {pinblock_claro}')

# Passo 4: Criptografar com 3DES
key = binascii.unhexlify(working_key)
cipher = DES3.new(key, DES3.MODE_ECB)

pinblock_bytes = binascii.unhexlify(pinblock_claro)
encrypted = cipher.encrypt(pinblock_bytes)

pinblock_criptografado = binascii.hexlify(encrypted).decode('utf-8')

print(f'Pinblock Criptografado: {pinblock_criptografado}')

return pinblock_criptografado

# Exemplo de uso
pin = '8374'
pan = '9357229116678858'
working_key = 'BF21C1AB96E97E1CF2D9EFAE4A9086F6458B9E6118B1AF8C'

pinblock = gerar_pinblock_iso0(pin, pan, working_key)
print(f'\nPinblock Final: {pinblock}')
# Resultado esperado: a760654cfeeffd24

Java

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.HexFormat;

public class PinblockISO0 {

public static String gerarPinblockISO0(String pin, String pan, String workingKey)
throws Exception {

// Validações
if (pin == null || pin.length() < 4 || pin.length() > 12) {
throw new IllegalArgumentException("PIN deve ter entre 4 e 12 dígitos");
}
if (pan == null || pan.length() < 13) {
throw new IllegalArgumentException("PAN inválido");
}

// Passo 1: Formatar PIN
StringBuilder passo1 = new StringBuilder("04");
passo1.append(pin);
while (passo1.length() < 16) {
passo1.append('F');
}

// Passo 2: Formatar PAN (posições 4 a 15)
String panPart = pan.substring(pan.length() - 13, pan.length() - 1);
String passo2 = ("0000" + panPart).substring(0, 16);

// Passo 3: XOR
StringBuilder pinblockClaro = new StringBuilder();
for (int i = 0; i < 16; i++) {
int xor = Character.digit(passo1.charAt(i), 16) ^
Character.digit(passo2.charAt(i), 16);
pinblockClaro.append(Integer.toHexString(xor).toUpperCase());
}

System.out.println("Passo 1 (PIN formatado): " + passo1);
System.out.println("Passo 2 (PAN formatado): " + passo2);
System.out.println("Passo 3 (XOR - Pinblock em claro): " + pinblockClaro);

// Passo 4: Criptografar com 3DES
byte[] keyBytes = HexFormat.of().parseHex(workingKey);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "DESede");

Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);

byte[] pinblockBytes = HexFormat.of().parseHex(pinblockClaro.toString());
byte[] encrypted = cipher.doFinal(pinblockBytes);

String pinblockCriptografado = HexFormat.of().formatHex(encrypted);

System.out.println("Pinblock Criptografado: " + pinblockCriptografado);

return pinblockCriptografado;
}

public static void main(String[] args) {
try {
String pin = "8374";
String pan = "9357229116678858";
String workingKey = "BF21C1AB96E97E1CF2D9EFAE4A9086F6458B9E6118B1AF8C";

String pinblock = gerarPinblockISO0(pin, pan, workingKey);
System.out.println("\nPinblock Final: " + pinblock);
// Resultado esperado: a760654cfeeffd24

} catch (Exception e) {
e.printStackTrace();
}
}
}

🔗 Usando na API de Venda

Após gerar o Pinblock, utilize-o no campo senhaCriptografada da API de venda:

{
"estabelecimento": "12345",
"codigoMaquina": "PDV001",
"cartao": {
"tarja": "9357229116678858",
"cvv2": "000",
"senhaCriptografada": "a760654cfeeffd24"
},
"nsu": "123456789",
"venda": {
"valor": 150.00,
"quantidadeParcelas": 1,
"tipoParcelamento": "A"
}
}

Exemplo de Chamada cURL

curl --location 'https://api.credsystem.com/v1/venda' \
--header 'Authorization: Bearer SEU_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"estabelecimento": "12345",
"codigoMaquina": "PDV001",
"cartao": {
"tarja": "9357229116678858",
"cvv2": "000",
"senhaCriptografada": "a760654cfeeffd24"
},
"nsu": "123456789",
"venda": {
"valor": 150.00,
"quantidadeParcelas": 1,
"tipoParcelamento": "A"
}
}'

🔑 Obtendo a Working Key

A Working Key deve ser obtida através da API de criptografia antes de gerar o Pinblock:

// Exemplo de obtenção da Working Key
const obterWorkingKey = async () => {
const response = await fetch('https://api.credsystem.com/v1/crypto/working-key', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
estabelecimento: '12345',
terminal: 'PDV001'
})
});

const data = await response.json();
return data.workingKey;
};

🧪 Ferramentas de Validação

Validar XOR Online

Use a Calculadora do Windows no modo Programador:

  1. Abra a Calculadora
  2. Vá em ExibirProgramador
  3. Selecione HEX
  4. Digite o primeiro valor
  5. Clique em XOR
  6. Digite o segundo valor
  7. Veja o resultado

Validar 3DES Online

Você pode validar a criptografia 3DES em: http://tripledes.online-domain-tools.com/

Configurações:

  • Mode: ECB
  • Key: Sua Working Key (hex)
  • Input: Pinblock em claro (hex)
  • Output: Deve corresponder ao seu resultado

⚠️ Considerações de Segurança

Boas Práticas

  • Nunca armazene o PIN ou Pinblock em claro
  • Use HTTPS para todas as comunicações
  • Renove a Working Key periodicamente
  • Implemente timeout para entrada de senha
  • Limite tentativas de senha incorreta
  • Use bibliotecas criptográficas confiáveis

Não Faça

  • Não envie o PIN em claro pela rede
  • Não registre o PIN ou Pinblock em logs
  • Não use chaves fixas em produção
  • Não implemente criptografia própria
  • Não armazene Working Keys no frontend

🔍 Troubleshooting

Problemas Comuns

ProblemaCausa ProvávelSolução
Pinblock diferente do esperadoErro no XOR ou formataçãoValidar cada passo individualmente
Erro de criptografiaWorking Key incorretaVerificar formato hex da chave
API rejeita PinblockFormato incorretoConfirmar formato ISO-0 e 3DES ECB
Erro de paddingPIN muito curto/longoValidar tamanho do PIN (4-12 dígitos)

Validação Passo a Passo

// Debug: Validar cada etapa
console.log('PIN:', pin);
console.log('PAN:', pan);
console.log('Passo 1:', passo1);
console.log('Passo 2:', passo2);
console.log('Pinblock Claro:', pinblockClaro);
console.log('Working Key:', workingKey);
console.log('Pinblock Criptografado:', pinblockCriptografado);

📚 Referências

  • ISO 9564-1: Personal Identification Number (PIN) management and security
  • ANSI X9.8: PIN Management and Security
  • 3DES: Triple Data Encryption Standard (FIPS 46-3)

🆘 Suporte

Para dúvidas ou problemas com geração de Pinblock:


Última atualização: Dezembro 2024