我在Clojure中编写了用于AES加密的代码。
这并不困难,因为可以使用Java标准库来完成。
aes.clj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | (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)) |
如何使用
1 2 3 4 5 6 7 8 | (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 / CBC /无填充
- AES / CBC / PKCS5填充
- AES / ECB /无填充
- AES / ECB / PKCS5填充
CBC是一种方法,即使AES密钥相同,每次执行加密时,都通过更改IV(初始化矢量)来生成相同的明文但不同的密文。每次解密时,都必须教导解密器IV。
在ECB中,如果密钥相同,则以相同的明文输出相同的密文,因此该密文较弱。
仅当确定明文是16字节AES块长度的倍数时,才可以使用NoPadding。如果不是16的倍数,则将引发异常。
当明文不总是16字节的倍数时,使用PKCS5Padding。 (作为一种方法,将字节数除以16,然后在余数为1时添加15字节的0x0f,在余数为2时添加14字节的0x0e,在余数为15时添加1字节的0x01,在余数为它是0,加上16个字节的0x10)
*官方名称似乎是PKCS#7 Padding。 PKCS#5填充是DES时块长度为8字节时的名称。我认为这是Bouncy Castle中的PKCS7名称。
*顺便说一句,如果在解密过程中发生与Padding相关的异常,则在大多数情况下,这不是Padding错误,而是解密失败(密钥,IV错误)。
在Oracle JDK中,默认情况下AES密钥长度只能为128位。如果要以192、256位使用它,则需要下载Java密码学扩展(JCE)无限强度管辖权策略文件,并将其放置(覆盖)在jre / lib / security中。
如果不这样做,则会出现类似