clojure文件加密程序中的javax.crypto.BadPaddingException
首先,让我说我对clojure非常陌生,而且自从我大量使用java或jvm以来已经有一段时间了 当我试图解密由同一程序加密的文件时,我得到了javax.crypto.BadPaddingException。代码如下:clojure文件加密程序中的javax.crypto.BadPaddingException,java,encryption,file-io,clojure,aes,Java,Encryption,File Io,Clojure,Aes,首先,让我说我对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 (
(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程序,有人认为这可能是最后几个字节的数据没有填充缓冲区的问题。我不确定这到底是不是真的。不管是什么原因,我都不知道该怎么解决。提前感谢您的帮助。导致BadPaddingException的主要原因有两个:
NoPadding
。该设置不会抛出错误,因此允许程序继续仅在调试时执行此操作。这将允许您查看解密消息的外观
如果整个消息都是随机垃圾,那么您要么加密不正确,要么解密不正确。检查密钥、IV模式等在字节级别的加密和解密都是相同的
如果消息是清楚的,但是在结尾添加了一些字节,那么这些额外的字节就是填充。对照各种填充类型进行检查,并将解密方法设置为预期的填充类型。或者,将加密和解密方法都设置为使用PKCS7填充
如果没有可见的填充,只有消息,那么您应该在加密之前添加完整的填充块(AES为16字节)。这可能意味着更改加密方法的设置
恐怕我不知道clojure,所以您必须在手册中查找如何执行此操作的详细信息。我想补充一点,上面的异常是在运行时生成的,而不是编译时生成的。我现在有了相关的工作代码,我将试着在某个时候发布它。我刚刚完成了对加密和解密函数的彻底测试,使用的字符串(随机生成)小到足以放入内存(高达18MB)。所有测试均成功。我确信我没有正确加密/解密文件I/O。我的问题是我不确定如何从文件中读取块,转换该块(在本例中为加密/解密),然后将转换后的块写入另一个文件,重复这些步骤,直到到达源文件的结尾。设置一个小文本文件作为测试,然后尝试从磁盘对其进行加密/解密。在Java中,处理未知长度数据的方法是使用流。我不确定clojure是否允许访问Java流。