terça-feira, 14 de março de 2023

Alterando encoding de arquivos no Linux

 As vezes precisamos mudar o Encoding de um arquivo para corrigir os caracteres estranhos.


Para descobrir a codificação de origem pode-se usar a ferramenta file, exemplo:


$ file [nome_arquivo]


Exemplo de conversão de ISO-8859-1 para UTF-8:


$ iconv -f iso-8859-1 -t utf-8 arquivo.txt > arquivo_novo.txt


Uma dica importante é criar um novo arquivo pra saída, pois assim você não perde seus dados... (ele apaga mesmo!) Crie um novo arquivo, verifique se está tudo certo e somente depois sobrescreva o arquivo original.

segunda-feira, 13 de março de 2023

Alternando entre versões do Java no Linux

        Nesse artigo vou mostrar como mudar da versão do Java em um servidor Linux. Essa mudança altera a versão padrão em uso pelo servidor, embora aplicações possam apontar diretamente para uma versão ao invés de usar a versão padrão definida para o servidor.


$ sudo update-alternatives --config java


       Irá aparecer a lista de versões disponíveis e você pode digitar o número correspondente a versão desejada e depois confirmar com Enter.




       Este comando também é útil para ver onde as versões foram instaladas no servidor, porque ele mostra o caminho completo. Importante lembrar que algumas versões que possam ter sido baixadas e descompactadas não irão aparecer.




segunda-feira, 6 de março de 2023

Particionando, Formatando e Montando discos no Linux

 

Nesse artigo vamos mostrar como montar um disco no Linux. Ao adicionar um novo disco, físico ou lógico dependendo do ambiente, é necessário adicioná-lo ao sistema. Esse processo é chamado de montagem.

 

Para vermos os discos disponíveis podemos usar o comando lsblk:

 

$ sudo lsblk

 

Antes de montar é necessário particionar e formatar o disco. Os discos seguem uma ordem alfabética: sda (principal), sdb (segundo), sdc (terceiro)... e assim por diante. Vamos seguir como se fosse o segundo disco. Primeiro vamos particionar:

 

$ fdisk /dev/sdb

 

Então o fdisk vai pedir algumas opções para poder particionar o disco e oferecer a opção “m” para ajuda. Para particionar como uma única partição primária de dados você pode fornecer a opção “n” e depois escolher “p” para a primária. Depois siga o prompt confirmando o número de partições (que é 1) e o início e fim dela. Após receber a mensagem que a partição foi criada, digite “w” para confirmar as alterações no disco.

 

Para formatar digite:

 

$ mkfs.ext4 /dev/sdb

 

Caso queira uma partição onde o Windows possa enxergar também use NTFS.

 

Agora vamos à montagem do disco para uso. As montagens podem ser feitas em qualquer pasta do sistema, porém existe um diretório padrão para isso que o /mnt.

 

Vamos imaginar que vamos montá-lo na pasta chamada “arquivos”. Primeiro criamos a pasta:

 

$ mkdir /mnt/arquivos

  

Agora fazemos a montagem apontando o disco para a pasta:

 

$ mount /dev/sdb /mnt/arquivos

 

Dessa maneira o disco está montado e disponível, a menos que o sistema seja reiniciado. Para manter o disco montado sempre que o sistema ligar ainda é necessário automatizar essa montagem. Abra o arquivo fstab que fica no etc e acrescente a seguinte linha informando o disco, pra onde vai e o sistema de arquivos, além do padrão “defaults 0 0”:

 

$ /dev/sdb /mnt/arquivos ext4 defaults 0 0

 

Agora é só salvar o arquivo e ele sempre será montado ao iniciar o sistema.




sábado, 4 de fevereiro de 2023

Instalando o Docker no Windows usando WSL 2 e Ubuntu

          Nesse artigo vamos configurar o Docker pra rodar no Ubuntu através do WSL 2 de forma nativa (como se a máquina fosse Linux puro). Caso não tenha o WSL 2 configurado veja aqui como fazer: Configuração WSL 2

 

Agora vamos ao Docker! O primeiro passo é atualizar a biblioteca do Ubuntu de gerenciamento de programas:

 

$ sudo apt update && sudo apt upgrade

 

Depois instalar as dependências como Http, certificados, acesso a URLs, etc...

 

$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

 

Agora adicionar o repositório Docker na biblioteca do Ubuntu:

 

$ sudo mkdir -p /etc/apt/keyrings

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

 

Agora para configurar o repositório:

 

$ echo \

  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

 

Vamos mais uma vez atualizar a biblioteca:

 

$ sudo apt-get update

 

Agora sim vamos instalar o Docker. Para a instalar a última versão usamos:

 

$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

 

Para instalar uma versão específica primeiro listamos as versões:

 

$ apt-cache madison docker-ce | awk '{ print $3 }'

 

E então instalamos a que desejamos. Ex:

 

$ VERSION_STRING=5:20.10.13~3-0~ubuntu-jammy

$ sudo apt-get install docker-ce=$VERSION_STRING docker-ce-cli=$VERSION_STRING containerd.io docker-compose-plugin

 

É preciso também dar permissão a pasta criada. A instalação do Docker já espera que haja um grupo chamado "docker". Veja com o comando "groups" se esse grupo "docker" já existe, caso não tenha sido criado, siga as duas linhas abaixo, caso tenha sido criado, apenas adicione seu usuário a ele.

 

$ sudo groupadd Docker

$ sudo usermod -aG docker $USER

 

Pronto, agora é só fazer logoff e login ou fechar o app do Ubuntu e abrir novamente para poder usar o docker.

 

Atenção! Em alguns casos ao sair e entrar no App do Ubuntu (e outras distribuições) ele desliga o serviço do Docker. Caso isso aconteça pode ser resolvido da seguinte maneira:

 

$ sudo systemctl enable docker.service

$ sudo systemctl enable containerd.service

 

Isso adiciona o serviço do Docker ao Systemd que gerencia serviços que inicializam automaticamente. Caso queira remover basta usar o "disable" ao invés do "enable".

 

 

Fonte:

https://docs.docker.com/engine/install/ubuntu/

https://docs.docker.com/engine/install/linux-postinstall/

https://github.com/codeedu/wsl2-docker-quickstart#instala%C3%A7%C3%A3o-do-wsl-2

 

Configurando o WSL 2 no Windows 10 - (Linux no Windows)

           Nesse artigo vou mostrar como configurar o WSL 2 no Windows para podermos usar uma distribuição Linux como se estivéssemos rodando ela direto sobre o hardware sem o Windows.

 

Abra o PowerShell em modo administrador e execute os comandos para habilitar o WSL 2:

 

> dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

 

> dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

 

Teste o comando wsl, se não funcionar é preciso reiniciar o computador. Funcionando, baixe e instale o kernel do WSL no endereço:  https://docs.microsoft.com/pt-br/windows/wsl/wsl2-kernel 

 

Agora mude a versão do WSL para a 2:

 

> wsl --set-default-version 2

  

Pronto, agora na Windows Store você escolhe a distribuição que você quer e clica em instalar. Geralmente a mais usada é o Ubuntu, mas fica a seu critério. No processo de instalação ou primeiro acesso vai ser pedido para você fornecer um nome de usuário e senha para o S.O do Linux. Você pode fornecer os mesmos que usa no Windows ou outro.

 

 

Fonte:

https://learn.microsoft.com/pt-br/windows/wsl/

https://github.com/codeedu/wsl2-docker-quickstart#instala%C3%A7%C3%A3o-do-wsl-2

 

terça-feira, 10 de janeiro de 2023

Java AES/CBC criptografia e descriptografia

 

Nesse artigo vou mostrar como criptografar e descriptografar um texto usando criptografia bidirecional assimétrica, ou seja, de chave única e privada. Esse tipo de criptografia é útil por exemplo para enviar uma URL de recuperação de senha para um usuário ou mesmo proteger o token de acesso.

 

Vamos usar o algoritmo AES (Advanced Encryption Standard) que possui algumas variações, da qual vamos usar o CBC - Cipher Block Chaining (Encadeamento de blocos cifrados). O modo CBC usa um vetor de inicialização (IV) para aumentar a criptografia. Primeiro, o CBC usa o bloco de texto simples XOR com o IV. Em seguida, ele criptografa o resultado para o bloco de texto cifrado. No próximo bloco, ele usa o resultado da criptografia para XOR com o bloco de texto simples até o último bloco. Uma das principais características do CBC é que ele usa um processo de encadeamento que faz com que a descriptografia de um bloco de texto cifrado dependa de todos os blocos de texto cifrado anteriores.

 

*XOR = Ou exclusivo ou disjunção exclusiva é um mecanismo de codificação usado para combinar diferentes entradas.

 

Vamos aos códigos. Serão 2 classes e um Teste Unitário para garantirmos que tudo está certo.

 

import java.security.spec.KeySpec;

 

import javax.crypto.Cipher;

import javax.crypto.SecretKey;

import javax.crypto.SecretKeyFactory;

import javax.crypto.spec.IvParameterSpec;

import javax.crypto.spec.PBEKeySpec;

import javax.crypto.spec.SecretKeySpec;

 

/**

 * Advanced Encryption Standard ( AES )

 *

 * @author Daniel Oliveira

 *

 * IV = Initialization Vector ou Vetor de inicialização

 *  é uma entrada para uma primitiva criptográfica sendo usada para fornecer

 *  o estado inicial. O IV geralmente precisa ser aleatório ou pseudo -aleatório,

 *  mas às vezes um IV só precisa ser imprevisível ou único.

 * 

 *  o AES tem um tamanho de bloco de 128 bits ou 16 bytes. O AES não altera o

 *  tamanho, e o tamanho do texto cifrado é igual ao tamanho do texto não

 *  criptografado. Além disso, nos modos ECB e CBC, devemos usar um algoritmo

 *  de preenchimento como PKCS 5. Portanto, o tamanho dos dados após a criptografia é: 256

 */

public class SymmetricCripto {     

      private static final String AES = "AES";

      private static final int ITERATION_COUNT = 65536;

      private static final int KEY_LENGTH = 256;

      private static final String ALGORIHM = "AES/CBC/PKCS5Padding";

      private static final String SECRET_KEY_FACTORY_INSTANCE = "PBKDF2WithHmacSHA256";

      private static final String ENCODING = "UTF-8";

// crie seu IV com 16 Bytes.

      private static final String IV = "8P7A6S5S4W3O2R1D";

 

      public static byte[] cripto(String text, SecretKey password )   {

            try {

                  return cripto(password, text.getBytes(ENCODING));

            } catch (Exception exception) {

                  exception.printStackTrace();

                  return new byte[0];

            }

      }

     

      private static byte[] cripto(SecretKey secretKey, byte[] text )   {

            try {

                  Cipher cipher = Cipher.getInstance(ALGORIHM);

                  cipher.init(Cipher.ENCRYPT_MODE, secretKey, generateIv());

                  return cipher.doFinal(text);

            } catch (Exception exception) {

                  exception.printStackTrace();

                  return new byte[0];

            }

      }

     

      public static byte[] descripto(SecretKey secretKey, byte[] text )   {

            try{

                  Cipher cipher = Cipher.getInstance(ALGORIHM);

                  cipher.init(Cipher.DECRYPT_MODE, secretKey, generateIv());

            return cipher.doFinal(text);

            } catch (Exception exception) {

                  exception.printStackTrace();

                  return new byte[0];

            }

      }

     

      public static SecretKey getSecretKey(String password, String salt){

            SecretKey secret = null;

            try {

                  SecretKeyFactory factory = SecretKeyFactory.getInstance(SECRET_KEY_FACTORY_INSTANCE);                 

                  KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), ITERATION_COUNT, KEY_LENGTH);

                  secret = new SecretKeySpec(factory.generateSecret(keySpec)

                      .getEncoded(), AES);

            } catch (Exception e) {

                  e.printStackTrace();

            }

          return secret;

      }

     

      public static IvParameterSpec generateIv() {

        byte[] iv = IV.getBytes();

        return new IvParameterSpec(iv);

    }

}

 

public final class Util {

      private static final String SALT = "12345678";

// crie seu PASSWORD com 16 Bytes.

      private static final String PASSWORD = "P1A2S3S4W5O6R7D8";

      public static String createToken(String username) {

            Timestamp currentTimeStamp = new Timestamp(Calendar.getInstance().getTime().getTime());

            return username + "_" + currentTimeStamp.toString();

      }

 

      public static String encodeToken(String token) {

            SecretKey secretKey = SymmetricCripto.getSecretKey(PASSWORD, SALT);

            byte[] criptografado = SymmetricCripto.cripto(token, secretKey);

            return Base64.getUrlEncoder().encodeToString(criptografado);      

      }

 

      public static String decodeToken(String token) {

            byte[] decodedBytes = Base64.decode(token.getBytes());

            SecretKey secretKey = SymmetricCripto.getSecretKey(PASSWORD, SALT);

            token = new String(SymmetricCripto.descripto(secretKey, decodedBytes), Charset.forName("UTF-8"));

            return token;

      }

}

 

         E agora para testar a criptografia vamos ver a classe de teste:

 

public class UtilTeste {

      @Test

      public void criptografaTokenTest() {

            String token = Util.createToken("Daniel");

            String tokenCriptografado = Util.encodeToken(token);

            String tokenDescriptografado = Util.decodeToken(tokenCriptografado);

            Assert.assertTrue(token.equals(tokenDescriptografado));

      }

     

      @Test

      public void criptografaTokenTest2() {      

            String token = Util.createToken("Daniel");

            String token2 = Util.createToken("Gadiel");

            System.out.println(token);

            System.out.println(token2);

 

            String tokenCriptografado1 = Util.encodeToken(token);

            System.out.println(tokenCriptografado1);

 

            String tokenCriptografado2 = Util.encodeToken(token2);

            System.out.println(tokenCriptografado2);

 

            String tokenDescriptografado1 = Util.decodeToken(tokenCriptografado1);

            System.out.println(tokenDescriptografado1);

 

            String tokenDescriptografado2 = Util.decodeToken(tokenCriptografado2);

            System.out.println(tokenDescriptografado2);

 

             Assert.assertTrue(token.equals(tokenDescriptografado1) && token2.equals(tokenDescriptografado2));

      }

 

      @Test

      public void criptografaTokenTest3() {

            String token = "Daniel_2023-01-10 18:58:09.642";

            String token2 = "Gadiel_2023-01-10 18:58:09.642";

            System.out.println(token);

            System.out.println(token2);

 

            String tokenCriptografado1 = Util.encodeToken(token);

            System.out.println(tokenCriptografado1);

 

            String tokenCriptografado2 = Util.encodeToken(token2);

            System.out.println(tokenCriptografado2);

 

            String tokenDescriptografado1 = Util.decodeToken(tokenCriptografado1);

            System.out.println(tokenDescriptografado1);

 

            String tokenDescriptografado2 = Util.decodeToken(tokenCriptografado2);

            System.out.println(tokenDescriptografado2);

 

            Assert.assertTrue(
tokenCriptografado1.equals("KOlEIFpg8oWmgIPQlwIZ9Ibaz4DU0Fq3Fx7ZWHwmLKw="&&    tokenCriptografado2.equals("7NzCr0fzeSNy9X2Ib+mjuFPY3EmTM03gpThBW5q6A3o="));

      }

}

 

Importante: Para se ter sempre o mesmo resultado de criptografia e descriptografia para valores iguais após a reinicialização do servidor ou em servidores diferentes (para quem usa cluster ou coisa do tipo) o PassWord que gera a SecretKey e o IV devem ser criados com o mesmo valor sempre. Note que eles são constantes no código.

 

Dica: O token pode (e deve) ser melhorado com o acréscimo de um número randômico e mais dados de acordo com a necessidade. O PassWord e o IV também devem ser alterados de tempos em tempos.

 

Solução adaptada à necessidade que tive a partir das seguintes fontes:

https://www.devmedia.com.br/introducao-a-seguranca-da-informacao-em-java/28247

https://www.baeldung.com/java-aes-encryption-decryption

https://www.techtarget.com/searchsecurity/definition/cipher-block-chaining

https://stackoverflow.com/questions/54874072/aes-encryption-in-node-resulting-is-different-output-compared-to-java