(iOS)Base64加密和DES加密、以及JAVA和iOS中DES加密统一性问题
我们在项目中为了安全方面的考虑,通常情况下会选择一种加密方式对需要安全性的文本进行加密,而Base64加密和DES64加密是常用的加密算法。我记得我在前一个项目中使用的就是这两种加密算法的结合:Base64 + DES加密。当然这需要移动端和后台服务器做一个统一。
1、Base64加解密
值得一提的是:apple提供了基础的Base64加解密算法。这样我们就可以直接使用方法去实现Base64加解密。先看一下apple都提供了哪些方法:
@interface NSData (NSDataBase64Encoding)
/* Create an NSData from a Base-64 encoded NSString using the given options. By default, returns nil when the input is not recognized as valid Base-64.
*/
- (nullable instancetype)initWithBase64EncodedString:(NSString *)base64String options:(NSDataBase64DecodingOptions)options NS_AVAILABLE(10_9, 7_0);
/* Create a Base-64 encoded NSString from the receiver's contents using the given options.
*/
- (NSString *)base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)options NS_AVAILABLE(10_9, 7_0);
/* Create an NSData from a Base-64, UTF-8 encoded NSData. By default, returns nil when the input is not recognized as valid Base-64.
*/
- (nullable instancetype)initWithBase64EncodedData:(NSData *)base64Data options:(NSDataBase64DecodingOptions)options NS_AVAILABLE(10_9, 7_0);
/* Create a Base-64, UTF-8 encoded NSData from the receiver's contents using the given options.
*/
- (NSData *)base64EncodedDataWithOptions:(NSDataBase64EncodingOptions)options NS_AVAILABLE(10_9, 7_0);
@end
@interface NSData (NSDeprecated)
/* These methods first appeared in NSData.h on OS X 10.9 and iOS 7.0.
They are deprecated in the same releases in favor of the methods in the NSDataBase64Encoding category.
However, these methods have existed for several releases, so they may be used for applications targeting releases prior to OS X 10.9 and iOS 7.0.
*/
- (nullable id)initWithBase64Encoding:(NSString *)base64String NS_DEPRECATED(10_6, 10_9, 4_0, 7_0);
- (NSString *)base64Encoding NS_DEPRECATED(10_6, 10_9, 4_0, 7_0);
@end
我们先创建一个NSData,再去一条一条的分析以上的方法
NSData *data = [@"Base64 encoding string" dataUsingEncoding:NSUTF8StringEncoding];
(1)创建一个Data(从一个Base64编码字符串使用给出的设置创建一个Data)
NSData *dataFromBase64String = [[NSData alloc]initWithBase64EncodedString:base64String options:0];
(2)创建一个Base64编码字符串(从接受者内容创建)
NSString *base64String = [data base64EncodedStringWithOptions:0];
(3)创建一个Data(从一个Base64、UTF-8编码的Data创建)
NSData *base64AndUTFData = [base64Data initWithBase64EncodedData:base64Data options:0];
(4)创建一个Base64、UTF-8编码的Data(从接受者内容创建)
NSData *base64Data = [data base64EncodedDataWithOptions:0];
当然,我们最后也可以将Data转化成String类型。
NSString *base64Decoded = [[NSString alloc]initWithData:dataFromBase64String encoding:NSUTF8StringEncoding];
以上是Base64加解密方法。下面我们看看DES的加解密。
2、DES加解密
我们都知道安卓和后台可以使用统一的代码去解决这个问题,这也是java的优势之一吧。这里我会附一段java的代码。主要是为了下面说明java和iOS端实现中需要注意的地方(也是不同点)。
为了使说明更方便一些,我们先看一下java的DES加密方法:
/**
* EDS加密
* @param originalStr
* @return
*/
public static String Encrypt(String originalStr) {
String result = null;
byte[] tmpOriginalStr = null;
try {
if (!Tools.isEmpty(originalStr)) {
tmpOriginalStr = originalStr.getBytes("utf-8");
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
DESKeySpec dks = new DESKeySpec(KEY);
SecretKey secretKey = keyFactory.generateSecret(dks);
IvParameterSpec param = new IvParameterSpec(IV);
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey,param);
byte[] tmpEncypt = cipher.doFinal(tmpOriginalStr);
if (tmpEncypt != null) {
result = Base64.encodeToString(tmpEncypt,Base64.NO_WRAP);
}
}
} catch (Exception e) {
Log.e("Erro",e.getMessage());
}
return result;
}
我们可以看出Java针对DES加密算法默认使用的是CBC模式,对齐方式采用的是PKCS5Padding。
而OC中的加密并不是java中的形式实现加密的,接下来我们看一看OC中实现DES加密的代码:
#pragma mark- 加密算法
+(NSString *) encryptUseDES:(NSString *)plainText //key:(NSString *)key
{
NSString *ciphertext = nil;
NSData *textData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
NSUInteger dataLength = [textData length];
unsigned char buffer[1024 * 5];
memset(buffer, 0, sizeof(char));
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES,
kCCOptionPKCS7Padding,
[key UTF8String], kCCKeySizeDES,
[iv UTF8String],
[textData bytes], dataLength,
buffer, 1024,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
ciphertext = [data base64EncodedStringWithOptions:0];
}
return ciphertext;
}
先说一下代码中红色里面的绿色部分:key和iv 。key:是DES加密的公钥。而iv:是初始化的矢量。两者都是DES加密的关键参数。这个是必须要和Android、后台有个统一的。
我们可以看出OC使用的是kCCOptionPKCS7Padding对齐方式。而java中很明确的指出使用的是PKCS5Padding。接下来我们点进去看看OC中给出的对齐选择有哪些,我直接以代码的形式展示出来:
enum {
/* options for block ciphers */
kCCOptionPKCS7Padding = 0x0001,
kCCOptionECBMode = 0x0002
/* stream ciphers currently have no options */
};
OC中给出的是 kCCOptionECBMode 和 kCCOptionPKCS7Padding 这两种选择。那么,问题现在出现了。java中的DES加密算法有很多种,例如:ECB,CBC,OFB,CFB等。
java 和 OC的DES加密怎样才能实现一致性呢?(这也是我在项目中遇到的问题)。
查阅很多资料,再加上自己的很多次测试,得出的结果如下:
在JAVA中使用这种方式加密:"DES/CBC/PKCS5Padding" 对应的Object-C的是 kCCOptionPKCS7Padding
而使用 "DES/ECB/PKCS5Padding" 对应的Object-C的是 kCCOptionPKCS7Padding | kCCOptionECBMod
觉得似乎OC目前只支持这两种方式的加密。当然结果是已经得到验证的。
注意:md5加密(iOS SDK中自带了CommonCrypto)出现警告⚠️ 。
解决方法添加:引入函数定义的头文件
#import <CommonCrypto/CommonDigest.h>
其他链接:
iOS 7: Base64 Encode and Decode NSData and NSString Objects
这里附上demo:https://github.com/Wheat-Qin/Base64-DES