How can I do this same encrypt/decrypt PHP function on iOS with Objective-C?

前端 未结 5 595
清酒与你
清酒与你 2021-02-06 15:50

I have a function in PHP that encrypts and decrypts strings:

function encrypt_decrypt($action, $string) 
{
   $output = false;
   $key = \'mykeyhereblah\';
   $i         


        
5条回答
  •  情深已故
    2021-02-06 16:50

    Ok there are a few things to point out here... First of all MD5 is not going to give you enough entropy to consider that key secure. While the IV can be even public it should anyway be random and thus, md5 is not working there either. Mind that having a fixed IV is more or less not having it at all.

    If you want to really use a passphrase to generate your encryption key the best way to do it is to use PBKDF2

    Now to the code:

    This is the code I'm currently using in one of my project

    - (NSData *)AES256EncryptWithKey:(NSString *)key andIV:(const void*)iv
    {
        // 'key' should be 32 bytes for AES256, will be null-padded otherwise
        char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
        bzero( keyPtr, sizeof( keyPtr ) ); // fill with zeroes (for padding)
    
        // fetch key data
        [key getCString:keyPtr maxLength:sizeof( keyPtr ) encoding:NSUTF8StringEncoding];
    
        NSUInteger dataLength = [self length];
    
        //See the doc: For block ciphers, the output size will always be less than or
        //equal to the input size plus the size of one block.
        //That's why we need to add the size of one block here
        size_t bufferSize = dataLength + kCCBlockSizeAES128;
        void *buffer = malloc( bufferSize );
    
        size_t numBytesEncrypted = 0;
        CCCryptorStatus cryptStatus = CCCrypt( kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                              keyPtr, kCCKeySizeAES256,
                                              iv /* initialization vector (optional) */,
                                              [self bytes], dataLength, /* input */
                                              buffer, bufferSize, /* output */
                                              &numBytesEncrypted );
        if( cryptStatus == kCCSuccess )
        {
            //the returned NSData takes ownership of the buffer and will free it on deallocation
            return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
        }
    
        free( buffer ); //free the buffer
        return nil;
    }
    
    
    - (NSData *)AES256DecryptWithKey:(NSString *)key andIV:(const void*)iv
    {
        // 'key' should be 32 bytes for AES256, will be null-padded otherwise
        char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
        bzero( keyPtr, sizeof( keyPtr ) ); // fill with zeroes (for padding)
    
        // fetch key data
        [key getCString:keyPtr maxLength:sizeof( keyPtr ) encoding:NSUTF8StringEncoding];
    
        NSUInteger dataLength = [self length];
    
        //See the doc: For block ciphers, the output size will always be less than or
        //equal to the input size plus the size of one block.
        //That's why we need to add the size of one block here
        size_t bufferSize = dataLength + kCCBlockSizeAES128;
        void *buffer = malloc( bufferSize );
    
        size_t numBytesDecrypted = 0;
        CCCryptorStatus cryptStatus = CCCrypt( kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                              keyPtr, kCCKeySizeAES256,
                                              iv /* initialization vector (optional) */,
                                              [self bytes], dataLength, /* input */
                                              buffer, bufferSize, /* output */
                                              &numBytesDecrypted );
    
        if( cryptStatus == kCCSuccess )
        {
            //the returned NSData takes ownership of the buffer and will free it on deallocation
            return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
        }
    
        free( buffer ); //free the buffer
        return nil;
    }
    

    The above code was borrowed from this SO's answer

    Now following is part of the code I used in one of my projects. Mind that this is functions are part of an object and I didn't post all the code, just the relevant.

    /**
     * Pads the data using PKCS7 padding scheme, as described in RFC 5652.
     * 
     * We do not want to rely on Mcrypt's zero-padding, because it differs from
     * OpenSSL's PKCS7 padding.
     * 
     * Note: $data is passed by reference.
     * 
     * @param string &$data 
     */
    static public function pkcs7Pad(&$data)
    {
    
        $blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        $padding = $blockSize - (strlen($data) % $blockSize);
    
        $data .= str_repeat(chr($padding), $padding);
    }
    
    /**
     * Removes the (PKCS7) padding bytes from $data.
     * 
     * Note: $data is passed by reference.
     * 
     * @param string &$data 
     */
    static public function pkcs7Strip(&$data)
    {
        $paddingByte = substr($data, -1);
        $paddingLen = ord($paddingByte);
        $dataLen = strlen($data) - $paddingLen;
    
        // Simple sanity check to make sure we have correct padding bytes. If padding
        // is not correct, we simply set $data to false. At this point, there
        // should be no need to worry about leaking side-channels.
        if (!isset($data[15]) || $paddingLen < 1 || $paddingLen > mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC) )
        {
            //$data = false;
        }
        else if (substr($data, $dataLen) === str_repeat($paddingByte, $paddingLen))
        {
            // Padding is correct, strip it off.
            $data = substr($data, 0, $dataLen);
        }
        else
        {
            //$data = false;
        }
    }
    
    public static function encrypt($dataString, $aesCipherKey, $iv = null, $returnBase64Encoded = false){
    
        // ensure source file exist
        if (!$dataString || empty($dataString))
            return null;
    
        try{
    
                // ===========
                // Ciphering
                $ciphered_data = null;
    
                //Make sure padding is pkcs7 based
                self::pkcs7Pad($dataString);                    
    
                //Encrypt data with AES
                $ciphered_data = @mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $aesCipherKey, $dataString, MCRYPT_MODE_CBC, $iv);
    
                return ( $returnBase64Encoded ? base64_encode( $ciphered_data ) : $ciphered_data );
    
    
            }
        catch(Exception $ex){
    
            return null;
        }
    
    
    }
    
    public static function decrypt($dataString, $aesCipherKey, $iv = null, $returnBase64Encoded = false){
    
        // ensure source file exist
        if (!$dataString || empty($dataString))
            return null;
    
        try{
    
                // ===========
                // Ciphering
                $ciphered_data = null;
    
                //Decrypt data with AES
                $ciphered_data = @mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $aesCipherKey, $dataString, MCRYPT_MODE_CBC, $iv);
    
                //Ensure no pkcs7 padding is left overs
                self::pkcs7Strip($ciphered_data);   
    
                return ( $returnBase64Encoded ? base64_encode( $ciphered_data ) : $ciphered_data );
    
    
            }
        catch(Exception $ex){
    
            return null;
        }
    
    }
    

    EDIT: Remember that you will need to comply to U.S. export laws for software that contains encryption.

提交回复
热议问题