使用AES进行文件加密算法
前言:最近想对手机上一些文件进行加密隐藏,想自己基于jvm平台写一个(kotlin/java)但是网上的加密算法都是不公开的,所以自己利用AES的算法整出了一个文件加密解密的工具 注意:因为我电脑上的JDK是12 ,所以如果移植到安卓上有出现报错,是正常现象,只需要修改 AESEncoder 文件就好了
FileEncoder.kt
代码语言:text复制import java.io.Closeable
import java.io.File
import java.io.RandomAccessFile
import java.lang.StringBuilder
/** * 文件加密 * 注意!!千万不可以使用多线程来同时加密/解密多个文件 */
class FileEncoder(passwd: String,val debug: Boolean = true, bufferSize: Int = (1024 * 1024 * 1)) : Closeable
{
private val aesEncoder = AESEncoder(passwd)
private val buffer = ByteArray(bufferSize)
private val spliteStr = "|"
/** * 加密算法 * [msgLen | encode_file | msg] */
fun encode(src: File, e_file: File, process: (process: Float) -> Unit)
{
val srcLen = src.length().toFloat()
val fis = src.inputStream()
val accessFile = RandomAccessFile(e_file, "rw")
// 这里在文件顶部写入8位的占位符
var msgLen = 0L
val headBytes = long2Bytes(msgLen)
accessFile.write(headBytes)
log("写入头部信息")
val msgBuilder = StringBuilder()
var readLen = fis.read(buffer)
var readCount = 0L
while (readLen > 0)
{
readCount = readLen
val encodeArray = aesEncoder.encode(buffer, readLen)
msgBuilder.append(encodeArray.size).append(spliteStr)
accessFile.write(encodeArray)
process.invoke(readCount / srcLen)
readLen = fis.read(buffer)
}
val msg = msgBuilder.toString()
msgBuilder.setLength(0)
log(msg)
// 将尾部信息转换成字节数组
val msgByteArry = msg.toByteArray()
// 将尾部信息字节数组,加密
val msgEncodeByteArray = aesEncoder.encode(msgByteArry, msgByteArry.size)
// 写入加密尾部信息
accessFile.write(msgEncodeByteArray)
log("写入加密尾部信息")
// 测量出加密后的信息长度是多少
msgLen = msgEncodeByteArray.size.toLong()
log("新的长度:$msgLen")
// 将光标移动到文件头,复写信息
accessFile.seek(0)
// 重新将长度写入进去
accessFile.write(long2Bytes(msgLen))
fis.close()
accessFile.close()
}
/** * 解密算法 */
fun decode(src: File, d_file: File, process: (process: Float) -> Unit)
{
val buffer: ByteArray
val raf = RandomAccessFile(src, "r")
val fos = d_file.outputStream()
val headBytes = ByteArray(8)
val headLen = raf.read(headBytes)
if (headLen != 8)
{
raf.close()
fos.close()
return
}
val msgLen = bytes2Long(headBytes)
log("解密:$msgLen")
val srcLen = src.length()
val msgByteArray = ByteArray(msgLen.toInt())
// 将光标移动到尾部,读取信息
raf.seek(srcLen - msgLen)
val readMsgLen = raf.read(msgByteArray)
log("已读取信息长度:$readMsgLen")
val decodeMsgArray = aesEncoder.decode(msgByteArray, msgByteArray.size)
val decodeMsg = String(decodeMsgArray)
log(decodeMsg)
val msgs = decodeMsg.split(spliteStr).dropLastWhile { it.isEmpty() }
val msgLong = msgs.map { it.toLong() }
val maxBufferSize = msgLong.max() ?: 0
buffer = ByteArray(maxBufferSize.toInt())
log(msgLong)
// 将光标回到读取完头部信息的位置
raf.seek(8)
msgLong.forEachIndexed { index, len ->
raf.read(buffer, 0, len.toInt())
val encodeArray = aesEncoder.decode(buffer, len.toInt())
fos.write(encodeArray)
process.invoke(index.toFloat() / msgLong.size)
}
process.invoke(1f)
fos.flush()
fos.close()
}
/** * 长整型转换成字节数组 */
private fun long2Bytes(num: Long): ByteArray
{
val byteNum = ByteArray(8)
for (ix in 0..7)
{
val offset = 64 - (ix 1) * 8
byteNum[ix] = (num shr offset and 0xff).toByte()
}
return byteNum
}
/** * 字节数组转换成长整型 */
private fun bytes2Long(byteNum: ByteArray): Long
{
var num: Long = 0
for (ix in 0..7)
{
num = num shl 8
num = num or (byteNum[ix].toInt() and 0xff).toLong()
}
return num
}
private inline fun log(msg: Any?)
{
if (debug)
{
println(msg)
}
}
override fun close()
{
aesEncoder.close()
}
}
AESEncoder.kt
代码语言:javascript复制import java.io.Closeable
import java.security.SecureRandom
import java.util.*
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.spec.SecretKeySpec
/* * AES对称加密和解密 */
class AESEncoder(encodeRules: String) : Closeable
{
private val encoder = Base64.getEncoder()
private val decoder = Base64.getDecoder()
private var encodeCipher: Cipher
private var decoderCipher: Cipher
private val bufferHolder = LinkedHashMap<Int, ByteArray>()
init
{
//1.构造密钥生成器,指定为AES算法,不区分大小写
val keygen = KeyGenerator.getInstance("AES")
//2.根据ecnodeRules规则初始化密钥生成器
//生成一个128位的随机源,根据传入的字节数组
keygen.init(128, SecureRandom(encodeRules.toByteArray()))
//3.产生原始对称密钥
val original_key = keygen.generateKey()
//4.获得原始对称密钥的字节数组
val raw = original_key.encoded
//5.根据字节数组生成AES密钥
val key = SecretKeySpec(raw, "AES")
//6.根据指定算法AES自成密码器
encodeCipher = Cipher.getInstance("AES")
decoderCipher = Cipher.getInstance("AES")
//7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEY
encodeCipher.init(Cipher.ENCRYPT_MODE, key)
//7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二个参数为使用的KEY
decoderCipher.init(Cipher.DECRYPT_MODE, key)
}
/* * 加密 * 1.构造密钥生成器 * 2.根据ecnodeRules规则初始化密钥生成器 * 3.产生密钥 * 4.创建和初始化密码器 * 5.内容加密 * 6.返回字符串 */
fun encode(content: ByteArray, len: Int): ByteArray
{
var buffer = bufferHolder[len]
if (buffer == null)
{
buffer = ByteArray(len)
bufferHolder[len] = buffer
}
System.arraycopy(content, 0, buffer, 0, len)
//8.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码
val byte_encode = buffer
//9.根据密码器的初始化方式--加密:将数据加密
val byte_AES = encodeCipher.doFinal(byte_encode)
//10.将加密后的数据转换为字符串
//这里用Base64Encoder中会找不到包
//解决办法: //在项目的Build path中先移除JRE System Library,再添加库JRE System Library,重新编译后就一切正常了。
//11.将字符串返回
return encoder.encode(byte_AES)
}
/* * 解密 * 解密过程: * 1.同加密1-4步 * 2.将加密后的字符串反纺成byte[]数组 * 3.将加密内容解密 */
fun decode(content: ByteArray, len: Int): ByteArray
{
var buffer = bufferHolder[len]
if (buffer == null)
{
buffer = ByteArray(len)
bufferHolder[len] = buffer
}
System.arraycopy(content, 0, buffer, 0, len)
//8.将加密并编码后的内容解码成字节数组
val byte_content = decoder.decode(buffer)
/* * 解密 */
val byte_decode = decoderCipher.doFinal(byte_content)
return byte_decode
}
override fun close()
{
bufferHolder.clear()
}
}
效果
右边是加密后的文件,左边是解密后的文件
老群被封, 新Q群709287944