Implementação de Algoritmos para Encurtamento de URLs em C++

O desenvolvimento de um sistema de encurtamento de links (Short URL) fundamenta-se na transformação de uma URL extensa em uma chave alfanumérica compacta. Diferente de identificadores puramente numéricos, os sistemas de links curtos utilizam frequentemente uma base superior à decimal, como a Base62, para maximizar o número de combinações possíveis com o menor número de caracteres.

Arquitetura e Requisitos do Algoritmo

Para que um algoritmo de encurtamento seja eficiente em um ambiente de produção, ele deve atender a critérios específicos de design:

  • Unicidade: Cada URL longa deve, preferencialmente, resultar em uma chave única para evitar colisões de redirecionamento.
  • Eficiência de Espaço: A chave gerada deve ser curta o suficiente para facilitar o compartilhamento em plataformas com limite de caracteres.
  • Mapeamento Persistente: Como o processo de hash é geralmente unidirecional ou baseado em perdas, é necessário armazenar o par (chave_curta, url_original) em uma base de dados para permitir a recuperação posterior.
  • Resolução de Conflitos: Estratégias como o uso de salts ou funções de hash secundárias devem ser aplicadas quando duas entradas diferentes geram a mesma saída.

Fluxo de Implementação

O processo técnico padrão envolve a aplicação de uma função de espalhamento (hash) seguida de uma conversão de base. Abaixo, apresenta-se uma implementação em C++ que utiliza a biblioteca OpenSSL para gerar um hash MD5 e converte os bytes resultantes em uma representação Base62.

#include <iostream>
#include <string>
#include <vector>
#include <openssl/md5.h>

/**
 * Converte um valor numérico para uma representação alfanumérica (Base62).
 * Utiliza o conjunto [0-9][a-z][A-Z].
 */
std::string converterParaBase62(unsigned long long valor) {
    const std::string caracteres = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    if (valor == 0) return "0";
    
    std::string resultado;
    while (valor > 0) {
        resultado.insert(0, 1, caracteres[valor % 62]);
        valor /= 62;
    }
    return resultado;
}

/**
 * Gera um identificador curto a partir de uma URL longa usando MD5.
 */
std::string gerarChaveCurta(const std::string& url_original) {
    unsigned char digest[MD5_DIGEST_LENGTH];
    MD5(reinterpret_cast<const unsigned char*>(url_original.c_str()), url_original.length(), digest);

    // Extrai os primeiros 8 bytes do hash para formar um número de 64 bits
    unsigned long long semente = 0;
    for (int i = 0; i < 8; ++i) {
        semente = (semente << 8) | digest[i];
    }

    return converterParaBase62(semente).substr(0, 7); // Retorna os primeiros 7 caracteres
}

int main() {
    std::string url_alvo = "https://www.exemplo-de-dominio-longo.com/artigo/algoritmos-de-hash";
    std::string chave = gerarChaveCurta(url_alvo);

    std::cout << "URL Original: " << url_alvo << std::endl;
    std::cout << "Chave Gerada: " << chave << std::endl;

    return 0;
}

Utilizando SHA-256 para Maior Integridade

Embora o MD5 seja computacionalmente rápido, ele é suscetível a colisões. Em sistemas onde a segurança ou a integridade dos dados é crítica, o SHA-256 é a escolha recomednada. O exemplo a seguir demonstra como extrair um hash SHA-256 em formato hxeadecimal utilizando C++ e OpenSSL:

#include <iostream>
#include <iomanip>
#include <sstream>
#include <openssl/sha.h>

std::string calcularSHA256(const std::string& entrada) {
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256_CTX contexto_sha;
    
    SHA256_Init(&contexto_sha);
    SHA256_Update(&contexto_sha, entrada.c_str(), entrada.size());
    SHA256_Final(hash, &contexto_sha);

    std::stringstream hex_stream;
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        hex_stream << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]);
    }
    
    return hex_stream.str();
}

int main() {
    std::string payload = "Dados para encriptação via SHA-256";
    std::string hash_resultado = calcularSHA256(payload);

    std::cout << "Entrada: " << payload << std::endl;
    std::cout << "Hash SHA-256: " << hash_resultado << std::endl;

    return 0;
}

Considerações Técnicas de Compilação

Ao trabalhar com bibliotecas criptográficas como a OpenSSL em sistemas baseados em Unix/Linux (como Ubuntu ou Debian), é necessário garantir que os cabeçalhos de desenvolvimento estejam instalados. Para compilar os exemplos acima utilizando o g++, deve-se vincular explicitamente a biblioteca de criptografia:

g++ -o encurtador_link main.cpp -lcrypto

O parâmetro -lcrypto instrui o linker a incluir as funções necessárias para o cálculo de MD5 e SHA-256. Em aplicações de larga escala, o hash gerado costuma ser truncado e armazenado em um banco de dados NoSQL (como Redis ou MongoDB) para garantir latência mínima durante a operação de redirecionamanto.

Tags: C++ algorithms cryptography openssl Base62

Publicado em 7-25 22:07