0

まず、私は clojure の初心者であり、java や jvm もかなり使ってからしばらく経っています。

同じプログラムで暗号化されたファイルを復号化しようとすると、javax.crypto.BadPaddingException が発生します。コードは次のとおりです。

(ns clojure-crypt-file.core
(:use [clojure.tools.cli :only [cli]])
(:require [clojure.java.io :as io]
      [me.raynes.fs :as fs])
(:import (org.apache.commons.codec.binary Base64)
     (javax.crypto Cipher KeyGenerator SecretKey)
     (javax.crypto.spec SecretKeySpec)
     (java.security SecureRandom))
(:gen-class))

(defn str-to-bytes [s] (.getBytes s "UTF-8"))
(defn bytes-to-str [bs] (apply str (map (comp char byte) bs)))

(defn base64 [b]
  (Base64/encodeBase64String b))

(defn debase64 [s]
  (Base64/decodeBase64 (str-to-bytes s)))

(defn fetch-b64-key [filename]
(let [encoded-key (slurp filename)
     size (count encoded-key)
     ekey-no-newline (apply str (take (dec size) encoded-key))]
     (bytes-to-str (debase64 ekey-no-newline))))

(defn get-raw-key [seed]
  (let [keygen (KeyGenerator/getInstance "AES")
    sr (SecureRandom/getInstance "SHA1PRNG")]
    (.setSeed sr (str-to-bytes seed))
    (.init keygen (count seed) sr)
    (.. keygen generateKey getEncoded)))

(defn get-cipher [mode seed]
  (let [key-spec (SecretKeySpec. (get-raw-key seed) "AES")
    cipher (Cipher/getInstance "AES")]
    (.init cipher mode key-spec) cipher))

(defn encrypt [ba key]
  (let [cipher (get-cipher Cipher/ENCRYPT_MODE key)]
    (.doFinal cipher ba)))


(defn decrypt [enc-buffer key]
  (let [cipher (get-cipher Cipher/DECRYPT_MODE key)]
  (str-to-bytes (String. (.doFinal cipher enc-buffer)))))


(defn encrypt-file [src-file dest-file key-text]
  (let  [in     (new java.io.FileInputStream src-file)
     out    (java.io.BufferedOutputStream. 
             (java.io.FileOutputStream. dest-file))
     buffer (make-array Byte/TYPE 16)
     encbuf (atom nil)]
    (loop [g (.read in buffer) r 0]
  (if-not (= g -1)
    (do
      (reset! encbuf (encrypt buffer key-text));(println r "/" size)
      (.write out (deref encbuf) 0 (count (deref encbuf)))
      (recur (.read in buffer) (+ r g)))))
(.close in)
(.close out)) nil)

(defn decrypt-file [src-file dest-file key-text]
  (let  [in     (new java.io.FileInputStream src-file)
     out    (java.io.BufferedOutputStream. 
             (java.io.FileOutputStream. dest-file))
     buffer (make-array Byte/TYPE 16)
     decbuf (atom nil)]
  (loop [g (.read in buffer) r 0]
    (if-not (= g -1)
      (do
        (reset! decbuf (decrypt buffer key-text));(println r "/" size)
        (.write out (deref decbuf) 0 (count (deref decbuf)))
        (recur (.read in buffer) (+ r g)))))
  (.close in)
  (.close out)) nil)

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  ;; work around dangerous default behaviour in Clojure
  (alter-var-root #'*read-eval* (constantly false))

 (def ret-val
      (let [[opts extra banner] 
      (cli args
          ["-e" "--encrypt" "Encrypt source file" :flag true :default false]
          ["-d" "--decrypt" "Decrypt source file" :flag true :default false] 
          ["-k" "--keyfile" "Path to keyfile" :default "./keyfile"]
          ["-h" "--help" "Help" :flag true :default false] 
          )]

    ;(println opts extra)
    (if (true? (:help opts)) banner
        (let [
            sfile (first extra) 
            dfile (if (= (count extra) 2) 
              (second extra)
              (if (true? (:encrypt opts))
                  (str (first extra) ".encrypted")
                  (str (first extra) ".decrypted"))) 
            ktext (slurp (:keyfile opts))
              ]

              (if (true? (:encrypt opts)) (encrypt-file sfile dfile ktext)
                                  (decrypt-file sfile dfile ktext))))))

(if (nil? ret-val) (println "Finished.") (println ret-val)))

以下は、完全なエラー リストです。

Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
  at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
  at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
  at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:317)
  at javax.crypto.Cipher.doFinal(Cipher.java:1813)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:616)
  at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:93)
  at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:28)
  at clojure_crypt_file.core$decrypt.invoke(core.clj:54)
  at clojure_crypt_file.core$decrypt_file.invoke(core.clj:83)
  at clojure_crypt_file.core$_main.doInvoke(core.clj:117)
  at clojure.lang.RestFn.applyTo(RestFn.java:137)
  at clojure_crypt_file.core.main(Unknown Source)

実際の Java プログラムに関する以前の投稿から、これはデータの最後の数バイトがバッファを満たさないという問題である可能性があることが示唆されました。ここでそれが正確かどうかはわかりません。原因が何であれ、それを修正する方法がわかりません。よろしくお願いします。

4

1 に答える 1

0

BadPaddingException の主な原因は 2 つあります。

  1. 誤って暗号化/復号化しているため、パディングがランダムなガベージとして出てきます。

  2. 暗号化時に 1 種類のパディング (またはなし) を追加し、復号化時に別の種類のパディングを期待しているため、2 つが一致しません。

確認する方法は、一時的に復号化メソッドを expect に設定することNoPaddingです。その設定はエラーをスローしないため、プログラムを続行できます。 これはデバッグの目的でのみ行ってください。これにより、復号化されたメッセージがどのように見えるかを確認できます。

メッセージ全体がランダムなごみである場合は、暗号化または復号化が正しく行われていません。チェックキー、IVモードなどは、バイトレベルでの暗号化・復号化ともに同じです。

メッセージが明確であるが、最後にいくつかのバイトが追加されている場合、それらの余分なバイトはパディングです。さまざまなパディング タイプを確認し、そのタイプのパディングを予期するように復号化方法を設定します。または、PKCS7 パディングを使用するように暗号化と復号化の両方の方法を設定します。

パディングが表示されず、メッセージだけが表示される場合は、暗号化の前にパディングの完全なブロック (AES の場合は 16 バイト) を追加する必要があります。これは、暗号化方法の設定を変更することを意味する場合があります。

残念ながら、私は clojure を知らないので、マニュアルでこれを行う方法の詳細を調べる必要があります。

于 2013-05-28T13:47:57.813 に答える