您的位置:首页 > 移动开发 > IOS开发

iOS通信加密

2015-12-08 20:54 411 查看
Base64加密算法

Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,可用于在HTTP环境下传递较长的标识信息。它的优点是算法效率高,编码出来的结果比较简短,同时也具有不可读性。

Base64要求把每三个8Bit的字节按照每6Bit一组的长度分割成四组(3*8 = 4*6 = 24),然后给每组6Bit的数据添加两位高位0,组成四个新的8Bit的字节。也就是说,转换后的字符串理论上将要比原来的长1/3。然后将新产生的四个8Bit字节根据转换表映射为ASCII字符,转换表如下所示(最后两个字符的定义在不同的系统中有所不同):

索引对应字符索引对应字符索引对应字符索引对应字符
0A16Q32g48w
1B17R33h49x
2C18S34i50y
3D19T35j51z
4E20U36k520
5F21V37l531
6G22W38m542
7H23X39n553
8I24Y40o564
9J25Z41p575
10K26a42q586
11L27b43r597
12M28c44s608
13N29d45t619
14O30e46u62+
15P31f47v63/
那么如果原文的字节数不是3的倍数,即转换到最后部分时bit数不够6的倍数该怎么办呢?我们规定,当遇到这种情况,不足的bit位使用全0来补足,转换后需要在密文的末尾添加=号来标注。如果原文剩余1字节(即需要补足4位0),那么就在密文末尾添加两个=号,如果原文剩余2字节(即需要补足2位0),则添加一个=号,这就是为什么有些编码后的结果会以=号结束的原因。

下面举一个例子

编码“Man”

「M」的ASCII碼 = 77 = 01001101

「a」的 = 97 = 01100001

「n」的 = 110 = 01101110

将这三个字节拼合,得出一个24位的资料:

010011010110000101101110

现在六个一组的分开并补高位0,得到4个新的字节为:

00010011 00010110 00000101 00101110

对应的十进制值为:

19 22 5 46

对应的ASCII字符为

T W F u

所以“Man”经过Base64加密后的结果为“TWFu”。

解码同理,把 TWFu的二进制位分割,去掉高位0,重组后得到三个8位值,最后得出原码。

下面是一个原码字节数不是三的倍数的例子:

加密“M”

「M」的ASCII碼 = 77 = 01001101

位数不够6的倍数,补0后变为

010011010000

六个一组分开是

010011 010000,结果是TQ

在密文末尾加两个“=”,结果就是“TQ==”。

3DES加密算法

要理解3DES,就必须先搞懂什么是DES。DES是美国一种由来已久的加密标准,它的工作原理是将数据按照8个字节一段进行加密或解密,从而得到一段8个字节的密文或者明文。之后按照顺序将计算所得的数据连在一起即可。这里需要注意的是,由于DES加密解密时要求数据长度必须为8个字节的倍数,因此当数据长度不足时必须先进行数据填充,这里使用的填充算法根据系统的不同可能会略有不同。

DES算法有两种工作模式,ECB(电子密本方式)和CBC(密文分组链接方式),下面具体解释一下这两种工作模式的不同。

DES ECB其实非常简单,就是将数据按照8个字节一段分别进行DES加密或解密(不足8个字节的按照需求先进行数据填充),最后按照顺序将加密或解密后的结果连在一起即可,各段数据之间互不影响。

DES CBC稍微复杂一些,它在每一段加密或解密的过程中都要与前一段的结果做一次异或操作。同时CBC模式定义了一个特殊的8字节key(称为初始化向量),用以和第一段的结果做异或时用。这种机制使得加密的各段数据之间有了联系。

加密步骤如下:

1)首先将数据按照8个字节一组进行分组得到D1D2......Dn(若数据长度不是8字节的整数倍,先进行数据填充)

2)第一组数据D1与初始化向量I异或后的结果进行DES加密得到第一组密文C1

3)第二组数据D2与第一组的加密结果C1异或以后的结果进行DES加密,得到第二组密文C2

4)之后的数据以此类推,得到Cn

5)按顺序连为C1C2C3......Cn即为加密结果。

解密是加密的逆过程,步骤如下:

1)首先将数据按照8个字节一组进行分组得到C1C2C3......Cn

2)将第一组数据进行解密后与初始化向量I进行异或得到第一组明文D1(注意:一定是先解密再异或)

3)将第二组数据C2进行解密后与第一组密文数据进行异或得到第二组数据D2

4)之后依此类推,得到Dn

5)按顺序连为D1D2D3......Dn即为解密结果。

这里注意一点,解密的结果并不一定是我们原来的加密数据,可能还含有你补得位,一定要把补位去掉才是你的原来的数据。

OK,最后我们来说说3DES。3DES又称Triple DES,顾名思义就是三次DES算法。比起最初的DES,3DES更为安全。它是以DES为基本模块,通过组合分组方法设计出的分组加密算法。设Ek()和Dk()代表DES算法的加密和解密过程,k代表DES算法使用的密钥,P代表明文,C代表密文,则3DES加密解密的过程可表示为:

C=Ek3(Dk2(Ek1(P)))

P=Dk1(Ek2(Dk3(C)))

这里可以k1=k3,但不能k1=k2=k3(如果相等的话就成了DES算法了)

3DES with 2 diffrent keys(k1=k3),可以是3DES-CBC,也可以是3DES-ECB,3DES-CBC整个算法的流程和DES-CBC一样,但是在原来的加密或者解密处增加了异或运算的步骤,使用的密钥是16字节长度的密钥,将密钥分成左8字节和右8字节的两部分,即k1=k3=左8字节,k2=右8字节,然后进行加密运算和解密运算。

3DES with 3 different keys,和3DES-CBC的流程完全一样,只是使用的密钥是24字节的,它将密钥分为3段8字节的密钥k1,k2,k3,在3DES加密时依次使用k1、k2、k3,在3DES解密时依次使用k3、k2、k1。

iPhone平台的Base64及3DES实现

实际应用中我们经常需要对一条消息先进行Base64编码,再进行3DES加密,然后才能在网络上传输,因此Base64和3DES的加密解密过程可封装为同一个接口。iPhone的SDK中并没有提供现成的base64及3DES的接口,需要自己写一个函数来实现。Base64用网上的开源GTMBase64库。

3DES加密基本也都是统一的,系统也直接提供了API,基本代码如下

[cpp] view
plaincopy

//3des加解密

+ (NSString*)TripleDES:(NSString*)plainText encryptOrDecrypt:(CCOperation)encryptOrDecrypt

{

const void *vplainText;

size_t plainTextBufferSize;

if (encryptOrDecrypt == kCCDecrypt)//解密

{

NSData *EncryptData = [GTMBase64 decodeData:[plainText dataUsingEncoding:NSUTF8StringEncoding]];

plainTextBufferSize = [EncryptData length];

vplainText = [EncryptData bytes];

}

else //加密

{

NSData* data = [plainText dataUsingEncoding:NSUTF8StringEncoding];

plainTextBufferSize = [data length];

vplainText = (const void *)[data bytes];

}

CCCryptorStatus ccStatus;

uint8_t *bufferPtr = NULL;

size_t bufferPtrSize = 0;

size_t movedBytes = 0;

bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);

bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));

memset((void *)bufferPtr, 0x0, bufferPtrSize);

// memset((void *) iv, 0x0, (size_t) sizeof(iv));

const void *vkey = (const void *) [DESKEY UTF8String];

// NSString *initVec = @"init Vec";

//const void *vinitVec = (const void *) [initVec UTF8String];

// Byte iv[] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF};

ccStatus = CCCrypt(encryptOrDecrypt,

kCCAlgorithm3DES,

kCCOptionPKCS7Padding | kCCOptionECBMode,

vkey,

kCCKeySize3DES,

nil,

vplainText,

plainTextBufferSize,

(void *)bufferPtr,

bufferPtrSize,

&movedBytes);

//if (ccStatus == kCCSuccess) NSLog(@"SUCCESS");

/*else if (ccStatus == kCC ParamError) return @"PARAM ERROR";

else if (ccStatus == kCCBufferTooSmall) return @"BUFFER TOO SMALL";

else if (ccStatus == kCCMemoryFailure) return @"MEMORY FAILURE";

else if (ccStatus == kCCAlignmentError) return @"ALIGNMENT";

else if (ccStatus == kCCDecodeError) return @"DECODE ERROR";

else if (ccStatus == kCCUnimplemented) return @"UNIMPLEMENTED"; */

NSString *result;

if (encryptOrDecrypt == kCCDecrypt)

{

result = [[[NSString alloc] initWithData:[NSData dataWithBytes:(const void *)bufferPtr

length:(NSUInteger)movedBytes]

encoding:NSUTF8StringEncoding]

autorelease];

}

else

{

NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];

result = [GTMBase64 stringByEncodingData:myData];

}

return result;

这个在网上也能搜索到详细代码。

但是要注意到一点:

[cpp] view
plaincopy

CCCrypt(encryptOrDecrypt,

kCCAlgorithm3DES,

kCCOptionPKCS7Padding | kCCOptionECBMode,

vkey,

kCCKeySize3DES,

nil,

vplainText,

plainTextBufferSize,

(void *)bufferPtr,

bufferPtrSize,

&movedBytes);

这个里面的参数可能会根据你服务端使用的对应的3des算法构造时参数的不同而需要自己调整。

比如我在网上看到的这个第三个参数只是用了kCCOptionPKCS7Padding,第六个可选参数用了上面一个自定义的iv。

但是这边根据服务器,这个参数是nil才对应。

这边也附上java端的加解密代码

[java] view
plaincopy

public String encryptThreeDESECB(String src,String key) throws Exception

{

DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));

SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");

SecretKey securekey = keyFactory.generateSecret(dks);

Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");

cipher.init(Cipher.ENCRYPT_MODE, securekey);

byte[] b=cipher.doFinal(src.getBytes());

BASE64Encoder encoder = new BASE64Encoder();

return encoder.encode(b).replaceAll("\r", "").replaceAll("\n", "");

}

//3DESECB解密,key必须是长度大于等于 3*8 = 24 位

public String decryptThreeDESECB(String src,String key) throws Exception

{

//--通过base64,将字符串转成byte数组

BASE64Decoder decoder = new BASE64Decoder();

byte[] bytesrc = decoder.decodeBuffer(src);

//--解密的key

DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));

SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");

SecretKey securekey = keyFactory.generateSecret(dks);

//--Chipher对象解密

Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");

cipher.init(Cipher.DECRYPT_MODE, securekey);

byte[] retByte = cipher.doFinal(bytesrc);

return new String(retByte);

}

内容也很少,这这么点。

然后是key,也就是共用密钥的客户端和服务端都保存一个。

简单从数据传输来说,密文传输了,安全性相对来说提高了不少。

但是如果破解了客户端代码,那么其实密钥也就暴露了。

这对于android上面来说,因为反编译额纯在,安全性不敢恭维,

ios的貌似好一点,因为暂未听说反编译ios的app的。

以上就是一种简单的通信加密方案。

特别需要注意的是:

首先,大家要分清Key(密钥),Data(待操作数据)跟Mode(加密模式)。其中Key必须为8字节(64位),Data需要是8字节(64位)的倍数,这里需要注意了,如果Data不是8字节的倍数,那么我们需要进行数据填充,数据填充使用的算法不一定相同。Mode貌似有许多种,这里只简单的说一下ECB跟CBC模式。

ECB模式:将待处理的数据分成若干块,每块的长度都为8字节(64位),与Key长度相同。然后对每块进行加密或解密,最后将他们连接在一起便是最终的结果。每一块的数据互不干扰。

CBC模式:也需要将待处理的数据分块,但是每一块数据在加密或者解密之前都要与前一块的结果做一次异或操作,因此该模式需要定义一个特殊的8字节Key,用于和第一块数据做异或操作。这个特殊的Key就是通常说的初始化向量。在代码中书写时需要配置iv参数,注意iv参数是对应CBC模式的。这样一来,每一块数据都是有联系的,这是与ECB模式不同的一点。

2. 再来说说3DES操作,也就是进行3次DES操作。设Ek()和Dk()分别代表DES算法的加密和解密过程,k代表DES算法使用的密钥,P代表明文,C代表密文,则3DES算法的过程可表示为:

C = Ek3(Dk2(Ek1(P)))

P = Dk1(Ek2(Dk3(C)))

3DES同样有ECB跟CBC模式,同上面讲的一样。这里需要注意一下Key的长度,应该是24位。比如我们已知的Key是16位的,那么我们需要将其分为2段,每一段都是8位,则k1=左8位, k2=右8位,k3=左8位,也就是 k1=k3,但不能k1=k2=k3,因为如果每段使用的Key都相同,就回到DES算法了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: