Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
9
Help us understand the problem. What is going on with this article?
@asuzuki2008

異なる言語間での暗号化/復号化(PythonでEncrypto、JavaでDecrypto)

More than 3 years have passed since last update.

Pythonで作ったデータを暗号化して、Javaで復号したい

セキュリティ上の話で、そんなことが必要になった。
どちらもCryptoというライブラリがあるからすぐできるだろうと思っていたら大ハマりで、復号に至るまでに4時間くらいかかった。

参考

http://nori3tsu.hatenablog.com/entry/2013/10/01/012130
ハマった私に降りた天使のようなページ。
https://qiita.com/pink/items/f795b0680a2a000e1934
http://pentan.info/doc/block_cipher.html#anc_padding
パディングについて説明してくれているページ。

ポイント

暗号化には次の考えておくべき要素がある。(かなりざっくり)

  • 暗号化の種類→今回はAESとする
    • ECB/CBC/OFB
    • 暗号化対象のパディング

16バイトなのか24バイトなのか32バイトなのか、どの長さか選ぶ必要がある。
Java側でECBを使う前提にしたら、16バイトしか受け付けなかったので、16バイトを使った。

ECB/CBC/OFB

色んなサイト見るとCBCを使う情報が多いが、IV(イニシャルベクタ)という値の生成が必要。
→ってことはこの値も渡す必要が出てくるのか?ということで不採用。

簡単さも必要だったためECBを採用。
OFBはあまり調べてない。

暗号化対象のパディング

最後の難関としてかなり苦労したのがこれ。
AESの暗号化は、暗号化対象のデータ長が16Byteの倍数である必要があった。
そして、python上で暗号化すると
   元のデータ長:192Byte
   暗号化後のデータ長:192Byte
となった。

この暗号化したデータをJavaでそのまま復号できるかというと、できなかった。
色々試したところ、Java側で暗号化すると
   元のデータ長:192Byte
   暗号化後のデータ長:208Byte
となり、勝手にさらに16Byteパディングされていた!

この問題の対応方法を参考のページで知ることになる。(本当に感謝)
自己流で16バイトの倍数にパディングして192Byteとかやってたのだけど、やはりパディングにもルールがあるんだなと知る。

プログラム

pythonソース
from Crypto.Cipher import AES
import base64

BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s : s[0:-ord(s[-1])]

key='XXXXXXXXXXXXXXXX' #16バイト必要
text='abcdefg'         #暗号化したいデータ
cipher = AES.new(key, AES.MODE_ECB)
raw = pad(text)
enc = cipher.encrypt(raw)
data = base64.b64encode(enc) #dataを何かしらの形でJavaに渡せばよい
Javaソース
import java.security.GeneralSecurityException;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class AESCipher {
  private SecretKeySpec key;

  public AESCipher(String key) {
        this.key = new SecretKeySpec(key.getBytes(), "AES");
  }

  public String decrypt(String str) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, this.key);

        return new String(cipher.doFinal(Base64.decodeBase64(str)));
  }

  public static void main(String[] args) throws GeneralSecurityException {
        String key = "XXXXXXXXXXXXXXXX";
        String text = args[0]; // pythonのdataを渡す

        AESCipher cipher = new AESCipher(key);

        String dectext = cipher.decrypt(text);
        System.out.println(dectext); // abcdefg
    }
}
9
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
asuzuki2008
最近IoT案件が多いWEB系のプログラマ。 会社に所属しているが、フリーランスな仕事の仕方に憧れがちょっとある。 →フリーランスになった。ストレスフリーな生活スタイルというものを構築したい。 →お仕事は完全リモートでお願いしますm(_ _)m

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
9
Help us understand the problem. What is going on with this article?