Enviar um arquivo
  1. base64hub
  2. Aprenda Base64
  3. Prefixos comuns de Base64
Referência

Prefixos comuns de Base64: identifique o arquivo pelo início

A maioria dos formatos de arquivo começa com bytes mágicos fixos, então o Base64 deles também começa com caracteres fixos. Aprenda uma dúzia de prefixos e você distingue um PNG de um PDF antes de decodificar qualquer coisa.

Tabela de prefixos

Cada linha foi conferida codificando os bytes mágicos reais do formato. O prefixo listado é a parte que nunca muda naquele formato. Os caracteres seguintes dependem do resto do arquivo.

Prefixo Base64Bytes mágicos (hex)FormatoAbrir com
iVBORw0KGgo89 50 4E 47 0D 0A 1A 0APNGBase64 para PNG
/9j/FF D8 FFJPEGBase64 para JPG
R0lGOD47 49 46 38 (GIF8)GIF (R0lGODlh = GIF89a, R0lGODdh = GIF87a)Base64 para GIF
UklGR52 49 46 46 (RIFF)WebP, WAV, AVIBase64 para WebP, Base64 para WAV
JVBERi025 50 44 46 2D (%PDF-)PDFBase64 para PDF
UEsDB50 4B 03 04 (PK..)ZIP, DOCX, XLSX, PPTX, JAR, APK, EPUBBase64 para ZIP, Word, Excel
H4sI1F 8B 08gzipDecodificar Base64 com gzip
eJ, eN, eF, eA78 9C, 78 DA, 78 5E, 78 01zlibZlib e Base64
eyJ7B 22 ({")Objeto JSON, JWTBase64 para JSON, decodificador de JWT
PD94bWwg3C 3F 78 6D 6C 20 (<?xml )XML, SVG com declaraçãoBase64 para XML
PHN2Zy3C 73 76 67 20 (<svg )SVG sem declaração (<svg seguido de quebra de linha dá PHN2Zw)Base64 para SVG
MII30 82DER: certificados, chaves, CSRsdecodificador de certificados
AAAA00 00 00Blob de chave pública SSH, ou zeros à esquerdafingerprint de chave SSH
SUQz49 44 33 (ID3)MP3 com tag ID3v2Base64 para MP3
AAABAA00 00 01 00ICOBase64 para ICO
d09GMg77 4F 46 32 00 (wOF2)Fonte WOFF2 com contornos TrueType (fontes CFF começam com d09GMk9UVE8)Base64 para fonte
TVqQ4D 5A 90 (MZ)EXE ou DLL do Windows (alguns linkers gravam MZP, que dá TVpQ)Base64 para arquivo
f0VMR7F 45 4C 46 (.ELF)Binário ELF do LinuxBase64 para arquivo

Algumas linhas merecem uma observação:

  • RIFF é um contêiner. O nome do formato fica nos bytes 8 a 11, e os bytes 9 a 11 viram do 13º ao 16º caractere: RUJQ para WebP (EBP), QVZF para WAV (AVE), Vkkg para AVI (VI ). A primeira letra do nome do formato divide um grupo de 3 bytes com o tamanho do arquivo, então não gera um caractere estável.
  • zlib não tem um prefixo único. O segundo byte registra o nível de compressão: eJ para o nível padrão, eN para os níveis 7 a 9, eF para 2 a 5, eA para 0 e 1 (como gravado pelo zlib do Python).
  • JSON só começa com eyJ quando os dois primeiros caracteres são {" sem espaço. { "a": 1 } começa com eyAi, um { formatado seguido de quebra de linha começa com ewo, e um array [ começa com W.
  • DER: as estruturas começam com a tag SEQUENCE 30, que sempre dá M. Um comprimento de dois bytes (30 82) dá MII, e o caractere seguinte acompanha o comprimento: uma chave pública RSA 2048 é MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA, um certificado típico é MIIC, MIID ou MIIE. Estruturas curtas usam comprimento de um byte: uma chave privada Ed25519 começa com MC4C, uma chave pública P-256 com MFkw.
  • Chaves públicas SSH começam com um comprimento big-endian de 4 bytes, então o blob começa com AAAA. Os caracteres seguintes soletram o tipo da chave: AAAAC3NzaC1lZDI1NTE5 é ssh-ed25519, AAAAB3NzaC1yc2E é ssh-rsa, AAAAE2VjZHNh é ecdsa. Fora do SSH, uma sequência de A significa apenas bytes zero.
  • MP3 sem tag ID3 começa direto com um cabeçalho de frame. Os bits de sincronização FF Fx geram um // inicial, por exemplo //uQ para FF FB 90.
  • Base64URL substitui + e /, então o prefixo do JPEG vira _9j_. Os outros prefixos da tabela não contêm nenhum dos dois e ficam iguais nos dois alfabetos.

Por que o prefixo é estável

O Base64 trabalha com grupos de 3 bytes. Cada grupo de 3 bytes vira exatamente 4 caracteres, e esses 4 caracteres dependem só desses 3 bytes. Nada do restante do arquivo vaza para trás. Então, se um formato sempre começa com os mesmos 3 bytes, o Base64 dele sempre começa com os mesmos 4 caracteres.

bytes:   FF       D8       FF
bits:    11111111 11011000 11111111
groups:  111111 111101 100011 111111
index:   63     61     35     63
chars:   /      9      j      /

Quando o valor mágico fixo não tem um comprimento múltiplo de 3 bytes, o último grupo mistura bits conhecidos com bits do resto do arquivo. Veja o %PDF-, de 5 bytes. Os 3 primeiros bytes dão 4 caracteres estáveis (JVBE). Os 2 bytes seguintes dão mais 2 (Ri), e o sétimo caractere mistura os últimos 4 bits do - com os 2 primeiros bits do dígito da versão. Todo dígito começa com os bits 00, então na prática esse caractere é sempre 0. Depois de JVBERi0 a versão aparece: JVBERi0xLjQ é %PDF-1.4, JVBERi0xLjc é %PDF-1.7, JVBERi0yLjA é %PDF-2.0.

A assinatura PNG tem 8 bytes, o que dá 10 caracteres estáveis. O décimo primeiro mistura o último byte da assinatura com o primeiro byte do comprimento do chunk IHDR, que é sempre 0, então iVBORw0KGgo se mantém. Como todo PNG continua com esse chunk IHDR, os PNGs reais compartilham um prefixo ainda maior: iVBORw0KGgoAAAANSUhEUg.

Quando o prefixo se desloca

O prefixo só funciona quando os bytes mágicos estão no deslocamento 0, 3, 6 e assim por diante. Acrescente um byte na frente e todos os grupos se deslocam, então os caracteres mudam completamente:

EntradaO Base64 começa com
Assinatura PNGiVBORw0KGgoAAAA
1 byte + assinatura PNGAIlQTkcNChoKAAAA
2 bytes + assinatura PNGAACJUE5HDQoaCgAA
3 bytes + assinatura PNGAAAAiVBORw0KGgoA

Com 3 bytes extras o alinhamento volta e o prefixo conhecido reaparece 4 caracteres depois. Motivos comuns para um prefixo deslocado ou ausente:

  • Uma marca de ordem de bytes (BOM). Texto UTF-8 com BOM começa com 77u/ (EF BB BF). O BOM tem 3 bytes, então um JSON depois dele ainda mostra eyJ: 77u/eyJ…. Texto UTF-16 com BOM começa com //4 ou //5 (little-endian) ou /v8 (big-endian).
  • Texto UTF-16. Texto salvo como UTF-16LE coloca um byte zero depois de cada caractere ASCII, o que produz muitos A: Hello vira SABlAGwAbABvAA==. O -EncodedCommand do PowerShell tem essa cara. Use o decodificador de PowerShell ou Base64 para UTF-16.
  • Compressão ou criptografia. Um PNG compactado com gzip começa com H4sI; um arquivo criptografado não tem prefixo reconhecível nenhum.
  • Um data URI. data:image/png;base64, é um cabeçalho; o Base64 começa depois da vírgula. O parser de data URI separa as duas partes para você.
  • Quebras de linha e espaços em branco. Eles não deslocam os bytes, mas uma busca de prefixo com startswith falha se a string começa com uma quebra de linha ou aspas. Remova-os antes, ou passe a string pelo Reparar Base64.

Verificando um prefixo no código

Dá para comparar os primeiros caracteres como strings, mas comparar os bytes decodificados é menos propenso a erro: os números mágicos vêm direto da especificação de cada formato, e você nunca precisa descobrir quais caracteres são estáveis. Decodificar só os primeiros 12 caracteres dá os primeiros 9 bytes, o suficiente para a maioria das assinaturas:

import base64

SIGNATURES = {
    b"\x89PNG\r\n\x1a\n": "png",
    b"\xff\xd8\xff": "jpeg",
    b"%PDF-": "pdf",
    b"PK\x03\x04": "zip",
    b"\x1f\x8b": "gzip",
}

def sniff(b64: str) -> str:
    head = base64.b64decode(b64.strip()[:12])
    for magic, name in SIGNATURES.items():
        if head.startswith(magic):
            return name
    return "unknown"

print(sniff("iVBORw0KGgoAAAANSUhEUgAAAAEAAAAB"))  # png
print(sniff("JVBERi0xLjcKJcfsj6IK"))              # pdf

A ferramenta Base64 para arquivo faz a mesma verificação com uma lista maior e mostra uma prévia quando o navegador consegue renderizar o formato. Para ver como os grupos de 6 bits viram caracteres, leia como o Base64 funciona e a tabela do alfabeto.

Perguntas frequentes

O que significa uma string Base64 que começa com iVBORw0KGgo?

É uma imagem PNG. iVBORw0KGgo é a forma Base64 da assinatura PNG de 8 bytes 89 50 4E 47 0D 0A 1A 0A. Cole no Base64 para PNG para vê-la.

O que é /9j/ no início de uma string Base64?

Um JPEG. Os bytes FF D8 FF que abrem todo arquivo JPEG viram /9j/ em Base64. Em Base64URL o mesmo prefixo é escrito _9j_.

Por que os JWTs sempre começam com eyJ?

O header de um JWT é um objeto JSON, então começa com {", e esses dois bytes viram eyJ em Base64. A parte do payload começa com eyJ pelo mesmo motivo.

Meu Base64 não bate com nenhum prefixo conhecido. E agora?

Os dados podem ter bytes extras na frente, estar compactados ou criptografados, ou ser texto comum. A ferramenta Base64 para arquivo decodifica os dados e compara os bytes com muitas assinaturas.

Continue lendo