关于AES(ECB)加密解密&Base64编码解码

873 阅读3分钟

加密类型

对称加密

对称加密又称公开密钥加密,加密和解密都会用到同一个密钥,如果密钥被攻击者获得,此时加密就失去了意义。常见的对称加密算法有DES、3DES、AES(本文重点)、Blowfish、IDEA、RC5、RC6。

非对称加密

非对称加密又称共享密钥加密,使用一对非对称的密钥,一把叫做私有密钥,另一把叫做公有密钥;公钥加密只能用私钥来解密,私钥加密只能用公钥来解密。常见的公钥加密算法有:RSA、ElGamal、背包算法、Rabin(RSA的特例)、迪菲-赫尔曼密钥交换协议中的公钥加密算法、椭圆曲线加密算法)。

AES

加密流程 20200119105033366.png 图片来至于网络

AES加密模式

  1. ECB模式(Electronic Code Book Mode)

  2. CBC模式(Cipher Block Chaining Mode)

  3. CFB模式(Cipher Feedback Mode)

  4. OFB模式(Output Feedback Mode)

  5. CTR模式(Counter Mode)

  6. PCBC模式(Propagating Cipher Block Chaining Mode)

除ECB模式外,其余都需要初始向量 也就是偏移量 这里主要说一下ECB模式。

ECB模式(Electronic Code Book Mode)

ECB模式是最早采用和最简单的模式,它将加密的数据分成若干组,每组的大小跟加密密钥长度相同,然后每组都用相同的密钥进行加密。

优点:有利于并行计算;误差不会累计(互不干扰)。

缺点:可能对明文进行主动攻击。

无论什么语言系统,AES的算法总是相同的, 因此导致结果不一致的原因在于 加密设置的参数不一致 。于是先来看看在两个平台使用AES加密时需要统一的几个参数。

  • 密钥长度(Key Size)
  • 加密模式(Cipher Mode)
  • 填充方式(Padding)
  • 初始向量(Initialization Vector)

填充方式

由于块加密只能对特定长度的数据块进行加密,因此CBC、ECB模式需要在最后一数据块加密前进行数据填充。(CFB,OFB和CTR模式由于与key进行加密操作的是上一块加密后的密文,因此不需要对最后一段明文进行填充)

在iOS SDK中提供了PKCS7Padding,而JDK则提供了PKCS5Padding。原则上PKCS5Padding限制了填充的Block Size为8 bytes,而Java实际上当块大于该值时,其PKCS5Padding与PKCS7Padding是相等的:每需要填充χ个字节,填充的值就是χ。

AES 加密解密代码实现

iOS 使用 RNCryptor 的OC端库。

代码实现很简单

对字符串进行AES加密后在进行base64编码

//字符串转data
NSData *stringData = [[separatedArray lastObject] dataUsingEncoding:NSUTF8StringEncoding];
//进行AES加密
NSData *encryptData = [RNEncryptor encryptData:stringData withSettings:kRNCryptorAES256Settings password:key error:nil];
//进行base64编码
encryptString = [GTMBase64 stringByWebSafeEncodingData:encryptData padded:YES];

base64字符串进行base64解码在AES解密

//字符串转data
NSData *encryptedData = [GTMBase64 decodeData:[tempEnStr dataUsingEncoding:NSUTF8StringEncoding]];
//AES解密
NSData *decryptedData = [RNDecryptor decryptData:encryptedData
                                    withPassword:key
                                           error:nil];
//data转String
NSString* decodeString = [[NSString alloc] initWithData:decryptedData 
encoding:NSUTF8StringEncoding];

Base64编码

普通的 Base64编码,得到的字符串可能存在 +/=号,比如+号,如果放在链接里请求后端接收的时候就变成了空格。所以需要使用安全的Base64编码, 可以上面使用了三方库 GTMBase64,或者自己转。方法如下:

// base64 url 编码
- (NSString *)base64UrlEncoder:(NSString *)str {
    NSData *data = [[str dataUsingEncoding:NSUTF8StringEncoding] base64EncodedDataWithOptions:0];
    NSMutableString *base64Str = [[NSMutableString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    base64Str = (NSMutableString * )[base64Str stringByReplacingOccurrencesOfString:@"+" withString:@"-"];
    base64Str = (NSMutableString * )[base64Str stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
    base64Str = (NSMutableString * )[base64Str stringByReplacingOccurrencesOfString:@"=" withString:@""];
    return base64Str;
}
// base64 url 解码
- (NSString *)base64UrlDecoder:(NSString *)str {
    NSMutableString *base64Str = [[NSMutableString alloc] initWithString:str];
    base64Str = (NSMutableString * )[base64Str stringByReplacingOccurrencesOfString:@"-" withString:@"+"];
    base64Str = (NSMutableString * )[base64Str stringByReplacingOccurrencesOfString:@"_" withString:@"/"];
    NSInteger mod4 = base64Str.length % 4;
    if (mod4) {
        [base64Str appendString:[@"====" substringToIndex:(4 - mod4)]];
    }
    NSData *data = [[NSData alloc] initWithBase64EncodedString:base64Str options:0];
    return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}