加密填充

只针对 aes 和rsa 加密。rsa签名是另外一个填充方式。其他加密算法使用不多。

  1. 为什么需要填充?
  2. 为什么需要知道填充?

为什么需要填充?

RSA和AES虽然属于两种截然不同的加密类型,但它们都属于块密码的应用范畴。
1.AES的块大小是固定的16字节,RSA的块大小根据密钥长度和填充方式而定。由于AES每次只能处理固定长度的数据(即一个块大小),当数据大小不是块大小的整数倍时,就需要对原始数据进行填充,因此填充对AES来说是技术原理上的需求。因为无法保证数据一定是对齐的。
2.RSA则不太一样,RSA填充的主要目的是为了加强算法的安全性。RSA填充在安全上的作用体现在以下两个方面:一方面,填充后明文长度变长,对应的密文长度也变长了;另一方面,某些填充方式会在明文中加入伪随机信息,将给定的明文消息加密为不同的密文。选择不填充只是会默认补0而已。

为什么需要知道填充?

关于这个,对于AES来说意义不大。对应RSA 来说,这个就决定了明文的长度。
因为AES一般都是多次的,但是RSA不一定希望多次,毕竟计算量太大。
RSA 一次加密的明文长度理论上是:密钥长度 128 bytes/1024 bi(keyLen/8)。所以,会因为填充模式的要求,明文长度出现一定的限制。
另外 ,RSA OEAP的填充模式,在各个语言上实现有点不一样(Android keyStore和Java也不一样)。所以,如果一定要选择oeap填充,除非明确两方实现相同,不然最好自己处理。

填充

AES填充

AES 的CTR和GCM不能填充。首先这两种模式下,明文不参加密钥运算,只是参与最后的异或,所以对明文长度没有要求。

本文只讨论几种比较常记的填充
pkcs5和pkcs7.
这两种对于AES 没有区别,规则就是:
加密:
数据长度%16=n。
n>0
数据 n个n。
n==0;
数据 16个16.
解密:
len=data.length
n= data[len-1]
然后倒序便利n个,必须都是等于n,证明是正常填充,否则就是无填充。但是不绝对,如果原始数据刚好符合,就会造成数据丢失,所以必须协商清楚,不能根据数据处理。

RSA 填充

RSA android里面最大加密长度: keyLen/8,但是极限长度的情况下,数据需要比Modulus要小,不然也是会报错:DATA_TOO_LARGE_FOR_MODULUS。

if (BN_ucmp(f, rsa->n) >= 0) {// usually the padding functions would catch thisOPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);goto err;}

1,NOPADDING
生成一个长度固定的keyLen/8,从尾部开始往前拷贝原数据进去,其他地方默认就是0.这种模式,计算结果固定,再次因为前面都是0,无法跟原始数据的0区分开,不推荐这种模式。而且这种模式要注意原数据可能会比Modulus大,造成加密失败。

2,RSA_PKCS1_PADDING
RSA_PKCS1_PADDING即PKCS#1 v1.5,属于PKCS#1的一个早期版本。在该填充模式下,如果明文长度不够K字节,加密的时候会在明文中随机填充一些数据,结果是相同的明文每次加密后的密文都不一样。这个规则也是固定填充,数据都是固定的。

a.生成长度为k-mLen-3的字节串PS包含随机生成的非零的伪随机数。PS的长度最小为8个字节。
b.级联PS,消息M和其它的填充组成长度为k的消息EM
EM = 0x00 || 0x02 || PS || 0x00 || M

这种模式下 ,明文最长k-11(比如128长度就是117)。

3.OEAP

PKCS#1 v2.1: RSA密码学规范中关于 OAEP的模式的讲解如下:

RSAES-OAEP-ENCRYPT  (( n,  e),  M, L )
可选:  Hash  哈希函数(hLen代表哈希函数的输出字节数)
MGF  掩码生成函数
输入:
(n,e)  输入的RSA公钥(k代表RSA模数n的字节长度)
M  待加密的数据, 一个长度为mLen的字节串,并且mLen<=k-2hLen-2
L  可选的和消息关联的标签;如果L没有提供,默认的值是空串
输出:
C  加密输出,长度为k的字节串
错误:  “消息太长”;“标签太长”
假设:  RSA公钥(n,e)是有效的。
操作:
1.长度检查
a.如果L的长度超过了哈希函数的输入限制(SHA-1是2^61-1字节),输出"标签太长“并中止。
b.如果mLen>k-2hLen-2,输出“消息太长”并中止。
2.EME-OAEP编码
a.如果标签L没有提供,使得L为空串。使得lHash=Hash(L),一个长度为hLen的字节串。
b.生成一个字节串PS,由k-mLen-2hLen-2个字节零组成,PS的长度有可能是0。
c.连接lHash,PS,一个单字节值为0x01和消息M,形成一个长度为k-hLen-1的字节串: DB = lHash || PS || 0x01 || M
d.生成一个长度为hLen的随机字节串种子seed。
e.使得 dbMask = MGF(seed, k-hLen-1)
f.使得 maskedDB = DB ⊕ dbMask.
g.使得 seedMask = MGF(maskedDB, hLen)
h.使得 maskedSeed = seed ⊕ seedMask
i.级联值为0x00的单字节,maskedSeed,和maskedDB形成长度为k的消息EM: EM = 0x00 || maskedSeed || maskedDB

这种模式下,每次填充都是随机。明文长度限制,与选择的hash算法相关。
关于这种模式需要说明的:L。label部分,算法要求,会参与hash 计算,但是在Android keystore hash的L固定是空串,而且不允许修改。与其他语言协作的时候注意。
另外:mgf里面的hash算法其实可以与外层hash算法不一样,只要两边协商就行。注意这里有个点,如果是go的oeap填充,mgf1里面的hash函数要和外面的hash一致。所以一般都使用一样的hash。
贴一些工具代码:

import java.security.MessageDigest;/*** 掩模生成函数* mask generator function, as described in PKCS1v2.*/
public class MGF1
{private MessageDigest digest;/*** Create a version of MGF1 for the given digest.** @param digest*            digest to use as the basis of the function.*/public MGF1(MessageDigest digest){this.digest = digest;}/*** int to octet string.*/private void I2OSP(int i, byte[] sp){sp[0] = (byte) (i >>> 24);sp[1] = (byte) (i >>> 16);sp[2] = (byte) (i >>> 8);sp[3] = (byte) (i >>> 0);}/*** Generate the mask.** @param seed*            source of input bytes for initial digest state* @param length*            length of mask to generate** @return a byte array containing a MGF1 generated mask*/public byte[]generateMask(byte[] seed, int length){byte[] mask = new byte[length];byte[] C = new byte[4];int counter = 0;int hLen = digest.getDigestLength();digest.reset();while (counter < (length / hLen)){I2OSP(counter, C);digest.update(seed);digest.update(C);//update 就是把之前的跟现在的连接在一起System.arraycopy(digest.digest(), 0, mask, counter * hLen, hLen);counter++;}if ((counter * hLen) < length){I2OSP(counter, C);digest.update(seed);digest.update(C);System.arraycopy(digest.digest(), 0, mask, counter * hLen,mask.length - (counter * hLen));}return mask;}
}import android.support.annotation.IntDef;
import android.support.annotation.StringDef;
import android.text.TextUtils;import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;/*** @author ricardo* @date 2020/10/28.* description:*/
public class OAEPUtils {/*** @hide*/@IntDef(flag = true, value = {BLOCK_SIZE_2048,BLOCK_SIZE_4096})@Retention(RetentionPolicy.SOURCE)public @interface BlockSize {}public static final int BLOCK_SIZE_2048 = 2048 / 8;public static final int BLOCK_SIZE_4096 = 4096 / 8;/*** @hide*/@StringDef(value = {SHA_1,SHA_224,SHA_256,SHA_384,SHA_512})@Retention(RetentionPolicy.SOURCE)public @interface HashName {}public static final String SHA_1 = "SHA-1";public static final String SHA_224 = "SHA-224";public static final String SHA_256 = "SHA-256";public static final String SHA_384 = "SHA-384";public static final String SHA_512 = "SHA-512";public static byte[] rsaOAEPMGF1SHA1PaddingEMEncode(byte[] sourceData, @HashName String hashName, String label, @BlockSize int blockSize) throws Exception {byte[] EM = null;if (sourceData == null || sourceData.length == 0) {return sourceData;}if (blockSize != BLOCK_SIZE_2048 || blockSize != BLOCK_SIZE_4096) {throw new Exception("block size error");}byte[] lHash = SHAUtils.encrypt(TextUtils.isEmpty(label) ? "" : label, hashName);if (lHash == null) {throw new Exception("hash error");}if (blockSize - 2 * lHash.length - 2 < sourceData.length) {throw new Exception(" data block size error");}byte[] ps = new byte[blockSize- sourceData.length - 2 * lHash.length - 2];for (int i = 0; i < ps.length; i++) {ps[i] = 0;}byte[] DB = new byte[blockSize- lHash.length - 1];System.arraycopy(lHash, 0, DB, 0, lHash.length);System.arraycopy(ps, 0, DB, lHash.length, ps.length);DB[lHash.length + ps.length] = 1;System.arraycopy(sourceData, 0, DB, lHash.length + ps.length + 1, sourceData.length);byte[] seed = SecureRandom.getSeed(lHash.length);MGF1 mgf1 = new MGF1(MessageDigest.getInstance(SHA_1));byte[] dbMask = mgf1.generateMask(seed, blockSize - lHash.length - 1);// DB和dbMask做异或运算生成maskedDBbyte[] maskedDB = new BigInteger(DB).xor(new BigInteger(dbMask)).toByteArray();byte[] seedMask = mgf1.generateMask(maskedDB, lHash.length);// seed和seedMask做异或运算生成maskedSeedbyte[] maskedSeed = new BigInteger(seed).xor(new BigInteger(seedMask)).toByteArray();EM = new byte[blockSize];EM[0] = 0;System.arraycopy(maskedSeed, 0, EM, 1, maskedSeed.length);System.arraycopy(maskedDB, 0, EM, maskedSeed.length + 1,maskedDB.length);return EM;}public static byte[] rsaOAEPMGF1SHA1PaddingEMDecode(byte[] EM, @HashName String hashName, String label, @BlockSize int blockSize) throws Exception {byte[] sourceData = null;if (EM == null || EM.length == 0 || EM.length != blockSize) {return sourceData;}if (blockSize != BLOCK_SIZE_2048 || blockSize != BLOCK_SIZE_4096) {throw new Exception("block size error");}byte[] lHash = SHAUtils.encrypt(TextUtils.isEmpty(label) ? "" : label, hashName);if (lHash == null) {throw new Exception("hash error");}byte[] maskSeed = Arrays.copyOfRange(EM, 1, lHash.length + 1);byte[] maskDB = Arrays.copyOfRange(EM, lHash.length + 1, EM.length);MGF1 mgf1 = new MGF1(MessageDigest.getInstance(SHA_1));byte[] seedMask = mgf1.generateMask(maskDB, lHash.length);byte[] seed = new BigInteger(maskSeed).xor(new BigInteger(seedMask)).toByteArray();byte[] dbMask = mgf1.generateMask(seed, blockSize - lHash.length - 1);byte[] DB = new BigInteger(maskDB).xor(new BigInteger(dbMask)).toByteArray();int index = -1;for (int k = 0; k < lHash.length; k++) {if (lHash[k] != DB[k]) {throw new Exception("hash error");}}for (int j = lHash.length; j < DB.length; j++) {if (DB[j] == 1) {index = j + 1;break;}}sourceData = Arrays.copyOfRange(DB, index, DB.length);return sourceData;}}
  1. RSA-PSS
    与上面的基本类似,主要是用于签名的。因为会对原文有再hash操作,所以不能用于加密。

加密填充AES和RSA相关推荐

  1. 常见加密工具类Base64、DES、AES、RSA、MD5汇总

    文章目录 引言 1.Base64加密 2.DES加密 3.AES加密 4.RSA加密 5.MD5加密 引言 项目中经常会用到Base64.DES.AES.RSA.MD5几种加解密方式,每次都要去网上搜 ...

  2. AES与RSA混合加密完整实例

    前段时间看到一篇文章讲如何保证API调用时数据的安全性(传送门:https://blog.csdn.net/ityouknow/article/details/80603617),文中讲到利用RSA来 ...

  3. 常用的加密有哪些?在Java中如何实现?(MD5、AES、RSA)

    参考: https://blog.csdn.net/qq_41570658/article/details/107694782 https://blog.csdn.net/qq_30054961/ar ...

  4. 对称加密、非对称加密、DES、AES、RSA、OpenSSL、数字签名、防篡改

    本公众号分享的所有技术仅用于学习交流,请勿用于其他非法活动,如果错漏,欢迎留言指正 <加密与解密>第4版 加解密 安全领域的重要分支和基础设施 互联网重要数据的传输需要加解密 TCP/IP ...

  5. AES和RSA加密解密(前后台交互)

    一.AES和RSA简单介绍 AES:对称加解密,加密解密使用同一个秘钥. RSA:非对称加解密,使用公钥加密数据,只有对应的私钥才能解密,加密方和解密方各自保存秘钥对中的一个.(这里推荐一个RSA密钥 ...

  6. 常用加密解密算法【RSA、AES、DES、MD5】介绍和使用

    为了防止我们的数据泄露,我们往往会对数据进行加密,特别是敏感数据,我们要求的安全性更高.下面将介绍几种常用的加密算法使用.这些算法的加密对象都是基于二进制数据,如果要加密字符串就使用统一编码(如:ut ...

  7. [crypto]-52-python3中rsa(签名验签加密解密)aes(ecb cbc ctr)hmac的使用,以及unittest测试用

    环境: 在ubuntu14.04下,记得安装:sudo pip3 install pycrypto 代码示例1: =========================== import base64 f ...

  8. WebSocket数据加密——AES与RSA混合加密

    前言 之前在写"一套简单的web即时通讯",写到第三版的时候没什么思路,正好微信公众号看到一篇讲API交互加密,于是就自己搞了一套AES与RSA混合加密,无意中产生应用在WebSo ...

  9. angular和JAVA实现aes、rsa加密解密,前后端交互,前端加解密和后端JAVA加解密实现

    今天实现了下AES和RSA加密解密,主要的功能是对前后端交互数据进行加密解密,为什么要用到两个算法呢,首先RSA默认的话加密长度是有限的100多个byte吧大约,并且需要公钥私钥,而AES加密没有限制 ...

最新文章

  1. andorid简单计算器java源码_Android之一个简单计算器源代码
  2. node python 速度_Java,Node,Python 运行速度比较
  3. python列表索引超出范围 等于啥_python - IndexError:列表分配索引超出范围,Python
  4. 怎么把4399小游戏的代码_25行代码带你爬取4399小游戏数据,看下童年的游戏是否还在...
  5. java质数判断程序_java判断一个数是否为素数/质数
  6. 荣耀推出MOSCHINO联名款荣耀20 PRO手机 售价3799元
  7. 七个迹象说明你可能受到APT 攻击
  8. 织梦tag标签按照设定的栏目id获取相应的内容或自动获取相应栏目tag
  9. 类与对象 - PHP手册笔记
  10. pytorch中torch.max和F.softmax函数的维度解释
  11. OEM 10g R5 online documentation
  12. 163个人邮箱注册申请流程,公司邮箱怎么注册?
  13. application.html.erb
  14. hello树先生经典台词
  15. 基于菜鸟教程重学HTML5部分
  16. 基于Autojs的66联盟快手版辅助
  17. 微软数据科学家助理(Data Scientist Associate)认证考试通过经验分享(DP-100)
  18. pythonjam怎么使用_Jam 使用说明
  19. 程序员注意了!应聘阿里P7岗,面试都过了,结果栽在背景调查!
  20. html点击添加购物车的,如何根据给定的html点击添加到购物车按钮?

热门文章

  1. 我们TMD学TMD计算机的不是TMD万能的!
  2. LocalDate、LocalDateTime互转String
  3. php 获取凌晨的时间,PHP 获取当天 凌晨 时间戳常用代码
  4. js中的onclick事件在ul获取li时点击两次才会执行的原因
  5. cobra mysql_Cobra安装和简单应用
  6. 万合通盈是真的吗:拼多多优化关键词做法
  7. Linux基础(3) Vim编辑器与Shell命令脚本
  8. Win10系统激活工具失败错误0xC004C003解决方法
  9. 短视频抖音拍摄网红达人运营SOP脚本计划表方案模板
  10. 计算机端口状态说明和解决占用的方法