Como Revisar seu Próprio Texto

Quando escrevemos um texto, é comum que o modifiquemos constantemente, até que as diversas estruturas estejam adequadas.

Primeiramente temos a estrutura do texto: os capítulos e as seções. Estes devem seguir uma hierarquia e uma ordem lógica, preferencialmente sequencial.

Em segundo lugar temos a estrutura dos parágrafos, dentro dos capítulos e das seções. Estes devem ser organizados de forma lógica e estritamente sequencial.

Em terceiro lugar temos a estrutura das frases dentro dos parágrafos. Neste ponto, expressamos uma ideia de forma clara, seguindo as regras gramaticais.

Em geral, a última estrutura sofre uma quantidade de modificações muito maior do que a primeira e, por isso, nela ocorrem a maioria dos erros. É comum que se reorganize uma frase, para escrevê-la melhor e de forma mais clara, e acabar por introduzir erros, por exemplo, artigos (o, a, os, as) discordantes com respeito ao gênero ou número e preposições inconsistentes.

No entanto, ao mesmo tempo que escrevemos e reorganizamos um parágrafo, nos acostumamos com sua estrutura e suas palavras-chave e acabamos por não avaliar com perícia diversos detalhes, como esses que acabamos de mencionar, os quais são extremamente importantes para uma leitura clara e prazerosa.

Diz-se que, ao escrever, estamos “viciados no texto”. Estamos tão acostumados com o ele que não o lemos mais com detalhe. Então, ao revisar o texto, mesmo quando focamos em ler cada palavra, com muita calma e analisando tudo, não é raro que algo passe despercebido.

No entanto, note que estamos “viciados” ao ler o texto, e não ao escutá-lo. É muito mais difícil enganar aos ouvidos do que aos olhos.

Então para revisar um texto, basta pedir que alguém o leia para você, em voz alta. Enquanto ouvimos o texto, fazemos sua leitura e anotamos as inconsistências. Dessa forma, é possível perceber muito mais do texto do que apenas lendo.

Mas quem faria um trabalho desses, de ler um texto em voz alta? Dez páginas, vinte paginas, cem páginas?

O Google Tradutor faria: selecione a língua, colote o texto e clique no botão “Ouvir”.

Linux: Áudio do computador em videoconferência

Para apresentar a defesa da minha dissertação de mestrado, eu precisava tocar executar um vídeo com áudio no computador e a audiência precisava escutá-lo.

Uma saída era, na hora do vídeo, colocar o meu fone de ouvido bem perto do microfone, de forma que fosse transmitido pela videoconferência. Fazendo isso, no entanto, perde-se muito na qualidade do áudio.

Com um pouco de pesquisa descobri que existe uma solução melhor:

  • Criar um canal de áudio Virtual-1, que recebe o áudio das aplicações compartilhadas com a videoconferência. Este canal é ouvido por mim e pela audiência.
  • Direcionar a saída de áudio Virtual-1 para meus fones de ouvido, de forma que eu possa ouvir os programas compartilhados.
  • Criar um canal de áudio Virtual-2, que recebe o Microfone no qual eu falo e a saída de áudio Virtual-1, com os áudios compartilhados. Este canal é transmitido para a audiência.
  • Direcionar a saída de áudio Virtual-2 para um microfone virtual, chamado Virtual-3, que pode ser utilizado pela plataforma de videoconferência Google Meet.

Dessa forma, em vez de enviar apenas o meu microfone para a videoconferência, envio a saída Virtual-3 que também contempla os programas compartilhados.

O sistema em uso

No meu caso, estava utilizando o Ubuntu Linux 18.04. Para configurar o computador dessa forma, fiz uso dos dois scripts a seguir:

  • O primeiro configura o Pulse Audio para criar esses dispositivos de entrada e saída de áudio; e
  • O segundo desfaz essa configuração.

pulse_setup.sh

#!/bin/bash
# This script sets up pulseaudio virtual devices
# The following variables must be set to the names of your own microphone and speakers devices
# You can find their names with the following commands :
# pacmd list-sources
# pacmd list-sinks
# Use pavucontrol to make tests for your setup and to make the runtime configuration
# Route your audio source to virtual1
# Record your sound (videoconference) from virtual2.monitor

# Unload
./pulse_unload.sh

set -e

MICROPHONE=${MICROPHONE:-"alsa_input.pci-0000_00_1b.0.analog-stereo"}
SPEAKERS=${SPEAKERS:-"alsa_output.pci-0000_00_1b.0.analog-stereo"}
#SPEAKERS=${SPEAKERS:-"alsa_output.pci-0000_00_03.0.hdmi-stereo"}

module_file="/tmp/pulseaudio_module_list.txt"

if ! pacmd list-sources | grep -P "^\s+name: <${MICROPHONE}>" >/dev/null; then
  echo "ERROR: Microphone (source) \"${MICROPHONE}\" was not found" >&2
  exit 1
fi

if ! pacmd list-sinks | grep -P "^\s+name: <${SPEAKERS}>" >/dev/null; then
  echo "ERROR: Speaker (sink) \"${SPEAKERS}\" was not found" >&2
  exit 1
fi

# Create the null sinks
# virtual1 gets your audio sources (mplayer ...) that you want to hear and share
# virtual2 gets all the audio you want to share (virtual1 + micro)
pactl load-module module-null-sink sink_name=virtual1 sink_properties=device.description="Compartilhar-Audio" | tee -a "${module_file}"
pactl load-module module-null-sink sink_name=virtual2 sink_properties=device.description="Intermediario" | tee -a "${module_file}"

# Now create the loopback devices, all arguments are optional and can be configured with pavucontrol
pactl load-module module-loopback source=virtual1.monitor sink="${SPEAKERS}" latency_msec=1 | tee -a "${module_file}"
pactl load-module module-loopback source=virtual1.monitor sink=virtual2 latency_msec=1 | tee -a "${module_file}"
pactl load-module module-remap-source source_name=virtual3 source_properties=device.description="Vmic" master=virtual2.monitor | tee -a "${module_file}"
pactl load-module module-loopback source="${MICROPHONE}" sink=virtual2 latency_msec=1 | tee -a "${module_file}"

# Make the default sink back to speakers
pactl set-default-sink "${SPEAKERS}"
pacmd set-default-source "virtual3"

pulse_unload.sh

#!/bin/bash
set -e
module_file="/tmp/pulseaudio_module_list.txt"
if [ ! -f "${module_file}" ]; then
  echo "ERROR: file ${module_file} doesn't exist" >&2
  exit 1
fi
while read -r module; do
  if [[ "${module}" =~ ^[0-9]+$ ]]; then
    pacmd unload-module "${module}"
  else
    echo "ERROR: file ${module_file} is not correctly formated" >&2
    exit 1
  fi
done < "${module_file}"
rm "${module_file}"

Usando OBS para apresentação em videoconferência

Para defender minha dissertação de mestrado, a banca foi realizada à distância, através de uma videoconferência pelo Google Meet.

Para dar mais flexibilidade para a apresentação, utilizei o software OBS para gerar a parte gráfica e para realizar a gravação da aprestação.

Vejamos a seguir os passos básicos para fazer isso.

O tamanho da tela

A primeira coisa a fazer é definir o tamanho da tela.

Entre em “Menu Arquivo > Configurações > Vídeo” e selecione a “Resolução de base (tela)”, ou seja, a resolução de onde será projetado, e a “Resolução de saída (escala)”, ou seja, a resolução da gravação. E clique OK.

É comum utilizar resoluções de proporção 16×9, por exemplo 1280×720 ou 1920×1080.

Existem várias outras configurações do OBS, mas vamos focar apenas no necessário para uma apresentação por videoconferência.

Criando a cena da apresentação

Com o OBS foi criada uma ‘cena’ que contem a apresentação de slides e a câmera.

A cena foi criada clicando no botão mais (+) da interface de cenas.

Capturando a câmera

Para capturar a câmera, clique no botão mais (+) da interface de fontes. No menu selecione “Dispositivo de captura de vídeo” e na janela da interface selecione “Criar nova > OK”. Então escolha a câmera e, se desejar, pode até ajustar sua resolução. Clique em OK e agora basta ajustar o tamanho e a posição da câmera.

Capturando a tela

Quando a apresentação é realizada em tela cheia, temos que capturar a tela em que ela é apresentada.

A tela teve ser capturada, clicando no botão mais (+) da interface de fontes. No menu selecione “Captura de tela” e na janela da interface selecione “Criar nova > OK”. Então selecione a tela da apresentação. É possível recortar bordas, se necessário. Clique em OK e agora basta ajustar o tamanho e a posição da captura de tela.

Capturando uma janela

No meu caso, em vez de capturar a tela, eu capturei apenas a janela da apresentação, porque eu precisava mexer ao mesmo em outras janelas e não queria que elas aparecessem para a audiência.

A apresentação de slides em PDF foi aberta maximizada, com opção de zoom para “ajustar à página”, de forma que fique com altura ou largura máxima, sem exceder a tela. Isso tem o objetivo de manter os slides com tamanho fixo, que será útil na hora de cortar a interface.

Então a apresentação foi adicionada à cena, clicando no botão (+) da interface de fontes. No menu foi selecionado “Captura de janela” e na janela da interface foi selecionado “Criar nova > OK”. Então foi selecionada a janela da apresentação de slides e foram recortadas as bordas desnecessárias. Então clica-se em OK. Agora basta ajustar o tamanho e a posição da janela da forma que desejar.

Projetando em uma janela

Agora que a cena está finalizada, precisamos projetar ela, de forma que possa ser compartilhada na videoconferência.

Quem não tem uma segunda tela, pode projetar em uma janela e compartilhá-la.

No OBS, abra a prévia em uma janela [Botão contrário > Projetor em janela (prévia)] e ajuste a prévia em um tamanho adequado.

Agora, no Google Meet, compartilhe a prévia [Apresentar Agora > Uma janela > Projetor em janela (prévia) > Compartilhar].

Ao compartilhar a janela, você tem a desvantagem de que, se a janela for fechada, seu compartilhamento é finalizado, tendo que ser reiniciado.

Projetando em uma segunda tela

Já quem tem uma segunda tela, pode projetar e compartilhar nesta. A vantagem é que se pode ver o resultado sem precisar ficar trocando de janelas.

No OBS, abra a prévia em tela cheia [Botão contrário > Projetor em tela cheia (prévia) > Monitor X].

Agora, no Google Meet, compartilhe a prévia, o que pode ser feito de duas formas: compartilhando a tela onde a prévia é projetada; ou compartilhando a janela invisível dessa prévia (semelhante acima).

Para compartilhar a tela use [Apresentar Agora > A tela inteira > Tela X > Compartilhar].

Para compartilhar a janela use [Botão contrário > Projetor em tela cheia (prévia) > Compartilhar].

Ao compartilhar a tela, você tem a vantagem de poder arrastar qualquer janela para esta segunda tela e exibi-la durante sua apresentação. Tudo o que estiver na segunda tela vai ser compartilhado.

Identicamente ao anterior, ao compartilhar a janela, você tem a desvantagem de que, se a janela for fechada, seu compartilhamento é finalizado, tendo que ser reiniciado.

Gravando a apresentação

Para gravar a apresentação, basta clicar em “Iniciar gravação” na interface de controles. Obviamente a resolução escolhida impactará no tamanho do arquivo da gravação.

Conclusão

Com isso tudo, agora sabemos como criar uma cena no OBS, gravá-la, projetá-la e compartilhá-la em uma videoconferência.

Foi dado exemplo com o Google Meet, porém imagino que fazer o mesmo com outras plataformas, como Zoom ou Teams, seja tão simples quanto nesse exemplo.

Gráficos vetoriais em PDF

Eu estava usando o LibreOffice Calc para criar gráficos para minha dissertação, porém não estava muito feliz com a conversão para imagem (PNG e JPEG). A solução é utilizar uma opção de exportação para e obter gráficos vetoriais em PDF, que pode ser aproximado sem perda de qualidade.

Criando os gráficos

A Planilha1 vamos deixar para os gráficos. As tabelas e cálculos ficam nas demais planilhas.

Na Planilha2 vamos criar duas tabelas: uma para o gráfico de uma reta e outra para parábola. Eixo X nos limites desejados e eixo Y calculado a partir do eixo X. A partir disso criamos dois gráficos: da reta e da parábola.

Veja que os gráficos possuem dimensão padrão de 16 cm x 9cm. No gráfico, clique com o botão contrário e selecione “Posição e Tamanho”.

Formatando a página

De volta à Planilha1, vamos formatar a página para que os gráficos caibam exatamente na página.

Selecione a Planilha1, entre em Menu Formatar > Página.

Na aba Página, configure Largura 16,1 cm, Altura 9,1 cm e as quatro margens 0 cm.

Na aba Cabeçalho, desative o cabeçalho. Na aba Rodapé, desative o rodapé.

Clique em OK para finalizar. O LibreOffice vai reclamar sobre as margens e impressão, aceite clicando em Sim.

Agora cada página possui tamanho 16,1 cm x 9,1 cm, um pouco maior que os gráficos, e não possui margens, cabeçalho ou rodapé para roubar espaço.

Organizando os gráficos

Agora recortamos os gráficos criados nas outras planilhas e colamos na Planilha1, um gráfico em cada página. Isso vai colocar um gráfico em cada página do PDF.

Para ver as divisões das páginas entre no menu Exibir > Quebras de página. É possível ajustar a altura e largura das células. Recomendo quatro colunas de 4 cm e três linhas de 3 cm.

Exportanto para PDF

Agora, para gerar o PDF com os gráficos, selecione a Planilha1, entre no menu Arquivo > Exportar como PDF, configure para imprimir seleção/planilhas selecionadas e clique em exportar.

Agora temos um arquivo com vários gráficos dentro dele. Ter menos arquivos é ótimo!

Importando no LaTeX

Agora basta importar os gráficos no seu documento LaTex:

\includegraphics[width=0.7\textwidth,page=1]{fig/Graficos.pdf}

Basta indicar qual a página que quer incluir com a opção page=?.

Também é possível recortar margens do gráfico importado usando as opções trim (ajustar as margens) e clip (recortar fora das margens):

\includegraphics[width=0.7\textwidth,page=2,trim=0.5cm 0.5cm 0.5cm 0.5cm,clip=true]{fig/Graficos.pdf}

Os comprimentos da opção trim são: esquerda, embaixo, direita e topo.

Então está feito!

Desta forma é possível criar gráficos vetoriais em PDF de qualidade utilizando o LibreOffice Calc, para inclusão em documentos LaTeX.

Alem dos gráficos vetoriais maravilhosos,outra vantagem é poder agrupar vários gráficos em um único arquivo PDF, ficando mais fácil organizar a pasta de imagens.

Autenticação Criptográfica

Resumão

MAC significa Código de Autenticação de Mensagem (Message Authentication Code). Este código é enviado junto com a mensagem, para provar sua integridade e autenticidade.

Integridade: Se algum bit da mensagem for alterado o MAC fica inválido. Semelhante a enviar a mensagem junto com sua hash.

Autenticidade: Apenas quem possui a chave criptográfica K é capaz de criar e verificar uma mensagem autenticada com esta chave.

A partir da chave e da mensagem criamos o código de autenticação, também chamado de TAG de autenticação. Enviamos o par (MENSAGEM, TAG) e quem recebe este par pode verificar a integridade e autenticidade da mensagem usando a chave K.

A chave K e a tag de autenticação precisam ambas ter comprimentos de acordo com o nível de segurança da aplicação.

Autenticação HMAC

A primeira opção é HMAC, que usa uma Função Hash para criar o código de autenticação. Eis o algoritmo:

se (comprimento(K) > Hash.Tamanho_Bloco) { K = Hash(K) }
enquanto (comprimento(K) < Hash.Tamanho_Bloco) { K = K || 00 }
K1 = K XOR 5C…5C
K2 = K XOR 36…36
TEMP = Hash(K2 || MENSAGEM)
TAG = Hash(K1 || TEMP)

Usamos uma chave para criar duas chaves diferentes. Cada uma é usada em uma etapa: criar uma hash da mensagem (TEMP) e tag de autenticação (TAG). Note que estamos utilizando o símbolo || com o significado de concatenação.

Antes de gerar K1 e K2, a chave K deve ter o tamanho do bloco da função hash. Este preenchimento do bloco permite pré-computar Hash(K1) e Hash(K2), acelerando a autenticação.

Se o comprimento da chave K for maior que o bloco de entrada da função hash (64 bytes/512 bits para SHA-256 ou 128 bytes/1024 bits SHA-512), primeiro realizamos a hash da chave.

Então, se o comprimento da cahve K for menor que o tamanho do bloco de entrada da função hash adicionamos zeros até completar o tamanho.

Podemos usar qualquer função hash com HMAC.

TAG =HMAC-SHA256(K, MENSAGEM)
TAG =HMAC-SHA512(K, MENSAGEM)

Obviamente vamos utilizar hashes que são criptograficamente seguras, por exemplo SHA2 e SHA3, e com comprimentos de saída adequados para o nível de segurança exigido pela aplicação. A chave K também precisa ser longa o suficiente para ser segura.

Autenticação KMAC

KMAC é uma extensão do padrão SHA3 usando XOFs (funções hash com saída de comprimento variável) baseada na esponja criptográfica Keccak.

Uma vantagem clara de usar KMAC, é que permite diferentes comprimentos de saída, gerando TAGs completamente diferentes para cada comprimento de saída.

KMAC é mais flexível e complicada que HMAC. Não vamos entrar em detalhes.

Podemos escolher entre os níveis de segurança máximos de 128 e 256 bits.

TAG =KMAC-128(K, MENSAGEM, COMPRIMENTO_TAG)
TAG =KMAC-256(K, MENSAGEM, COMPRIMENTO_TAG)

A chave K e a TAG precisam ter comprimentos compatíveis com o nível de segurança da aplicação e a função KMAC também precisa ser escolhida adequadamente. Ex: chave 256 bits e tag 256 bits só fazem sentido com KMAC-256.

Autenticação CBC-MAC

É possível também usar o sistema de autenticação CBC-MAC, que usa cifras em blocos como AES em modo CBC.

CBC-MAC possui características semelhantes a HMAC. Usa duas chaves diferentes K1 e K2, geradas a partir de uma chave mestre K. Primeiro calculamos Cn, o último bloco do modo CBC com a chave K1. Então criptografamos este bloco com a chave K2, gerando a tag de autenticação.

K1 = K XOR 5C…5C
K2 = K XOR 36…36
C0 = EK1(IV)
Ci = EK1(Pi XOR Ci-1)
Cn = EK1(Pn XOR Cn-1)
TAG = EK2(Cn)

A tag de autenticação tem o mesmo comprimento do bloco da cifra, 128 bits no caso de AES.

TAG = CBC-MAC-AES(K, MENSAGEM)

Porque não usar HMAC ou KMAC sempre? Em sistemas embarcados com pouca memória de programa, por exemplo, pode ser inviável implementar uma cifra (como AES-128) e também uma hash (como SHA2 ou SHA3). Então usa-se a cifra para ambos criptografia e autenticação.

Vetor de inicialização e MACs

Note que no modo CBC-MAC, deixamos explícito a existência de um vetor de inicialização (IV).

Este é um nonce, um número utilizado apenas uma vez com a chave K. Ele pode ser aleatório ou um contador incrementado a cada mensagem.

O nonce serve para que duas mensagens tenham tags diferentes, mesmo se o conteúdo seja idêntico.

HMAC e KMAC também podem utilizar um IV, basta colocá-lo logo antes da mensagem:

MENSAGEM = IV || MENSAGEM

Isso é semelhante ao CBC-MAC, que coloca o IV no bloco zero, antes da mensagem.

Se considerarmos os IV como sendo parte da mensagem, sua função é de fazer com que sempre tenhamos uma mensagem diferente sendo autenticada, gerando sempre uma tag diferente.

Note que o vetor de inicialização (IV) é enviado junto com a mensagem, ou seja, não é secreto. Em alguns casos ele não é transmitido, se pode ser identificado pelo contexto.

Links Externos

Wikipedia HMAC

HMAC – FIPS PUB 198-1 – The Keyed-Hash Message Authentication Code

KMAC – NIST 800-185 – SHA-3 Derived Functions

Wikipedia CBC-MAC

CBC-MAC – FIPS PUB 113 – Computer Data Authentication

Leia mais:

Veja mais posts na Categoria Criptografia!

Criptografia Modos de Operação

Resumão

Exitem diversos modos de operação de criptografia com os quais podemos utilizar cifras de blocos, como a Criptografia AES.

Cada um tem suas características, que os fazem mais ou menos adequados para certas aplicações.

Os modos de operação mais comuns são: ECB, CBC, OFB, CFB, CTR.

EBC – Electronic Codebook

Livro Eletrônico de Códigos.

Cada chave criptográfica possui um livro de códigos, que relaciona dados plenos com dados cifrados. Este modo de operação é o mais simples, mas dificilmente é recomendado.

Encriptar:
Ci = EK(Pi)

Para n blocos, envia-se:
C1, C2, …, Cn

Decriptar:
Pi = DK(Ci)

Note que este modo revela igualdade igualdade de blocos.

Este modo exige que as mensagens sejam de tamanho divisível pelo tamanho do bloco (16 bytes para AES). Caso contrário, a mensagem deve ser preenchida (padding). [TODO Link padding.]

CBC – Cipher Block Chaining

Cadeia de Blocos Cifrados.

Os dados plenos Pi são misturados (XOR) com a cifra Ci-1 do bloco anterior antes de encriptar.

Encriptar:
C0 = EK(IV)
Ci = EK(Pi XOR Ci-1)

Para n blocos, envia-se:
IV, C1, C2, …, Cn

Decriptar:
C0 = EK(IV)
Pi = DK(Ci) XOR Ci-1

Este modo utiliza um vetor de inicialização (IV) que deve ser um número utilizado apenas uma vez (nonce) para cada chave K, ou seja, cada mensagem criptografada com a chave K precisa de um IV diferente. O IV não precisa ser secreto, pode ser transmitido junto com a mensagem.

Se repetir o mesmo IV os dados cifrados revelam igualdade dos primeiros blocos e a diferença (XOR) do primeiro bloco diferente. Conhecendo uma mensagem, revela-se a outra, exceto depois do bloco diferente. Isso no melhor dos casos, ou seja, com uma cifra ideal. Algumas cifras são extremamente fracas caso houver repetição de IV.

Note que o primeiro bloco cifrado é misturado com C0, que é o IV encriptado. Não se envia C0.

Este modo, assim como ECB, também exige que as mensagens sejam de tamanho divisível pelo tamanho do bloco ou que o último bloco seja preenchido (padding).

OFB – Output Feedback

Realimentação da saída.

Este modo transforma uma cifra de blocos (block cipher) em uma cifra de corrente (stream cipher).

Os dados plenos Pi são misturados (XOR) com a fonte pseudo-aleatória Oi-1 para realizar a encriptação.

Encriptar:
O0 = EK(IV)
Oi = EK(Oi-1)
Ci = Pi XOR Oi-1

Para n blocos, envia-se:
IV, C1, C2, …, Cn

Decriptar (idêntico a encriptar):
O0 = EK(IV)
Oi = EK(Oi-1)
Pi = Ci XOR Oi-1

Este modo utiliza um vetor de inicialização (IV) que deve ser um número utilizado apenas uma vez (nonce) para cada chave K, ou seja, cada mensagem criptografada com a chave K precisa de um IV diferente. O IV não precisa ser secreto, pode ser transmitido junto com a mensagem.

Se repetir o mesmo IV os dados cifrados revelam igualdade dos blocos e a diferença (XOR) dos blocos diferentes. Conhecendo uma mensagem, revela-se a outra. [Novamente… Isso no melhor dos casos, ou seja, com uma cifra ideal. Algumas cifras são extremamente fracas caso houver repetição de IV.]

Este modo não exige preenchimento (padding). Se o último bloco não está completo com dados plenos, podemos enviar apenas estes bytes encriptados de Cn, ignorando o restante dos bytes. Note que isso revela o tamanho da mensagem. Se o tamanho da mensagem deve ser secreto ou obfuscado é necessário realizar o preenchimento (padding).

CFB – Cipher Feedback

Realimentação de cifra.

Este modo transforma uma cifra de blocos (block cipher) em uma cifra de corrente (stream cipher).

Os dados plenos Pi são misturados (XOR) com a cifra anterior Ci-1 para realizar a encriptação.

Encriptar:
C0 = IV
Ci = Pi XOR EK(Ci-1)

Para n blocos, envia-se:
IV, C1, C2, …, Cn

Decriptar (idêntico a encriptar):
C0 = IV
Pi = Ci XOR EK(Ci-1)

Este modo utiliza um vetor de inicialização (IV) que deve ser um número utilizado apenas uma vez (nonce) para cada chave K, ou seja, cada mensagem criptografada com a chave K precisa de um IV diferente. O IV não precisa ser secreto, pode ser transmitido junto com a mensagem.

Como no modo CBC, se repetir o mesmo IV os dados cifrados revelam igualdade dos primeiros blocos e a diferença (XOR) do primeiro bloco diferente. Conhecendo uma mensagem, revela-se a outra, exceto depois do bloco diferente. [Novamente… Isso no melhor dos casos, ou seja, com uma cifra ideal. Algumas cifras são extremamente fracas caso houver repetição de IV.]

Este modo não exige preenchimento (padding). Se o último bloco não está completo com dados plenos, podemos enviar apenas estes bytes encriptados de Cn, ignorando o restante dos bytes. Note que isso revela o tamanho da mensagem. Se o tamanho da mensagem deve ser secreto ou obfuscado é necessário realizar o preenchimento (padding).

Outros modos

Existem ainda outros modos de operação.

CTR (Counter): Usa um nonce (número usado apenas uma vez) em conjunto com um contador para gerar uma sequência pseudo-aleatória e realizar XOR com os dados plenos (parecido com o que acontece nos modos OFB e CFB).

CFB “parcial”: É possível usar blocos menores do que o bloco da cifra no modo CFB.

Links Externos

Wikipedia Block Cipher Modes of Operation

NIST Recommendation for Block Cipher Modes of Operation

Leia mais:

Veja mais posts na Categoria Criptografia!

Criptografia AES

Resumão

A criptografia AES é um padrão de criptografia simétrica em blocos.

A criptografia tem o objetivo de esconder uma mensagem de uma pessoa que não deve lê-la. Uma função criptográfica possui uma chave e uma função inversa. Existem dois tipos de criptografia: simétrica e assimétrica.

Criptografia simétrica tem a característica de que todas as pessoas realizando a comunicação devem possuir a mesma chave.

Mesma chave = Criptografia simétrica.

Atualmente existem dois padrões de função criptográfica simétrica considerados seguros: AES e 3DES (DES triplo). Recomenda-se sempre utilizar AES, pois é mais rápido e mais seguro que 3DES.

O padrão AES trabalha em blocos de dados de 128 bits (16 bytes), ou seja, a entrada e a saída da função criptográfica tem este tamanho, e pode utilizar chaves criptográficas de 128, 192 e 256 bits, dependendo do nível de segurança necessário para a aplicação.

O padrão 3DES trabalha com blocos de 64 bits (8 bytes) e possui chaves de 112 bits.

Se a aplicação exige n bits de segurança, utilize uma função criptográfica de segurança equivalente. Na dúvida ou se não estiver especificado, utilize 128 bits de segurança.

Na dúvida ou se não estiver especificado, utilize 128 bits de segurança.

Função criptográficaTamanho do bloco (Entrada/Saída)Tamanho da chave (Segurança)Função hash equivalente
3DES (DES triplo)64 bits (8 bytes)112 bitsSHA-224
SHA3-224
AES-128128 bits (16 bytes)128 bitsSHA-256
SHA3-256
AES-192128 bits (16 bytes)192 bitsSHA-384
SHA3-384
AES-256128 bits (16 bytes)256 bitsSHA-512
SHA3-512
Funções criptográficas simétricas seguras AES e 3DES, tamanho do bloco, tamanho da chave, segurança e funções hash de segurança equivalente.

Hash e Criptografia

Funções Hash e Funções de Criptografia tem objetivos diferentes.

A hash serve para gerar um valor associado a uma mensagem. Qualquer outra pessoa pode calcular esse valor a partir da mensagem, desde que conheça qual algoritmo usar.

A criptografia serve para esconder uma mensagem de quem não possua a chave utilizada para encriptar. Mesmo sabendo o algoritmo utilizado, sem saber a chave deve ser muito difícil (praticamente impossível) determinar qual a mensagem a partir dela encriptada.

Ainda, diferente de uma função hash, uma função de criptografia possui uma chave e uma função inversa. Uma função hash é utilizada por todos da mesma maneira para dar o mesmo resultado, enquanto uma função criptográfica pode ser utilizada com chaves diferentes, dando resultados diferentes. A operação inversa é importante pois quem recebe a mensagem criptografada deve ser capaz de, através da chave, reverter ela para a mensagem original.

Para uma função criptográfica ser considerada segura: sua segurança deve depender apenas da chave; a mensagem criptografada deve ser indistinguível de valores gerados aleatoriamente; e conhecendo a mensagem e a mensagem criptografada, não deve ser possível determinar a chave.

Padrão de Criptografia AES

O padrão AES (Advanced Encryption Standard – Padrão de Criptografia Avançado) é um padrão de criptografia simétrica de blocos.

“Simétrica” significa que a mesma chave é utilizada para encriptar e para decriptar. “Blocos” significa que ela opera em um número fixo de bits.

A criptografia AES opera em blocos de 128 bits (16 bytes), ou seja, pega um bloco como entrada e gera como saída outro bloco de mesmo tamanho, com os bits misturados de acordo com a chave utilizada.

A chave utilizada na criptografia AES pode ser de três tamanhos: 128, 192, 256 bits. O tamanho da chave é escolhido a partir do nível de segurança exigido pela aplicação.

Encriptar um bloco com o algoritmo da criptografia AES consiste em executar diversas rodadas (turnos) de quatro operações: AddRoundKey, SubBytes, ShiftRows, MixColumns. Cada uma dessas operações possui uma função dentro do algoritmo.

Cada uma dessas operações tem uma operação inversa, utilizada na decriptação.

Adicionar chave da rodada (AddRoundKey)

Faz-se XOR do bloco com um a chave da rodada.

Essa é a única parte do algoritmo AES onde a chave criptográfica é utilizada e é ela que faz cada chave dar uma saída diferente.

A “chave da rodada” é um valor obtido a partir da chave de criptográfica, utilizando o algoritmo de escalonamento de chaves (key sechedule).

Adição ou XOR?

Note que no nome “AddRoundKey” falamos em “adicionar”, mas a operação utilizada é XOR. Eis a explicação:

O padrão AES não pensa nos bytes como números, mas como polinômios em GF(28).

Cada bit representa um coeficiente do polinômio. Por exemplo o byte 00001001, em vez do número 1×23 + 1×20 = 9, é o polinômio 1×x3 + 1×x0 = x3 + 1.

Os coeficientes só podem ser 0 ou 1 e, quando fazemos adição, consideramos sempre módulo 2, ou seja 0+0=0, 1+0=1, 0+1=1 e 1+1=0, o que é igual a operação binária XOR.

Por que usar essa matemática esquisita? Ela tem vantagens, características interessantes, que são utilizadas!

Substituição não-linear (SubBytes)

Cada um dos 16 bytes do bloco são trocados por outros 16 bytes, de acordo com uma tabela de substituição.

Esta é a única operação não-linear do algoritmo AES. A existência de operações não-lineares dificultam a utilização de técnicas lineares de criptanálise.

Esta substituição faz difusão dos bits dentro de um byte, ou seja, espalha os bits dentro de um byte.

DE onde veio tal tabela?

Note que a tabela não foi simplesmente inventada.

Ela foi criada a partir de uma propriedade muito legal dos polinômios GF(28). Lembra?

Todo polinômio tem um inverso multiplicativo, ou seja, todo polinômio p possui um inverso q = 1/p tal que pq = 1.

Devemos considerar a multiplicação de p e q módulo (resto da divisão por) um outro polinômio, que deve ser irredutível. Polinômio irredutível é como se fosse um “polinômio primo”, não pode ser divisível por outro polinômio, similar a números primos não serem divisíveis por outros números. O polinômio do módulo utilizado no algoritmo é x8 + x4 + x3 + x + 1.

Esta é a parte não linear: o inverso.

Depois de tirar o inverso do byte, faz-se uma multiplicação dos bits por uma matriz e uma soma (XOR) com constante. Isso serve para atrapalhar alguma criptanalise de utilizar a relação de inverso recém utilizada.

Em vez de fazer todos esses cálculos toda vez, utilizamos uma tabela.

Trocar linhas (ShiftRows)

Considerando o bloco de 16 bytes como sendo uma matriz 4×4, esta operação troca a posição dos bytes de cada linha.

A primeira linha é mantida, a segunda linha é deslizada um byte, a terceira linha é deslizada dois bytes e a quarta linha é deslizada três bytes.

Não tem segredo!

Esta substituição faz difusão dos bits nas linhas, que são blocos de 32 bits (4 bytes).

Misturar colunas (MixColumns)

Novamente consideramos o bloco de 16 bytes como sendo uma matriz 4×4, esta operação mistura cada uma das colunas.

Esta mistura faz difusão dos bits nas colunas, que também são blocos de 32 bits (4 bytes).

Por algum motivo (qual?), essa operação não é realizada na última rodada.

Mas como se calcula?

Aqui não há uma operação equivalente ou uma tabela.

Selecionamos uma coluna, cada byte dessa coluna é considerado um coeficiente GF(28) de um polinômio de terceiro grau em Z. Essa é a parte esquisita, onde todo mundo quebra a cabeça: Os coeficientes do polinômio são polinômios.

Note que estou usando o Z maiúsculo para os polinômios-coluna com coeficientes em GF(28). Anteriormente usei x minúsculo para os polinômios-byte GF(28).

Reiterando a explicação: cada coeficiente do “polinômio-coluna-em-Z” é um “polinômio-byte-em-x”.

Fazemos uma multiplicação do polinômio-coluna pelo polinômio {3}Z3 + {1}Z2 + {1}Z + {2}, módulo ao polinômio é Z4 + 1.

Como os coeficientes estão em GF(28), multiplicações são sempre calculadas módulo algum polinômio irredutível de oitavo grau. Usamos o mesmo polinômio citado anteriormente: x8 + x4 + x3 + x + 1.

Então, se a coluna é formada por 255, 1, 2 e 3, o polinômio é
{255}Z3 + {1}Z2 + {2}Z + {3}.

Lembre-se que os coeficientes são, na verdade, polinômios em GF(28). Então o polinômio acima, na verdade é…
(x7+x6+x5+x4+x3+x2+x+1)Z3 + (1)Z2 + (x)Z + (x+1)

E o polinômio multiplicador {3}Z3 + {1}Z2 + {1}Z + {2}, na verdade é…
(x+1)Z3 + (1)Z2 + (1)Z + (x)

É isso ai, os coeficientes do polinômio em Z são polinômios em x.

Fazendo a multiplicação do polinômio-coluna com o polinômio 3Z3 + Z2 + Z + 2 obtemos um polinômio de sexto grau. Então fazemos a redução módulo Z4 + 1 e obtemos um polinômio de terceiro grau {231}Z3 + {248}Z2 + {255}Z + {31}.

Assim, depois da operação MixColumns, a coluna formada pelos números 255, 1, 2 e 3 é transformada na coluna 231, 248, 255 e 31.

Existe um atalho, que evita realizar as operações de multiplicação em Z e redução módulo Z4 + 1. Basta realizar uma multiplicação de um vetor (que representa a coluna) por uma matriz (que representa o polinômio multiplicador). Relembrando que os bytes sendo multiplicados, na verdade são polinômios em GF(28) e devem ser reduzidos módulo x8 + x4 + x3 + x + 1.

Número de rodadas

As quatro operações acima (AddRoundKey, SubBytes, ShiftRows, MixColumns) são realizadas diversas vezes, com o objetivo de realizar difusão (propagação de diferenças) e tornar mais difícil um ataque de criptanálise.

O número de rodadas executadas depende do tamanho da chave. Enquanto maior a chave, mais rodadas são necessárias.

Tamanho da chaveNúmero de rodadas
128 bits10
192 bits12
256 bits14
Número de rodadas da criptografia simétrica AES em relação ao tamanho da chave.

Links externos

Wikipedia AES

Especificação AES

Leia mais:

Veja mais posts na Categoria Criptografia!

Funções HASH Criptográficas

Resumão

Uma função hash processa uma mensagem de tamanho arbitrário (qualquer número de bytes) e cria a partir dela uma sequência de bytes de tamanho fixo.

Ela deve ser uma função unidirecional, ou seja, não deve ser possível (ao menos na prática) realizar sua inversa. Deve dar resultados iguais para mensagens iguais e resultados claramente diferentes para mensagens diferentes. Mesmo para mensagens parecidas (trocando ou adicionando um bit ou uma letra) a diferença no resultado deve ser bem evidente.

Atualmente existem dois padrões de função hash considerados criptograficamente seguros: SHA2 e SHA3.

Ambos padrões definem hashes de diferentes tamanhos de saída e, consequentemente, diferentes níveis de segurança criptográficos: 224, 256, 384 e 512 bits.

Para uma aplicação que exige n bits de segurança criptográfica, usa-se uma hash com 2n bits de saída. Por exemplo, se eu preciso de 128 bits de segurança eu vou utilizar SHA-256 (SHA2) ou SHA3-256, que possuem o dobro de bits de saída.

Na dúvida ou se não estiver especificado, utilize 128 bits de segurança.

HashSaídaSegurançaUsado em conjunto
com criptografia
SHA-224
SHA3-224
224 bits112 bits3DES (DES triplo)
SHA-256
SHA3-256
256 bits128 bitsAES-128
SHA-384
SHA3-384
384 bits192 bitsAES-192
SHA-512
SHA3-512
512 bits256 bitsAES-256
Hashes criptográficas seguras SHA2 e SHA3, tamanho da saída, segurança e algorítimos de criptografia com segurança equivalente.

Para que serve uma função Hash?

As funções hash servem ser utilizadas para diferentes propósitos.

Integridade de dados. Pode ser utilizada para confirmar que uma mensagem (ou arquivo) foi enviado corretamente. Quem envia a mensagem manda junto sua hash. Quem recebe a mensagem calcula a hash da mensagem e compara com a recebida.

Assinatura digital. Diretamente assinar digitalmente uma mensagem (ou arquivo) de tamanho arbitrário é complicado. Especialmente se muito grande exigiria chaves criptográficas tão grande quanto as mensagens. A assinatura digital então é realizada sobre a hash da mensagem, que tem um comprimento fixo.

Funções Hash Criptográficas

Funções hash criptográficas, além de associar uma saída de tamanho fixo com uma mensagem de tamanho arbitrário, tem objetivo de resistir a ataques criptográficos. Dessa forma elas podem ser utilizadas em conjunto com esquemas de criptografia.

Para isso ela deve resistir a três diferentes ataques: pré-imagem, segunda pré-imagem e colisão. Eles são discutidos abaixo.

Ataque Pré-imagem de Hash

Deve ser muito difícil (praticamente impossível) de encontrar uma mensagem x que gere uma hash pré-definida y. Ou seja, a função hash não deve ser invertível.

Por exemplo, o só o gênio da lâmpada poderia atender a este desejo:
“Eu quero encontrar uma mensagem cujo valor da SHA3-256 é e05dbb98c0c3665c1c95290a8c2245ba32ad7e366502f2a5fdb37b4001054692.”
Talvez nem ele.

Resposta: Uma palavra, dez letras, sem acentos, tudo minúsculo. Se calcular SHA3-224 dá 80ab895e2f664ab13a76581f41e8226a85540d5d9617eab2c29a5792.
Quer tentar? Você tem 2610 = 141.167.095.653.376 chances. Calculadora online SHA3-256.

Alguém capaz de realizar a pré-imagem, pode descobrir qual a mensagem a partir de sua hash.

De onde vem esse nome “pré-imagem”? Vem do conteúdo de matemática chamado funções. Uma função y = f(x) tem seu domínio (valores de x) e sua imagem (valores de y). Para uma função hash, o algoritmo é f, o domínio são as mensagens x e a imagem são os valores das hashes y. Pré-imagem significa ter a imagem e, a partir dela, determinar o domínio correspondente (como uma função inversa).

Ataque Segunda Pré-imagem de Hash

Se eu tenho uma mensagem x1 que tem uma hash y, deve ser muito difícil (praticamente impossível) de encontrar uma mensagem diferente x2 que dê a mesma hash y.

Pode soar muito parecido com o anterior. Sim, é!

Mas este ataque considera que o atacante conhece a mensagem original e quer descobrir uma segunda mensagem com mesma hash. Ou seja, conhecer a mensagem não deve dar nenhuma vantagem adicional para um ataque.

Eis aqui mais um pedido para o gênio da lâmpada:
“Eu quero uma mensagem diferente que dê a mesma SHA3-256 que ‘Olá, banco! Envie R$1.000,00 para Oscar. Obrigado!’ “

Alguém capaz de realizar a segunda pré-imagem, pode forjar assinaturas digitais. Pode trocar a mensagem assinada por uma outra mensagem, sem que isso seja percebido.

De onde vem esse nome “segunda pré-imagem”? Já temos uma pré-imagem: a pré-imagem de y é x1. Mas queremos uma segunda pré-imagem x2.

Ataque Colisão de Hash

Deve ser muito difícil (praticamente impossível) de encontrar duas mensagens diferentes x1 e x2 que dão uma mesma hash y.

Pode soar muito parecido com o anterior. Sim, é!

Mas este ataque não faz nenhuma restrição com respeito as mensagens, nem ao valor da hash.

Eis aqui mais um pedido para o gênio da lâmpada:
“Eu quero duas mensagens diferentes que dão a mesma SHA3-256. Não importa qual valor final da hash.”

Alguém capaz de realizar colisões pode gerar muita confusão e dor de cabeça em sistemas que dependem de hashes.

De onde vem esse nome “colisão”? Imagine que as mensagens são carros e o resultado da hash seja a vaga do estacionamento que devem usar. Mesmo quando da mesma marca, modelo, ano… são carros diferente e vão estacionar em vagas diferentes. Dois carros querendo entrar na mesma vaga geram uma colisão.

Links Externos

Wikipedia SHA2

Especificação SHA2

Wikipedia SHA3

Especificação SHA3

Leia mais:

Veja mais posts na Categoria Criptografia!

Software R no Ubuntu Linux

Instalando software R

É fácil instalar o software R no Ubuntu Linux. Use o comando abaixo:

$ sudo apt install r-base

Executável em linguagem R

No Linux podemos criar scripts (programas executáveis em arquivos de texto) e marcá-los com uma configuração para que possam ser executados facilmente. Basta usar o comando chmod. Assim podemos executar o programa com o comando ./PROGRAMA.

$ chmod +x PROGRAMA
$ ./PROGRAMA

Linux, a linguagem é R!

Mas e se o programa estiver escrito na linguagem do software R? Como fazer para o Linux saber que deve ser executado com na linguagem de programação R?

Basta colocar a seguinte primeira linha do programa em software R:

#!/usr/bin/r
# Programa ...
print(1+1)

#!/usr/bin/r – faz o Linux saber que o programa está escrito na linguagem do software R, já com opções adequadas para execução de scripts.

Outra opção, que imprime os comandos e as respostas intermediárias é o seguinte:

#!/usr/bin/R --vanilla -q -f
# Programa ...
print(1+1)

#!/usr/bin/R – faz o Linux saber que o programa está escrito na linguagem do software R.

--vanilla – faz o R não salvar, nem restaurar, o espaço de trabalho.

-q – faz o R não imprimir a versão

-f – indica que o R deve ler o próprio arquivo sendo executado (./PROGRAMA)

Para explorar mais opções verifique o manual do programa R. Só não se esqueça de deixar a opção -f por último!

man R

Memória de programa AVR/ATmega328P

Sempre que utilizamos strings e arrays constantes em nossos programas, por padrão elas vão parar na memória RAM. Como tempo pouca memória RAM, seria ótimo conseguir colocar isso na memória de programa, liberando a preciosa RAM para as variáveis.

Neste post vemos como fazer isso nos microcontroladores AVR, como o ATmega328P do Arduino Uno.

Continue lendo “Memória de programa AVR/ATmega328P”