AES-128: O Padrão Avançado de Criptografia em Detalhes
▶ Introdução
O AES-128 (Advanced Encryption Standard) é um dos algoritmos de criptografia mais utilizados no mundo, garantindo a proteção de dados em sistemas bancários, comunicações seguras e até mesmo em dispositivos IoT. Desde sua adoção pelo NIST (National Institute of Standards and Technology) em 2001, o AES substituiu o antigo DES (Data Encryption Standard) e se tornou um pilar da segurança digital.
Neste artigo, “o algoritmo AES-128”, vamos explorar em profundidade o funcionamento do AES-128, sua estrutura matemática, níveis de segurança, aplicações práticas e como ele se compara a outras variantes, como o AES-192 e o AES-256. Se você é um profissional de TI, entusiasta de segurança ou simplesmente quer entender como seus dados são protegidos, este guia é para você.
▶ O Que é o AES-128?
O AES-128 é um algoritmo de criptografia simétrica que utiliza uma chave de 128 bits para codificar e decodificar informações. Ele opera em blocos de 128 bits (16 bytes) e é composto por várias rodadas de transformações matemáticas que garantem a confidencialidade dos dados.
Principais Características do AES-128
- Simétrico: Usa a mesma chave para criptografar e descriptografar.
- Bloco de 128 bits: Processa dados em blocos fixos.
- 10 Rodadas de Criptografia: Cada rodada aplica operações de substituição, permutação e mistura.
- Eficiente em Hardware e Software: Otimizado para desempenho em diferentes plataformas.
▶ Como o AES-128 Funciona?
➧ I – Expansão da Chave (Key Schedule) no AES-128
A Expansão da Chave é um processo crucial no AES-128 que transforma a chave original de 128 bits (16 bytes) em 11 subchaves de 128 bits cada, usadas nas rodadas de criptografia. Esse processo garante que cada rodada utilize uma chave diferente, aumentando a segurança do algoritmo.
Vamos decompor os passos em detalhes:
➜ 1. Divisão da Chave Original
A chave inicial de 128 bits é representada como 16 bytes. Esses bytes são organizados em 4 palavras de 32 bits (W[0] a W[3]), onde cada palavra contém 4 bytes consecutivos da chave.
Exemplo:
Se a chave for K = 2B 7E 15 16 28 AE D2 A6 AB F7 15 88 09 CF 4F 3C
(em hexadecimal), as primeiras 4 palavras são:
- W[0] = 2B 7E 15 16
- W[1] = 28 AE D2 A6
- W[2] = AB F7 15 88
- W[3] = 09 CF 4F 3C
➜ 2. Geração das Palavras Seguintes (W[4] a W[43])
A partir dessas 4 palavras iniciais, o algoritmo gera mais 40 palavras (W[4] a W[43]), totalizando 44 palavras (176 bytes). A geração depende do índice i da palavra:
Caso 1: i não é múltiplo de 4 (Ex: W[5], W[6], W[7], W[9], etc.)
Fórmula:
W[i]=W[i−4]⊕W[i−1]
Simplesmente faz-se um XOR entre a palavra 4 posições atrás (W[i-4]) e a palavra anterior (W[i-1]).
Exemplo (W[4]):
W[4]=W[0]⊕W[3]=2B7E1516⊕09CF4F3C=22B15A2A
Caso 2: i é múltiplo de 4 (Ex: W[4], W[8], W[12], …, W[40])
Quando i é divisível por 4, aplicam-se três operações especiais antes do XOR:
- RotWord (Rotação de Bytes)
A palavra W[i-1] é rotacionada 1 byte para a esquerda.
Exemplo:
W[7] = [A, B, C, D]→RotWord(W[7]) = [B, C, D, A]
2. SubWord (Substituição via S-Box)
Cada byte da palavra rotacionada passa pela S-Box (tabela de substituição não-linear do AES).
Exemplo:
B1→S-Box(B1)=7A
(A S-Box é pré-definida e fornece confusão criptográfica.)
3. Rcon (Round Constant)
Um valor constante (Rcon[j], onde j = i/4) é aplicado via XOR apenas no primeiro byte.
As constantes são pré-calculadas em GF(2⁸) e variam a cada rodada.
Exemplo (Rcon[1] para W[4]):
Rcon[1] = 01 00 00 00
4. Cálculo Final da Palavra
W[i]=W[i−4]⊕SubWord(RotWord(W[i-1]))⊕Rcon[j]
Exemplo (W[8]):
Suponha:
W[4]=22B15A2A,W[7]=A6ABF715
RotWord(W[7]) = AB F7 15 A6
SubWord(AB F7 15 A6) = 62 68 59 9B
(após S-Box)
Rcon[2] = 02 00 00 00
Cálculo:
W[8]=W[4]⊕SubWord(RotWord(W[7]))⊕Rcon[2]=22B15A2A⊕6268599B⊕02000000=40D903B1=22B15A2A⊕6268599B⊕02000000=40D903B1
➜ 3. Formação das Subchaves (Round Keys)
Cada subchave K₀ a K₁₀ consiste em 4 palavras consecutivas do array expandido:
- K₀ = W[0..3] → Subchave da Rodada Inicial
- K₁ = W[4..7] → Subchave da Rodada 1
- …
- K₁₀ = W[40..43] → Subchave da Rodada Final
Exemplo (Primeiras Subchaves):
- K₀ =
2B7E1516 28AED2A6 ABF71588 09CF4F3C
- K₁ =
22B15A2A 40D903B1 ...
- …
- K₁₀ =
D014F9A8 C9EE2589 ...
➜ Resumo do Processo
Índice (i) | Método de Cálculo de W[i] | Exemplo (W[4], W[8]) |
---|---|---|
i % 4 ≠ 0 | W[i] = W[i-4] ⊕ W[i-1] | W[5] = W[1] ⊕ W[4] |
i % 4 = 0 | W[i] = W[i-4] ⊕ SubWord(RotWord(W[i-1])) ⊕ Rcon[j] | W[8] = W[4] ⊕ (SubWord(RotWord(W[7]))) ⊕ Rcon[2] |
➜ Conclusão
A Expansão da Chave no AES-128 assegura que:
- Cada rodada use uma subchave única (diversificação).
- Seja computacionalmente difícil recuperar a chave original a partir das subchaves (resistência a ataques).
- As operações RotWord, SubWord e Rcon introduzem não-linearidade e difusão, fortalecendo a segurança.
Esse processo é fundamental para a robustez do AES e é executado uma única vez antes do início da cifragem.
➧ II – Rodada Inicial (AddRoundKey) no AES-128
A Rodada Inicial é a primeira fase do processo de cifragem no AES-128 e consiste em uma operação relativamente simples, mas essencial, que prepara o bloco de dados para as transformações mais complexas das rodadas subsequentes. Vamos decompor cada passo com exemplos claros.
➜ 1. Estado Inicial: Organização do Bloco de Dados em uma Matriz 4×4 (State)
O AES opera sobre um bloco de 128 bits (16 bytes) de dados, que é organizado em uma matriz chamada State. Essa matriz tem 4 linhas e 4 colunas, onde cada célula armazena 1 byte (8 bits).
Como o bloco é organizado?
- Os 16 bytes do bloco de entrada são dispostos coluna por coluna (não linha por linha).
- Ou seja, os primeiros 4 bytes preenchem a primeira coluna, os próximos 4 bytes a segunda coluna, e assim por diante.
Exemplo:
Suponha que o bloco de entrada (plaintext) seja:32 43 F6 A8 88 5A 30 8D 31 31 98 A2 E0 37 07 34
(em hexadecimal).
A matriz State fica assim:
Coluna 0 | Coluna 1 | Coluna 2 | Coluna 3 | |
---|---|---|---|---|
Linha 0 | 32 | 88 | 31 | E0 |
Linha 1 | 43 | 5A | 31 | 37 |
Linha 2 | F6 | 30 | 98 | 07 |
Linha 3 | A8 | 8D | A2 | 34 |
➜ 2. AddRoundKey: Aplicação da Primeira Subchave (K₀) via XOR
Nesta etapa, o State é combinado com a primeira subchave (K₀) usando uma operação XOR (OU exclusivo) bit a bit.
O que é a subchave K₀?
- K₀ é a primeira das 11 subchaves geradas pelo Key Schedule (Expansão da Chave).
- Assim como o State, ela também é uma matriz 4×4 bytes.
Exemplo:
Suponha que K₀ seja:2B 7E 15 16 28 AE D2 A6 AB F7 15 88 09 CF 4F 3C
Organizada em matriz 4×4:
Coluna 0 | Coluna 1 | Coluna 2 | Coluna 3 | |
---|---|---|---|---|
Linha 0 | 2B | 28 | AB | 09 |
Linha 1 | 7E | AE | F7 | CF |
Linha 2 | 15 | D2 | 15 | 4F |
Linha 3 | 16 | A6 | 88 | 3C |
Como o AddRoundKey funciona?
Para cada byte do State, faz-se um XOR com o byte correspondente em K₀:
State[linha][coluna]=State[linha][coluna]⊕K₀[linha][coluna]
Cálculo do primeiro byte (Linha 0, Coluna 0):
32⊕2B=19
(Em binário: 00110010
XOR 00101011
= 00011001
= 19
em hexadecimal)
Resultado completo após AddRoundKey:
Coluna 0 | Coluna 1 | Coluna 2 | Coluna 3 | |
---|---|---|---|---|
Linha 0 | 19 | A0 | 9A | E9 |
Linha 1 | 3D | F4 | C6 | F8 |
Linha 2 | E3 | E2 | 8D | 48 |
Linha 3 | BE | 2B | 2A | 08 |
➜ Por que o AddRoundKey é importante?
- Introduz dependência da chave: O bloco de dados é imediatamente misturado com a chave secreta.
- Operação reversível: O mesmo XOR é aplicado na descriptografia (já que
A ⊕ B ⊕ B = A
). - Simplicidade e eficiência: O XOR é uma operação muito rápida em hardware e software.
➜ Conclusão
A Rodada Inicial no AES-128 consiste em:
- Organizar os 16 bytes do bloco em uma matriz 4×4 (State).
- Aplicar um XOR entre o State e a primeira subchave (K₀).
Essa etapa não possui SubBytes, ShiftRows ou MixColumns, mas é crucial para “semear” a chave no processo de cifragem, garantindo que todas as rodadas subsequentes dependam do segredo criptográfico.
➧ III – 9 Rodadas Principais no AES-128
As 9 Rodadas Principais são o núcleo do processo de cifragem no AES-128. Cada uma dessas rodadas aplica quatro operações consecutivas ao bloco de dados (State), adicionando complexidade e segurança ao algoritmo. Vamos decompor cada etapa com exemplos práticos.
➜ Visão Geral das 9 Rodadas Principais
Cada uma das 9 rodadas repete a seguinte sequência de operações:
- SubBytes (Substituição de bytes via S-Box)
- ShiftRows (Deslocamento cíclico das linhas)
- MixColumns (Transformação linear das colunas)
- AddRoundKey (XOR com a subchave da rodada)
Essas operações garantem confusão (dificuldade em relacionar chave e texto cifrado) e difusão (disseminação dos bits pelo bloco).
➜ 1. SubBytes (Substituição de Bytes)
O que faz?
- Cada byte do State é substituído por outro byte usando a S-Box, uma tabela de substituição não-linear pré-definida.
- A S-Box é derivada da inversão multiplicativa no corpo GF(2⁸) seguida de uma transformação afim.
Exemplo Prático:
Suponha o State após a Rodada Inicial:
Col 0 | Col 1 | Col 2 | Col 3 | |
---|---|---|---|---|
Linha 0 | 19 | A0 | 9A | E9 |
Linha 1 | 3D | F4 | C6 | F8 |
Linha 2 | E3 | E2 | 8D | 48 |
Linha 3 | BE | 2B | 2A | 08 |
- O byte
19
(linha 0, coluna 0) é substituído pelo valor da S-Box na posição19
: - Consultando a S-Box,
19
→D4
. - O byte
A0
(linha 0, coluna 1) é substituído porA0
→E0
.
State após SubBytes:
Col 0 | Col 1 | Col 2 | Col 3 | |
---|---|---|---|---|
Linha 0 | D4 | E0 | B8 | 1E |
Linha 1 | 27 | BF | B4 | 41 |
Linha 2 | 11 | 98 | 5D | 52 |
Linha 3 | AE | F1 | E5 | 30 |
➜ 2. ShiftRows (Deslocamento de Linhas)
O que faz?
- Cada linha da matriz é deslocada ciclicamente para a esquerda:
- Linha 0: Sem deslocamento.
- Linha 1: Deslocada 1 byte para a esquerda.
- Linha 2: Deslocada 2 bytes para a esquerda.
- Linha 3: Deslocada 3 bytes para a esquerda.
Exemplo Prático:
Antes de ShiftRows:
| Linha 0 | D4
| E0
| B8
| 1E
|
| Linha 1 | 27
| BF
| B4
| 41
|
| Linha 2 | 11
| 98
| 5D
| 52
|
| Linha 3 | AE
| F1
| E5
| 30
|
Após ShiftRows:
- Linha 0: Permanece igual →
D4 E0 B8 1E
- Linha 1:
27 BF B4 41
→BF B4 41 27
(deslocamento de 1) - Linha 2:
11 98 5D 52
→5D 52 11 98
(deslocamento de 2) - Linha 3:
AE F1 E5 30
→30 AE F1 E5
(deslocamento de 3)
State resultante:
Col 0 | Col 1 | Col 2 | Col 3 | |
---|---|---|---|---|
Linha 0 | D4 | E0 | B8 | 1E |
Linha 1 | BF | B4 | 41 | 27 |
Linha 2 | 5D | 52 | 11 | 98 |
Linha 3 | 30 | AE | F1 | E5 |
➜ 3. MixColumns (Mistura de Colunas)
O que faz?
- Cada coluna é transformada usando uma multiplicação matricial por uma matriz fixa em GF(2⁸) (corpo de Galois).
- A operação difunde os bytes entre colunas, aumentando a difusão.
Matriz de MixColumns:
[
\begin{bmatrix}
02 & 03 & 01 & 01 \
01 & 02 & 03 & 01 \
01 & 01 & 02 & 03 \
03 & 01 & 01 & 02 \
\end{bmatrix}
]
Exemplo (Coluna 0):
Coluna original: [D4, BF, 5D, 30]
Cada novo byte é calculado como:
Novo Byte=(02⋅D4)⊕(03⋅BF)⊕(01⋅5D)⊕(01⋅30)
(onde ·
é multiplicação em GF(2⁸) e ⊕
é XOR).
Resultado aproximado após MixColumns (detalhes matemáticos omitidos):
Coluna 0 transformada → [04, 66, 81, E5]
State após MixColumns (exemplo simplificado):
Col 0 | Col 1 | Col 2 | Col 3 | |
---|---|---|---|---|
Linha 0 | 04 | E0 | B8 | 1E |
Linha 1 | 66 | B4 | 41 | 27 |
Linha 2 | 81 | 52 | 11 | 98 |
Linha 3 | E5 | AE | F1 | E5 |
➜ 4. AddRoundKey (XOR com a Subchave da Rodada)
O que faz?
- O State é combinado com a subchave da rodada atual (K₁ a K₉) usando XOR.
- Cada rodada usa uma subchave diferente, gerada no Key Schedule.
Exemplo:
Suponha a subchave K₁ para a Rodada 1:A0 88 23 2A FA 54 A3 6C FE 2C 39 76 17 B1 39 05
Organizada em matriz 4×4:
Col 0 | Col 1 | Col 2 | Col 3 | |
---|---|---|---|---|
Linha 0 | A0 | FA | FE | 17 |
Linha 1 | 88 | 54 | 2C | B1 |
Linha 2 | 23 | A3 | 39 | 39 |
Linha 3 | 2A | 6C | 76 | 05 |
Aplicando XOR (exemplo para o primeiro byte):04 (State) ⊕ A0 (K₁) = A4
State final após AddRoundKey (exemplo simplificado):
Col 0 | Col 1 | Col 2 | Col 3 | |
---|---|---|---|---|
Linha 0 | A4 | 1A | 46 | 09 |
Linha 1 | EE | E0 | 6D | 96 |
Linha 2 | A2 | F1 | 28 | A1 |
Linha 3 | CF | C2 | 87 | E0 |
➜ Resumo das 9 Rodadas Principais
Operação | Efeito Principal | Exemplo (Rodada 1) |
---|---|---|
SubBytes | Substituição não-linear via S-Box | 19 → D4 |
ShiftRows | Deslocamento cíclico das linhas | [27, BF, B4, 41] → [BF, B4, 41, 27] |
MixColumns | Mistura linear das colunas | Coluna [D4, BF, 5D, 30] → [04, 66, 81, E5] |
AddRoundKey | XOR com a subchave da rodada | 04 ⊕ A0 = A4 |
➜ Por que essas operações são seguras?
- SubBytes: Introduz não-linearidade, resistindo a ataques algébricos.
- ShiftRows + MixColumns: Garantem difusão, espalhando a influência de um byte por todo o bloco.
- AddRoundKey: Adiciona dependência da chave em cada rodada.
Essas 9 rodadas repetem o mesmo processo, mas com subchaves diferentes, até a Rodada Final (que omite MixColumns).
➧ IV – Rodada Final no AES-128 (Sem MixColumns)
A Rodada Final é a última etapa do processo de cifragem no AES-128 e possui uma estrutura ligeiramente diferente das rodadas principais. Ela omite a operação MixColumns, mantendo apenas SubBytes, ShiftRows e AddRoundKey. Vamos analisar cada aspecto dessa rodada especial.
➜ Por que a Rodada Final é diferente?
Nas 9 Rodadas Principais, o AES aplica quatro operações:
- SubBytes
- ShiftRows
- MixColumns
- AddRoundKey
Na 10ª Rodada (Final), MixColumns é removido por dois motivos:
- Simetria com a descriptografia: A operação inversa (InvMixColumns) seria redundante na última rodada.
- Eficiência: Remove uma operação desnecessária sem comprometer a segurança.
➜ Passos da Rodada Final
1. SubBytes (Substituição de Bytes)
- Igual às rodadas anteriores: cada byte do State passa pela S-Box.
- Exemplo:
- Se o State contém
[A4, EE, A2, CF, ...]
, cada valor é substituído pela S-Box. A4
→49
,EE
→54
, etc.
2. ShiftRows (Deslocamento de Linhas)
- Aplica-se o mesmo deslocamento cíclico das rodadas principais:
- Linha 0: Sem deslocamento.
- Linha 1: 1 byte para a esquerda.
- Linha 2: 2 bytes para a esquerda.
- Linha 3: 3 bytes para a esquerda.
3. AddRoundKey (XOR com a Última Subchave)
- Usa a 10ª subchave (K₁₀) gerada no Key Schedule.
- Exemplo:
- Se o State após ShiftRows for
[49, 54, 58, BD, ...]
e K₁₀ for[D0, EF, AA, FB, ...]
, o XOR é calculado byte a byte:49 ⊕ D0 = 99
,54 ⊕ EF = BB
, etc.
➜ Exemplo Completo da Rodada Final
Suponha o State antes da Rodada Final:
Col 0 | Col 1 | Col 2 | Col 3 | |
---|---|---|---|---|
Linha 0 | A4 | 68 | 5B | 02 |
Linha 1 | EE | 53 | A0 | C1 |
Linha 2 | A2 | F1 | D5 | 8A |
Linha 3 | CF | E4 | 39 | 4D |
Passo 1: SubBytes
- Consulta à S-Box:
A4
→49
,EE
→54
,A2
→3A
,CF
→8A
, etc.
State após SubBytes:
Col 0 | Col 1 | Col 2 | Col 3 | |
---|---|---|---|---|
Linha 0 | 49 | 45 | 7F | 77 |
Linha 1 | 54 | ED | E0 | 78 |
Linha 2 | 3A | D9 | 6E | C5 |
Linha 3 | 8A | 47 | 12 | E8 |
Passo 2: ShiftRows
- Linha 0: Permanece igual (
49 45 7F 77
). - Linha 1: Desloca 1 byte →
ED E0 78 54
. - Linha 2: Desloca 2 bytes →
6E C5 3A D9
. - Linha 3: Desloca 3 bytes →
E8 8A 47 12
.
State após ShiftRows:
Col 0 | Col 1 | Col 2 | Col 3 | |
---|---|---|---|---|
Linha 0 | 49 | 45 | 7F | 77 |
Linha 1 | ED | E0 | 78 | 54 |
Linha 2 | 6E | C5 | 3A | D9 |
Linha 3 | E8 | 8A | 47 | 12 |
Passo 3: AddRoundKey (K₁₀)
Suponha a subchave K₁₀:
Col 0 | Col 1 | Col 2 | Col 3 | |
---|---|---|---|---|
Linha 0 | D0 | 15 | 37 | FE |
Linha 1 | EF | A8 | C6 | 2B |
Linha 2 | AA | D8 | 4F | E6 |
Linha 3 | FB | 03 | 67 | 28 |
Aplicando XOR (exemplo para o primeiro byte):49 ⊕ D0 = 99
State Final (Texto Cifrado):
Col 0 | Col 1 | Col 2 | Col 3 | |
---|---|---|---|---|
Linha 0 | 99 | 50 | 48 | 89 |
Linha 1 | 02 | 48 | BE | 7F |
Linha 2 | C4 | 1D | 75 | 3F |
Linha 3 | 13 | 89 | 20 | 3A |
O bloco resultante (99 02 C4 13 50 48 1D 89 ...
) é o texto cifrado final.
➜ Tabela Comparativa: Rodada Principal vs. Rodada Final
Operação | Rodada Principal | Rodada Final |
---|---|---|
SubBytes | ✅ Sim | ✅ Sim |
ShiftRows | ✅ Sim | ✅ Sim |
MixColumns | ✅ Sim | ❌ Não |
AddRoundKey | ✅ Sim | ✅ Sim |
➜ Conclusão
A Rodada Final no AES-128:
- Remove MixColumns para simplificar o processo sem perda de segurança.
- Mantém SubBytes e ShiftRows para preservar confusão e difusão.
- Usa a última subchave (K₁₀) para garantir que o texto cifrado dependa totalmente da chave.
Essa etapa finaliza o processo de cifragem, produzindo um bloco de 128 bits seguro e pronto para transmissão ou armazenamento.
▶ Segurança do AES-128: É Realmente Inquebrável?
Muitos se perguntam: “O AES-128 é seguro o suficiente?” A resposta é sim, mas com ressalvas.
Resistência a Ataques
- Força Bruta: Um ataque de força bruta exigiria 2¹²⁸ tentativas—impraticável com a tecnologia atual.
- Ataques Criptoanalíticos: Nenhum ataque eficiente foi descoberto contra o AES-128 em sua forma pura.
- Side-Channel Attacks: Vulnerabilidades podem surgir em implementações mal feitas (ex: timing attacks).
Comparação com AES-192 e AES-256
Variante | Tamanho da Chave | Rodadas | Nível de Segurança |
---|---|---|---|
AES-128 | 128 bits | 10 | Alto |
AES-192 | 192 bits | 12 | Muito Alto |
AES-256 | 256 bits | 14 | Extremo |
Embora o AES-256 ofereça maior segurança teórica, o AES-128 ainda é considerado suficiente para a maioria das aplicações comerciais e governamentais.
▶ Aplicações do AES-128 no Mundo Real
O AES-128 está presente em diversas tecnologias do dia a dia:
1. Comunicações Seguras
- SSL/TLS: Protege conexões HTTPS.
- VPNs: Criptografa dados em redes privadas.
- Mensagens Criptografadas: WhatsApp e Signal usam AES (entre outros algoritmos).
2. Armazenamento de Dados
- Discos Rígidos Criptografados: BitLocker (Windows) e FileVault (Mac).
- Bancos de Dados: Proteção de informações sensíveis.
3. Dispositivos IoT
- Garante a segurança em dispositivos inteligentes com recursos limitados.
▶ Limitações e Considerações
Apesar de sua robustez, o AES-128 tem algumas considerações importantes:
- Gestão de Chaves: Se a chave for comprometida, toda a segurança é perdida.
- Implementação Inadequada: Erros na codificação podem criar brechas.
- Quantum Computing: No futuro, computadores quânticos podem reduzir a segurança do AES-128 (mas soluções pós-quânticas estão em desenvolvimento).
▶ Conclusão
O AES-128 continua sendo um dos algoritmos de criptografia mais confiáveis e eficientes do mundo. Sua combinação de desempenho e segurança o torna ideal para aplicações que vão desde transações bancárias até a proteção de dados pessoais.
Recomendações Finais
- Use AES-128 para a maioria dos casos onde a segurança é crítica, mas o desempenho também importa.
- Combine com boas práticas como troca periódica de chaves e proteção contra side-channel attacks.
- Mantenha-se atualizado, pois a criptografia evolui com novas ameaças e tecnologias.
Se você busca um equilíbrio entre segurança e eficiência, o AES-128 é uma escolha excelente.
Este artigo foi desenvolvido para o blog Hand Code Solutions, trazendo informações técnicas e práticas para profissionais de TI. Ficou com dúvidas? Deixe nos comentários! 🚀
Não deixe de, também visitar o Supremacia Militar – História e Tecnologia Militar, e conheça detalhes que moldaram os conflitos ao longo do tempo, suas inovações tecnológicas que transformaram os campos de batalhas e o impacto das forças armadas no desenvolvimento da sociedade ao longo do tempo até os dias atuais. Passado, presente e futuro em um só lugar.