Erreichen Sie eine OpenSSL-kompatible Verschlüsselung mit Java / PHP

Ich habe OpenSSL CLI-kompatible Verschlüsselungs- / Entschlüsselungsverarbeitung in verschiedenen Sprachen ausprobiert

In einem bestimmten Projekt war ich gezwungen, den mit OpenSSL cli mit verschiedenen Skriptsprachen verschlüsselten Text zu entschlüsseln, und es war im Fall von Java und PHP ein wenig problematisch, daher habe ich die Informationen zusammengefasst.

OpenSSL CLI-Verschlüsselungs- / Entschlüsselungsprozess

Mit OpenSSL cli können Sie beispielsweise Text einfach mit einem Kennworttempo verschlüsseln, indem Sie die unten gezeigte Option enc verwenden. Wenn Sie jedoch versuchen, dies mit Java zu entschlüsseln, werden OpenSSL-kompatible Headerinformationen hinzugefügt und analysiert. Es konnte nicht entschlüsselt werden, da es keine entsprechende Funktion gibt.

Wenn Sie den Inhalt einer Textdatei mit OpenSSL cli verschlüsseln, können Sie leicht eine verschlüsselte Zeichenfolge erhalten, indem Sie einfach die Verschlüsselungsmethode und das Kennwort als Optionen angeben, wie im folgenden Beispiel gezeigt.

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

Wenn AES als Verschlüsselungsmethode angegeben ist, ist es normalerweise erforderlich, beim Ver- und Entschlüsseln zusätzlich zum Kennwort Salt und IV (Initialisierungsvektor) anzugeben, in OpenSSL jedoch dieses Salt und Die IV wird automatisch generiert und in den Header der verschlüsselten Daten eingebettet, sodass der Benutzer nur das Kennwort kennen muss. Wie Sie im Beispielskript in diesem Artikel sehen können, verfügt die OpenSSL-Bibliothek von Perl und Ruby über einen Salt- und IV-Generierungsmechanismus, der mit OpenSSL cli verschlüsselt ist, sodass die Verwendung von mit OpenSSL cli verschlüsseltem Text relativ einfach ist. Im Fall der OpenSSL-Bibliothek für Java und PHP war es jedoch erforderlich, den Salt- und IV-Generierungsmechanismus selbst zu integrieren, da dieser OpenSSL-CLI-kompatible Mechanismus nicht vorhanden war.

Übrigens, wenn die Verschlüsselung durch die AES-Methode unter Verwendung der enc-Option mit OpenSSL cli durchgeführt wird, hat Salt eine zufällige 8-Byte-Bitfolge (64 Bit) und IV hat 16 Bytes (16 Bytes), die mit der folgenden Methode generiert werden. 128 Bit) Bitfolge wird verwendet.

IV Generationsformel Schlüssel = Passwort + Salt MD5 IV = Schlüssel + Passwort + Salt MD5

Diese werden als Header-Informationen am Anfang der verschlüsselten Daten hinzugefügt und als verschlüsselte Daten zurückgegeben.

Zeichenkette "Salted __" (8 Bytes) + Salt (8 Bytes) + IV (16 Bytes) + [verschlüsselte Daten]

Wenn Sie beim Entschlüsseln bestätigen, dass der Anfang der verschlüsselten Daten "Salted__" ist, verwenden Sie die folgenden 8 Datenbytes als Salt und aus dem Kennwort Salt wie bei der Verschlüsselung Erzeugt eine IV und entschlüsselt den Körper der verschlüsselten Daten, die auf Salt folgen.

Für Java

Der folgende Beispielcode wird durch Einbeziehen dieses Codes geschrieben. Das getKeyAndGenerateIv in diesem Code wird verwendet, um Salt und IV auf OpenSSL Cli-kompatible Weise zu generieren.

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 {
        //Lesen Sie die zu verschlüsselnden Daten / Passwörter
        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();

        //Verschlüsselungsprozess
        String encrypted = EncryptorDecryptor.encrypt(plain_text, password);
        System.out.print("encrypted:" + encrypted);
        System.out.println();

        //Entschlüsselungsprozess
        String decrypted = EncryptorDecryptor.decrypt(encrypted, password);
        System.out.print("decrypted:" + decrypted);
        System.out.println();
    }
}

Für PHP

python


<?php

function encrypt($plain_text, $password) {
    //Generieren Sie ein zufälliges 8-Byte-Salz
    $random_salt = openssl_random_pseudo_bytes(8);

    //Generieren Sie Schlüssel und IV aus Passwort und Salt
    $key_data = $password.$random_salt;
    $raw_key = md5($key_data, true);

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

    //Verschlüsselung
    $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) {
    //Entschlüsselung
    $payload_text = base64_decode($encrypted_text);
    $header = substr($payload_text, 0, 7);
    $salt = substr($payload_text, 8, 8);
    $data = substr($payload_text, 16);
    //Generieren Sie Schlüssel und IV aus Passwort und Salt
    $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";

//Verschlüsselungsprozess
$encrypted = encrypt($str, $password);
print "encrypted:" . $encrypted . "\n";

//Entschlüsselungsprozess
$decrypted = decrypt($encrypted, $password);
print "decrypted:" . $decrypted . "\n";

Für 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:
#Verschlüsselungsprozess
my $str = (scalar <>);
print "Plain text: " . $str . "\n";
my $password = $ARGV[0];
print "Password: " . $password . "\n";

#Verschlüsselungsprozess
my $encrypted = encrypt($str, $password);
print "encrypted:" . $encrypted . "\n";

#Entschlüsselungsprozess
my $decrypted = decrypt($encrypted, $password);
print "decrypted:" . $decrypted . "\n";

Für 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
  )
  #Im Fall von Ruby müssen Sie die Header-Informationen selbst zur Zeichenfolge hinzufügen.
  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)
  #Im Fall von Ruby müssen Sie die Header-Informationen auch selbst zerlegen
  @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";

#Verschlüsselungsprozess
encrypted = encrypt(str, password);
print "encrypted:" + encrypted + "\n";

#Entschlüsselungsprozess
decrypted = decrypt(encrypted, password);
print "decrypted:" + decrypted + "\n";

Für Shell-Skript (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"

#Verschlüsselungsprozess
encrypted=`encrypt "$str" "$password"`
echo "encrypted:$encrypted"

#Entschlüsselungsprozess
decrypted=`decrypt "$encrypted" "$password"`
echo "decrypted:$decrypted"

Recommended Posts

Erreichen Sie eine OpenSSL-kompatible Verschlüsselung mit Java / PHP
KMS) Umschlagverschlüsselung mit OpenSL- und Java-Entschlüsselung
RSA-Verschlüsselung / Entschlüsselung mit Java 8
Machen Sie die SpringBoot1.5 + Gradle4.4 + Java8 + Docker-Umgebung mit Java11 kompatibel
Verschlüsseln / Entschlüsseln mit AES256 in PHP und Java
Machen Sie mit JavaFX erstellte Kalender-Gadgets mit Java SE 9 kompatibel
[Java] Verschlüsselung mit AES-Verschlüsselung mit Standardbibliothek
Installieren Sie Java mit Homebrew
Wechseln Sie die Plätze mit Java
Bequemer Download mit JAVA
Schalten Sie Java mit direnv
Java-Download mit Ansible
Lass uns mit Java kratzen! !!
Erstellen Sie Java mit Wercker
Einweg-PHP mit Docker
Endian-Konvertierung mit JAVA
Im ersten Jahr versuchte der Java-Entwickler bei udemy, mit PHP zu beginnen
Erzielen Sie eine Mixin-ähnliche Implementierungsvererbung: Ruby-Modul, Java-Schnittstelle, PHP-Eigenschaft