DEV Community

Matheus Mina
Matheus Mina

Posted on

Implementando a Cifra de César em Ruby

A Cifra de César é a mais simples e conhecida técnica de encriptação. Ela também é conhecida por cifra de troca, código de César, troca de César, ROT N ou ROT13, sendo esse o nome mais comum, trocando as letras em treze rotações.

Este algoritmo é extremamente simples, pois somente funciona para letras entre A e Z, ignorando todos os caracteres especiais como pontos, espaços em branco e letras como Ç or Á.

Começando nossa implementação, vamos precisar criar uma classe responsável por saber o que queremos encriptar e quantas trocas vamos fazer.

class Caeser
attr_reader :text, :rotation
def initialize(text, rotation)
@text = text
@rotation = rotation
end
end
view raw caeser_class.rb hosted with ❤ by GitHub

Feito isso, precisamos trocar os caracteres pelo correspondente depois de N rotações, então vamos adicionar o método shift:

def shift(byte, initial_byte, limit_byte)
new_byte = byte + rotation
return initial_byte - (limit_byte - new_byte) - 1 if new_byte > limit_byte
new_byte
end
view raw caeser_shift.rb hosted with ❤ by GitHub

Neste ponto, nos deparamos com um pequeno problema. Se o valor de new_byte (o valor original em bytes somado com quantos bytes que desejamos trocar) for maior que Z ou z, é necessário voltar ao valor de A ou a novamente. Quando isso acontece, também é necessário subtrair um, pois temos que levar o valor do caractere inicial em consideração.

Neste código, initial_byte é referente ao valor de A ou a e limit_byte é o byte referente a Z ou z. Desta maneira, sempre vamos rotacionar entre as letras.

Vamos agora descobrir como é possível encontrar os bytes presentes em cada caractere de uma string. Olhando mais a fundo no Ruby, isto é facilmente feito pelo método *bytes. * Tendo conhecimento disto, temos o seguinte:

  • A é representado pelo byte 65.
  • Z é representado pelo byte 90.
  • a é representado pelo byte 97.
  • z é representado pelo byte 122.
'AZaz'.bytes
view raw bytes.rb hosted with ❤ by GitHub

Então, o próximo passo é encontrar qual o valor que vamos usar para initial_byte e limit_byte ou se vamos ignorar este caractere. Para isso, vamos checar se os bytes dentro do texto fornecido estão dentro da variação de bytes para as letras que queremos, se não, vamos simplesmente retornar o valor do byte.

def cipher
text.bytes.map do |byte|
case byte
when 65..90 then shift(byte, 65, 90)
when 97..122 then shift(byte, 97, 122)
else byte
end
end.pack('c*')
end
view raw cipher.rb hosted with ❤ by GitHub

Em Ruby, a maneira mais fácil de converter estes bytes em uma string é chamando o método pack. Também é necessário fornecer ao método a opção c como um parâmetro. Neste caso, c significa um valor inteiro positivo de 8-bit e significa que todo o array deve ser convertido.

Com estes dois métodos somos capazes de encriptar uma mensagem utilizando a Cifra de César. Se quisermos decifrar uma mensagem, devemos trocar as letras na direção oposta, como código abaixo:

def unshift(byte, initial_byte, limit_byte)
new_byte = byte - rotation
return limit_byte - (initial_byte - new_byte) + 1 if new_byte < initial_byte
new_byte
end

Já o método decipher deve ser exatamente igual ao método cipher, portanto só é necessário duplicar o método cipher e trocar a assinatura do método para decipher.

Agora vamos finalmente testar o nosso código!

Caeser.new('Why did the chicken cross the road?', 13).cipher
view raw caeser_run_1.rb hosted with ❤ by GitHub

Também é possível decifrar uma mensagem:

Caeser.new('Jul qvq gur puvpxra pebff gur ebnq?', 13).decipher
view raw caeser_run_2.rb hosted with ❤ by GitHub

Uma coisa interessantíssima acontece quando nós utilizamos a quantidade de rotações igual a 13. Como temos 26 letras entre A e Z, não faz diferença nenhuma se chamamos o método cipher ou decipher, pois ele sempre vai retornar exatamente o mesmo resultado.

caeser = Caeser.new('Why did the chicken cross the road?', 13)
caeser.cipher == caeser.decipher
view raw caeser_run_3.rb hosted with ❤ by GitHub

Para ter resultados diferentes, é necessário trocar a quantidade de rotações.

Infelizmente essa implementação tem um problema. Os caracteres em Ruby podem ser multi-bytes e originalmente não levei isto em consideração. Para que funcione ignorando os caracteres multi-bytes deve se implementar a solução utilizando divisão modular.

Este é minha primeira postagem sobre criptografia e minha ideia é implementar algumas das técnicas conhecidas e tentar explicar facilmente aqui. Se você tiver interesse em olhar o código completo, por favor acesse o repositório no Github.

Você também pode me encontrar no Twitter, Github ou LinkedIn.

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

While many AI coding tools operate as simple command-response systems, Qodo Gen 1.0 represents the next generation: autonomous, multi-step problem-solving agents that work alongside you.

Read full post

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more