首先,让我说我对 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 程序,有人建议这可能是最后几个字节的数据没有填充缓冲区的问题。我不确定这是否完全正确。不管是什么原因,我不知道如何解决它。在此先感谢您的帮助。