文章目录

  • 1. AES算法
    • 1.1 AES加密过程
      • 1.1.1 字节代替(SubBytes)
      • 1.1.2 行移位(ShiftRows)
      • 1.1.3 列混合(MixColumns)
      • 1.1.4 加轮密钥(AddRoundKey)
    • 1.2 AES加解密实现
      • 1.2.1 创建密钥
      • 1.2.2 AES加密
      • 1.2.3 AES解密
    • 1.3 AES与DES的对比
  • 2. RSA算法
    • 2.1 RSA算法原理
    • 2.2 RSA加解密实现
      • 2.2.1 创建RSA密钥对
      • 2.2.1 RSA加密
      • 2.2.2 RSA解密
  • 3. MD5算法
  • 4. Base64算法

在Android直播开发之旅(14):使用RC4算法加解密音视频流一文中,我们了解了一种面向字节操作的对称加密算法–RC4,该算法实现简洁、加密速度快且安全性较高(密钥可变长,为1~256字节),通常用于加密流数据。本节将介绍另外一种对称加密–AES,通过分析它的实现原理并结合实战项目来了解其在文件加密方面的应用。

1. AES算法

 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。AES 是一个迭代的、对称密钥分组的密码,AES算法加密强度大,执行效率高,使用简单。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用,是目前对称密钥加密中最流行的算法之一。AES的分组区块长度固定为128位,密钥长度则可以是128,192或256位。密钥长度越长,加密等级越高,但是效率会有所降低。AES算法常见参数配置:

参数类型 AES128 AES192 AES256
密码长度(bits) 128 192 256
明文分组长度(bits) 128 128 128
加密轮数 10 12 14
轮密钥长度(bits) 128 128 128
扩展密钥长度(words) 44 52 60

 AES算法在对明文加密的时候,并不是把整个明文一股脑加密成一整段密文,而是把明文拆分成一个个独立的明文块(分组),每一个明文块长度128bit=16字节。这些明文块经过AES加密器的复杂处理,生成一个个独立的密文块,这些密文块拼接在一起,就是最终的AES加密结果。本文将以AES128为例,讲解AES的实现过程。

1.1 AES加密过程

 AES加密过程是在一个4×4的字节(即16字节)矩阵上运作,这个矩阵又称为“体(state)”,其初值就是一个明文区块(矩阵中一个元素大小就是明文区块中的一个Byte)。加密时,各轮AES加密分为初始轮(Initial Round,1次)、普通轮(Rounds,N次)和最终轮(Final Rounds,1次),并且不同阶段的Round由多同的处理步骤,整个AES加密过程如下图所示(以AES128为例):

 其中,SubBytes表示字节代替变换、ShiftRows表示行移位变换、MixColumns表示列混合变换、AddRoundKey表示加轮密钥变换。

1.1.1 字节代替(SubBytes)


 所谓字节替换,是指将明文块(16字节组成的4x4矩阵)中的每一个字节都替换成另外一个字节,其中替换的依据是一个被称为S盒(Subtitution Box)的16x16大小的二维常量数组。比如明文块当中a[2, 2] = 19,那么经过被S盒替换后输出的目标b[2, 2] = S[1][9]=2D,即a[2,2]的值被替换成S矩阵中行下标为1、列下标为9的元素。

1.1.2 行移位(ShiftRows)


 所谓行移位,是指对进行字节替换后的矩阵进行行移位,其规则如下:

  • 第一行不变;
  • 第二行循环左移1个字节;
  • 第三行循环左移2个字节;
  • 第三行循环左移3个字节;

1.1.3 列混合(MixColumns)


 所谓列混合,是指将经过行移位得到的矩阵将其每一列和一个名为修补矩阵(fixed matrix)的二维常量数组做矩阵相乘,得到对应的输出列。举例如下:

1.1.4 加轮密钥(AddRoundKey)


 所谓加轮密钥,是指将输入的数组的每一个字节a[i,j]与密钥对应位置的字节k[i,j]进行异或依次,从而得到处理后的输出值b[i,j]。这时唯一利用到密钥的一步,且128bit的密钥也同样被排列成4x4的矩阵。需要注意的是,由于加密的每一轮所用到的密钥并不是相同的,而每一轮的密钥通过**扩展密钥(KeyExpansions)**产生,扩展密钥算法计算过程为:

注:关于AES的加解密过程,可参照《A高级加密标准AES 徐娟》和《AES加密算法动画》来理解。另外,还有一个知识点就是AES的工作模式,AES加密算法提供了五种不同的工作模式:ECB、CBC、CTR、CFB、OFB,其中,ECB模式为默认工作模式,这种模式的每一个明文块的加密都是完全独立的,互不干涉的,因此实现起来比较简单且有利于并行计划,但是安全性稍微差一点。如果希望提高安全性,可以采用CBC模式,该模式在每一个明文块加密前会让明文块和一个值先做异或操作,但是缺点是无法并行计算,且由于增加了异或操作,性能上不如ECB模式。

1.2 AES加解密实现

1.2.1 创建密钥

public static byte[] getAutoCreateAESKey() throws Exception {// 实例化一个AES加密算法的密钥生成器KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM_AES);// 初始化密钥生成器,指定密钥位数为128位keyGenerator.init(AES_KEY_LEN, new SecureRandom());// 生成一个密钥SecretKey secretKey = keyGenerator.generateKey();return secretKey.getEncoded();
}

1.2.2 AES加密

/** AES加密* * @param sourceFile 源文件* @param encryptFile 加密文件* @param password 密钥,128bit* @throws Exception 抛出异常
*/
public static void aesEncryptFile(String sourceFile, String encryptFile, byte[] password) throws Exception {// 创建AES密钥SecretKeySpec key = new SecretKeySpec(password,  "AES");// 创建加密引擎(CBC模式)。Cipher类支持DES,DES3,AES和RSA加加密// AES:算法名称// CBC:工作模式// PKCS5Padding:明文块不满足128bits时填充方式(默认),即在明文块末尾补足相应数量的字符,// 且每个字节的值等于缺少的字符数。另外一种方式是ISO10126Padding,除最后一个字符值等于少的字符数// 其他字符填充随机数。Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");// 初始化加密器cipher.init(Cipher.ENCRYPT_MODE, key,  new IvParameterSpec(new byte[cipher.getBlockSize()]));// 原始文件流FileInputStream inputStream = new FileInputStream(sourceFile);// 加密文件流FileOutputStream outputStream = new FileOutputStream(encryptFile);// 以加密流写入文件CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher);byte[] tmpArray = new byte[1024];int len;while((len = cipherInputStream.read(tmpArray)) != -1) {outputStream.write(tmpArray, 0, len);outputStream.flush();}cipherInputStream.close();inputStream.close();outputStream.close();
}

1.2.3 AES解密

/** AES解密*  * @param encryptFile 加密文件* @param decryptFile 解密文件* @param password 密钥,128bit* @throws Exception 抛出异常
*/
public static void aesDecryptFile(String encryptFile, String decryptFile, byte[] password) throws Exception {// 创建AES密钥,即根据一个字节数组构造一个SecreteKey// 而这个SecreteKey是符合指定加密算法密钥规范SecretKeySpec key = new SecretKeySpec(password,   "AES");// 创建解密引擎(CBC模式)// Cipher类支持DES,DES3,AES和RSA加解密Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");// 初始化解密器cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(new byte[cipher.getBlockSize()]));// 加密文件流FileInputStream fileInputStream = new FileInputStream(encryptFile);// 解密文件流FileOutputStream fileOutputStream = new FileOutputStream(decryptFile);// 以解密流写出文件CipherOutputStream cipherOutputStream = new CipherOutputStream(fileOutputStream, cipher);byte[] buffer = new byte[1024];int len;while((len = fileInputStream.read(buffer)) >= 0) {cipherOutputStream.write(buffer, 0, len);}cipherOutputStream.close();fileInputStream.close();fileOutputStream.close();
}

1.3 AES与DES的对比

 AES、DES均为对称加密算法,它们的对比如下:

DES AES
安全性 密钥长度较短(56bits),不能抵抗密钥的穷举搜索攻击;轮密钥通过置换和循环移位进行扩展,存在弱密钥和半弱密钥 密钥长度至少128bits,安全性能超过3-DES;轮密钥通过非线性代换、线性混合和密钥加进行扩展
效率 快于3-DES
灵活性 密钥长度不可变(56bits) 密钥长度可变(128bits、192bits、256bits)
复杂性 采用Feistel网络结构,每轮数据的变换不均匀,设计较为复杂 采用SP网络结构,每轮数据的变换均匀,设计简单

2. RSA算法

  RSA加密算法是一种非对称加密算法,该算法在公开密钥加密和电子商业中被广泛使用,只要其钥匙长度足够长(注:至少为500位长,推荐使用1024位),世界上还没有任何可靠的攻击RSA算法的方式。所谓非对称加密算法,是指算法的加解密需要两个(一对)密钥,即公开密钥(publickey,简称公钥)和私有密钥(privatekey,简称私钥),其中公钥通常用于对数据进行加密且公开,而私钥用于对数据进行解密且私有。

2.1 RSA算法原理

 RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。在RSA算法加解密过程中,假设用户A生成一对RSA密钥,其中私钥由A自己保管,公钥将对外公开。用户B获得A公布的公钥后,它拿着公钥对数据进行加密然后传输给A,A获得B传输过来的加密数据后,就用自己保存的私钥进行解密,进而获得明文。整个加解密过程如下图所示:

1. RSA密钥对生成流程

(1)随意选择两个大的素数p、q
(2)计算两个大素数的乘机n = p * q
(3)φ(n) = (p-1)(q-1)(欧拉函数);
(4)公钥e: 满足 1<e<φ(n)的整数 且和 φ(n)互质;
(5)私钥d: 满足e*d mod φ(n)==1
(6)销毁p, q;
(7)公开发布n和公钥e;

2. 加、解密

(1)加密:假设明文m(m应为小于n的整数),m的e次幂取n的余数,得到密文c。

(2)解密:计算密文c的d次幂取n的余数,即得到明文m。

2.2 RSA加解密实现

2.2.1 创建RSA密钥对

private static Map<Integer, String> keyMap = new HashMap<Integer, String>();
/*** 随机生成密钥对* @throws NoSuchAlgorithmException
*/
public static void genKeyPair() throws NoSuchAlgorithmException {// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");// 初始化密钥对生成器,密钥大小为96-1024位keyPairGen.initialize(1024,new SecureRandom());// 生成一个密钥对,保存在keyPair中KeyPair keyPair = keyPairGen.generateKeyPair();// 得到私钥RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();  // 得到公钥RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 将公钥和私钥保存到Map// 0表示公钥// 1表示私钥keyMap.put(0,Base64.getEncoder().encodeToString(publicKey.getEncoded())); keyMap.put(1,Base64.getEncoder().encodeToString(privateKey.getEncoded()));
}

2.2.1 RSA加密

/*** RSA公钥加密** @param str*            加密字符串* @param publicKey*            公钥* @return 密文,经过Base64处理* @throws Exception*             加密过程中的异常信息*/
public static String rsaEncrypt(String str, String publicKey ) throws Exception{// 获取公钥byte[] decoded = Base64.getDecoder().decode(publicKey);RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));//RSA加密Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.ENCRYPT_MODE, pubKey);return Base64.getEncoder().encodeToString((cipher.doFinal(str.getBytes("UTF-8")));
}

2.2.2 RSA解密

/*** RSA私钥解密** @param str*            加密字符串* @param privateKey*            私钥* @return 铭文* @throws Exception*             解密过程中的异常信息*/
public static String rsaDecrypt(String str, String privateKey) throws Exception{//64位解码加密后的字符串byte[] inputByte = Base64.getDecoder().decode(str.getBytes("UTF-8"));// base64编码的私钥byte[] decoded = Base64.getDecoder().decode(privateKey);RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));//RSA解密Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.DECRYPT_MODE, priKey);return  new String(cipher.doFinal(inputByte));
}

3. MD5算法

 MD5信息摘要算法(MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息(文件)传输完整一致。MD5能把一个不管多长的文件都变成定长的且是不可逆的,它的实现原理大致为:MD5码以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。总体流程如下图所示:

代码实现:

/** 计算文件的md5值 */
public static String calculateMD5(File updateFile, int offset, int partSize) {MessageDigest digest;try {digest = MessageDigest.getInstance("MD5");} catch (NoSuchAlgorithmException e) {Log.e("FileUtils", "Exception while getting digest", e);return null;}InputStream is;try {is = new FileInputStream(updateFile);} catch (FileNotFoundException e) {Log.e("FileUtils", "Exception while getting FileInputStream", e);return null;}//DigestInputStreamfinal int buffSize = 8192;//单块大小byte[] buffer = new byte[buffSize];int read;try {if (offset > 0) {is.skip(offset);}int byteCount = Math.min(buffSize, partSize), byteLen = 0;while ((read = is.read(buffer, 0, byteCount)) > 0 && byteLen < partSize) {digest.update(buffer, 0, read);byteLen += read;//检测最后一块,避免多读数据if (byteLen + buffSize > partSize) {byteCount = partSize - byteLen;}}byte[] md5sum = digest.digest();BigInteger bigInt = new BigInteger(1, md5sum);String output = bigInt.toString(16);// Fill to 32 charsoutput = String.format("%32s", output).replace(' ', '0');return output;} catch (IOException e) {throw new RuntimeException("Unable to process file for MD5", e);} finally {try {is.close();} catch (IOException e) {Log.e("FileUtils", "Exception on closing MD5 input stream", e);}}
}

4. Base64算法

 Bse64是一种以64个可见字符集(又称“Base64编码表”)对二进制数据进行编码的编码算法,这种编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到,因此常用于电子邮件加密数据简单加密以及图片和文件网络传输。Base64编码表如下图所示:

(1)Base64编码过程

 在Base64编码过程中,每3个8位明文数据为一组(注:即每3个字节为一组),取这3个字数据的ASCII码,然后以6位为一组组成1个新的数据。对于不足3字节的处理:(1)不足三字节后面填充0;(2)对于编码前的数据产生的6位,如果为0,则索引到的字符为‘A’;因不足3字节而填充的0,用’=’来替代。举例如下:

由此可知,“ABCD”的base64编码为:“QUJDRA==”。代码实现:

Base64.getEncoder().encode("ABCD".getBytes());

(2)Base64解码过程

 Base64解码,即是base64编码的逆过程,即将base64编码数据根据编码表分别索引到编码值,然后每4个编码值一组组成一个24位的数据流,解码为3个字符(注:每个字符占8位)。对于末尾位“=”的base64数据,最终取得的4字节数据,需要去掉“=”再进行转换。代码实现:

Base64.getDecoder().decode("QUJDRA==");

Android直播开发之旅(25):使用AES算法加密多媒体文件(+RSA+MD5+Base64)相关推荐

  1. Android直播开发之旅(17):使用FFmpeg提取MP4中的H264和AAC

    最近在开发中遇到了一个问题,即无法提取到MP4中H264流的关键帧进行处理,且保存到本地的AAC音频也无法正常播放.经过调试分析发现,这是由于解封装MP4得到的H264和AAC是ES流,它们缺失解码时 ...

  2. Android直播开发之旅(3):AAC编码格式分析与MP4文件封装(MediaCodec+MediaMuxer)

    Android直播开发之旅(3):AAC编码格式分析与MP4文件封装(MediaCodec+MediaMuxer) (码字不易,转载请声明出处:http://blog.csdn.net/andrexp ...

  3. Android直播开发之旅(13):使用FFmpeg+OpenSL ES播放PCM音频

    文章目录 1. OpenSL ES原理 1.1 OpenSL ES核心API讲解 1.1.1 对象(Object)与接口(Interface) 1.1.2 [OpenSL ES的状态机制](https ...

  4. Android直播开发之旅(4):MP3编码格式分析与lame库编译封装

    转载请声明出处:http://blog.csdn.net/andrexpert/article/77683776 一.Mp3编码格式分析 MP3,全称MPEG Audio Layer3,是一种高效的计 ...

  5. Android直播开发之旅(9):OkCamera,Android 相机应用开发通用库

    OkCamera,Android 相机应用开发通用库 转载请声明出处:http://blog.csdn.net/andrexpert/article/details/79302576 明天就可以回家过 ...

  6. Android直播开发之旅(7):Android视频直播核心技术(架构)详解

    (转载请声明出处:http://blog.csdn.net/andrexpert/article/details/76919535) 一.直播架构解析 目前主流的直播架构中主要有两种方案,即流媒体转发 ...

  7. Android直播开发之旅(15):libjpeg库的编译移植与使用

    1. libjpeg介绍  libJPEG库是一款功能强大的JPEG图像处理开源库,它支持将图像数据压缩编码为JPEG格式和对原有的JPEG图像解压缩,Android系统底层处理图片压缩就是用得lib ...

  8. Android直播开发之旅(18):FFmpeg中滤镜(filter)的工作原理

    文章目录 1. 什么是滤镜 1.1 简单滤镜(滤镜链) 1.2 复杂滤镜(滤镜图) 2. 滤镜API介绍与使用 2.1 滤镜API介绍 2.1.1 结构体 2.1.2 功能函数 2.2 滤镜API的使 ...

  9. h5直播开发之旅总结

    前言 关于直播,有很多相关技术文章,这里不多说. 作为前端,我们比较关心我们所需要的. 直播的大致流程: APP端调用摄像头 -> 拍摄视频 -> 实时上传视频 -> 服务器端获取视 ...

最新文章

  1. Codeforces #449 div2 C题
  2. MLPerf发布首个AI芯片推理测试排行榜:阿里平头哥含光800获得多项第一
  3. 【C++ 语言】C++字符串 ( string 类 | 创建方法 | 控制台输出 | 字符串操作 | 栈内存字符串对象 | string* )
  4. avue 文字点击 弹窗_经验 | UI设计师必懂的App弹窗设计方法
  5. 一款霸榜 GitHub 的开源 Linux 资源监视器!
  6. 删除文件后,磁盘空间没有释放的处理记录
  7. 【codeforces】【比赛题解】#872 CF Round #440 (Div.2)
  8. archman linux教程,Archman GNU/Linux 2020-01 发布,基于Arch的Xfce桌面发行版
  9. springboot 整合 storm 无法使用注解获取 Ioc 里的 bean,获取不到 spring 上下文 applicationContext
  10. 最详细Python批量字典暴力破解zip密码
  11. [题解]luogu_P3593_[NOIP2017]逛公园(最短路相关计数
  12. 5步操作,解决SOLIDWORKS处理复杂零件时卡顿的问题
  13. 兵以诈立 —— 三国的谋略
  14. Nginx学习笔记(Docker版)-2
  15. beyondcompare ubuntu revoked问题
  16. springboot项目结构_从零搭建Spring Boot脚手架(1):开篇以及技术选型
  17. 中蜂几月份自然分蜂_中蜂养殖,如何给蜜蜂分蜂?时间是关键
  18. 关于电子邮件客户端设计中QQ邮箱授权码问题。(运行提示535错误,说授权码error。)
  19. 【Docker】Docker进阶(二)
  20. 一颗白菜的云原生之旅

热门文章

  1. 生成前端海报的 N 种方案和优劣
  2. 防火墙、WAF、IPS、IDS、堡垒机的区别
  3. 【IO】Java 中的 BIO、NIO、AIO
  4. vimdiff比较两个文件
  5. 国家自然科学基金 计算机视觉,【科研新成果】我院2019年国家自然科学基金项目取得新突破...
  6. Java加密技术(一)—— HMACSHA1 加密算法
  7. 苏州源特国产隔离DC-DC电源芯片替代SN6505/SGM46000/MAX256/B0505-1W的方案
  8. fifo的rdata_FIFO的使用总结
  9. 高通平台开发系列讲解(系统篇)系统关机流程
  10. 在unreal中的基于波叠加的波浪水面材质原理和制作