美文网首页iOS
RSA加密(非对称加密)和对称加密(AES/DES)在公司项目的

RSA加密(非对称加密)和对称加密(AES/DES)在公司项目的

作者: 李昭宏 | 来源:发表于2017-01-11 18:20 被阅读264次

    在看公司的项目代码的时候,注意到公司在请求数据,获取数据的时候,客户端都做了加密和解密,因为之前并没有在实际开发中使用过,因此也认真去查看了一下RSA算法。
    首推 阮一峰RSA算法原理(一) - 阮一峰的网络日志RSA算法原理(二) - 阮一峰的网络日志

    算法的部分可以查看上面的文章,我想说的在实际开发中RSA算法的应用,我们都知道RSA算法是目前使用最多的比较安全的非对称加密算法, 阮一峰的文章中

    提到了公钥(n,e) 只能加密小于n的整数m,那么如果要加密大于n的整数,该怎么办?有两种解决方法:一种是把长信息分割成若干段短消息,每段分别加密;另一种是先选择一种"对称性加密算法"(比如DES / AES),用这种算法的密钥加密信息,再用RSA公钥加密DES/AES密钥。

    本文只写了AES,DES也是一样的,修改一些配置参数罢了。

    对称加密

    引入<CommonCrypto/CommonCryptor.h>,还好苹果自身带有加密的api,开发者只需要调用api即可,核心框架是CommonCrypto,先贴下来代码
    先来看一下CommonCrypto库的头文件以及核心操作函数,一些关键的地方写了注释方便理解

    /*!
        @header     CommonCryptor.h
        @abstract   Generic interface for symmetric encryption. 
    
        @discussion This interface provides access to a number of symmetric 
                    encryption algorithms. Symmetric encryption algorithms come 
                    in two "flavors" -  block ciphers, and stream ciphers. Block
                    ciphers process data (while both encrypting and decrypting) 
                    in discrete chunks of  data called blocks; stream ciphers 
                    operate on arbitrary sized data. 
    
                    The object declared in this interface, CCCryptor, provides
                    access to both block ciphers and stream ciphers with the same
                    API; however some options are available for block ciphers that
                    do not apply to stream ciphers. 
    
                    The general operation of a CCCryptor is: initialize it
                    with raw key data and other optional fields with
                    CCCryptorCreate(); process input data via one or more calls to
                    CCCryptorUpdate(), each of which may result in output data
                    being written to caller-supplied memory; and obtain possible
                    remaining output data with CCCryptorFinal(). The CCCryptor is
                    disposed of via CCCryptorRelease(), or it can be reused (with
                    the same key data as provided to CCCryptorCreate()) by calling
                    CCCryptorReset(). 
    
                    CCCryptors can be dynamically allocated by this module, or 
                    their memory can be allocated by the caller. See discussion for
                    CCCryptorCreate() and CCCryptorCreateFromData() for information 
                    on CCCryptor allocation.
                    
                    One option for block ciphers is padding, as defined in PKCS7;
                    when padding is enabled, the total amount of data encrypted
                    does not have to be an even multiple of the block size, and 
                    the actual length of plaintext is calculated during decryption. 
                    //CBC模式需要起始向量(如果要选择CBC模式 应该将CCOptions 设置成0x0000即可) 文档中没有这个CCOptions,下面有注释说到
                    Another option for block ciphers is Cipher Block Chaining, known
                    as CBC mode. When using CBC mode, an Initialization Vector (IV)
                    is provided along with the key when starting an encrypt
                    or decrypt operation. If CBC mode is selected and no IV is 
                    provided, an IV of all zeroes will be used. 
    
                    CCCryptor also implements block bufferring, so that individual
                    calls to CCCryptorUpdate() do not have to provide data whose
                    length is aligned to the block size. (If padding is disabled,
                    encrypting with block ciphers does require that the *total*
                    length of data input to CCCryptorUpdate() call(s) be aligned
                    to the block size.)
    
                    A given CCCryptor can only be used by one thread at a time;
                    multiple threads can use safely different CCCryptors at the
                    same time.              
    */
    
    /*!
        @enum       CCAlgorithm
        @abstract   Encryption algorithms implemented by this module.
    
        @constant   kCCAlgorithmAES128  Advanced Encryption Standard, 128-bit block
                                        This is kept for historical reasons.  It's
                                        preferred now to use kCCAlgorithmAES since
                                        128-bit blocks are part of the standard.
        @constant   kCCAlgorithmAES     Advanced Encryption Standard, 128-bit block
        //AES128和AES 一样的,只是历史遗留问题
        @constant   kCCAlgorithmDES     Data Encryption Standard
        @constant   kCCAlgorithm3DES    Triple-DES, three key, EDE configuration
        @constant   kCCAlgorithmCAST    CAST
      @constant   kCCAlgorithmRC4     RC4 stream cipher
      @constant   kCCAlgorithmBlowfish    Blowfish block cipher
    */
    enum {
        kCCAlgorithmAES128 = 0,
        kCCAlgorithmAES = 0,
        kCCAlgorithmDES,
        kCCAlgorithm3DES,       
        kCCAlgorithmCAST,       
        kCCAlgorithmRC4,
        kCCAlgorithmRC2,   
        kCCAlgorithmBlowfish    
    };
    typedef uint32_t CCAlgorithm;
    
    /*!
        @enum       CCOptions
        @abstract   Options flags, passed to CCCryptorCreate().
    
        @constant   kCCOptionPKCS7Padding   Perform PKCS7 padding. 
        @constant   kCCOptionECBMode        Electronic Code Book Mode. 
        Default is CBC.(就是说 这里使用0x0000 就是CBC了)
    */
    enum {
        /* options for block ciphers */
        kCCOptionPKCS7Padding   = 0x0001,
        kCCOptionECBMode        = 0x0002
        /* stream ciphers currently have no options */
    };
    typedef uint32_t CCOptions;
    
    /*!
        @enum           Key sizes
    
        @discussion     Key sizes, in bytes, for supported algorithms.  Use these
                        constants to select any keysize variants you wish to use
                        for algorithms that support them (ie AES-128, AES-192, AES-256)
    
        @constant kCCKeySizeAES128      128 bit AES key size.
        @constant kCCKeySizeAES192      192 bit AES key size.
        @constant kCCKeySizeAES256      256 bit AES key size.
        @constant kCCKeySizeDES         DES key size.
        @constant kCCKeySize3DES        Triple DES key size.
        @constant kCCKeySizeMinCAST     CAST minimum key size.
        @constant kCCKeySizeMaxCAST     CAST maximum key size.
        @constant kCCKeySizeMinRC4      RC4 minimum key size.
        @constant kCCKeySizeMaxRC4      RC4 maximum key size.
    
        @discussion     DES and TripleDES have fixed key sizes.
                        AES has three discrete key sizes.
                        CAST and RC4 have variable key sizes.
    */
    enum {
        kCCKeySizeAES128          = 16,
        kCCKeySizeAES192          = 24,
        kCCKeySizeAES256          = 32,
        kCCKeySizeDES             = 8,
        kCCKeySize3DES            = 24,
        kCCKeySizeMinCAST         = 5,
        kCCKeySizeMaxCAST         = 16,
        kCCKeySizeMinRC4          = 1,
        kCCKeySizeMaxRC4          = 512,
        kCCKeySizeMinRC2          = 1,
        kCCKeySizeMaxRC2          = 128,
        kCCKeySizeMinBlowfish     = 8,
        kCCKeySizeMaxBlowfish     = 56,
    };
    
    /*!
        @enum           Block sizes
    
        @discussion     Block sizes, in bytes, for supported algorithms. 
    
        @constant kCCBlockSizeAES128    AES block size (currently, only 128-bit 
                                        blocks are supported).
        @constant kCCBlockSizeDES       DES block size.
        @constant kCCBlockSize3DES      Triple DES block size.
        @constant kCCBlockSizeCAST      CAST block size.
    */
    enum {
        /* AES */
        kCCBlockSizeAES128        = 16,
        /* DES */
        kCCBlockSizeDES           = 8,
        /* 3DES */
        kCCBlockSize3DES          = 8,
        /* CAST */
        kCCBlockSizeCAST          = 8,
        kCCBlockSizeRC2           = 8,
        kCCBlockSizeBlowfish      = 8,
    };
    
    /*!
        @enum       Minimum context sizes
        @discussion Minimum context sizes, for caller-allocated CCCryptorRefs.
                    To minimize dynamic allocation memory, a caller can create 
                    a CCCryptorRef by passing caller-supplied memory to the 
                    CCCryptorCreateFromData() function.
    
                    These constants define the minimum amount of memory, in 
                    bytes, needed for CCCryptorRefs for each supported algorithm. 
    
                    Note: these constants are valid for the current version of 
                    this library; they may change in subsequent releases, so 
                    applications wishing to allocate their own memory for use 
                    in creating CCCryptorRefs must be prepared to deal with 
                    a kCCBufferTooSmall return from CCCryptorCreateFromData().
                    See discussion for the CCCryptorCreateFromData() function.
    
        @constant kCCContextSizeAES128 - Minimum context size for kCCAlgorithmAES128.
        @constant kCCContextSizeDES    - Minimum context size for kCCAlgorithmDES.
        @constant kCCContextSize3DES   - Minimum context size for kCCAlgorithm3DES.
        @constant kCCContextSizeCAST   - Minimum context size for kCCAlgorithmCAST.
        @constant kCCContextSizeRC4    - Minimum context size for kCCAlgorithmRC4.
    */
    
    enum {
        kCCContextSizeAES128 = 404,
        kCCContextSizeDES  = 240,
        kCCContextSize3DES  = 496,
        kCCContextSizeCAST  = 240,
        kCCContextSizeRC4  = 1072
    };
    
    CCCryptorStatus CCCrypt(
     CCOperation op,          // operation: kCCEncrypt加密 or kCCDecrypt解密 
     CCAlgorithm alg,         // algorithm: kCCAlgorithmAES128(AES128加密)...  
     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
    

    AES128加密

    //(key和iv向量这里是16位的) 这里是CBC加密模式,安全性更高
    - (NSData *)AES128EncryptWithKey:(NSString *)key iv:(NSString *)ivStr {//加密
        char keyPtr[kCCKeySizeAES128 + 1];
        bzero(keyPtr, sizeof(keyPtr));
        //objective c字符串转化c语言字符串
        [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
        
        char ivPtr[kCCKeySizeAES128+1];
        memset(ivPtr, 0, sizeof(ivPtr));
        //objective c字符串转化c语言字符串
        [ivStr getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
        
        //这里进行核心返回数据的配置
        NSUInteger dataLength = [self length];
        size_t bufferSize = dataLength + kCCBlockSizeAES128;
        void *buffer = malloc(bufferSize);
        size_t numBytesEncrypted = 0;
        
        CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                              kCCAlgorithmAES128, //AES加密(需要偏移向量)
                                              kCCOptionPKCS7Padding,  //这里是使用PKCS7Padding
                                              keyPtr,
                                              kCCBlockSizeAES128,
                                              ivPtr,
                                              [self bytes],
                                              dataLength,
                                              buffer,
                                              bufferSize,
                                              &numBytesEncrypted);
        if (cryptStatus == kCCSuccess) {
            return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
        }
        free(buffer);
        return nil;
    }
    
    
    - (NSData *)AES128DecryptWithKey:(NSString *)key iv:(NSString *)ivStr{//解密
        char keyPtr[kCCKeySizeAES128+1];
        bzero(keyPtr, sizeof(keyPtr));
        [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
        
        char ivPtr[kCCKeySizeAES128+1];
        memset(ivPtr, 0, sizeof(ivPtr));
        [ivStr getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
        
        NSUInteger dataLength = [self length];
        size_t bufferSize = dataLength + kCCBlockSizeAES128;
        void *buffer = malloc(bufferSize);
        size_t numBytesDecrypted = 0;
        CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                              kCCAlgorithmAES128,
                                              kCCOptionPKCS7Padding,
                                              keyPtr,
                                              kCCBlockSizeAES128,
                                              ivPtr,
                                              [self bytes],
                                              dataLength,
                                              buffer,
                                              bufferSize,
                                              &numBytesDecrypted);
        if (cryptStatus == kCCSuccess) {
            return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
        }
        free(buffer);
        return nil;
    }
    

    当然大家 也可以使用网上一个开源的NSData+CommonCrypto,读者看完上面的原理,实际项目中可以直接使用开源的来实现对称加密

    非对称加密

    引入Security.framework

    /*!
        @function SecKeyEncrypt
        @abstract Encrypt a block of plaintext. 
        @param key Public key with which to encrypt the data.
        @param padding See Padding Types above, typically kSecPaddingPKCS1.
        @param plainText The data to encrypt.
        @param plainTextLen Length of plainText in bytes, this must be less
        or equal to the value returned by SecKeyGetBlockSize().
        @param cipherText Pointer to the output buffer.
        @param cipherTextLen On input, specifies how much space is available at
        cipherText; on return, it is the actual number of cipherText bytes written.
        @result A result code. See "Security Error Codes" (SecBase.h).
        @discussion If the padding argument is kSecPaddingPKCS1 or kSecPaddingOAEP,
        PKCS1 (respectively kSecPaddingOAEP) padding will be performed prior to encryption.
        If this argument is kSecPaddingNone, the incoming data will be encrypted "as is".
        kSecPaddingOAEP is the recommended value. Other value are not recommended 
        for security reason (Padding attack or malleability).
    
        When PKCS1 padding is performed, the maximum length of data that can
        be encrypted is the value returned by SecKeyGetBlockSize() - 11.
    
        When memory usage is a critical issue, note that the input buffer
        (plainText) can be the same as the output buffer (cipherText). 
     */
    OSStatus SecKeyEncrypt(
        SecKeyRef           key,
     SecPadding          padding,
     const uint8_t  *plainText,
     size_t              plainTextLen,
     uint8_t             *cipherText,
     size_t              *cipherTextLen)
        __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0);
    
    /*!
        @function SecKeyDecrypt
        @abstract Decrypt a block of ciphertext. 
        @param key Private key with which to decrypt the data.
        @param padding See Padding Types above, typically kSecPaddingPKCS1.
        @param cipherText The data to decrypt.
        @param cipherTextLen Length of cipherText in bytes, this must be less
        or equal to the value returned by SecKeyGetBlockSize().
        @param plainText Pointer to the output buffer.
        @param plainTextLen On input, specifies how much space is available at
        plainText; on return, it is the actual number of plainText bytes written.
        @result A result code. See "Security Error Codes" (SecBase.h).
        @discussion If the padding argument is kSecPaddingPKCS1 or kSecPaddingOAEP,
        the corresponding padding will be removed after decryption. 
        If this argument is kSecPaddingNone, the decrypted data will be returned "as is".
    
        When memory usage is a critical issue, note that the input buffer
        (plainText) can be the same as the output buffer (cipherText). 
     */
    OSStatus SecKeyDecrypt(
        SecKeyRef           key,                /* Private key */对应的密钥
     SecPadding          padding,               /* kSecPaddingNone,
                                                   kSecPaddingPKCS1,
                                                   kSecPaddingOAEP 
                                                   解密方式:一般是kSecPaddingPKCS1
    */
     const uint8_t       *cipherText,                               对应需要解密的字符串
     size_t              cipherTextLen,  /* length of cipherText */ 需要解密的字符串的长度
     uint8_t             *plainText,                                返回的字符串 
     size_t              *plainTextLen)  /* IN/OUT */               返回解密之后的字符串长度
        __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0);
    

    RSA的实际应用,可以参考Objective-C-RSA,作者已经封装好了RSA的加密和解密。项目开发 调用对应的encryptData和DecryptData即可

    相关文章

      网友评论

        本文标题:RSA加密(非对称加密)和对称加密(AES/DES)在公司项目的

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