diff --git a/ktx/resources/dec b/ktx/resources/dec new file mode 100644 index 0000000..ba275fd Binary files /dev/null and b/ktx/resources/dec differ diff --git a/ktx/resources/enc b/ktx/resources/enc new file mode 100644 index 0000000..42f5595 Binary files /dev/null and b/ktx/resources/enc differ diff --git a/ktx/src/main/java/luyao/util/ktx/ext/AesExt.kt b/ktx/src/main/java/luyao/util/ktx/ext/AesExt.kt new file mode 100644 index 0000000..dc2be33 --- /dev/null +++ b/ktx/src/main/java/luyao/util/ktx/ext/AesExt.kt @@ -0,0 +1,91 @@ +package luyao.util.ktx.ext + +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.security.Key +import javax.crypto.Cipher +import javax.crypto.CipherInputStream +import javax.crypto.KeyGenerator +import javax.crypto.spec.IvParameterSpec +import javax.crypto.spec.SecretKeySpec + +/** + * Created by luyao + * on 2019/7/1 16:09 + */ + +private const val KEY_ALGORITHM = "AES" +private const val CIPHER_ALGORITHM_DEFAULT = "AES" +private const val AES_CFB_NOPADDING = "AES/CFB/NoPadding" + +fun ByteArray.aesEncrypt(key: ByteArray, iv: ByteArray, cipherAlgotirhm: String = AES_CFB_NOPADDING): ByteArray { + val cipher = initCipher(Cipher.ENCRYPT_MODE, key, iv, cipherAlgotirhm) + return cipher.doFinal(this) +} + +fun ByteArray.aesDecrypt(key: ByteArray, iv: ByteArray, cipherAlgotirhm: String = AES_CFB_NOPADDING): ByteArray { + val cipher = initCipher(Cipher.DECRYPT_MODE, key, iv, cipherAlgotirhm) + return cipher.doFinal(this) +} + +fun File.aesEncrypt(key: ByteArray, iv: ByteArray, destFilePath: String): File? { + return handleFile(Cipher.ENCRYPT_MODE, key, iv, path, destFilePath) +} + +fun File.aesDecrypt(key: ByteArray, iv: ByteArray, destFilePath: String): File? { + return handleFile(Cipher.DECRYPT_MODE, key, iv, path, destFilePath) +} + +fun initAESKey(size: Int): ByteArray { + val kg = KeyGenerator.getInstance(KEY_ALGORITHM) + kg.init(size) + return kg.generateKey().encoded +} + +private fun toKey(key: ByteArray): Key = SecretKeySpec(key, KEY_ALGORITHM) + +private fun initCipher(mode: Int, key: ByteArray, iv: ByteArray, cipherAlgotirhm: String): Cipher { + val k = toKey(key) + val cipher = Cipher.getInstance(cipherAlgotirhm) + val cipherAlgorithm = cipherAlgotirhm.toUpperCase() + if (cipherAlgorithm.contains("CFB") || cipherAlgorithm.contains("CBC") + || cipherAlgorithm.contains("CTR") + ) + cipher.init(mode, k, IvParameterSpec(iv)) + else + cipher.init(mode, k) + return cipher +} + +private fun handleFile(mode: Int, key: ByteArray, iv: ByteArray, sourceFilePath: String, destFilePath: String): File? { + val sourceFile = File(sourceFilePath) + val destFile = File(destFilePath) + + if (sourceFile.exists() && sourceFile.isFile) { + if (!destFile.parentFile.exists()) destFile.parentFile.mkdirs() + destFile.createNewFile() + + val inputStream = FileInputStream(sourceFile) + val outputStream = FileOutputStream(destFile) + val cipher = initCipher(mode, key, iv, AES_CFB_NOPADDING) + val cin = CipherInputStream(inputStream, cipher) + + val b = ByteArray(1024) + var read = 0 + do { + read = cin.read(b) + if (read > 0) + outputStream.write(b, 0, read) + } while (read > 0) + + outputStream.flush() + cin.close() + inputStream.close() + outputStream.close() + + return destFile + } + return null +} + diff --git a/ktx/src/main/java/luyao/util/ktx/ext/HashExt.kt b/ktx/src/main/java/luyao/util/ktx/ext/HashExt.kt index 84683ce..2cb4245 100644 --- a/ktx/src/main/java/luyao/util/ktx/ext/HashExt.kt +++ b/ktx/src/main/java/luyao/util/ktx/ext/HashExt.kt @@ -44,7 +44,7 @@ fun ByteArray.sha512Bytes(): ByteArray = hash(this, Hash.SHA512) fun ByteArray.sha512(): String = hash(this, Hash.SHA512).toHexString() fun String.sha512(charset: Charset = Charset.forName("utf-8")): String = toByteArray(charset).sha512() -fun File.hash(algorithm: Hash): String { +fun File.hash(algorithm: Hash = Hash.SHA1): String { if (!exists() || !isFile) return "" val fin: FileInputStream val messageDigest: MessageDigest diff --git a/ktx/src/test/java/luyao/util/ktx/ext/AesExtKtTest.kt b/ktx/src/test/java/luyao/util/ktx/ext/AesExtKtTest.kt new file mode 100644 index 0000000..af39a99 --- /dev/null +++ b/ktx/src/test/java/luyao/util/ktx/ext/AesExtKtTest.kt @@ -0,0 +1,68 @@ +package luyao.util.ktx.ext + +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import java.io.File + +/** + * Created by luyao + * on 2019/7/1 16:24 + */ +class AesExtKtTest { + + private val plainText = "luyao" + var key: ByteArray = ByteArray(128) + var iv: ByteArray = ByteArray(128) + + @Before + fun setUp() { + key = initAESKey(128) + iv = initAESKey(128) + } + + @Test + fun aesCFB() { + val byteEncrypt = plainText.toByteArray().aesEncrypt(key, iv) + val byteDecrypt = byteEncrypt.aesDecrypt(key, iv) + assertEquals(plainText, String(byteDecrypt)) + } + + @Test + fun aesCBC() { + val byteEncrypt = plainText.toByteArray().aesEncrypt(key, iv, "AES/CBC/PKCS5Padding") + val byteDecrypt = byteEncrypt.aesDecrypt(key, iv, "AES/CBC/PKCS5Padding") + assertEquals(plainText, String(byteDecrypt)) + } + + + @Test + fun aesECB() { + val byteEncrypt = plainText.toByteArray().aesEncrypt(key, iv, "AES/ECB/PKCS5Padding") + val byteDecrypt = byteEncrypt.aesDecrypt(key, iv, "AES/ECB/PKCS5Padding") + assertEquals(plainText, String(byteDecrypt)) + } + + @Test + fun aesCTR() { + val byteEncrypt = plainText.toByteArray().aesEncrypt(key, iv, "AES/CTR/PKCS5Padding") + val byteDecrypt = byteEncrypt.aesDecrypt(key, iv, "AES/CTR/PKCS5Padding") + assertEquals(plainText, String(byteDecrypt)) + } + + @Test + fun handleFile() { + val sourceFilePath = "resources/ELF文件系统格式.pdf" + val encFilePath = "resources/enc" + val decFilePath = "resources/dec" + + File(sourceFilePath).aesEncrypt(key, iv, encFilePath) + File(encFilePath).aesDecrypt(key, iv, decFilePath) + + assertEquals( + File(sourceFilePath).hash(), + File(decFilePath).hash() + ) + } + +} \ No newline at end of file