Criptografia - Cadastro do Portador

Veja exemplos em Node.js de como é feita a criptografia da bcryptPassword, do challenge e do sensitive, presentes na API Cadastro do Portador.

Feito para:  Estabelecimentos ComerciaisEmissoresAdquirentesFacilitadoresOutros Desenvolvedores

Nesta seção, você pode encontrar um exemplo de código para a geração da bcryptPassword, campo necessário na mutation createUser e na geração do challenge - utilizado na mutation login.

Para mais informações sobre como gerar a bcryptPassword, acesse a documentação da API Cadastro do Portador.

O exemplo a seguir foi feito em Node.js e foram utilizadas as bibliotecas bcryptjs e crypto-js. Para instalá-las, pode rodar o comando npm i bcryptjs crypto-js

import bcrypt from 'bcryptjs'
import crypto from 'crypto-js'

function hexToBytes(hex) {
    let bytes = []
    for (let c = 0; c < hex.length; c += 2) {
        bytes.push(parseInt(hex.substr(c, 2), 16))
    }
    return bytes
}

async function generateBcryptPassword(username, password) {
    const usernameSha256 = crypto.SHA256(username.toString())
    const usernameSalt = `$2a$12$${bcrypt.encodeBase64(
        hexToBytes(usernameSha256.toString()),
        16
    )}`
    const passwordSha256 = crypto.SHA256(password.toString())
    const base64Password = crypto.enc.Base64.stringify(passwordSha256)
    const bcryptPassword = bcrypt.hashSync(base64Password, usernameSalt)

    return bcryptPassword
}

console.log(await generateBcryptPassword('username', 'password'))

Nesta seção, você pode encontrar um exemplo de código para a geração do challenge necessário na mutation login. A bcryptPassword será necessária para a geração do challenge, acesse a seção anterior para visualizar como é ela gerada

Para mais informações sobre como gerar o challenge, acesse a documentação da API Cadastro do Portador.

O exemplo a seguir foi feito em Node.js e foram utilizadas as bibliotecas axios e bcryptjs. Para instalá-las, pode rodar o comando npm i axios bcryptjs.

import axios from 'axios'
import bcrypt from 'bcryptjs'

const client_id = 'SEU_CLIENT_ID'
const graphQLurl = 'https://hml-api.elo.com.br/graphql'

const query = `
    mutation createLoginSalt($username: String!) {
        createLoginSalt(input: { username: $username }) {
            username
            salt
        }
    }
`

async function createChallenge(username, bcryptPassword) {
    const variables = {
        username,
    }

    const data = JSON.stringify({
        query,
        variables,
    })

    const options = {
        headers: {
            'Content-Type': 'application/json',
            client_id,
        },
    }

    const {
        data: {
            data: {
                createLoginSalt: { salt },
            },
        },
    } = await axios.post(graphQLurl, data, options)

    const challenge = bcrypt.hashSync(bcryptPassword, salt)

    return challenge
}

console.log(
    await createChallenge(
        'username',
        'bcryptPassword'
    )
)

Nesta seção, você pode encontrar um exemplo de código para a geração do sensitive (informações criptografadas do cartão).

Para mais informações sobre como gerar o sensitive, acesse a documentação da API Cadastro do Portador.

O exemplo a seguir foi feito em Node.js e foram utilizadas as bibliotecas axios e node-jose. Para instalá-las, pode rodar o comando npm i node-jose bcryptjs.

import jose from 'node-jose'
import axios from 'axios'

const client_id = '' // Seu client_id
const graphQLurl = 'https://hml-api.elo.com.br/graphql' // URL da API

// Dados do cartão a ser criptografado
const cardData = {
    pan: '8505060000000000',
    expiry: {
        month: 1,
        year: 2025,
    },
    name: 'Name',
    csc: 123,
}

// Query GraphQL para adquirir a chave públic Elo
const query = `
    query serverPublicKey {
        serverPublicKey {
            key
        }
    }
`

function jweEncrypt(input, key) {
    return jose.JWE.createEncrypt({ format: 'compact' }, key).update(input).final()
}

function jwsSign(input, key) {
    return jose.JWS.createSign({ format: 'compact', alg: 'ES256' }, key).update(input).final()
}

async function generateKeyPair(kid) {
    const jwk = await jose.JWK.createKey('EC', 'P-256', { kid })
    const key = {
        pair: jwk.toJSON(true),
        public: jwk.toJSON(false),
    }
    return { jwk, key }
}

export async function generateSensitive(cardData) {
    const kid = 'KeyID'

    // Chamada que resgata a chave pública Elo
    const {
        data: {
            data: {
                serverPublicKey: { key: eloKey },
            },
        },
    } = await axios.post(
        graphQLurl,
        JSON.stringify({
            query,
        }),
        {
            headers: {
                'Content-Type': 'application/json',
                client_id,
            },
        }
    )

    const { jwk, key } = await generateKeyPair(kid) // Gera um par de chaves de curvas elípticas
    const cardSensitiveDataStringified = JSON.stringify(cardData) // Transforma os dados do cartão em string

    let serverKey = JSON.parse(eloKey) // Chave Elo retornada em string é transformada em JSON
    serverKey.kid = kid // Adicionada a propriedade kid com o ID da chave gerada

    if (jwk) {
        const signedJws = await jwsSign(cardSensitiveDataStringified, jwk) // Faz a assinatura
        const sensitive = await jweEncrypt(signedJws, serverKey) // Gera o sensitive
        return { sensitive, key } // Retorna o sensitive a chave gerada/usada na criptografia do cartão
    }
}

// Exibe no console o sensitive e a chave utilizada pelo cliente ao criptografar o cartão
console.log(await generateSensitive(cardData))