iOS中加密算法的学习

本文介绍了iOS中DES加密算法的工作原理、安全性及其代码实现,强调了DES密钥管理的重要性。同时提到了Base64编码的作用和实现,并提及MD5在一致性验证中的应用,以及数字证书和安全访问认证在保障通信安全的角色。

DES算法简介: 

DES算法的入口参数有三个:Key、Data、Mode。其中Key為8个字节共64位,是DES算法的工作密钥;Data也為8个字节64位,是要被加密或被解密的数据;Mode為DES的工作

方式,有两种:加密或解密。


  DES算法是这样工作的:如Mode為加密,则用Key 去把数据Data进行加密, 生成Data的密码形式(64位)作為DES的输出结果;如Mode為解密,则用Key去把密码形式的数

据Data解密,还原為Data的明码形式(64位)作為DES的输出结果。在通信网络的两端,双方约定一致的Key,在通信的源点用Key对核心数据进行DES加密,然后以密码形式在

公共通信网(如电话网)中传输到通信网络的终点,数据到达目的地后,用同样的Key对密码数据进行解密,便再现了明码形式的核心数据。这样,便保证了核心数据(如PIN、

MAC等)在公共通信网中传输的安全性和可靠性。


  通过定期在通信网络的源端和目的端同时改用新的Key,便能更进一步提高数据的保密性,这正是现在金融交易网络的流行做法。


DES算法具有极高安全性,到目前為止,除了用穷举搜索法对DES算法进行攻击外,还没有发现更有效的办法。而56位长的密钥的穷举空间為256,这意味著如果一

台计算机的速度是每一秒种检测一百万个密钥,则它搜索完全部密钥就需要将近2285年的时间,可见,这是难以实现的,当然,随著科学技术的发展,当出现超高速

计算机后,我们可考虑把DES密钥的长度再增长一些,以此来达到更高的保密程度。


在DES密钥Key的使用、管理及密钥更换的过程中,应绝对避开DES 算法的应用误区,即:绝对不能把Key的第8,16,24......64位作為有效数据位,来对Key 进行管

理。这一点,特别推荐给金融银行界及非金融业界的领导及决策者们,尤其是负责管理密钥的人,要对此点予以高度重视。有的银行金融交易网络,利用定期更换

DES密钥Key的办法来进一步提高系统的安全性和可靠性,如果忽略了上述应用误区,那麼,更换新密钥将是徒劳的,对金融交易网络的安全运行将是十分危险的,

所以更换密钥一定要保证新Key与旧Key真正的不同,即除了第8,16,24,...64位外其它位数据发生了变化,请务必对此保持高度重视!


iOS中DES加密的代码实现:

/************************************************************
 函数名称 : + (NSData *)DESEncrypt:(NSData *)data WithKey:(NSString *)key
 函数描述 : 文本数据进行DES加密
 输入参数 : (NSData *)data
 (NSString *)key
 输出参数 : N/A
 返回参数 : (NSData *)
 备注信息 : 此函数不可用于过长文本
 **********************************************************/
/*!
 @function   CCCrypt
 @abstract   Stateless, one-shot encrypt or decrypt operation.
 This basically performs a sequence of CCCrytorCreate(),
 CCCryptorUpdate(), CCCryptorFinal(), and CCCryptorRelease().
    (无国界的,一个基本的加密或解密操作。 以这个方法为基础展示了一系列的方法:)
 
 @param      alg             Defines the encryption algorithm. 
                            (定义加密算法 --> CCAlgorithm)
 
 @param      op              Defines the basic operation: kCCEncrypt or
 kCCDecrypt.
                             (定义基本的操作:加密或解密)
 
 @param      options         A word of flags defining options. See discussion
 for the CCOptions type.
                             (定义选择权??)
 
 @param      key             Raw key material, length keyLength bytes.
                             (未经处理的秘钥)
 
 @param      keyLength       Length of key material. Must be appropriate
 for the select algorithm. Some algorithms may
 provide for varying key lengths.(钥匙原料的长度。必须适应选择的算法。一些算法可以提供不同的秘钥长度)
 
 @param      iv              Initialization vector, optional. Used for
 Cipher Block Chaining (CBC) mode. If present,
 must be the same length as the selected
 algorithm's block size. If CBC mode is
 selected (by the absence of any mode bits in
 the options flags) and no IV is present, a
 NULL (all zeroes) IV will be used. This is
 ignored if ECB mode is used or if a stream
 cipher algorithm is selected.
                            (初始化向量,可选的。 用于密码块链接(CBC)模式。如果存在的话,必须与所选择的算法的块大小相同长度。如果CBC模式被选择(由不存在,在选项标志的任何模式的比特),并且如果目前没有IV,一个NULL(全零)将被使用。如果ECB模式被使用,或者流密码算法被选择参数将会被忽略)??晕了
 
 @param      dataIn          Data to encrypt or decrypt, length dataInLength
 bytes.                     
                             (待加密解密数据的字节长度)
 
 @param      dataInLength    Length of data to encrypt or decrypt.
                             (待加密解密数据的长度)
 
 @param      dataOut         Result is written here. Allocated by caller.
 Encryption and decryption can be performed
 "in-place", with the same buffer used for
 input and output.
                            输出已加密串的内存地址(结果被写入这里。通过回调被分配任务。)
 
 @param      dataOutAvailable The size of the dataOut buffer in bytes.
             (已加密数据的大小)
 
 @param      dataOutMoved    On successful return, the number of bytes
 written to dataOut. If kCCBufferTooSmall is
 returned as a result of insufficient buffer
 space being provided, the required buffer space
 is returned here.(返回成功后,字节数写入dataOut)
 
 @result     kCCBufferTooSmall indicates insufficent space in the dataOut
 buffer. In this case, the *dataOutMoved
 parameter will indicate the size of the buffer
 needed to complete the operation. The
 operation can be retried with minimal runtime
 penalty.
 kCCAlignmentError indicates that dataInLength was not properly
 aligned. This can only be returned for block
 ciphers, and then only when decrypting or when
 encrypting with block with padding disabled.
 kCCDecodeError  Indicates improperly formatted ciphertext or
 a "wrong key" error; occurs only during decrypt
 operations.
 
 CCCryptorStatus CCCrypt(
    CCOperation op,         // kCCEncrypt, etc.
    CCAlgorithm alg,        //kCCAlgorithmAES128, etc.
    CCOptions options,      // kCCOptionPKCS7Padding, etc.
    const void *key,
    size_t keyLength,
    const void *iv,         // optional initialization vector
    const void *dataIn,     // optional per op and alg
    size_t dataInLength,
    void *dataOut,          // data RETURNED here
    size_t dataOutAvailable,
    size_t *dataOutMoved)
 __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0);

 */

+ (NSData *)DESEncrypt:(NSData *)data WithKey:(NSString *)key{
    char keyPtr[kCCKeySizeAES256 + 1];
    bzero(keyPtr, sizeof(keyPtr));//void bzero(void *s, size_t n);函数把字符串s的前n个字节置成零
    
    //将OC字符串转化成c语言字符串 ,存入字符数组keyPer
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    
    //确定加密过后的字符串在内存中存放的大小,根据文档,对于块密码方式(这个库还包括流密码方式)
    //加密过后的字符串大小总是小于或等于加密之前数据的大小加上对应加密算法的块大小
    //但看到一些大牛还这样一下 & ~(kCCBlockSizeDES - 1) 目前不知道为嘛
    NSUInteger dataLength = [data length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize); //动态分配长度为size_t字节的内存块,但之后要记得free掉
    
    size_t numBytesEncrypted = 0; //CCCrypt方法中&numBytesEncrypted 是动态记录内存增加的长度
    
    //加密数据,采用库中的CCCrypt方法,这个方法会按次序执行CCCrytorCreate(),
    // CCCryptorUpdate(), CCCryptorFinal(), and CCCryptorRelease() 如果开发者自己create这个对象,
    //那么后面就必须执行final、release之类的函数,CCCrypt方法一次性解决
    
    // Byte iv[] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF};
    //Byte iv[] = {1,2,3,4,5,6,7,8}; 加密所需的随机字符
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES,
                                          kCCOptionPKCS7Padding | kCCOptionECBMode,//加密额外参数,注意此处各个平台之间指定的时候要记得一样
                                          keyPtr, kCCBlockSizeDES,
                                          NULL,
                                          [data bytes], dataLength,
                                          buffer, bufferSize,
                                          &numBytesEncrypted);
    //CCCrypt(  <#CCOperation op#>, <#CCAlgorithm alg#>, 
<span style="white-space: pre;">	</span>        <#CCOptions options#>, 
<span style="white-space:pre">	</span>        <#const void *key#>, <#size_t keyLength#>, 
<span style="white-space:pre">		</span><#const void *iv#>, 
<span style="white-space:pre">		</span><#const void *dataIn#>, <#size_t dataInLength#>,
<span style="white-space:pre">		</span> <#void *dataOut#>, <#size_t dataOutAvailable#>,
<span style="white-space:pre">		</span> <#size_t *dataOutMoved#>)
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }
    
    //失败,释放动态内存,返回nil
    free(buffer);
    return nil;
}

/************************************************************
 函数名称 : + (NSData *)DESDecrypt:(NSData *)data WithKey:(NSString *)key
 函数描述 : 文本数据进行DES解密
 输入参数 : (NSData *)data
 (NSString *)key
 输出参数 : N/A
 返回参数 : (NSData *)
 备注信息 : 此函数不可用于过长文本
 **********************************************************/
+ (NSData *)DESDecrypt:(NSData *)data WithKey:(NSString *)key{
    //操作秘钥
    char keyPtr[kCCKeySizeAES256 + 1];
    bzero(keyPtr, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    
    //操作需加密数据
    NSUInteger dataLength = [data length];
    //指定内存长度
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    //存储结果的动态内存
    void *buffer = malloc(bufferSize);
    //动态记录内存长度的标记
    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmDES,
                                          kCCOptionECBMode | kCCOptionPKCS7Padding,
                                          keyPtr, kCCBlockSizeDES,
                                          NULL,
                                          [data bytes], dataLength,
                                          buffer, bufferSize,
                                          &numBytesDecrypted);
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytes:buffer length:numBytesDecrypted];
    }
    
    free(buffer);
    return nil;
}

2.Base64编码说明
  Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式。 如果剩下的字符

不足3个字节,则用0填充,输出字符使用'=',因此编码后输出的文本末尾可能会出现1或2个'='。

  为了保证所输出的编码位可读字符,Base64制定了一个编码表,以便进行统一转换。编码表的大小为2^6=64,这也是Base64名称的由来。

   base64编码表:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/


具体实现见第三方库GTM


3.MD5

MD5即Message-Digest Algorithm 5(信息-摘要 算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译 摘要算法哈希算法),主流编程语言普遍已有MD5实现。将 数据(如 汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、 MD3MD4
MD5算法具有以下特点:
1、压缩性:任意长度的数据,算出的MD5值长度都是固定的。
2、容易计算:从原数据计算出MD5值很容易。
3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
4、弱抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
5、强抗碰撞:想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。
MD5的作用是让大容量信息在用 数字签名软件签署私人 密钥前被" 压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的 十六进制数字串)。除了MD5以外,其中比较有名的还有 sha-1RIPEMD以及 Haval等。

一致性验证

具体来说文件的MD5值就像是这个文件的“ 数字指纹”。每个文件的MD5值是不同的,如果任何人对文件做了任何改动,其 MD5值也就是对应的“数字指纹”就会发生变化。比如下载服务器针对一个文件预先提供一个MD5值,用户下载完该文件后,用我这个算法重新计算下载文件的MD5值,通过比较这两个值是否相同,就能判断下载的文件是否出错,或者说下载的文件是否被篡改了。
利用MD5算法来进行文件校验的方案被大量应用到软件下载站、论坛数据库、 系统文件安全等方面。

数字证书

MD5的典型应用是对一段Message(字节串)产生fingerprint( 指纹),以防止被“ 篡改”。举个例子,你将一段话写在一个叫 readme.txt文件中,并对这个readme.txt产生一个MD5的值并记录在案,然后你可以传播这个文件给别人,别人如果修改了文件中的任何内容,你对这个文件重新计算MD5时就会发现(两个MD5值不相同)。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。

安全访问认证

MD5还广泛用于 操作系统的登陆认证上,如Unix、各类 BSD系统登录密码、 数字签名等诸多方面。如在Unix系统中用户的密码是以MD5(或其它类似的算法)经Hash运算后存储在文件系统中。当用户登录的时候,系统把用户输入的密码进行MD5 Hash运算,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这可以避免用户的密码被具有系统管理员权限的用户知道。MD5将任意长度的“字节串”映射为一个128bit的大整数,并且是通过该128bit反推原始字符串是困难的,换句话说就是,即使你看到源程序和算法描述,也无法将一个MD5的值变换回原始的字符串,从数学原理上说,是因为原始的字符串有无穷多个,这有点象不存在反函数的数学函数。所以,要遇到了md5密码的问题,比较好的办法是:你可以用这个系统中的md5()函数重新设一个密码,如admin,把生成的一串密码的Hash值覆盖原来的Hash值就行了。

正是因为这个原因,现在被黑客使用最多的一种破译密码的方法就是一种被称为"跑字典"的方法。有两种方法得到字典,一种是日常搜集的用做密码的字符串表,另一种是用排列组合方法生成的,先用MD5程序计算出这些字典项的MD5值,然后再用目标的MD5值在这个字典中检索。我们假设密码的最大长度为8位字节(8 Bytes),同时密码只能是字母和数字,共26+26+10=62个字符,排列组合出的字典的项数则是P(62,1)+P(62,2)….+P(62,8),那也已经是一个很天文的数字了,存储这个字典就需要TB级的磁盘阵列,而且这种方法还有一个前提,就是能获得目标账户的密码MD5值的情况下才可以。这种加密技术被广泛的应用于Unix系统中,这也是为什么Unix系统比一般操作系统更为坚固一个重要原因。

+ (NSString *)md5:(NSString *)inPutText{
    const char *cStr = [inPutText UTF8String];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    //将字符cStr按指定长度存入指定的字符数组
    CC_MD5(cStr, (CC_LONG)strlen(cStr), result);
    
    //    return [[NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
    //             result[0], result[1], result[2], result[3],
    //             result[4], result[5], result[6], result[7],
    //             result[8], result[9], result[10], result[11],
    //             result[12], result[13], result[14], result[15]
    //             ] lowercaseString];
    NSMutableString *MD5EncryptStr = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [MD5EncryptStr appendFormat:@"%02x",result[i]];
    }
    return MD5EncryptStr;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值