当前位置: 首页 > 知识库问答 >
问题:

使用PHP OpenSSL用JAVA密码解密aes-128-gcm编码的内容

呼延靖
2023-03-14

我必须解密一些数据发送到我的网站,使用aes-128-gcm加密与JAVA密码。

private static String encrypt(String data, String mainKey, int ivLength) throws Exception {
  final byte[] dataBytes = data.getBytes(UNICODE_FORMAT);
  byte[] initializationVector = generateInitializationVector(ivLength);
  final Cipher cipher = getAesGcmCipher(Cipher.ENCRYPT_MODE, mainKey, initializationVector);

  final byte[] encryptedData = cipher.doFinal(dataBytes);
  final byte[] encryptedBytes = new byte[encryptedData.length + ivLength];
  System.arraycopy(initializationVector, 0, encryptedBytes, 0, ivLength);
  System.arraycopy(encryptedData, 0, encryptedBytes, ivLength, encryptedData.length);

  return BASE64_ENCODER.apply(encryptedBytes);
}

private static String decrypt(String data, String mainKey, int ivLength) throws Exception {
  final byte[] encryptedBytes = BASE64_DECODER.apply(data.getBytes(UNICODE_FORMAT));

  final byte[] initializationVector = new byte[ivLength];
  System.arraycopy(encryptedBytes, 0, initializationVector, 0, ivLength);

  final Cipher cipher = getAesGcmCipher(Cipher.DECRYPT_MODE, mainKey, initializationVector);
  return new String(cipher.doFinal(encryptedBytes, ivLength, encryptedBytes.length - ivLength),
      UNICODE_FORMAT);
}
static final String ALGO = "AES"; //$NON-NLS-1$
static final String GCMALGO = "AES/GCM/NoPadding"; //$NON-NLS-1$
static final String UNICODE_FORMAT = "UTF8"; //$NON-NLS-1$
static final String DES_ENCRYPTION_SCHEME = "DES"; //$NON-NLS-1$
private static final int DEFAULT_IV_LENGTH = 16;
public static final String NULL_PARAMETER_MESSAGE = "The parameter should not be null"; //$NON-NLS-1$
public static final String EMPTY_PARAMETER_MESSAGE = "String is empty"; //$NON-NLS-1$
private static final String KEY_GEN_ALGO = "PBKDF2WithHmacSHA256"; //$NON-NLS-1$
static final Random random = new SecureRandom();
static final BASE64Encoder b64Encoder = new DataMasking().new BASE64Encoder();
static final BASE64Decoder b64Dencoder = new DataMasking().new BASE64Decoder();
public static final Function<byte[], String> BASE64_ENCODER = bytes -> Base64.getEncoder().encodeToString(bytes);
public static final Function<byte[], byte[]> BASE64_DECODER = bytes -> Base64.getDecoder().decode(bytes);

我想知道这是否与我必须对二进制数据进行的字符串操作有关,或者提供者没有给我所需的所有必要信息。

我也不知道解密数据必须使用的Tag_length是什么。提供程序还告诉我IV_Length是16个字符长,但是当我使用openssl_cipher_iv_length('aes-128-gcm')时,它建议是12个字符。

下面是我现在PHP端的代码:

/**
 * @param string $str
 *   The URL parameter string
 */
function test_decrypt($str) {
  $key = 'MySuperPassword7';
  $cipher = 'aes-128-gcm';

  $iv_len = 16;
  $tag_length = 16;

  echo $str . '<br>';
  /**
   * Encryption test
   */
//  $tag = ""; 
//  $iv = openssl_random_pseudo_bytes($iv_len);
//  $enc_str = openssl_encrypt('Test of data to send', $cipher, $key, OPENSSL_RAW_DATA, $iv, $tag, "", $tag_length);
//  $encrypt = base64_encode($iv.$enc_str.$tag);

//  echo $key . '::' . $iv . '::' . $tag . '<br>';
//  echo '$enc_str<pre>';
//  var_dump($enc_str);
//  echo '</pre>';
//  echo '$encrypt<pre>';
//  var_dump($encrypt);
//  echo '</pre>';

  /**
   * Decryption part
   */
  $encrypt = base64_decode($str);
  $iv = substr($encrypt, 0, $iv_len);
  $tag = substr($encrypt, - $tag_length);
  $ciphertext = substr($encrypt, $iv_len, -$tag_length);

  $uncrypt = openssl_decrypt($ciphertext, $cipher, $key, 0, $iv, $tag);//OPENSSL_RAW_DATA + OPENSSL_NO_PADDING
  echo $iv_len . '::' . $tag_length . '<br>';
  echo $key . '::' . $iv . '::' . $tag . '<br>';
  echo '$encrypt<pre>';
  var_dump($encrypt);
  echo '</pre>';
  echo '$ciphertext<pre>';
  var_dump($ciphertext);
  echo '</pre>';
  echo '$uncrypt<pre>';
  var_dump($uncrypt);
  echo '</pre>';
  exit;
}
    null

其长度与答案的加密长度相同(P8KU/GF27LU9QGMLPA8GPFHMDVUW5CC7XEKVIGMB3RGGZYJG0YHX5P/CFRROZPUXXTEKZJ8)。

像以前一样,我不能解密数据...

以下是Talend组件的完整代码:

// ============================================================================
//
// Copyright (C) 2006-2019 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================

package routines;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PushbackInputStream;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Base64;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import java.util.function.Function;
import java.util.stream.Stream;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;


/**
 * created by talend on 2016-04-08 Detailled comment.
 *
 */
public class DataMasking {

    static final String ALGO = "AES"; //$NON-NLS-1$

    static final String GCMALGO = "AES/GCM/NoPadding"; //$NON-NLS-1$

    static final String UNICODE_FORMAT = "UTF8"; //$NON-NLS-1$

    static final String DES_ENCRYPTION_SCHEME = "DES"; //$NON-NLS-1$

    private static final int DEFAULT_IV_LENGTH = 16;

    public static final String NULL_PARAMETER_MESSAGE = "The parameter should not be null"; //$NON-NLS-1$

    public static final String EMPTY_PARAMETER_MESSAGE = "String is empty"; //$NON-NLS-1$

    private static final String KEY_GEN_ALGO = "PBKDF2WithHmacSHA256"; //$NON-NLS-1$

    static final Random random = new SecureRandom();

    static final BASE64Encoder b64Encoder = new DataMasking().new BASE64Encoder();

    static final BASE64Decoder b64Dencoder = new DataMasking().new BASE64Decoder();

    public static final Function<byte[], String> BASE64_ENCODER = bytes -> Base64.getEncoder().encodeToString(bytes);

    public static final Function<byte[], byte[]> BASE64_DECODER = bytes -> Base64.getDecoder().decode(bytes);

    public static class DataMaskingRoutineException extends RuntimeException {

        private static final long serialVersionUID = -8622896150657449668L;

        public DataMaskingRoutineException() {
            super();
        }

        public DataMaskingRoutineException(String s) {
            super(s);
        }

        public DataMaskingRoutineException(String s, Object o) {
            super(s);
            System.out.println(o);
        }

    }


    /**
     * Encrypt String: Encrypts a string using AES 128 .
     * warning: this is not considered a secure function.
     *
     *
     * {talendTypes} String
     *
     * {Category} Data Masking
     *
     * {param} String("foo") encryptString: The string to be encrypted.
     * 
     * {param} byte[](new byte[] { 'T', 'a', 'l', 'e', 'n', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y' })
     * keyValue: the
     * key material of the secret key. The contents of the array are copied to protect against subsequent modification.
     * 
     * {example} encryptAES("foo", new byte[] { 'T', 'a', 'l', 'e', 'n', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y' })
     * result is UQ0VJZq5ymFkMYQeDrPi0A==
     *
     * @deprecated use {@link #encryptAESGCM(String, String, int)} instead of it
     * 
     */

    @Deprecated
    public static String encryptAES(String encryptString, byte[] keyValue) {

        if (encryptString == null || keyValue == null) {
            return NULL_PARAMETER_MESSAGE;
        }
        if (encryptString.length() == 0) {
            return EMPTY_PARAMETER_MESSAGE;
        }
        try {
            Key key = new SecretKeySpec(keyValue, ALGO);
            Cipher cipher = Cipher.getInstance(ALGO);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] encVal = cipher.doFinal(encryptString.getBytes());
            String encryptedValue = b64Encoder.encode(encVal);
            return encryptedValue;

        } catch (Exception e) {
            throw new DataMaskingRoutineException(e.getMessage(), e);
        }
    }


    /**
     * Encrypt String: Encrypts a string using AES GCM 128 .
     * 
     * {talendTypes} String
     * 
     * {Category} Data Masking
     * 
     * {param} String("foo") encryptString: The string to be encrypted.
     * 
     * {param} String("TalendMainKey123") the main key used to encrypt the data.
     * 
     * {example} encryptAESGCM("foo","TalendMainKey123") result could be
     * +ngs4RohAx8OvInmioRwRYS0pymcNkQJCKqsdUPZqUZppN4= (but it should change from an execution to another).
     * 
     */

    public static String encryptAESGCM(String encryptString, String mainKey) {

        return encryptAESGCM(encryptString, mainKey, DEFAULT_IV_LENGTH);
    }

    /**
     * Encrypt String: Encrypts a string using AES GCM 128 .
     * 
     * {talendTypes} String
     * 
     * {Category} Data Masking
     * 
     * {param} String("foo") encryptString: The string to be encrypted.
     * 
     * {param} String("TalendMainKey123") the main key used to encrypt the data.
     * 
     * {param} int the length of initializationVector. must be one of 12/13/14/15/16.
     * 
     * {example} encryptAESGCM("foo","TalendMainKey123",16) result could be
     * +ngs4RohAx8OvInmioRwRYS0pymcNkQJCKqsdUPZqUZppN4= (but it should change from an execution to another).
     * 
     */

    public static String encryptAESGCM(String encryptString, String mainKey, int ivLength) {

        if (encryptString == null || mainKey == null) {
            return NULL_PARAMETER_MESSAGE;
        }

        if (encryptString.length() == 0) {
            return EMPTY_PARAMETER_MESSAGE;
        }

        try {
            return encrypt(encryptString, mainKey, ivLength);
        } catch (Exception e) {
            throw new DataMaskingRoutineException(e.getMessage(), e);
        }
    }



    /**
     * decrypt String: Decrypts a string using AES 128.
     * warning: this is not considered a secure function.
     *
     *
     * {talendTypes} String
     *
     * {Category} Data Masking
     *
     * {param} String("UQ0VJZq5ymFkMYQeDrPi0A==") encryptedString: The string to be decrypted.
     *
     * {param} byte[](new byte[] { 'T', 'a', 'l', 'e', 'n', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y' })
     * keyValue: the key material of the secret key. The contents of the array are copied to protect against subsequent
     * modification.
     * 
     * {example} decryptAES("UQ0VJZq5ymFkMYQeDrPi0A==",new byte[] { 'T', 'a', 'l', 'e', 'n', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y' })
     * result is "foo"
     * 
     * @deprecated use {@link #decryptAESGCM(String, String, int)} instead of it
     * 
     */

    @Deprecated
    public static String decryptAES(String encryptedString, byte[] keyValue) {

        if (encryptedString == null || keyValue == null) {
            return NULL_PARAMETER_MESSAGE;
        }

        if (encryptedString.length() == 0) {
            return EMPTY_PARAMETER_MESSAGE;
        }
        try {
            Key key = new SecretKeySpec(keyValue, ALGO);
            Cipher cipher = Cipher.getInstance(ALGO);
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] decordedValue = b64Dencoder.decodeBuffer(encryptedString);
            byte[] decValue = cipher.doFinal(decordedValue);
            String decryptedValue = new String(decValue);
            return decryptedValue;

        } catch (Exception e) {
            throw new DataMaskingRoutineException(e.getMessage(), e);
        }
    }

    /**
     * decrypt String: Decrypts a string using AES GCM 128.
     * 
     * {talendTypes} String
     * 
     * {Category} Data Masking
     * 
     * {param} String("+ngs4RohAx8OvInmioRwRYS0pymcNkQJCKqsdUPZqUZppN4=") encryptedString: The string to be decrypted.
     * 
     * {param} String("TalendMainKey123") the main key used to decrypt the data.
     * 
     * {param} int the length of initializationVector. must be one of 12/13/14/15/16.
     * 
     * {example} decryptAESGCM("+ngs4RohAx8OvInmioRwRYS0pymcNkQJCKqsdUPZqUZppN4=","TalendMainKey123",16) result
     * is "foo"
     * 
     */

    public static String decryptAESGCM(String encryptedString, String mainKey, int ivLength) {

        if (encryptedString == null || mainKey == null) {
            return NULL_PARAMETER_MESSAGE;
        }

        if (encryptedString.length() == 0) {
            return EMPTY_PARAMETER_MESSAGE;
        }

        try {
            return decrypt(encryptedString, mainKey, ivLength);

        } catch (Exception e) {
            throw new DataMaskingRoutineException(e.getMessage(), e);
        }

    }

    /**
     * decrypt String: Decrypts a string using AES GCM 128.
     * 
     * {talendTypes} String
     * 
     * {Category} Data Masking
     * 
     * {param} String("+ngs4RohAx8OvInmioRwRYS0pymcNkQJCKqsdUPZqUZppN4=") encryptedString: The string to be decrypted.
     * 
     * {param} String("TalendMainKey123") the main key used to decrypt the data.
     * 
     * {example} decryptAESGCM("+ngs4RohAx8OvInmioRwRYS0pymcNkQJCKqsdUPZqUZppN4=","TalendMainKey123") result
     * is "foo"
     * 
     */

    public static String decryptAESGCM(String encryptedString, String mainKey) {

        return decryptAESGCM(encryptedString, mainKey, DEFAULT_IV_LENGTH);
    }

    /**
     * Encrypt String: Encrypts a string using DES .
     * warning: this is not considered a secure function.
     *
     *
     * {talendTypes} String
     *
     * {Category} Data Masking
     *
     * {param} String("foo") unencryptedString: The string to be encrypted.
     *
     * {param} String("ThisIsSecretEncryptionKey") myEncryptionKey: the string with the DES key material.
     *
     * {example} encryptDES("foo") result is DmNj+x2LUXA=
     *
     * @throws Exception
     */

    public static String encryptDES(String unencryptedString, String myEncryptionKey) {

        if (unencryptedString == null || myEncryptionKey == null) {
            return NULL_PARAMETER_MESSAGE;
        }
        if (unencryptedString.length() == 0) {
            return EMPTY_PARAMETER_MESSAGE;
        }
        try {
            String encryptedString = null;

            String myEncryptionScheme = DES_ENCRYPTION_SCHEME;
            byte[] keyAsBytes = myEncryptionKey.getBytes(UNICODE_FORMAT);
            KeySpec myKeySpec = new DESKeySpec(keyAsBytes);
            SecretKeyFactory mySecretKeyFactory = SecretKeyFactory.getInstance(myEncryptionScheme);
            Cipher encipher = Cipher.getInstance(myEncryptionScheme);
            SecretKey key = mySecretKeyFactory.generateSecret(myKeySpec);

            encipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] plainText = unencryptedString.getBytes(UNICODE_FORMAT);
            byte[] encryptedText = encipher.doFinal(plainText);
            encryptedString = b64Encoder.encode(encryptedText);

            return encryptedString;

        } catch (Exception e) {
            throw new DataMaskingRoutineException(e.getMessage());
        }

    }

    /**
     * Decrypt String: Decrypts a string using DES .
     * warning: this is not considered a secure function.
     *
     *
     * {talendTypes} String
     *
     * {Category} Data Masking
     *
     * {param} String("DmNj+x2LUXA=") encryptedString: the string with the DES key material.
     *
     * {param} String("ThisIsSecretEncryptionKey") myDecryptionKey: The string to be encrypted.
     *
     * {example} decryptDES("DmNj+x2LUXA=") result is "foo"
     *
     */

    public static String decryptDES(String encryptedString, String myDecryptionKey) {

        if (encryptedString == null || myDecryptionKey == null) {
            return NULL_PARAMETER_MESSAGE;
        }

        if (encryptedString.length() == 0) {
            return EMPTY_PARAMETER_MESSAGE;
        }
        try {
            String decryptedText = null;

            String myDecryptionScheme = DES_ENCRYPTION_SCHEME;

            byte[] keyAsBytes = myDecryptionKey.getBytes(UNICODE_FORMAT);

            KeySpec myKeySpec = new DESKeySpec(keyAsBytes);
            Cipher decipher = Cipher.getInstance(myDecryptionScheme);
            SecretKeyFactory mySecretKeyFactory = SecretKeyFactory.getInstance(myDecryptionScheme);
            SecretKey key = mySecretKeyFactory.generateSecret(myKeySpec);

            decipher.init(Cipher.DECRYPT_MODE, key);
            byte[] encryptedText = b64Dencoder.decodeBuffer(encryptedString);
            byte[] plainText = decipher.doFinal(encryptedText);

            StringBuilder stringBuilder = new StringBuilder();
            for (byte element : plainText) {
                stringBuilder.append((char) element);
            }
            decryptedText = stringBuilder.toString();
            return decryptedText;

        } catch (Exception e) {
            throw new DataMaskingRoutineException(e.getMessage(), e);
        }

    }


    /**
     * This method generates a secret Key using the key-stretching algorithm PBKDF2 of
     * <a href="https://docs.oracle.com/javase/7/docs/api/javax/crypto/package-summary.html">javax.crypto</a>.
     * It is basically a hashing algorithm slow by design, in order to increase the time
     * required for an attacker to try a lot of passwords in a bruteforce attack.
     * <br>
     * About the salt :
     * <ul>
     * <li>The salt is not secret, the use of Random is not critical and ensure determinism.</li>
     * <li>The salt is important to avoid rainbow table attacks.</li>
     * <li>The salt should be generated with SecureRandom() in case the passwords are stored.</li>
     * <li>In that case the salt should be stored in plaintext next to the password and a unique user identifier.</li>
     * </ul>
     *
     * @param password a password given as a {@code String}.
     * @param keyLength key length to generate
     * @return a {@code SecretKey} securely generated.
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    private static byte[] generateSecretKeyFromPassword(String password, int keyLength)
            throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] salt = new byte[keyLength];
        new Random(password.hashCode()).nextBytes(salt);
        SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_GEN_ALGO);
        KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, keyLength << 3);
        return factory.generateSecret(spec).getEncoded();
    }

    private static String encrypt(String data, String mainKey, int ivLength) throws Exception {
        final byte[] dataBytes = data.getBytes(UNICODE_FORMAT);
        byte[] initializationVector = generateInitializationVector(ivLength);
        final Cipher cipher = getAesGcmCipher(Cipher.ENCRYPT_MODE, mainKey, initializationVector);

        final byte[] encryptedData = cipher.doFinal(dataBytes);
        final byte[] encryptedBytes = new byte[encryptedData.length + ivLength];
        System.arraycopy(initializationVector, 0, encryptedBytes, 0, ivLength);
        System.arraycopy(encryptedData, 0, encryptedBytes, ivLength, encryptedData.length);

        return BASE64_ENCODER.apply(encryptedBytes);
    }


    private static String decrypt(String data, String mainKey, int ivLength) throws Exception {
        final byte[] encryptedBytes = BASE64_DECODER.apply(data.getBytes(UNICODE_FORMAT));

        final byte[] initializationVector = new byte[ivLength];
        System.arraycopy(encryptedBytes, 0, initializationVector, 0, ivLength);

        final Cipher cipher = getAesGcmCipher(Cipher.DECRYPT_MODE, mainKey, initializationVector);
        return new String(cipher.doFinal(encryptedBytes, ivLength, encryptedBytes.length - ivLength),
                UNICODE_FORMAT);
    }

}
private static Cipher getAesGcmCipher(int encryptMode, String mainKey, byte[] initializationVector)
            throws Exception {
    int ivLength = initializationVector.length;
    if (Stream.of(12, 13, 14, 15, 16).noneMatch(i -> i == ivLength)) {
        throw new IllegalArgumentException("Invalid IV length"); //$NON-NLS-1$
    }
    final Cipher cipher = Cipher.getInstance(GCMALGO);
    SecretKey key = new SecretKeySpec(generateSecretKeyFromPassword(mainKey, mainKey.length()), ALGO);
    final GCMParameterSpec spec = new GCMParameterSpec(ivLength * 8, initializationVector);
    cipher.init(encryptMode, key, spec);
    return cipher;
}



private static byte[] generateSecretKeyFromPassword(String password, int keyLength)
          throws NoSuchAlgorithmException, InvalidKeySpecException {
      byte[] salt = new byte[keyLength];
      new Random(password.hashCode()).nextBytes(salt);
      SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_GEN_ALGO);
      KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, keyLength << 3);
      return factory.generateSecret(spec).getEncoded();
}

共有1个答案

蓬祺
2023-03-14

我在Java中设置代码,并使用(固定)密钥和随机初始化向量进行加密:

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Random;

public class SO_Main_Final {

    static final String ALGO = "AES"; //$NON-NLS-1$
    static final String GCMALGO = "AES/GCM/NoPadding"; //$NON-NLS-1$
    static final String UNICODE_FORMAT = "UTF8"; //$NON-NLS-1$
    static final Random random = new SecureRandom();

    public static void main(String[] args) throws Exception {
        System.out.println("https://stackoverflow.com/questions/62129604/decrypt-aes-128-gcm-encoded-content-with-java-cipher-using-php-openssl");
        String myData = "Secret data for TytooF";
        String myKey = "1234567890123456";
        String encryptString = encrypt(myData, myKey, 16);
        String decryptString = decrypt(encryptString, myKey, 16);
        System.out.println("encryptString:         " + encryptString);
        System.out.println("decryptString:         " + decryptString);

    }

    private static String encrypt(String data, String mainKey, int ivLength) throws Exception {
        final byte[] dataBytes = data.getBytes(UNICODE_FORMAT);
        // byte[] initializationVector = generateInitializationVector(ivLength);
        byte[] initializationVector = new byte[ivLength];
        random.nextBytes(initializationVector);
        SecretKeySpec secretKeySpec = new SecretKeySpec(mainKey.getBytes(UNICODE_FORMAT), ALGO);
        GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, initializationVector);
        Cipher cipher = Cipher.getInstance(GCMALGO);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, gcmParameterSpec);
        final byte[] encryptedData = cipher.doFinal(dataBytes);
        final byte[] encryptedBytes = new byte[encryptedData.length + ivLength];
        System.arraycopy(initializationVector, 0, encryptedBytes, 0, ivLength);
        System.arraycopy(encryptedData, 0, encryptedBytes, ivLength, encryptedData.length);
        System.out.println("data [String]        : " + data);
        System.out.println("data           length: " + dataBytes.length
                + " data: " + bytesToHex(dataBytes));
        System.out.println("mainKey        length: " + mainKey.getBytes(UNICODE_FORMAT).length
                + " data: " + bytesToHex(mainKey.getBytes(UNICODE_FORMAT)));
        System.out.println("initvector     length: " + initializationVector.length
                + " data: " + bytesToHex(initializationVector));
        System.out.println("encryptedBytes length: " + encryptedBytes.length
                + " data: " + bytesToHex(encryptedBytes));
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    private static String decrypt(String data, String mainKey, int ivLength) throws Exception {
        final byte[] encryptedBytes = Base64.getDecoder().decode(data.getBytes(UNICODE_FORMAT));
        final byte[] initializationVector = new byte[ivLength];
        System.arraycopy(encryptedBytes, 0, initializationVector, 0, ivLength);
        SecretKeySpec secretKeySpec = new SecretKeySpec(mainKey.getBytes(UNICODE_FORMAT), ALGO);
        GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, initializationVector);
        Cipher cipher = Cipher.getInstance(GCMALGO);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, gcmParameterSpec);
        return new String(cipher.doFinal(encryptedBytes, ivLength, encryptedBytes.length - ivLength),
                UNICODE_FORMAT);
    }

    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();
    }
}

最后,我得到了这样的结果--需要将“EncryptString”传输到您的网站:

https://stackoverflow.com/questions/62129604/decrypt-aes-128-gcm-encoded-content-with-java-cipher-using-php-openssl
data [String]        : Secret data for TytooF
data           length: 22 data: 536563726574206461746120666f72205479746f6f46
mainKey        length: 16 data: 31323334353637383930313233343536
initvector     length: 16 data: 3fc914fc67f6ecb53daa098ba40f20a5
encryptedBytes length: 54 data: 3fc914fc67f6ecb53daa098ba40f20a5f1e6755b96e5c0bb5de29522099bdeb806cf28c6d181d7e4ffdc15f451a19a54c714c42b38fc
encryptString:         P8kU/Gf27LU9qgmLpA8gpfHmdVuW5cC7XeKVIgmb3rgGzyjG0YHX5P/cFfRRoZpUxxTEKzj8
decryptString:         Secret data for TytooF

在WebServer/PHP端,我稍微修改了您的代码(“主要更改”是openssl_decrypt($ciphertext,$cipher,$key,true,$iv,$tag)一行的更改,因为我们不像以前的一些代码那样向decrypt方法提供base64编码的数据($encrypt=base64_decode($str)。

<?php

/**
 * @param string $str
 *   The URL parameter string
 */
function test_decrypt($str)
{
    $key = '1234567890123456';
    $cipher = 'aes-128-gcm';
    $iv_len = 16;
    $tag_length = 16;
    echo $str . '<br>';
    /**
     * Decryption part
     */
    $encrypt = base64_decode($str);
    $iv = substr($encrypt, 0, $iv_len);
    $tag = substr($encrypt, -$tag_length);
    $ciphertext = substr($encrypt, $iv_len, -$tag_length);
    echo "" . "\n";
    $value = unpack('H*', $iv);
    echo '<br>iv:' . $value[1];
    echo "" . "\n";
    $value = unpack('H*', $ciphertext);
    echo '<br>ciphertext:' . $value[1];
    echo "" . "\n";
    $value = unpack('H*', $tag);
    echo '<br>tag:' . $value[1];
    echo "<br>" . "\n";
    $uncrypt = openssl_decrypt($ciphertext, $cipher, $key, true, $iv, $tag);//OPENSSL_RAW_DATA + OPENSSL_NO_PADDING
    echo '<br>DecryptedString: ' . $uncrypt . "\n";
    $value = unpack('H*', $uncrypt);
    echo '<br>DecryptedString [byte[]]:' . $value[1];
    exit;
}

echo '<b>Output for https://stackoverflow.com/questions/62129604/decrypt-aes-128-gcm-encoded-content-with-java-cipher-using-php-openssl</b><br>' . "\n";
echo '' . "\n";
echo 'Start decryption' . "\n";
$receivedData = "P8kU/Gf27LU9qgmLpA8gpfHmdVuW5cC7XeKVIgmb3rgGzyjG0YHX5P/cFfRRoZpUxxTEKzj8";
test_decrypt($receivedData);
?>

这是WebServer上的解密输出:

Output for https://stackoverflow.com/questions/62129604/decrypt-aes-128-gcm-encoded-content-with-java-cipher-using-php-openssl
Start decryption P8kU/Gf27LU9qgmLpA8gpfHmdVuW5cC7XeKVIgmb3rgGzyjG0YHX5P/cFfRRoZpUxxTEKzj8

iv:3fc914fc67f6ecb53daa098ba40f20a5
ciphertext:f1e6755b96e5c0bb5de29522099bdeb806cf28c6d181
tag:d7e4ffdc15f451a19a54c714c42b38fc

DecryptedString: Secret data for TytooF
DecryptedString [byte[]]:536563726574206461746120666f72205479746f6f46

2021年10月10日编辑:上面的代码使用的是长度为16字节的IV/nonce,但建议的IV/nonce长度为12。

 类似资料:
  • 我正在尝试在运行FreeRTOS的微处理器上使用mbedTLS加密一些文本。我正在使用带有PKCS7填充的AES 128 CBC。如果我尝试在mbedTLS中加密,并在文本少于16个字符时在Java中解密,则可以正常工作。我可以在Java中解密它,并且文本匹配。如果它更长,那么它就不再有效。我做错了什么? mbedTLS 代码: Java代码: Java抛出javax.crypto。BadPadd

  • 尝试将数据解密为用AES-128加密的字节数组,使用字符串密钥"keykeykeykey1" 代码: 给我BadPaddingExc0019。我错过了什么?

  • 本文向大家介绍java使用Hex编码解码实现Aes加密解密功能示例,包括了java使用Hex编码解码实现Aes加密解密功能示例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了java使用Hex编码解码实现Aes加密解密功能。分享给大家供大家参考,具体如下: 这里的Aes加密解密方法使用Hex进行了编码解码 这个方法在正式的项目中已经在使用木有问题,注意这里的AES加密解密你要要对哦…… 上

  • 我用Delphi加密“sifrelenecek”字符串,使用AES 128 ECB,使用密钥为“KRPTTT101103”,它给了我“FBE4A4405D6C1B54503D9B213E41AE56”,我正在检查http://aes.online-domain-tools.com/,它是正确的。我试图使用此功能创建相同的PHP加密; 但是php给我的结果是“wL2yf 72thixicjw0duQ

  • 我用java编写了这段代码,以便解密密文。我有钥匙。对我来说,一切都是正确的,但我有我要解释的问题。 这是我的代码: 我收到以下错误: 出了什么问题?我知道这个问题在某种程度上与衬垫有关,但我不知道确切的解决方案。我只有一个密文IV和密钥。

  • 节点模块: Java类:主要方法现在只是用于测试,稍后将被删除。