1

PHP関数:

$privateKey = "1234567812345678";
$iv = "1234567812345678";
$data = "Test string";

$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $privateKey, $data, MCRYPT_MODE_CBC, $iv);

echo(base64_encode($encrypted));

Result: iz1qFlQJfs6Ycp+gcc2z4w==

Java関数

public static String encrypt() throws Exception{
try{
    String data = "Test string";
    String key = "1234567812345678";
    String iv = "1234567812345678";

    javax.crypto.spec.SecretKeySpec keyspec = new javax.crypto.spec.SecretKeySpec(key.getBytes(), "AES");
    javax.crypto.spec.IvParameterSpec ivspec = new javax.crypto.spec.IvParameterSpec(iv.getBytes());

    javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("AES/CBC/NoPadding");
    cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, keyspec, ivspec);
    byte[] encrypted = cipher.doFinal(data.getBytes());

    return new sun.misc.BASE64Encoder().encode(encrypted);

}catch(Exception e){
    return null;
}

}

nullを返します。

PHPコードを変更することは許可されていないことに注意してください。誰かがJavaで同じ結果を得るのを手伝ってくれませんか?どうもありがとう。

4

1 に答える 1

10

ルーチンException内で可能なものを単純に飲み込まなかった場合は、何が起こっているのかをよりよく理解できたはずです。encrypt()関数が戻ってきた場合はnull、明らかに例外が発生したため、それが何であったかを知る必要があります。

実際、例外は次のとおりです。

javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
    at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:854)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:828)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
    at javax.crypto.Cipher.doFinal(Cipher.java:2087)
    at Encryption.encrypt(Encryption.java:20)
    at Encryption.main(Encryption.java:6)

そして確かに、プレーンテキストの長さはわずか11 Java文字であり、デフォルトのエンコーディングでは11バイトになります。

mcrypt_encryptPHP関数が実際に何をするかを確認する必要があります。それが機能するので、それは明らかにいくつかのパディングスキームを使用しています。あなたはそれがどれであるかを見つけて、あなたのJavaコードでそれを使う必要があります。

わかりました-のマニュアルページを調べましたmcrypt_encrypt。それは言う:

指定された暗号とモードで暗号化されるデータ。データのサイズが。でないn * blocksize場合、データには。が埋め込まれ\0ます。

したがって、Javaでそれを複製する必要があります。これが1つの方法です:

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Encryption
{
    public static void main(String args[]) throws Exception {
        System.out.println(encrypt());
    }

    public static String encrypt() throws Exception {
        try {
            String data = "Test string";
            String key = "1234567812345678";
            String iv = "1234567812345678";

            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            int blockSize = cipher.getBlockSize();

            // We need to pad with zeros to a multiple of the cipher block size,
            // so first figure out what the size of the plaintext needs to be.
            byte[] dataBytes = data.getBytes();
            int plaintextLength = dataBytes.length;
            int remainder = plaintextLength % blockSize;
            if (remainder != 0) {
                plaintextLength += (blockSize - remainder);
            }

            // In java, primitive arrays of integer types have all elements
            // initialized to zero, so no need to explicitly zero any part of
            // the array.
            byte[] plaintext = new byte[plaintextLength];

            // Copy our actual data into the beginning of the array.  The
            // rest of the array is implicitly zero-filled, as desired.
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);

            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

            cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
            byte[] encrypted = cipher.doFinal(plaintext);

            return new sun.misc.BASE64Encoder().encode(encrypted);

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

そして、私がそれを実行すると、次のようになります。

iz1qFlQJfs6Ycp+gcc2z4w==

これはあなたのPHPプログラムが得たものです。


更新(2016年6月12日):Java 8の時点で、JavaSEは最終的に文書化されたbase64コーデックとともに出荷されます。だから代わりに

return new sun.misc.BASE64Encoder().encode(encrypted);

あなたは次のようなことをする必要があります

return Base64.Encoder.encodeToString(encrypted);

commons-codecまたは、文書化されていない内部メソッドを使用するのではなく、base64のエンコード/デコードにサードパーティのライブラリ(など)を使用します。

于 2012-06-01T00:39:11.207 に答える