Basicamente precisa do:
- CARTAO, vulgo PAN
- Vencimento
e das chaves de criptografia
o código de segurança varia de acordo com o que vamos calcular, mas bora deixar fixo em 999 que acho era o valor pra quando formos calcular o que fica atrás do cartao, o CVV2/CVC2/CVE2.
Vamos usar esses dados aqui
5067240000000019 --> confere pra ver se é 9 mesmo o digito verificador!
2512
CVK A - (em claro) - 0123456789012345
CVK B - (em claro) - ABCDEF0123456789
- CARTAO, vulgo PAN
- Vencimento
e das chaves de criptografia
o código de segurança varia de acordo com o que vamos calcular, mas bora deixar fixo em 999 que acho era o valor pra quando formos calcular o que fica atrás do cartao, o CVV2/CVC2/CVE2.
Vamos usar esses dados aqui
5067240000000019 --> confere pra ver se é 9 mesmo o digito verificador!
2512
CVK A - (em claro) - 0123456789012345
CVK B - (em claro) - ABCDEF0123456789
Beleza, nao precisamos de mais nada, só isso já basta
Agora é pra quem é virjão de tudo, pode ir nesse site aqui
http://software.codemagus.com/WebTools/cgi-bin/cmlvccomputevisacvv
e colocar os dados tudo e clicar em compute, puf, código gerado!
ou pode ser aqui
https://paymentcardtools.com/card-security-values/cvv-calculator
http://software.codemagus.com/WebTools/cgi-bin/cmlvccomputevisacvv
e colocar os dados tudo e clicar em compute, puf, código gerado!
ou pode ser aqui
https://paymentcardtools.com/card-security-values/cvv-calculator
Figura 2 - Print Screen geracao do CVC pelo paymentcardtools.com |
esse até mais legal que mostra até um KCV - key check value de cada chave! e valida o numero do cartao!
temos ainda outras opções, como o
https://fint-1227.appspot.com/cvvcalc/
Figura 3 - Geracao de código de segurança pelo site https://fint-1227.appspot.com/ |
Mas voce é curioso e quer saber como as coisas funcionam, fazer um código, um programa! Mas antes disso, vamos executar o calculo usando um grande companheiro, o BPTools
Figura 4 - Geracao do CVV usando o BPTools - módulo de Calculadora Criptografica |
Criptografa com a chave 1 -> Descriptografa com a chave 2 -> Criptografa com a chave 1
O algoritmo pra calcular o CVV é basicamente isso aqui
Dados necessários
- Chave em claro (2 componentes)
- Cartao
- Vencimento
- Código de serviço
Preparação dos Dados -> DATA
Combine os dados: Concatene o Número do Cartão (PAN), a data de validade e o código de serviço.
Complete com zeros: Adicione zeros à direita dessa sequência até que ela tenha 32 caracteres no total.
Processo de Criptografia
Com a "DATA" preparada, o processo de criptografia e descriptografia é o seguinte:
- Criptografe a primeira metade da "DATA" (parte da esquerda) usando a primeira metade da chave, bom deixar claro, parte da esquerda é a primeira! (é uma operação DES) .
- Aplique uma operação XOR no resultado com a segunda metade da "DATA".
==> aqui é o tal do Triple DES (3DES)
- Criptografe novamente o resultado utilizando a primeira metade da chave (DES).
- Descriptografe o resultado com a segunda metade da chave (DES).
- Criptografe mais uma vez o valor obtido, usando a primeira metade da chave (DES).
Geração do CVV
Extraia apenas os dígitos da ultima operacao de DES, os primeiros três números correspondem ao CVV.
Segue o código abaixo de exemplo
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
from Crypto.Cipher import DESimport binasciiimport re
# Função para verificar o dígito verificador - mod 10def luhn_check(card_number): digits = [int(d) for d in card_number] checksum = 0 parity = len(digits) % 2 for i, d in enumerate(digits): if i % 2 == parity: d *= 2 if d > 9: d -= 9 checksum += d return checksum % 10 == 0
# Função para preencher à direita com zeros def pad_right(s, length, pad_char='0'): return s.ljust(length, pad_char)
# Funções de criptografia DES - encriptardef des_encrypt(key, data): cipher = DES.new(key, DES.MODE_ECB) return cipher.encrypt(data)
# Funções de criptografia DES - decriptardef des_decrypt(key, data): cipher = DES.new(key, DES.MODE_ECB) return cipher.decrypt(data)
# Função para converter string hexadecimal em bytesdef hexstr_to_bytes(hexstr): return binascii.unhexlify(hexstr)
# Função para gerar o código de segurança!# CVV (Card Verification Value) CVC (Card Verification Code) CVE (Código de Verificacao ELO)
def generate_cvv(pan, expiry, service_code, key_hex): # Quebra a chave em duas partes ("chave a e chave b") com 16 caracteres cada key_a = hexstr_to_bytes(key_hex[:16]) key_b = hexstr_to_bytes(key_hex[16:32])
# Concatena Cartao, vencimento (AAMM) e código de serviço data = pan + expiry + service_code # "pad" com zeros até 32 caracteres data = pad_right(data, 32, '0') # Quebra em duas metades left e right halves com 16 caracteres cada left = data[:16] right = data[16:] # Converte para hexadecimal left_bytes = binascii.unhexlify(left) right_bytes = binascii.unhexlify(right) # Criptografa a parte da esqueda com a "chave_a" encrypted_left = des_encrypt(key_a, left_bytes)
# Faz XOR com o resultado com a parte direita xor_result = bytes([a ^ b for a, b in zip(encrypted_left, right_bytes)]) # Criptografa com a "chave a" TDES_passo1 = des_encrypt(key_a, xor_result) # Decriptografa com a "chave b" TDES_passo2 = des_decrypt(key_b, TDES_passo1)
# Criptografa novamente com a "chave a" TDES_passo3 = des_encrypt(key_a, TDES_passo2)
# Pega apenas os dígitos do resultado, afinal estavamos trabalhando com hexadecimal digits = re.sub(r'\D', '', TDES_passo3.hex())
# e queremos os primeiros 3 dígitos que é nosso CVV return digits[:3]
# Nossos dados de entrada #key_hex = "0123456789012345ABCDEF0123456789"pan = "5067240000000019"expiry = "2512" service_code = "999"
# Validações dos dados de entrada #if not luhn_check(pan): raise ValueError("Número do cartão inválido (verifique o dígito verificador).")if len(pan) != 16 or not pan.isdigit(): raise ValueError("O PAN deve ter 16 dígitos numéricos.")if len(expiry) != 4 or not expiry.isdigit(): raise ValueError("A data de validade deve ter 4 dígitos numéricos (YYMM).")if len(service_code) != 3 or not service_code.isdigit(): raise ValueError("O código de serviço deve ter 3 dígitos numéricos.")if len(key_hex) != 32 or not all(c in '0123456789ABCDEF' for c in key_hex.upper()): raise ValueError("A chave deve ter 32 caracteres hexadecimais (16 bytes).")if not key_hex.isalnum(): raise ValueError("A chave deve conter apenas caracteres alfanuméricos (hexadecimais).")if not key_hex.isupper(): raise ValueError("A chave deve estar em letras maiúsculas (hexadecimais).")# Se todos os dados de entrada forem válidos, gera o CVVelse: cvv = generate_cvv(pan, expiry, service_code, key_hex) print("CVV gerado :", cvv)
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxque da um belo display de saida
CVV gerado : 728
ou podemos usar um HSM, ai é coisa séria, bonita de ver!
Digamos que voce vá usar o Thales Payshield 9000 (que ja ta fora de linha e acho que é bem bom pra ilustrar os comandos e mesmo ser simulado), bom, nao vou dar aula de chaves aqui, mas a de CVV é do esquema U, e do tipo 402, variante 4 e o setimo par de chaves de LMK, que sao {"E0E0010101010101", "F1F1010101010101"} e usando novamente nosso amigo BP-TOOLS, vai dar isso aqui!
UC68879EF8F0E22A2B8A51FE73409DC16
na real nao estou importando, o comando seria o A4, se nao me engano!
Figura 5 - "Importação da Chave" no HSM |
Poderia "importar" de verdade ou usar um outro simulador, igual esse aqui em go, por exemplo
root@Tecladinho:/mnt/c/Windows/System32/go_hsm/bin#
./go_hsm keys import --key 0123456789012345ABCDEF0123456789 --type 402 --scheme U
Key Type: Name: CVK/CSCK, Code: 402, LMKPairIndex: 7, VariantID: 4
Key Scheme: U
Encrypted Key: UC68879EF8F0E22A2B8A51FE73409DC16
KCV: 7FFC84
root@Tecladinho:/mnt/c/Windows/System32/go_hsm/bin#
que gera a mesma coisa, bom sinal!
Figura 6 - Execucao do comando CW pelo BPTools |
mas nao to ligado num HSM de verdade, é um Thales Payshield HSM Simulator!
Figura 7 - Thales Simulator |
e olha ai, 728! Grande numero!
é isso, grandes lembranças!
Ah, a importação da chave no HSM faz mais ou menos isso aqui
Ah, a importação da chave no HSM faz mais ou menos isso aqui
#!/usr/bin/env python3
"""
HSM Thales PayShield - Cálculo de Chave Criptografada
Este script simula o processo de criptografia de uma chave (ex: CVK/CSCK)
sob LMK, seguindo o padrão do HSM Thales PayShield, incluindo aplicação de variants
e cálculo de Key Check Value (KCV).
Ideal para estudos, troubleshooting e validação de processos de importação de chaves.
"""
from Crypto.Cipher import DES3
import binascii
def hex_to_bytes(hex_str):
"""Converte uma string hexadecimal para bytes."""
return binascii.unhexlify(hex_str)
def bytes_to_hex(data):
"""Converte bytes para uma string hexadecimal maiúscula."""
return binascii.hexlify(data).decode().upper()
def apply_key_type_variant(lmk_left, lmk_right, variant_id):
"""
Aplica o variant_id no primeiro byte do LMK LEFT.
Exemplo: Variant 4 = 0xDE (usado para CVK/CSCK).
Retorna LMK LEFT modificado e LMK RIGHT inalterado.
"""
variant_map = {
0: 0x00, # Sem variant
1: 0xA6,
2: 0x5A,
3: 0x6A,
4: 0xDE, # Usado para CVK/CSCK
5: 0x2B,
6: 0x50,
7: 0x74,
8: 0x9C,
9: 0xFA,
}
if variant_id == 0:
return lmk_left[:], lmk_right[:] # Sem alteração
variant_value = variant_map.get(variant_id, 0x00)
# Aplica XOR no primeiro byte do LMK LEFT
modified_left = bytearray(lmk_left)
modified_left[0] ^= variant_value
return bytes(modified_left), lmk_right[:]
def encrypt_under_variant_lmk(input_key, lmk_left, lmk_right, scheme_tag):
"""
Criptografa a chave de entrada sob LMK modificado, usando o esquema 'U' (double-length).
Para cada metade da chave, aplica um variant diferente no LMK RIGHT.
"""
if scheme_tag == 'U':
if len(input_key) != 16:
raise ValueError("Double-length key necessária para o scheme U")
scheme_variants = [0xA6, 0x5A] # Variants padrão do scheme U
else:
raise ValueError(f"Unknown scheme tag: {scheme_tag}")
encrypted = bytearray()
for i, scheme_variant in enumerate(scheme_variants):
# Monta LMK para este segmento (LEFT + RIGHT)
variant_lmk = bytearray(16)
variant_lmk[:8] = lmk_left
variant_lmk[8:16] = lmk_right
# Aplica o variant no primeiro byte do LMK RIGHT
variant_lmk[8] ^= scheme_variant
# Cria chave 3DES (K1-K2-K1)
triple_des_key = bytes(variant_lmk) + bytes(variant_lmk[:8])
# Criptografa 8 bytes do segmento da chave
cipher = DES3.new(triple_des_key, DES3.MODE_ECB)
segment = input_key[i*8:(i+1)*8]
encrypted_segment = cipher.encrypt(segment)
encrypted.extend(encrypted_segment)
return bytes(encrypted)
def calculate_thales_payshield_key():
"""
Simula o cálculo da chave criptografada sob LMK, conforme o HSM Thales PayShield.
Mostra passo a passo do processo, incluindo aplicação de variants e análise detalhada.
"""
print("=== CÁLCULO THALES PAYSHIELD ===\n")
# 1. Dados de entrada (exemplo de CVK double-length)
clear_key = "0123456789012345ABCDEF0123456789"
key_type_code = "402" # CVK/CSCK
scheme_tag = 'U' # Esquema double-length
print(f"Chave original: {clear_key}")
print(f"Key Type: {key_type_code} (CVK/CSCK)")
print(f"Scheme: {scheme_tag}")
# 2. Detalhes do tipo de chave (exemplo baseado em tabela Go)
# "402": {Name: "CVK/CSCK", Code: "402", LMKPair: 7, VariantID: 4}
lmk_pair_index = 7 # LMK 14-15
variant_id = 4 # Variant 4 = 0xDE
print(f"LMK Pair Index: {lmk_pair_index} (LMK 14-15)")
print(f"Variant ID: {variant_id}")
# 3. LMKs originais (exemplo)
lmk_14 = "E0E0010101010101"
lmk_15 = "F1F1010101010101"
print(f"\nLMK 14 (original): {lmk_14}")
print(f"LMK 15 (original): {lmk_15}")
lmk_14_bytes = hex_to_bytes(lmk_14)
lmk_15_bytes = hex_to_bytes(lmk_15)
# 4. Aplica o variant do tipo de chave no LMK LEFT
modified_lmk_14, modified_lmk_15 = apply_key_type_variant(
lmk_14_bytes, lmk_15_bytes, variant_id
)
print(f"\nApós aplicar Variant {variant_id} (0xDE):")
print(f"LMK 14 modificado: {bytes_to_hex(modified_lmk_14)}")
print(f"LMK 15 (inalterado): {bytes_to_hex(modified_lmk_15)}")
# Verificação do XOR aplicado
print(f"Verificação: 0xE0 XOR 0xDE = 0x{0xE0 ^ 0xDE:02X}")
# 5. Prepara a chave de entrada (em bytes)
input_key_bytes = hex_to_bytes(clear_key)
print(f"\nChave de entrada ({len(input_key_bytes)} bytes): {bytes_to_hex(input_key_bytes)}")
# 6. Criptografa a chave sob LMK modificado, usando o scheme U
encrypted_key = encrypt_under_variant_lmk(
input_key_bytes,
modified_lmk_14,
modified_lmk_15,
scheme_tag
)
print(f"\n=== PROCESSO DE ENCRIPTAÇÃO ===")
print(f"Scheme '{scheme_tag}' usa variants: [0xA6, 0x5A]")
print(f"Cada variant encripta 8 bytes da chave")
# 7. Monta resultado final (scheme tag + chave criptografada)
result = scheme_tag + bytes_to_hex(encrypted_key)
# 8. Análise detalhada dos segmentos
print(f"\n=== ANÁLISE DETALHADA ===")
cvk_a = clear_key[:16]
cvk_b = clear_key[16:]
encrypted_a = bytes_to_hex(encrypted_key[:8])
encrypted_b = bytes_to_hex(encrypted_key[8:16])
print(f"CVK A: {cvk_a} -> {encrypted_a}")
print(f"CVK B: {cvk_b} -> {encrypted_b}")
# 9. Mostra os LMKs usados para cada segmento (com variants)
print(f"\n=== VARIANTS DE SCHEME ===")
base_lmk = modified_lmk_14 + modified_lmk_15
# Para primeiro segmento (variant 0xA6)
variant_1 = bytearray(base_lmk)
variant_1[8] ^= 0xA6
print(f"LMK para CVK A (variant 0xA6): {bytes_to_hex(variant_1)}")
# Para segundo segmento (variant 0x5A)
variant_2 = bytearray(base_lmk)
variant_2[8] ^= 0x5A
print(f"LMK para CVK B (variant 0x5A): {bytes_to_hex(variant_2)}")
return result
def calculate_kcv(key_hex):
"""
Calcula o Key Check Value (KCV) de uma chave.
O KCV é obtido criptografando 8 bytes zero com a chave e pegando os 6 primeiros hex.
"""
key_bytes = hex_to_bytes(key_hex)
zeros = b'\x00' * 8
if len(key_bytes) == 16:
# Double-length key - usa 3DES (K1-K2-K1)
triple_key = key_bytes + key_bytes[:8]
cipher = DES3.new(triple_key, DES3.MODE_ECB)
else:
cipher = DES3.new(key_bytes, DES3.MODE_ECB)
encrypted = cipher.encrypt(zeros)
return bytes_to_hex(encrypted)[:6]
if __name__ == "__main__":
# Executa o cálculo principal e mostra resultados
result = calculate_thales_payshield_key()
print(f"\n=== RESULTADO FINAL ===")
print(f"Chave criptografada: {result}")
print(f"Esperado: UC68879EF8F0E22A2B8A51FE73409DC16")
print(f"Match? {result == 'UC68879EF8F0E22A2B8A51FE73409DC16'}")
# Calcula e mostra o KCV da chave original
original_key = "0123456789012345ABCDEF0123456789"
kcv = calculate_kcv(original_key)
print(f"\n=== KEY CHECK VALUE ===")
print(f"KCV calculado: {kcv}")
print(f"KCV esperado: 7FFC84")
print(f"KCV Match? {kcv == '7FFC84'}")