Obtenez un cryptage compatible OpenSSL avec Java / PHP

J'ai essayé le traitement de cryptage / décryptage compatible OpenSSL cli dans différentes langues

Dans un certain projet, j'ai été obligé de déchiffrer le texte chiffré en utilisant OpenSSL cli avec divers langages de script, et c'était un peu gênant dans le cas de Java et PHP, j'ai donc résumé les informations.

Processus de cryptage / décryptage OpenSSL cli

Avec OpenSSL cli, par exemple, vous pouvez facilement crypter du texte à un rythme de mot de passe en utilisant l'option enc comme indiqué ci-dessous, mais si vous essayez de décrypter cela en utilisant Java, il ajoutera et analysera les informations d'en-tête compatibles OpenSSL Il n'a pas pu être décrypté tel quel car il n'y a pas de fonction correspondante.

Lors du cryptage du contenu d'un fichier texte avec OpenSSL cli, vous pouvez facilement obtenir une chaîne de caractères cryptée simplement en donnant la méthode de cryptage et le mot de passe comme options, comme indiqué dans l'exemple ci-dessous.

cat plain.txt | openssl enc -e -aes-128-cbc -base64 -k <mot de passe>

Normalement, si AES est spécifié comme méthode de cryptage, il est nécessaire de donner Salt et IV (Initialization Vector) en plus du mot de passe lors du cryptage et du décryptage, mais dans OpenSSL ce Salt et Le IV est automatiquement généré et intégré dans l'en-tête des données chiffrées, de sorte que l'utilisateur n'a qu'à connaître le mot de passe. Comme le montre l'exemple de script de cet article, la bibliothèque OpenSSL de Perl et Ruby a un mécanisme de génération Salt et IV qui est chiffré avec OpenSSL cli, il est donc relativement facile d'utiliser du texte chiffré avec OpenSSL cli. Cependant, dans le cas de la bibliothèque OpenSSL pour Java et PHP, puisqu'elle ne disposait pas de ce mécanisme compatible OpenSSL cli, il était nécessaire d'incorporer seul le mécanisme de génération Salt et IV.

À propos, lorsque le chiffrement est effectué par la méthode AES à l'aide de l'option enc avec OpenSSL cli, Salt a une chaîne de bits aléatoire de 8 octets (64 bits) et IV a 16 octets (16 octets) générés par la méthode suivante. 128 bits) une chaîne de bits est utilisée.

Formule de génération IV Clé = mot de passe + Salt MD5 IV = clé + mot de passe + Salt MD5

Ceux-ci sont ajoutés en tant qu'informations d'en-tête au début des données cryptées et renvoyés sous forme de données cryptées.

Chaîne "Salted__" (8 octets) + Salt (8 octets) + IV (16 octets) + [données chiffrées]

Lors du décryptage, si vous confirmez que le début des données cryptées est "Salted__", utilisez les 8 octets de données suivants comme Salt, et à partir du mot de passe, Salt comme dans le cas du cryptage Génère un IV et décrypte le corps des données cryptées qui suivent Salt.

Pour Java

L'exemple de code suivant est écrit en l'incorporant. Le getKeyAndGenerateIv dans ce code est utilisé pour générer Salt et IV d'une manière compatible OpenSSL Cli.

EncryptDecryptText.java


import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import java.security.spec.KeySpec;
import java.security.SecureRandom;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Arrays;
import java.io.BufferedReader;
import java.io.InputStreamReader;

class EncryptDecryptText {

    public static boolean getKeyAndGenerateIv(String password, byte[] salt, byte[] key_bytes, byte[] iv_bytes) {
        try {
            byte[] password_bytes = password.getBytes(StandardCharsets.UTF_8);
            int length = password_bytes.length + salt.length;
            ByteBuffer byte_buffer = ByteBuffer.allocate(length);
            byte_buffer.put(password_bytes);
            byte_buffer.put(salt);
            byte_buffer.rewind();
            byte[] byte_array = new byte[length];
            byte_buffer.get(byte_array);
            System.arraycopy(MessageDigest.getInstance("MD5").digest(byte_array), 0, key_bytes, 0, key_bytes.length);
            length = password_bytes.length + salt.length + key_bytes.length;
            byte_buffer = ByteBuffer.allocate(length);
            byte_buffer.put(key_bytes);
            byte_buffer.put(password_bytes);
            byte_buffer.put(salt);
            byte_buffer.rewind();
            byte_array = new byte[length];
            byte_buffer.get(byte_array);
            System.arraycopy(MessageDigest.getInstance("MD5").digest(byte_array), 0, iv_bytes, 0, iv_bytes.length);
        }
        catch ( NoSuchAlgorithmException e ) {
            return false;
        }
        return true;
    }

    public static String encrypt(String plaintext, String password) throws Exception {
        // Generate random salt.
        byte[] random_bytes = new byte[8];
        new SecureRandom().nextBytes(random_bytes);

        byte[] key_bytes = new byte[16];
        byte[] iv_bytes = new byte[16];
        getKeyAndGenerateIv(password, random_bytes, key_bytes, iv_bytes);

        SecretKey secret = new SecretKeySpec(key_bytes, "AES");
        IvParameterSpec ivspec = new IvParameterSpec(iv_bytes);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret, ivspec);
        byte[] encrypted_bytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

        final String header_string = "Salted__";
        byte[] header_bytes = header_string.getBytes(StandardCharsets.UTF_8);
        int length = header_bytes.length + random_bytes.length + encrypted_bytes.length;
        ByteBuffer byte_buffer = ByteBuffer.allocate(length);
        byte_buffer.put(header_bytes);
        byte_buffer.put(random_bytes);
        byte_buffer.put(encrypted_bytes);
        byte_buffer.rewind();
        byte[] byte_array = new byte[length];
        byte_buffer.get(byte_array);

        return new String(Base64.getEncoder().encodeToString(byte_array));
    }

    public static String decrypt(String payload, String password) throws Exception {
        byte[] payload_bytes = Base64.getDecoder().decode(payload.getBytes(StandardCharsets.UTF_8));
        byte[] header_bytes = new byte[8];
        byte[] salt_bytes = new byte[8];
        int length = payload_bytes.length;
        ByteBuffer byte_buffer = ByteBuffer.allocate(length);
        byte_buffer.put(payload_bytes);
        byte_buffer.rewind();
        byte_buffer.get(header_bytes);
        byte_buffer.get(salt_bytes);
        length = payload_bytes.length - header_bytes.length - salt_bytes.length;
        byte[] data_bytes = new byte[length];
        byte_buffer.get(data_bytes);

        byte[] key_byte = new byte[16];
        byte[] iv_bytes = new byte[16];
        getKeyAndGenerateIv(password, salt_bytes, key_byte, iv_bytes);

        SecretKey secret = new SecretKeySpec(key_byte, "AES");
        IvParameterSpec ivspec = new IvParameterSpec(iv_bytes);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secret, ivspec);
        byte[] decrypted = cipher.doFinal(data_bytes);

        return new String(decrypted);
    }

    public static void main(String[] args) throws Exception {
        //Lire les données / mot de passe à chiffrer
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.print("Plain text: ");
        System.out.flush();
        String plain_text = br.readLine();

        System.out.print("Password: ");
        System.out.flush();
        String password = br.readLine();

        //Processus de cryptage
        String encrypted = EncryptorDecryptor.encrypt(plain_text, password);
        System.out.print("encrypted:" + encrypted);
        System.out.println();

        //Processus de décryptage
        String decrypted = EncryptorDecryptor.decrypt(encrypted, password);
        System.out.print("decrypted:" + decrypted);
        System.out.println();
    }
}

Pour PHP

python


<?php

function encrypt($plain_text, $password) {
    //Générer un sel aléatoire de 8 octets
    $random_salt = openssl_random_pseudo_bytes(8);

    //Générer la clé et l'IV à partir du mot de passe et du sel
    $key_data = $password.$random_salt;
    $raw_key = md5($key_data, true);

    $iv_data = $raw_key.$password.$random_salt;
    $iv = md5($iv_data, true);

    //chiffrement
    $encrypted = openssl_encrypt($plain_text, 'aes-128-cbc', $raw_key, OPENSSL_RAW_DATA, $iv);
    return ( base64_encode("Salted__".$random_salt.$encrypted) );
}

function decrypt($encrypted_text, $password) {
    //Décryptage
    $payload_text = base64_decode($encrypted_text);
    $header = substr($payload_text, 0, 7);
    $salt = substr($payload_text, 8, 8);
    $data = substr($payload_text, 16);
    //Générer la clé et l'IV à partir du mot de passe et du sel
    $key_data = $password.$salt;
    $raw_key = md5($key_data, true);
    $iv_data = $raw_key.$password.$salt;
    $iv = md5($iv_data, true);
    $decrypted_text = openssl_decrypt($data, 'aes-128-cbc', $raw_key, OPENSSL_RAW_DATA, $iv);
    return ( $decrypted_text );
}

// Usage:
$str = file_get_contents('php://stdin');
print "Plain text: " . $str . "\n";
$password = $argv[1];
print "Password: " . $password . "\n";

//Processus de cryptage
$encrypted = encrypt($str, $password);
print "encrypted:" . $encrypted . "\n";

//Processus de décryptage
$decrypted = decrypt($encrypted, $password);
print "decrypted:" . $decrypted . "\n";

Pour Perl

python


#!/usr/bin/perl

use MIME::Base64;
use strict;
use Crypt::CBC;
use Config;

sub encrypt {
  my ($plain_text, $passphrase) = @_;
  my $pbe = Crypt::CBC->new(
     -key => $passphrase,
     -cipher  => 'Crypt::Rijndael',
     -keysize => 128/8,
  );
  my $cipher_text = $pbe->encrypt($plain_text);
  my $encrypted_text = encode_base64($cipher_text);
  return $encrypted_text;
}

sub decrypt {
  my ($encrypted_text, $passphrase) = @_;
  my $cipher_text = decode_base64($encrypted_text);
  my $pbe = Crypt::CBC->new(
     -key => $passphrase,
     -cipher => 'Crypt::Rijndael',
     -keysize => 128/8,
  );
  my $plain_text = $pbe->decrypt($cipher_text);
  return $plain_text;
}

# Usage:
#Processus de cryptage
my $str = (scalar <>);
print "Plain text: " . $str . "\n";
my $password = $ARGV[0];
print "Password: " . $password . "\n";

#Processus de cryptage
my $encrypted = encrypt($str, $password);
print "encrypted:" . $encrypted . "\n";

#Processus de décryptage
my $decrypted = decrypt($encrypted, $password);
print "decrypted:" . $decrypted . "\n";

Pour Ruby

python


#!/usr/bin/ruby

require "openssl"
require "base64"

def encrypt(plain_text, password)
  salt = OpenSSL::Random.random_bytes(8)
  cipher = OpenSSL::Cipher.new("aes-128-cbc")
  cipher.encrypt()
  cipher.pkcs5_keyivgen(
     password,
     salt,
     1
  )
  #Dans le cas de Ruby, vous devez ajouter vous-même les informations d'en-tête à la chaîne de caractères.
  encrypted_text = "Salted__" + salt + cipher.update(plain_text) + cipher.final
  return Base64.encode64(encrypted_text)
end

def decrypt(encrypted_text, password)
  decoded_str = Base64.decode64(encrypted_text)
  #Dans le cas de Ruby, vous devez également décomposer vous-même les informations d'en-tête
  @cipher_text = decoded_str.unpack("a8a8a*")
  cipher = OpenSSL::Cipher.new("aes-128-cbc")
  cipher.pkcs5_keyivgen(
     password,
     @cipher_text[1],
     1
  )
  cipher.decrypt()
  decrypted_text = cipher.update(@cipher_text[2]) + cipher.final
  return decrypted_text
end

# Usage:
str = gets
print "Plain text: " + str + "\n";
password = ARGV[0]
print "Password: " + password + "\n";

#Processus de cryptage
encrypted = encrypt(str, password);
print "encrypted:" + encrypted + "\n";

#Processus de décryptage
decrypted = decrypt(encrypted, password);
print "decrypted:" + decrypted + "\n";

Pour le script shell (bash)

python


#!/bin/bash

function encrypt() {
  plain_text=$1
  password=$2
  encrypted_text=`echo -n "$plain_text" | openssl enc -e -aes-128-cbc -base64 -k "$password"`
  echo $encrypted_text
}

function decrypt() {
  encrypted_text=$1
  password=$2
  plain_text=`echo "$encrypted_text" | openssl enc -d -aes-128-cbc -base64 -k "$password"`
  echo $plain_text
}

# Useage:
str="$(cat -)"
echo "Plain text: $str"
password=$1
echo "Password: $password"

#Processus de cryptage
encrypted=`encrypt "$str" "$password"`
echo "encrypted:$encrypted"

#Processus de décryptage
decrypted=`decrypt "$encrypted" "$password"`
echo "decrypted:$decrypted"

Recommended Posts

Obtenez un cryptage compatible OpenSSL avec Java / PHP
KMS) Chiffrement d'enveloppe avec décryptage openssl et java
Cryptage / décryptage RSA avec Java 8
Rendre l'environnement SpringBoot1.5 + Gradle4.4 + Java8 + Docker compatible avec Java11
Crypter / décrypter avec AES256 en PHP et Java
Rendre les gadgets de calendrier créés avec JavaFX compatibles avec Java SE 9
[Java] Comment chiffrer avec le chiffrement AES avec une bibliothèque standard
Installez java avec Homebrew
Changer de siège avec Java
Téléchargement confortable avec JAVA
Changer java avec direnv
Téléchargement Java avec Ansible
Raclons avec Java! !!
Construire Java avec Wercker
PHP jetable avec Docker
Conversion Endian avec JAVA
Un développeur Java de première année chez udemy a essayé de se lancer avec PHP
Atteindre l'héritage d'implémentation de type Mixin: module Ruby, interface Java, trait PHP