AES / CBC / PKCS5Padding encryption java to php with IV values ​​in array in Java - как преобразовать код из Java в PHP? - PullRequest
0 голосов
/ 18 июня 2020

Мне нужно иметь возможность шифровать и расшифровывать php. У меня есть код Sample Java, который нужно преобразовать в Java, и я привел его ниже. Насколько я искал, я не могу найти ни одного экземпляра, в котором значение iv задано в виде массива (я думаю). См. Код Java ниже

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

import java.net.URL; 
import java.net.URLEncoder; 
import java.net.URLDecoder; 

public class SecurityTest {

private static byte[] sharedkey = "A1234&ABCDE/98745#000078".getBytes();

private static byte[] sharedvector = {8, 7, 5, 6, 4, 1, 2, 3, 18, 17, 15, 16, 14, 11, 12, 13};

private static String decyptString ;
    public static void main(String args[]) 
    {
        SecurityTest test = new SecurityTest();
        System.out.println("Before assignment :"+sharedkey);
        System.out.println("IV Value is :"+sharedvector);

            sharedkey = "A1234&ABCDE/98745#000078".getBytes();
            System.out.println("API Doc Key :"+sharedkey);
            decyptString = "f5s0RMaYtr4WQseVR9E%2F3A%3D%3D";

        String text = "Hello World";
        System.out.println("This is a hello world encryption effort");
        test.EncryptButton("Hello World");

        test.DecryptButton(decyptString);

    }

private void EncryptButton(String actualTxt){
        try{
        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
        c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(sharedkey, "AES"), new IvParameterSpec(sharedvector));
        byte[] encrypted = c.doFinal(actualTxt.getBytes("UTF-8"));
        String strret = Base64.getEncoder().encodeToString(encrypted);
        strret = strret.replace("\n", "");
        System.out.println("Encoded String :"+strret);
        System.out.println("URL Encoded :"+URLEncoder.encode(strret,"UTF-8"));
        }catch(Exception e){
        e.printStackTrace();
        }

    }
private void DecryptButton(String encryptedString){
    try{

        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
        c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(sharedkey, "AES"), new IvParameterSpec(sharedvector));
        // byte[] decrypted = c.doFinal(Base64.getDecoder().decode(URLDecoder.decode(encryptedString,"UTF-8")));
        byte[] decrypted = c.doFinal(Base64.getDecoder().decode(URLDecoder.decode(encryptedString,"UTF-8")));
        System.out.println(new String(decrypted, "UTF-8"));
        }catch(Exception e){
        e.printStackTrace();
        }
    }
}

Вывод Java Это попытка шифрования hello world

Закодированная строка: f5s0RMaYtr4WQseVR9E / 3A ==

URL-адрес в кодировке: f5s0RMaYtr4WQseVR9E% 2F3A% 3D% 3D

* 1011 где шифрование в PHP выполняется с использованием openssl, но значения IV не такие, как здесь, например, массив. Значения IV находятся в общем векторе байтового массива. Это та часть, где мне нужна помощь в написании эквивалента в PHP

private stati c byte [] sharedvector = {8, 7, 5, 6, 4, 1, 2, 3, 18, 17, 15, 16, 14, 11, 12, 13};

Как мне написать этот IV в PHP?

Код PHP который у меня есть, указан ниже:

$method = "AES-256-CBC";
$plaintext="Hello World";
$key="A1234&ABCDE/98745#000078";
    $sharedvector =  "\x08\x07\x05\x06\x04\x01\x02\x03\x12\x11\x0f\x10\x0e\x0b\x0c\x0d";
    $sharedvectorHex = unpack('H*', $sharedvector);

$encrypted = base64_encode(openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $sharedvectorHex[1]));
echo "encrypted is ".$encrypted;

Я получаю следующую ошибку.

openssl_encrypt (): пройденный IV имеет длину 32 байта, что больше, чем 16, ожидаемые выбранный шифр, усечение

Может ли кто-нибудь указать мне правильное направление?

Спасибо.

Ответы [ 2 ]

1 голос
/ 18 июня 2020

При построении байтового массива, как написано в вашем коде, используются десятичные значения, которые были преобразованы в шестнадцатеричное строковое представление следующим образом:

byte[] sharedvector = {8, 7, 5, 6, 4, 1, 2, 3, 18, 17, 15, 16, 14, 11, 12, 13};
System.out.println("\nsharedvector (Java): " + bytesToHex(sharedvector));
// byte array to hexstring method:
private static String bytesToHex(byte[] bytes) {
        StringBuffer result = new StringBuffer();
        for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
        return result.toString();
    }

Результат:

sharedvector (Java): 080705060401020312110f100e0b0c0d

Тот же рабочий процесс в PHP - помните, что десятичные значения в Java преобразуются в шестнадцатеричные значения вручную:

$sharedvector =  "\x08\x07\x05\x06\x04\x01\x02\x03\x12\x11\x0f\x10\x0e\x0b\x0c\x0d";
$sharedvectorHex = unpack('H*', $sharedvector);
echo "sharedvector (PHP): " . $sharedvectorHex[1];

Результат:

sharedvector (PHP) : 080705060401020312110f100e0b0c0d

Конечно, вы можете преобразовать десятичные значения в шестнадцатеричные с помощью PHP -функции, но мне лень реализовывать это для stati c значения 16 байтов: -)

Function in PHP:
dechex ( int $number ) : string

Edit - решение с PHP полным рабочим образцом:

Этот ответ следует простому правилу «никогда ничему не доверять» (я шучу) :-). На стороне Java вы используете строку в качестве источника ключа шифрования, который закодирован в массив байтов через ".getBytes ()". Распечатка длины ключа представит нам « 24 », и это длина ключа для AES-CB C -192 шифрования:

System.out.println("sharedKey length: " + sharedkey.length);
sharedKey length: 24

С учетом этого я изменил ваш PHP -код на « AES-192-CB C», и вы можете использовать $ sharedvector напрямую, как есть. Зашифрованная строка одинакова для Java и PHP: f5s0RMaYtr4WQseVR9E/3A==. Чтобы убедиться, что все работает, я также добавил расшифровку в PHP.

0 голосов
/ 21 июня 2020

Я неправильно понял, для чего нужны данные, извините.

Использование функции типа

function hexToStr($hex){
    // Remove spaces if the hex string has spaces
    $hex = str_replace(' ', '', $hex);
    return hex2bin($hex);
}

, которая вызывается в вашем PHP -коде:

$method = "AES-256-CBC";
$plaintext = "Hello World";
$key = "A1234&ABCDE/98745#000078";
$sharedvector = "8 7 5 6 4 1 2 3 18 17 15 16 14 11 12 13";
$iv = hexToStr($sharedvector);
$encrypted = base64_encode(openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv));
echo "encrypted is " . $encrypted;

приводит к рабочему шифрованию:

encrypted is Pi1TfbyAcEOxvfzFMItPLA==
...