iOS 中 3DES加密、MD5加密

作者: 天空中的球 | 来源:发表于2016-01-21 00:02 被阅读3080次

    加密算法通常分为对称性加密算法和非对称性加密算法,以及线性散列算法,对应着比较常见的是 DES,RSA,MD5。

    • 对称性加密算法,信息接收双方都需事先知道密匙和加解密算法且其密匙是相同的,之后便是对数据进行加解密了。
    • 非对称加密算法,发送双方A,B事先均生成一堆密匙,然后A将自己的公有密匙发送给B,B将自己的公有密匙发送给A,如果A要给B发送消 息,则先需要用B的公有密匙进行消息加密,然后发送给B端,此时B端再用自己的私有密匙进行消息解密,B向A发送消息时为同样的道理。
    • 线性散列加密算法, 只生成一串不可逆的密文,经常用其效验数据传输过程中是否经过修改,因为相同的生成算法对于同一明文只会生成唯一的密文,若相同算法生成的密文不同,则证明传输数据进行过了修改。

    3DES 和 MD5 是我用到过的,特此记录下。

    3DES

    3DES是一种基于DES的加密算法,使用3个不同密匙对同一个分组数据块进行3次加密,如此以使得密文强度更高。

    当然一般我们现有的涉及到文件/信息加密,或提高数据安全级别一般都会选择 CommonCrypto 来完成任务。

    可以从Oc 上面先了解它的函数声明:

    CCCryptorStatus CCCrypt(
           CCOperation op,          // operation: kCCEncrypt or kCCDecrypt
           CCAlgorithm alg,         // algorithm: kCCAlgorithmAES128... 
           CCOptions options,       // operation: kCCOptionPKCS7Padding...
           const void *key,         // key
           size_t keyLength,        // key length
           const void *iv,          // initialization vector (optional)
           const void *dataIn,      // input data
           size_t dataInLength,     // input data length
           void *dataOut,           // output data buffer
           size_t dataOutAvailable, // output data length available
           size_t *dataOutMoved)    // real output data length generated
      )
    

    Swift + 3DES

    extension String {
     
        /**
        3DES的加密过程 和 解密过程
        
        - parameter op : CCOperation: 加密还是解密
                         CCOperation(kCCEncrypt)加密
                         CCOperation(kCCDecrypt) 解密
         
        - parameter key: 专有的key,一个钥匙一般
        - parameter iv : 可选的初始化向量,可以为nil
        - returns      : 返回加密或解密的参数
        */
        func threeDESEncryptOrDecrypt(op: CCOperation,key: String,iv: String) -> String? {
            
            // Key
            let keyData: NSData = (key as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
            let keyBytes         = UnsafeMutablePointer<Void>(keyData.bytes)
            
            // 加密或解密的内容
            var data: NSData = NSData()
            if op == CCOperation(kCCEncrypt) {
                data  = (self as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
            }
            else {
                data =  NSData(base64EncodedString: self, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)!
            }
            
            let dataLength    = size_t(data.length)
            let dataBytes     = UnsafeMutablePointer<Void>(data.bytes)
            
            // 返回数据
            let cryptData    = NSMutableData(length: Int(dataLength) + kCCBlockSize3DES)
            let cryptPointer = UnsafeMutablePointer<Void>(cryptData!.mutableBytes)
            let cryptLength  = size_t(cryptData!.length)
            
            //  可选 的初始化向量
            let viData :NSData = (iv as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
            let viDataBytes    = UnsafeMutablePointer<Void>(viData.bytes)
            
            // 特定的几个参数
            let keyLength              = size_t(kCCKeySize3DES)
            let operation: CCOperation = UInt32(op)
            let algoritm:  CCAlgorithm = UInt32(kCCAlgorithm3DES)
            let options:   CCOptions   = UInt32(kCCOptionPKCS7Padding)
            
            var numBytesCrypted :size_t = 0
            
            let cryptStatus = CCCrypt(operation, // 加密还是解密
                algoritm, // 算法类型
                options,  // 密码块的设置选项
                keyBytes, // 秘钥的字节
                keyLength, // 秘钥的长度
                viDataBytes, // 可选初始化向量的字节
                dataBytes, // 加解密内容的字节
                dataLength, // 加解密内容的长度
                cryptPointer, // output data buffer
                cryptLength,  // output data length available
                &numBytesCrypted) // real output data length 
      
            
          
            if UInt32(cryptStatus) == UInt32(kCCSuccess) {
         
              cryptData!.length = Int(numBytesCrypted)
              if op == CCOperation(kCCEncrypt)  {
                    let base64cryptString = cryptData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
                    return base64cryptString
                }
                else {
               //   let base64cryptString = NSString(bytes: cryptPointer, length: cryptLength, encoding: NSUTF8StringEncoding) as? String  // 用这个会导致返回的JSON数据格式可能有问题,最好不用
                    let base64cryptString = NSString(data: cryptData!,  encoding: NSUTF8StringEncoding) as? String
                    return base64cryptString
                }
            } else {
                print("Error: \(cryptStatus)")
            }
            return nil
        }
        
    
    }
    

    补充:
    CCOperation(操作)、CCAgorithm(算法) 和 CCOptions(设置)本质上就是 uint32_t(一个占32位存储的 unsigned int),所以我们可以通过 CommonCrypto 常量来构造它们。

    let operation = CCOperation(kCCEncrypt)
    let algorithm = CCAlgorithm(kCCAlgorithmAES) // 后面算法随你选择
    let options = CCOptions(kCCOptionECBMode) // 设置项
    

    附带一个Oc版的 3DES加解密 (此处没有用系统的base64,用的是GTMBase64)

    + (NSString*)TripleDES:(NSString*)plainText encryptOrDecrypt:(CCOperation)encryptOrDecrypt key:(NSString*)key {
        
        
        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);
     
        NSString *initVec = @"p2p_s2iv";
        const void *vkey = (const void *) [key UTF8String];
        const void *vinitVec = (const void *) [initVec UTF8String];
        
        ccStatus = CCCrypt(encryptOrDecrypt,
                           kCCAlgorithm3DES,
                           kCCOptionPKCS7Padding,
                           vkey, //"123456789012345678901234", //key
                           kCCKeySize3DES,
                           vinitVec, //"init Vec", //iv,
                           vplainText, //"Your Name", //plainText,
                           plainTextBufferSize,
                           (void *)bufferPtr,
                           bufferPtrSize,
                           &movedBytes);
    
        
        NSString *result;
        
        if (encryptOrDecrypt == kCCDecrypt)
        {
            result = [[NSString alloc] initWithData:[NSData dataWithBytes:(const void *)bufferPtr
                                                                    length:(NSUInteger)movedBytes]
                                            encoding:NSUTF8StringEncoding]
                      ;
        }
        else
        {
            NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
            result = [GTMBase64 stringByEncodingData:myData];
        }
        
        return result;
        
    }
    

    附带一个Swift 版的 Base64 + String

    extension String {
        
        //Encode base64
        func base64Encoded() -> String {
            let plainData = self.dataUsingEncoding(NSUTF8StringEncoding)
            let base64String = plainData?.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
            return base64String!
        }
        
        //Decode base64
        func base64Decoded() -> String {
            let decodedData = NSData(base64EncodedString: self, options: .IgnoreUnknownCharacters)
            let decodedString = NSString(data: decodedData!, encoding: NSUTF8StringEncoding)
            return decodedString! as String
        }
    }
    

    MD5

    MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
    MD5的典型应用是对一段Message(字节串)产生fingerprint(指纹),以防止被“篡改”。举个例子,你将一段话写在一个叫 readme.txt文件中,并对这个readme.txt产生一个MD5的值并记录在案,然后你可以传播这个文件给别人,别人如果修改了文件中的任何内容,你对这个文件重新计算MD5时就会发现。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。

    swift + MD5

    extension String  {
        var MD5: String! {
            let str = self.cStringUsingEncoding(NSUTF8StringEncoding)
            let strLen = CC_LONG(self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))
            let digestLen = Int(CC_MD5_DIGEST_LENGTH)
            let result = UnsafeMutablePointer<CUnsignedChar>.alloc(digestLen)
            
            CC_MD5(str!, strLen, result)
            
            let hash = NSMutableString()
            for i in 0..<digestLen {
                hash.appendFormat("%02x", result[i])
            }
            
            result.dealloc(digestLen)
            
            return String(format: hash as String)
        }
    }
    

    Oc + MD5

    // 注意导入
    #import <CommonCrypto/CommonDigest.h>
    - (NSString *)MD5Hash
    {
        const char *cStr = [self UTF8String];
        unsigned char result[16];
        CC_MD5(cStr, (unsigned)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]];
    }
    

    一定要注意, Swift 剔除了 Objective-C 中属于 C 的部分,因此我们需要做一些准备工作才能在 Swift 和 Cocoa 中使用 CommonCrypto,我们需要在Bridging-Header.h 中加入#import <CommonCrypto/CommonCrypto.h>

    备注参考

    http://www.cnblogs.com/yangywyangyw/archive/2012/07/31/2620861.html
    http://stackoverflow.com/questions/25754147/issue-using-cccrypt-commoncrypt-in-swift
    http://www.itupup.com/?it09/525141.htm

    相关文章

      网友评论

      • 什么的黑夜:您好,3des oc的demon有吗?
        沧冥海:我发现直接使用OC的3DES解密,无法解开服务器发过来的密文。不知道是否需要修改解密的参数?
        什么的黑夜:@天空中的球 谢谢
        天空中的球:@什么的黑夜 没有,但你可以看看这个老的Demo,https://github.com/dev5tec/FBEncryptor
      • 415c742fdf1a:3DES 图片加密怎么破,ALAssetsLibrary *assetLibrary=[[ALAssetsLibrary alloc] init];
        NSURL *url=[NSURL URLWithString:self.ary[i]];
        [assetLibrary assetForURL:url resultBlock:^(ALAsset *asset) {
        UIImage *image=[UIImage imageWithCGImage:asset.aspectRatioThumbnail];
        } 类型是这样的 。。。可以做到吗? :smile:
        415c742fdf1a:@天空中的球 谢谢 :grin:
        天空中的球:@果冻呀 用DES加密图片,用法是一样的啊
        将图片转化成String后进行加密就ok啦,解密后再转化成UIImage之后就恢复了
      • 23f7dfa990db:我居然看完了

      本文标题:iOS 中 3DES加密、MD5加密

      本文链接:https://www.haomeiwen.com/subject/vjfckttx.html