AES(对称加密)和RSA(非对称加密)使用详情
一.AES(对称加密)
1.1.AES加密填充方式
待加密的明文以16字节分组进行加密,如果数据字节长度不是16的倍数,最后的一组则需要在有效数据后面进行填充,使得数据长度变为16字节,AES填充方式分为NoPadding、PKCS5(PKCS7)、ISO10126、Zeros。
NoPadding:不填充,那就只能加密长度为16倍数的数据,一般不使用;
Zeros:补0,如果原数据长度恰好是16的倍数,也要补16个0;
ISO10126:最后一个字节是填充的字节数(包括最后一字节),其他全部填随机数
1 2 3 4 5 6 7 8 9 10 – x x x x x 6
填充6个字节
PKCS5(PKCS7):应用比较多,最后一组缺几个字节就填充几
1 2 3 4 5 6 7 8 9 10 – 6 6 6 6 6 6
前面10个字节,缺6字节才能为一组,填充6个6;如果恰好是16个字节,则填充16个16.
二.RSA(非对称加密)
首先生成两个密钥,一个公钥,一个私钥,前者加密,后者解密,客户端和服务器各执一份.一般为了安全,私钥是不会给前端暴露出来 的,只会通过私钥生成一个公开的公钥提供给外部对数据进行加密。将加密后的数据传给后端,后端使用私钥解密.当客户端向服务器发送数据的时候,先用公钥加密,再有私钥加签,到了服务器一端,用公钥验签,用私钥解密,然后再往下走.加密是为了安全,加签是为了防止冒充APP 客户端进行请求,导致服务器的瘫痪.
三.前后端常用的加密方式
3.1.对称加密:指加密和解密使用相同密钥的加密算法,速度较快(包括DES算法,3DES算法,RC5算法,AES算法等);
3.2.非对称对称加密:指加密和解密使用不同密钥的加密算法,速度较慢(包括RSA等);
3.3.哈希算法:简单来说就是一种将数据通过算法变成不可逆的数据(包括:MD5、HMAC等);
3.4.数字签名:是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法
四.AES和RSA结合使用流程:
客户端签名
4.1.通讯时,客户端先将数据进行签名,签名可参照微信支付将请求参数按照参数名ASCII码从小到大排序(字典升序进行排列),使用URL键值对的格式(即key1=value1&key2=value2…)进行拼接成字符串。然后用MD5进行加密得到sign1。最后将签名sign1放在请求头中(温馨提示:请求参数中可加入时间戳和随机字符串,可防止重放攻击);
客户端加密
4.2.服务器先生成一对RSA的公钥和私钥,然后私钥留在服务器,公钥返回给我们客户端;
4.3.其次客户端随机生成一个字符串作为AES加密的key1(16位)==>(用AES加密算法来加密与服务器传输的主要内容);
4.4.最后 客户端 使用从服务器获取的RSA 公钥 将自己本地随机生成的AES的key1进行加密,将加密后的数据放入到请求头中传递给服务器;
4.5.客户端将请求参数转换为json字符串后,使用本地随机生成的AES加密的key1进行AES加密,然后将加密后的字符串放在请求体中传递给服务器;
服务器解密
4.6.服务器 端先用RSA的 私钥 将AES的key1进行解密(因为AES是使用RSA的公钥加密过的,所以需要使用对应的私钥进行解密),然后使用这个key1来解密传输的主要内容;
服务器签名比对(确认数据是否被篡改过)
4.7. 然后服务器运用客户端使用的签名方法将主要内容进行签名得到sign,然后跟sign1进行对比。如果相同即数据没有被篡改
4.8.第6步确认无误后,服务器将要返回给客户端的数据进行签名得到sign2
服务器加密
4.9.然后服务器随机生成一个字符串作为AES加密的key2,用AES加密算法来加密需要返回的数据内容;
4.10.其次 服务器 再使用RSA的 私钥 将AES的key2进行加密,与AES加密后的内容和sign2一同返回给客户端;
客户端解密
4.11.客户端 收到服务器返回的数据后先用RSA的 公钥 将AES的key2进行解密,然后使用这个key2来解密返回的主要内容;
4.12.最后将主要内容进行签名得到sign,与sign2进行对比。如果一致则表示数据无误。可进行后续操作
五.代码实例:
+ (NSURLSessionTask *)requestPostEncryptionWithURL:(NSString *)URL parameters:(NSDictionary *)parameter networkRequestGraceTimeType:(NetworkRequestGraceTimeType)type success:(PPRequestSuccess)success failure:(PPRequestFailure)failure
{
ZHHud * hud = [DFHTTPRequest hud:type];
AFHTTPSessionManager * manager = [DFHTTPRequest sharedZHNetWorking].manager;
/**
签名
*/
//获取当前的时间戳
NSString*timeStamp=[NSString df_getNowTimeTimestamp];
//字典按照升序进行排列
NSString*sign=[self accordingSortDic:parameter];
//将拼接起来的字符串后面追加时间戳
NSString*signComponentTimeStamp=[sign stringByAppendingFormat:@"_timestamp%@",timeStamp];
//字符串的首段和尾部追加appkey
NSString*lastStr=[NSString stringWithFormat:@"%@%@%@",encryption_Appkey,signComponentTimeStamp,encryption_Appkey];
//字符串使用MD5进行加密
NSString*MD5Str=[NSString md532BitLower:lastStr];
/**
加密
*/
//1.先随机生成一个16位的AES key
NSString*AES_Key=[self ret32bitString];
//从服务器获取RSA的公钥==>使用RSA的公钥对AES的公钥进行加密并放在请求头中传递给服务器
NSString*RSA_Public_Key=[[NSUserDefaults standardUserDefaults]objectForKey:@"publicKey"];
//2.使用RSA进行加密(放入到请求头里面)
NSString*RSA_Str=[RSAEncryptor encryptString:AES_Key publicKey:RSA_Public_Key];//加密后的AES公钥
//使用RSA公钥加密后的AES Key
[manager.requestSerializer setValue:RSA_Str forHTTPHeaderField:@"_secret"];
//当前时间戳
[manager.requestSerializer setValue:timeStamp forHTTPHeaderField:@"_timestamp"];
//签名
[manager.requestSerializer setValue:MD5Str forHTTPHeaderField:@"_sign"];
NSString*token=[DFSaveDataClass df_getLocalData:@"token"];
NSString*newToken=[NSString stringWithFormat:@"bearer %@",token];
[manager.requestSerializer setValue:newToken forHTTPHeaderField:@"Authorization"];
//请求体使用AES加密后传给给服务器
NSString*jsonStr=[NSString df_dicConversionWithJsonStringData:parameter];//将请求体转化为json字符串
NSString*dicEncryption=[AESCrypt AES128Encrypt:jsonStr key:AES_Key];
[manager.requestSerializer setValue:[NSURL URLWithString:URL].host forHTTPHeaderField:@"host"];
return [manager POST:URL parameters:dicEncryption progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
[hud hideAnimated:YES];
if (responseObject)
{
//获取返回后的字符串
NSString *result = [[NSString alloc]initWithData:responseObject encoding:NSUTF8StringEncoding];
if ([task.response isKindOfClass:[NSHTTPURLResponse class]])
{
NSHTTPURLResponse *r = (NSHTTPURLResponse *)task.response;
//取出所有的请求头
NSDictionary*dict=[r allHeaderFields];
//取出使用RSA加密后的AES 的key
NSString*secretStr=dict[@"_secret"];
NSDictionary*lastDic=nil;
//对加密后的AES key进行解密
NSString*decryptionStr=[RSA decryptString:secretStr publicKey:RSA_Public_Key];
//将返回的结果使用解密后的AES Key进行解密
NSString*responseStr=[AESCrypt AES128Decrypt:result key:decryptionStr];
//将JSON字符串转化为字典
lastDic=[NSDictionary df_JsonStringConversionWithDic:responseStr];
}
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
failure(error);
}];
}
//获取当前时间戳
+(NSString*)df_getNowTimeTimestamp
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
[formatter setDateStyle:NSDateFormatterMediumStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss SSS"]; // ----------设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制
//设置时区,这个对于时间的处理有时很重要
NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"Asia/Shanghai"];
[formatter setTimeZone:timeZone];
NSDate *datenow = [NSDate date];//现在时间,你可以输出来看下是什么格式
NSString *timeSp = [NSString stringWithFormat:@"%ld", (long)[datenow timeIntervalSince1970]*1000];
return timeSp;
}
//字典按照升序进行排列
+(NSString*)accordingSortDic:(NSDictionary*)dic
{
/**
将字典按照升序进行排列(具体分为下面五个步骤)
*/
//1.取出所有的key
NSArray *keyArray = [dic allKeys];
//2.将key按照升序进行排列
NSArray *sortArray = [keyArray sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
return [obj1 compare:obj2 options:NSNumericSearch];
}];
//3.根据排序好的key,取出对应的value值
NSMutableArray *valueArray = [NSMutableArray array];
NSMutableArray*sortKeyArray=[NSMutableArray array];
for (NSString*sortString in sortArray)
{
id value=[dic objectForKey:sortString];
if ([value isKindOfClass:[NSString class]]||[value isKindOfClass:[NSNumber class]])
{
NSString*valueStr=[NSString stringWithFormat:@"%@",value];
//[[NSString stringWithFormat:@"%@",value] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if (valueStr.length>0)
{
[sortKeyArray addObject:sortString];
[valueArray addObject:valueStr];
}
}
}
//4.现在我们有两个数组,分别对应升序排序的key和value,所以再创建一个keyValue的数组来存储每一个key和value的格式。
NSMutableArray *signArray = [NSMutableArray array];
for (int i = 0; i < sortKeyArray.count; i++) {
NSString *keyValueStr = [NSString stringWithFormat:@"%@%@",sortKeyArray[i],valueArray[i]];
[signArray addObject:keyValueStr];
}
//5.将字符串进行拼接起来
NSString *sign =[signArray componentsJoinedByString:@""];
return sign;
}
//随机生成一个32位字符串
+(NSString*)ret32bitString
{
char data[32];
for (int x=0; x <16; data[x++] = (char)('A' + (arc4random_uniform(26))));
return [[NSString alloc] initWithBytes:data length:16 encoding:NSUTF8StringEncoding];
}
更多推荐
所有评论(0)