In a certain project, I was forced to decrypt the text encrypted using OpenSSL cli with various script languages, and it was a little troublesome in the case of Java and PHP, so I summarized the information.
You can easily encrypt text at the password pace by using the enc option with OpenSSL cli, for example, but if you try to decrypt it using Java, it will add and analyze OpenSSL compatible header information. It could not be decrypted as it is because there is no corresponding function.
When encrypting the contents of a text file with OpenSSL cli, you can easily obtain an encrypted character string simply by giving the encryption method and password as options as shown in the example below.
cat plain.txt | openssl enc -e -aes-128-cbc -base64 -k <password>
Normally, if AES is specified as the encryption method, it is necessary to give Salt and IV (Initialization Vector) in addition to the password when encrypting and decrypting, but in OpenSSL this Salt and The IV is automatically generated and embedded in the header of the encrypted data, so the user only needs to be aware of the password. As you can see in the sample script in this article, Perl and Ruby's OpenSSL library has an OpenSSL cli encryption compatible Salt and IV generation mechanism, so it's relatively easy to use OpenSSL cli encrypted text. However, in the case of the OpenSSL library for Java and PHP, since it did not have this OpenSSL cli compatible mechanism, it was necessary to incorporate the Salt and IV generation mechanism on its own.
By the way, when encryption is performed by AES method using the enc option with OpenSSL cli, Salt has a random 8-byte (64-bit) bit string, and IV has 16 bytes (16 bytes) generated by the following method. A bit string of 128 bits) is used.
IV generation formula Key = password + Salt MD5 IV = key + password + Salt MD5
These are added as header information to the beginning of the encrypted data and returned as encrypted data.
String "Salted__" (8 bytes) + Salt (8 bytes) + IV (16 bytes) + [encrypted data]
When decrypting, if you confirm that the beginning of the encrypted data is "Salted__", use the following 8 bytes of data as Salt, and from the password, Salt as in the case of encryption Generates an IV and decrypts the body of the encrypted data that follows Salt.
The following sample code is written by incorporating this.
The getKeyAndGenerateIv
in this code is used to generate Salt and IV in an OpenSSL Cli compatible way.
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 {
//Read the data / password to be encrypted
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();
//Encryption process
String encrypted = EncryptorDecryptor.encrypt(plain_text, password);
System.out.print("encrypted:" + encrypted);
System.out.println();
//Decryption process
String decrypted = EncryptorDecryptor.decrypt(encrypted, password);
System.out.print("decrypted:" + decrypted);
System.out.println();
}
}
python
<?php
function encrypt($plain_text, $password) {
//Generate a random 8-byte Salt
$random_salt = openssl_random_pseudo_bytes(8);
//Generate Key and IV from password and Salt
$key_data = $password.$random_salt;
$raw_key = md5($key_data, true);
$iv_data = $raw_key.$password.$random_salt;
$iv = md5($iv_data, true);
//encryption
$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) {
//Decryption
$payload_text = base64_decode($encrypted_text);
$header = substr($payload_text, 0, 7);
$salt = substr($payload_text, 8, 8);
$data = substr($payload_text, 16);
//Generate Key and IV from password and 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";
//Encryption process
$encrypted = encrypt($str, $password);
print "encrypted:" . $encrypted . "\n";
//Decryption process
$decrypted = decrypt($encrypted, $password);
print "decrypted:" . $decrypted . "\n";
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:
#Encryption process
my $str = (scalar <>);
print "Plain text: " . $str . "\n";
my $password = $ARGV[0];
print "Password: " . $password . "\n";
#Encryption process
my $encrypted = encrypt($str, $password);
print "encrypted:" . $encrypted . "\n";
#Decryption process
my $decrypted = decrypt($encrypted, $password);
print "decrypted:" . $decrypted . "\n";
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
)
#In the case of Ruby, you have to add the header information to the character string by yourself.
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)
#In the case of Ruby, you have to decompose the header information yourself.
@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";
#Encryption process
encrypted = encrypt(str, password);
print "encrypted:" + encrypted + "\n";
#Decryption process
decrypted = decrypt(encrypted, password);
print "decrypted:" + decrypted + "\n";
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"
#Encryption process
encrypted=`encrypt "$str" "$password"`
echo "encrypted:$encrypted"
#Decryption process
decrypted=`decrypt "$encrypted" "$password"`
echo "decrypted:$decrypted"
Recommended Posts