35729


現在PHPで暗号化したデータをJavaで復号化しようと試みています。  
暗号化の処理（PHP）  
<https://paiza.io/projects/vGzC24BQEQC105lXB_Ya_Q>

[code]

    <?php
    
    $output = array();
    $output["data"] = "Hello world!";
    $output["password"] = "Password";
    
    $output["enc"] = openssl_encrypt($output["data"], "BF-ECB", $output["password"]);
    var_dump($output);
    
[/code]

復号化の処理（Java）  
<https://paiza.io/projects/glDa6DCtgOUAtFMnRVXiTQ>

[code]

    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import javax.crypto.*;
    import javax.crypto.spec.*;
    import java.security.*;
    import java.util.Base64;
    import javax.xml.bind.DatatypeConverter;
    
    public class Main {
        public static void main(String[] args) throws Exception {
            // Here your code !
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String line = br.readLine();
    
            String key = "Password";
            String key_hex = DatatypeConverter.printHexBinary(key.getBytes());
            System.out.println(key_hex);
            String enc = "S1oraGJsPc3RupyhpvSYqw==";
            byte[] enc_decode = Base64.getDecoder().decode(enc.getBytes());
    
            Cipher cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
            Key skey = new SecretKeySpec(key_hex.getBytes(), "Blowfish");
            cipher.init(Cipher.DECRYPT_MODE, skey);
    
            System.out.println(cipher.doFinal(enc_decode));
        }
    }
    
[/code]

出ているエラー

[code]

    Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
        at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:989)
        at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:845)
        at com.sun.crypto.provider.BlowfishCipher.engineDoFinal(BlowfishCipher.java:319)
        at javax.crypto.Cipher.doFinal(Cipher.java:2165)
        at Main.main(Main.java:25)
    
[/code]

実行環境については  
Paizaの環境ベースで  
java 1.8.0  
php 7.0.15  
です。  
ちなみにコマンドラインで復号化もできたのですが、  
複合（コマンドライン）

[code]

    echo "S1oraGJsPc3RupyhpvSYqw==" |openssl enc -d -bf-ecb -base64 -K $(echo -n "Password"|xxd -p) -nosalt
    
[/code]

鍵を１６進数のデータに置き換える必要がありました。よってJavaも同様に置き換えを実施しています。


CC BY-SA 3.0
2017-06-19T08:03:40.860
35707
2017-06-20T00:16:51.730
22665
question
php java
PHPで暗号化したデータをJavaで復号化できない


`openssl enc`は暗号データの前に16bitのマジックナンバーとsalt(乱数)がついてるので、そのままではJavaに渡せません。

あとkeyもパスワードではなく、パスとsaltから生成されたものです。これはopensslに`-p`オプションを渡す事で表示させられます。


CC BY-SA 3.0
2017-06-19T15:18:54.067
35721
2017-06-19T15:18:54.067
3974
35707
answer


暗号化の時にキーの長さが足りないので'\0'が埋められていますね。

[code]

    % echo -n 'Hello world!' | openssl enc -e -bf-ecb -base64 -K `echo -n "Password" | xxd -p ` -nosalt -p
    key=50617373776F72640000000000000000
    S1oraGJsPc3RupyhpvSYqw==
    
[/code]

また鍵を16進文字列に変換していますがこれは不要です。復号結果はバイト配列なので文字列として表示するなら変換する必要があります。

[code]

    String key = "Password\0\0\0\0\0\0\0\0";
    String enc = "S1oraGJsPc3RupyhpvSYqw==";
    byte[] enc_decode = Base64.getDecoder().decode(enc.getBytes());
    
    Cipher cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
    Key skey = new SecretKeySpec(key.getBytes(), "Blowfish");
    cipher.init(Cipher.DECRYPT_MODE, skey);
    
    System.out.println(new String(cipher.doFinal(enc_decode), "UTF-8"));
    
[/code]

* * *

ところで、このコードには

  * Blowfishは今から使うには古い→今時はAESが第一選択です
  * 暗号利用モードにECBを使用している→目的に応じた適切な暗号化モードを使用しましょう
  * 鍵に文字列をそのまま使用している→パスワードを用いる場合、パスワードを元に生成した乱数列を鍵として用います(PBKDF)

という大きな問題があります。どこかのサイトを参考にされたのかもしれませんが、いい加減なことが書かれていることも多いので、きちんとした書籍で基礎を勉強されたほうがよいです。

入門書として[暗号技術入門 第3版](http://www.hyuki.com/cr/)を紹介します。


CC BY-SA 3.0
2017-06-20T00:16:51.730
35729
2017-06-20T00:16:51.730
5793
35707
answer