LoginSignup
21
19

More than 5 years have passed since last update.

ClojureでAES暗号化をしてみる&AESのちょっと細かい話

Last updated at Posted at 2014-04-24

ClojureでのAES暗号化するコードを作ってみました。
Javaの標準ライブラリを使ってできるのでそんなに難しくないですね。

aes.clj
(import '[java.security SecureRandom Key]
        '[javax.crypto KeyGenerator Cipher]
        '[javax.crypto.spec IvParameterSpec]
        '[java.security.spec AlgorithmParameterSpec])

(defn ^bytes rand-bytes [n]
  (let [b (byte-array n)]
    (.. (SecureRandom.) (nextBytes b))
    b))

(defn ^Key aes-genkey [^long bits]
  {:pre[(#{128 192 256} bits)]}
  (let [kg (KeyGenerator/getInstance "AES")]
    (.init kg bits)
    (.generateKey kg)))

(def ^:dynamic *aes-mode* "AES/CBC/PKCS5Padding")

(defn- ^bytes aes-*code [^long mode ^bytes bytes ^Key key ^AlgorithmParameterSpec spec]
  (let [c (Cipher/getInstance *aes-mode*)]
    (if spec
      (.init c mode key spec)
      (.init c mode key))
    (.doFinal c bytes)))

(defn ^bytes aes-encode [^bytes bytes ^Key key & [^AlgorithmParameterSpec spec]]
  (aes-*code Cipher/ENCRYPT_MODE bytes key spec))

(defn ^bytes aes-decode [^bytes bytes ^Key key & [^AlgorithmParameterSpec spec]]
  (aes-*code Cipher/DECRYPT_MODE bytes key spec))

使い方はこんな感じで

(def k (aes-genkey 128))
(def iv (rand-bytes 16))
(def encoded (aes-encode (byte-array 2) k (IvParameterSpec. iv)))
(def decoded (aes-decode encoded k (IvParameterSpec. iv)))

(binding [*aes-mode* "AES/ECB/NoPadding"] 
  (let [e (aes-encode (byte-array 16) k)]
    (seq (aes-decode e k))))

*aes-mode*には以下のものが指定できるようです。

  • AES/CBC/NoPadding
  • AES/CBC/PKCS5Padding
  • AES/ECB/NoPadding
  • AES/ECB/PKCS5Padding

CBCはAES鍵は同じでも暗号化のたびにIV(Initialization Vector)を変えることで、同じ平文でも異なる暗号文にする方式です。復号する側には暗号化のたびにIVを教える必要があります。
ECBでは鍵が同じなら同じ平文には同じ暗号文が出力されるので、暗号強度は弱くなります。

NoPaddingは平文がAESのブロック長である16バイトの倍数であると確定している場合にのみ使えます。16の倍数でない場合は例外が発生します。
PKCS5Paddingは平文が16バイトの倍数であるとは限らない場合に使います。(方式としてはバイト数を16で割った余りが1のときは0x0fを15バイト追加、余りが2のときは0x0eを14バイト追加、余りが15のときは0x01を1バイト追加、そして余りが0のときは0x10を16バイト追加します)

※なお、正式な名称としてはPKCS#7 Paddingとなるようです。PKCS#5 PaddingはDESの頃のブロック長が8バイトのときの名称とのこと。Bouncy CastleではPKCS7の名称になっていたと思います。
※ちなみに、復号の際にPadding関連の例外が発生した場合、Paddingの誤りではなく復号の失敗(鍵、IVの誤り)であるケースがほとんどです。

AESの鍵長はOracle JDKではデフォルトでは128ビットしか使えません。192, 256ビットで使いたい場合はJava Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Filesをダウンロードしてjre/lib/securityに配置(上書き)する必要があります。
この処置を行わないとjava.security.InvalidKeyException: Illegal key sizeのような例外が発生します。

21
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
19