如何在iOS中使用Objective-C对PHP函数进行加密/解密?

时间:2022-09-07 08:51:51

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

我有一个PHP函数对字符串进行加密和解密:

function encrypt_decrypt($action, $string) 
{
   $output = false;
   $key = 'mykeyhereblah';
   $iv = md5(md5($key));
   if( $action == 'encrypt' ) {
       $output = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string, MCRYPT_MODE_CBC, $iv);
       $output = base64_encode($output);
   }
   else if( $action == 'decrypt' ){
       $output = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($string), MCRYPT_MODE_CBC, $iv);
       $output = rtrim($output, "");
   }
   return $output;
}

and I call it like this:

我这样称呼它:

echo encrypt_decrypt('decrypt', '2Fa9cICuUFa/UnmAAa5FjXZK4ht9q3cN2qgk1pCvDSs=');

How can I do this exact same thing on iOS with Objective-C for an NSString? It needs to be compatible with this PHP function.

如何在iOS上用Objective-C处理NSString?它需要与这个PHP函数兼容。

5 个解决方案

#1


8  

So you want to encrypt using AES256 in CBC mode. The library you are looking for is CommonCrypto and you can find a good article about it here:http://robnapier.net/aes-commoncrypto.

所以你想要在CBC模式下使用AES256加密。您正在寻找的库是CommonCrypto,您可以在这里找到一篇关于它的好文章:http://robnapier.net/aes-commoncrypto。

You will also need an MD5 function that you can find here: http://www.makebetterthings.com/iphone/how-to-get-md5-and-sha1-in-objective-c-ios-sdk/

您还需要一个MD5函数,您可以在这里找到:http://www.makebetterthings.com/iphone/howto -get- MD5 -and- in-objective-c-ios-sdk/。

Your code should look something like this:

您的代码应该如下所示:

NSString *originalString,*keyString;
NSData *key = [[self md5:keyString] dataUsingEncoding:NSUTF8StringEncoding];
NSData *iv = [[self md5:[self md5:key]] dataUsingEncoding:NSUTF8StringEncoding];
NSData *data = [originalString dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *cipherData = [NSMutableData dataWithLength:data.length + kCCBlockSizeAES128]; //The block size of MCRYPT_RIJNDAEL_256 is just like AES128
size_t outLength;

CCCryptorStatus result
       = CCCrypt(kCCEncrypt, // operation, replace with kCCDecrypt to decrypt
                 kCCAlgorithmAES, // Same as MCRYPT_RIJNDAEL_256
                 nil, // CBC mode
                 key.bytes, // key
                 32, // Since you are using AES256
                 iv.bytes,// iv
                 data.bytes, // dataIn
                 data.length, // dataInLength,
                 cipherData.mutableBytes, // dataOut
                 cipherData.length, // dataOutAvailable
                 &outLength); // dataOutMoved
NSString resultString = [cipherData base64Encoding];

And make sure you are using the same UTF8 encoding in both cases, and use this import:

确保在这两种情况下都使用相同的UTF8编码,并使用此导入:

#import <CommonCrypto/CommonCryptor.h>

I am pretty sure this should work.

我很确定这是可行的。

EDIT: the key length should be 32 since you are using AES256 256bit=32bytes. The MD5 output wouldn't match this length by default I think.

编辑:键长应该是32,因为您使用的是AES256 256bit=32字节。MD5的输出默认不匹配这个长度。

#2


2  

Why not use the same mcrypt that PHP uses?

为什么不使用PHP使用的相同的mcrypt呢?

The problem is that Rijndael is NOT exactly AES, so I am not sure if the other solutions will really work here. The Rijndael allows different pairs of block sizes and keys, AES is a particular case of Rijndael with key sizes os 128, 192 and 256 but block size always 128. So use the same mcrypt that PHP uses will guarantee the same result.

问题是Rijndael并不是完全的AES,所以我不确定其他的解决方案在这里是否有效。Rijndael允许不同的块大小和键对,AES是Rijndael的一个特例,它的键大小为os 128、192和256,但是块大小总是128。因此,使用PHP使用的相同的mcrypt将保证相同的结果。

This sample in C++ is exactly what you need, here is the output:

这个c++的示例正是您所需要的,输出如下:

plain text: the book is on the table!
cipher text: dGhlIGJvb2sgaXMgb24gdGhlIHRhYmxlIQ==
back to: the book is on the table!

sample cipher text: 2Fa9cICuUFa/UnmAAa5FjXZK4ht9q3cN2qgk1pCvDSs=
sample plain text: “:F‚m&X”Öwÿ ï@í`D’ühà¢äè"˜‚)

The output of your sample is exactly like your PHP code (just test it! :-)). The code below compiles by itself.

您的示例的输出与您的PHP代码完全一样(只是测试一下!:-))。下面的代码自己编译。

  • It requires you to compile libmcrypt (I used the version 2.5.8 in this sample)
  • 它要求您编译libmcrypt(我在本示例中使用了版本2.5.8)
  • It also requires OpenSSL for md5 and Base64 functions (but you can skip...)
  • 它还要求md5和Base64函数使用OpenSSL(但是您可以跳过…)

... note that I used OpenSSL just for md5() and my Base64 class, that is the same one that I use for many things, but you can replace for other md5/base64 solution, then you get rid of OpenSSL. Pretty easy. Apple is moving to CommonCrypto now...

…注意,我只对md5()和我的Base64类使用OpenSSL,这与我在很多事情上使用的是同一个类,但是您可以替换其他md5/ Base64解决方案,然后您就可以删除OpenSSL。非常容易的。苹果公司现在要搬到CommonCrypto…

/////////////////////////
// Base64.h

#ifndef BASE64_H
#define BASE64_H

#include <string>
#include <vector>

class Base64
{
public:
    static std::string encode( const unsigned char * p_buffer, size_t p_size );

    static std::string encode( const std::string & p_string );

    static std::string encode( const std::vector< unsigned char > & p_buffer );

    static std::string decode( const std::string & p_input );

    static void decode( const std::string & p_input, std::vector< unsigned char > & p_output );
};

#endif // BASE64_H

/////////////////////////
// Base64.cpp

//#include "Base64.h"

#include <openssl/evp.h>

using namespace std;

string Base64::encode( const unsigned char * p_buffer, size_t p_size )
{
    unsigned char * output( new unsigned char[ p_size * 4 / 3 + 4 ] );

    size_t outputLength( EVP_EncodeBlock( output, p_buffer, static_cast< int >( p_size ) ) );

    string ret( reinterpret_cast< char * >( output ), outputLength );

    delete [] output;

    return ret;
}

string Base64::encode( const string & p_string )
{
    return Base64::encode( reinterpret_cast< const unsigned char * >( p_string.c_str() ), p_string.size() );
}

string Base64::encode( const vector< unsigned char > & p_buffer )
{
    return Base64::encode( &p_buffer[ 0 ], p_buffer.size() );
}

void Base64::decode( const string & p_input, vector< unsigned char > & p_output )
{
    p_output.resize( p_input.length() * 3 / 4 );

    size_t outputLength( EVP_DecodeBlock( &p_output[ 0 ], reinterpret_cast< const unsigned char * >( p_input.c_str() ), static_cast< int >( p_input.size() ) ) );

    size_t length( p_input.length() );

    if ( p_input[ length - 2 ] == '=' )
    {
        outputLength -= 2;
    }
    else if ( p_input[ length - 1 ] == '=' )
    {
        outputLength--;
    }

    p_output.resize( outputLength );
}

string Base64::decode( const string & p_input )
{
    vector< unsigned char > output;
    Base64::decode( p_input, output );
    return reinterpret_cast< const char * >( &output[ 0 ] );
}

/////////////////////////
// main.cpp

#include <iostream>
#include <string>
#include <regex>

#include <openssl/evp.h>
#include <mcrypt.h>

#define MCRYPT_MODE_CBC "cbc"

using namespace std;

string md5( const string & p_string )
{
    EVP_MD_CTX mdContext;
    const EVP_MD * md;
    unsigned int outputLength;
    unsigned char output[ 16 ];

    OpenSSL_add_all_digests();

    if ( !( md = EVP_get_digestbyname( "MD5" ) ) )
    {
        throw std::runtime_error( "Unable to init MD5 digest." );
    }

    EVP_MD_CTX_init( &mdContext );
    EVP_DigestInit_ex( &mdContext, md, 0 );
    EVP_DigestUpdate( &mdContext, p_string.c_str(), p_string.length() );
    EVP_DigestFinal_ex( &mdContext, output, &outputLength );
    EVP_MD_CTX_cleanup( &mdContext );

    char outputString[ sizeof( output ) * 2 + 1 ];

    for ( int i( 0 ); i < sizeof( output ); ++i )
    {
        snprintf( outputString + i * 2, 2 + 1, "%02x", output[ i ] );
    }

    return outputString;
}

string trimString( const string & p_string )
{
    string ret( p_string );

    regex functionRegex( "\\s*(.*)\\s*", regex_constants::icase );
    smatch matches;

    if ( regex_search( p_string, matches, functionRegex ) )
    {
        ret = matches[ 1 ].str();
    }

    return ret;
}

void mcrypt_encrypt( vector< unsigned char > & p_output, const char * p_cryptEngine, const string & p_key, const vector< unsigned char > & p_input, const char * p_mode, const string & p_iv )
{
    MCRYPT td = mcrypt_module_open( ( char * )p_cryptEngine, 0, ( char * )p_mode, 0 );

    if ( td == MCRYPT_FAILED )
    {
        throw std::runtime_error( "can't init mcrypt" );
    }

    if ( mcrypt_generic_init( td, ( char * )p_key.c_str(), mcrypt_enc_get_key_size( td ), ( char * )p_iv.c_str() ) < 0 )
    {
        throw std::runtime_error( "can't setup key/iv" );
    }

    p_output.reserve( p_input.size() );
    copy( p_input.begin(), p_input.end(), back_inserter( p_output ) );

    mcrypt_generic( td, ( void * )&p_output[ 0 ], (int)p_output.size() );

    mcrypt_generic_end( td );
}

void mcrypt_decrypt( vector< unsigned char > & p_output, const char * p_cryptEngine, const string & p_key, const vector< unsigned char > & p_input, const char * p_mode, const string & p_iv )
{
    MCRYPT td = mcrypt_module_open( ( char * )p_cryptEngine, 0, ( char * )p_mode, 0 );

    if ( td == MCRYPT_FAILED )
    {
        throw std::runtime_error( "can't init mcrypt" );
    }

    if ( mcrypt_generic_init( td, ( char * )p_key.c_str(), mcrypt_enc_get_key_size( td ), ( char * )p_iv.c_str() ) < 0 )
    {
        throw std::runtime_error( "can't setup key/iv" );
    }

    p_output.reserve( p_input.size() );
    copy( p_input.begin(), p_input.end(), back_inserter( p_output ) );

    mdecrypt_generic( td, ( void * )&p_output[ 0 ], (int)p_output.size() );

    mcrypt_generic_end( td );
}

string encrypt_decrypt( const string & action, const string & p_string )
{
    string output = "";

    string key = "mykeyhereblah";
    string iv = md5( md5( key ) );

    vector< unsigned char > cipherText, plainText;

    if ( action == "encrypt" )
    {
        copy( p_string.begin(), p_string.end(), back_inserter( plainText ) );

        mcrypt_encrypt( cipherText, MCRYPT_RIJNDAEL_256, md5( key ), plainText, MCRYPT_MODE_CBC, iv );

        output = Base64::encode( cipherText );
    }
    else if ( action == "decrypt" )
    {
        Base64::decode( p_string, cipherText );
        mcrypt_decrypt( plainText, MCRYPT_RIJNDAEL_256, md5( key ), cipherText, MCRYPT_MODE_CBC, iv );

        output = string( ( char* )&plainText[ 0 ], plainText.size() );
        output = trimString( output );
    }

    return output;
}

int main( int argc, char * argv[] )
{
    string plainText = "the book is on the table!";
    string cipherText = encrypt_decrypt( "encrypt", plainText );

    cout << "plain text: " << plainText << endl;
    cout << "cipher text: " << cipherText << endl;
    cout << "back to: " << encrypt_decrypt( "decrypt", cipherText ) << endl;
    cout << endl;
    cout << "your sample: " << encrypt_decrypt( "decrypt", "2Fa9cICuUFa/UnmAAa5FjXZK4ht9q3cN2qgk1pCvDSs=" ) << endl;

    return 0;
}

#3


0  

I think this category might help you

我想这个分类可能对你有帮助

NSString+hashes

NSString +散列

also don't forget to import

也不要忘记导入

#import <CommonCrypto/CommonCryptor.h>

#4


0  

I use http://searchcode.com/codesearch/view/14846108 for MD5 encryption... and prove me wrong but it suppose MD5 is just one way encryption, it can't be decrypted just like that. It can be decrypted with brute force or with a large database of encrypted strings. That's why it's suppose to be safe.

我使用http://searchcode.com/codesearch/view/14846108进行MD5加密…证明我错了,假设MD5只是一种加密方式,不能像这样解密。它可以用蛮力解密,也可以用一个大的加密字符串数据库。这就是为什么它应该是安全的。

#5


0  

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.

好吧,这里有几点需要指出……首先,MD5不会给你足够的熵来考虑关键的安全性。虽然IV可以是公开的,但它应该是随机的,因此,md5也没有在那里工作。记住,有固定的IV或多或少是完全没有的。

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

如果您真的想要使用密码短语来生成加密密钥,最好的方法是使用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

上面的代码是从这个SO的答案中借来的

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.

编辑:请记住,对于包含加密的软件,您需要遵守美国的出口法律。

#1


8  

So you want to encrypt using AES256 in CBC mode. The library you are looking for is CommonCrypto and you can find a good article about it here:http://robnapier.net/aes-commoncrypto.

所以你想要在CBC模式下使用AES256加密。您正在寻找的库是CommonCrypto,您可以在这里找到一篇关于它的好文章:http://robnapier.net/aes-commoncrypto。

You will also need an MD5 function that you can find here: http://www.makebetterthings.com/iphone/how-to-get-md5-and-sha1-in-objective-c-ios-sdk/

您还需要一个MD5函数,您可以在这里找到:http://www.makebetterthings.com/iphone/howto -get- MD5 -and- in-objective-c-ios-sdk/。

Your code should look something like this:

您的代码应该如下所示:

NSString *originalString,*keyString;
NSData *key = [[self md5:keyString] dataUsingEncoding:NSUTF8StringEncoding];
NSData *iv = [[self md5:[self md5:key]] dataUsingEncoding:NSUTF8StringEncoding];
NSData *data = [originalString dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *cipherData = [NSMutableData dataWithLength:data.length + kCCBlockSizeAES128]; //The block size of MCRYPT_RIJNDAEL_256 is just like AES128
size_t outLength;

CCCryptorStatus result
       = CCCrypt(kCCEncrypt, // operation, replace with kCCDecrypt to decrypt
                 kCCAlgorithmAES, // Same as MCRYPT_RIJNDAEL_256
                 nil, // CBC mode
                 key.bytes, // key
                 32, // Since you are using AES256
                 iv.bytes,// iv
                 data.bytes, // dataIn
                 data.length, // dataInLength,
                 cipherData.mutableBytes, // dataOut
                 cipherData.length, // dataOutAvailable
                 &outLength); // dataOutMoved
NSString resultString = [cipherData base64Encoding];

And make sure you are using the same UTF8 encoding in both cases, and use this import:

确保在这两种情况下都使用相同的UTF8编码,并使用此导入:

#import <CommonCrypto/CommonCryptor.h>

I am pretty sure this should work.

我很确定这是可行的。

EDIT: the key length should be 32 since you are using AES256 256bit=32bytes. The MD5 output wouldn't match this length by default I think.

编辑:键长应该是32,因为您使用的是AES256 256bit=32字节。MD5的输出默认不匹配这个长度。

#2


2  

Why not use the same mcrypt that PHP uses?

为什么不使用PHP使用的相同的mcrypt呢?

The problem is that Rijndael is NOT exactly AES, so I am not sure if the other solutions will really work here. The Rijndael allows different pairs of block sizes and keys, AES is a particular case of Rijndael with key sizes os 128, 192 and 256 but block size always 128. So use the same mcrypt that PHP uses will guarantee the same result.

问题是Rijndael并不是完全的AES,所以我不确定其他的解决方案在这里是否有效。Rijndael允许不同的块大小和键对,AES是Rijndael的一个特例,它的键大小为os 128、192和256,但是块大小总是128。因此,使用PHP使用的相同的mcrypt将保证相同的结果。

This sample in C++ is exactly what you need, here is the output:

这个c++的示例正是您所需要的,输出如下:

plain text: the book is on the table!
cipher text: dGhlIGJvb2sgaXMgb24gdGhlIHRhYmxlIQ==
back to: the book is on the table!

sample cipher text: 2Fa9cICuUFa/UnmAAa5FjXZK4ht9q3cN2qgk1pCvDSs=
sample plain text: “:F‚m&X”Öwÿ ï@í`D’ühà¢äè"˜‚)

The output of your sample is exactly like your PHP code (just test it! :-)). The code below compiles by itself.

您的示例的输出与您的PHP代码完全一样(只是测试一下!:-))。下面的代码自己编译。

  • It requires you to compile libmcrypt (I used the version 2.5.8 in this sample)
  • 它要求您编译libmcrypt(我在本示例中使用了版本2.5.8)
  • It also requires OpenSSL for md5 and Base64 functions (but you can skip...)
  • 它还要求md5和Base64函数使用OpenSSL(但是您可以跳过…)

... note that I used OpenSSL just for md5() and my Base64 class, that is the same one that I use for many things, but you can replace for other md5/base64 solution, then you get rid of OpenSSL. Pretty easy. Apple is moving to CommonCrypto now...

…注意,我只对md5()和我的Base64类使用OpenSSL,这与我在很多事情上使用的是同一个类,但是您可以替换其他md5/ Base64解决方案,然后您就可以删除OpenSSL。非常容易的。苹果公司现在要搬到CommonCrypto…

/////////////////////////
// Base64.h

#ifndef BASE64_H
#define BASE64_H

#include <string>
#include <vector>

class Base64
{
public:
    static std::string encode( const unsigned char * p_buffer, size_t p_size );

    static std::string encode( const std::string & p_string );

    static std::string encode( const std::vector< unsigned char > & p_buffer );

    static std::string decode( const std::string & p_input );

    static void decode( const std::string & p_input, std::vector< unsigned char > & p_output );
};

#endif // BASE64_H

/////////////////////////
// Base64.cpp

//#include "Base64.h"

#include <openssl/evp.h>

using namespace std;

string Base64::encode( const unsigned char * p_buffer, size_t p_size )
{
    unsigned char * output( new unsigned char[ p_size * 4 / 3 + 4 ] );

    size_t outputLength( EVP_EncodeBlock( output, p_buffer, static_cast< int >( p_size ) ) );

    string ret( reinterpret_cast< char * >( output ), outputLength );

    delete [] output;

    return ret;
}

string Base64::encode( const string & p_string )
{
    return Base64::encode( reinterpret_cast< const unsigned char * >( p_string.c_str() ), p_string.size() );
}

string Base64::encode( const vector< unsigned char > & p_buffer )
{
    return Base64::encode( &p_buffer[ 0 ], p_buffer.size() );
}

void Base64::decode( const string & p_input, vector< unsigned char > & p_output )
{
    p_output.resize( p_input.length() * 3 / 4 );

    size_t outputLength( EVP_DecodeBlock( &p_output[ 0 ], reinterpret_cast< const unsigned char * >( p_input.c_str() ), static_cast< int >( p_input.size() ) ) );

    size_t length( p_input.length() );

    if ( p_input[ length - 2 ] == '=' )
    {
        outputLength -= 2;
    }
    else if ( p_input[ length - 1 ] == '=' )
    {
        outputLength--;
    }

    p_output.resize( outputLength );
}

string Base64::decode( const string & p_input )
{
    vector< unsigned char > output;
    Base64::decode( p_input, output );
    return reinterpret_cast< const char * >( &output[ 0 ] );
}

/////////////////////////
// main.cpp

#include <iostream>
#include <string>
#include <regex>

#include <openssl/evp.h>
#include <mcrypt.h>

#define MCRYPT_MODE_CBC "cbc"

using namespace std;

string md5( const string & p_string )
{
    EVP_MD_CTX mdContext;
    const EVP_MD * md;
    unsigned int outputLength;
    unsigned char output[ 16 ];

    OpenSSL_add_all_digests();

    if ( !( md = EVP_get_digestbyname( "MD5" ) ) )
    {
        throw std::runtime_error( "Unable to init MD5 digest." );
    }

    EVP_MD_CTX_init( &mdContext );
    EVP_DigestInit_ex( &mdContext, md, 0 );
    EVP_DigestUpdate( &mdContext, p_string.c_str(), p_string.length() );
    EVP_DigestFinal_ex( &mdContext, output, &outputLength );
    EVP_MD_CTX_cleanup( &mdContext );

    char outputString[ sizeof( output ) * 2 + 1 ];

    for ( int i( 0 ); i < sizeof( output ); ++i )
    {
        snprintf( outputString + i * 2, 2 + 1, "%02x", output[ i ] );
    }

    return outputString;
}

string trimString( const string & p_string )
{
    string ret( p_string );

    regex functionRegex( "\\s*(.*)\\s*", regex_constants::icase );
    smatch matches;

    if ( regex_search( p_string, matches, functionRegex ) )
    {
        ret = matches[ 1 ].str();
    }

    return ret;
}

void mcrypt_encrypt( vector< unsigned char > & p_output, const char * p_cryptEngine, const string & p_key, const vector< unsigned char > & p_input, const char * p_mode, const string & p_iv )
{
    MCRYPT td = mcrypt_module_open( ( char * )p_cryptEngine, 0, ( char * )p_mode, 0 );

    if ( td == MCRYPT_FAILED )
    {
        throw std::runtime_error( "can't init mcrypt" );
    }

    if ( mcrypt_generic_init( td, ( char * )p_key.c_str(), mcrypt_enc_get_key_size( td ), ( char * )p_iv.c_str() ) < 0 )
    {
        throw std::runtime_error( "can't setup key/iv" );
    }

    p_output.reserve( p_input.size() );
    copy( p_input.begin(), p_input.end(), back_inserter( p_output ) );

    mcrypt_generic( td, ( void * )&p_output[ 0 ], (int)p_output.size() );

    mcrypt_generic_end( td );
}

void mcrypt_decrypt( vector< unsigned char > & p_output, const char * p_cryptEngine, const string & p_key, const vector< unsigned char > & p_input, const char * p_mode, const string & p_iv )
{
    MCRYPT td = mcrypt_module_open( ( char * )p_cryptEngine, 0, ( char * )p_mode, 0 );

    if ( td == MCRYPT_FAILED )
    {
        throw std::runtime_error( "can't init mcrypt" );
    }

    if ( mcrypt_generic_init( td, ( char * )p_key.c_str(), mcrypt_enc_get_key_size( td ), ( char * )p_iv.c_str() ) < 0 )
    {
        throw std::runtime_error( "can't setup key/iv" );
    }

    p_output.reserve( p_input.size() );
    copy( p_input.begin(), p_input.end(), back_inserter( p_output ) );

    mdecrypt_generic( td, ( void * )&p_output[ 0 ], (int)p_output.size() );

    mcrypt_generic_end( td );
}

string encrypt_decrypt( const string & action, const string & p_string )
{
    string output = "";

    string key = "mykeyhereblah";
    string iv = md5( md5( key ) );

    vector< unsigned char > cipherText, plainText;

    if ( action == "encrypt" )
    {
        copy( p_string.begin(), p_string.end(), back_inserter( plainText ) );

        mcrypt_encrypt( cipherText, MCRYPT_RIJNDAEL_256, md5( key ), plainText, MCRYPT_MODE_CBC, iv );

        output = Base64::encode( cipherText );
    }
    else if ( action == "decrypt" )
    {
        Base64::decode( p_string, cipherText );
        mcrypt_decrypt( plainText, MCRYPT_RIJNDAEL_256, md5( key ), cipherText, MCRYPT_MODE_CBC, iv );

        output = string( ( char* )&plainText[ 0 ], plainText.size() );
        output = trimString( output );
    }

    return output;
}

int main( int argc, char * argv[] )
{
    string plainText = "the book is on the table!";
    string cipherText = encrypt_decrypt( "encrypt", plainText );

    cout << "plain text: " << plainText << endl;
    cout << "cipher text: " << cipherText << endl;
    cout << "back to: " << encrypt_decrypt( "decrypt", cipherText ) << endl;
    cout << endl;
    cout << "your sample: " << encrypt_decrypt( "decrypt", "2Fa9cICuUFa/UnmAAa5FjXZK4ht9q3cN2qgk1pCvDSs=" ) << endl;

    return 0;
}

#3


0  

I think this category might help you

我想这个分类可能对你有帮助

NSString+hashes

NSString +散列

also don't forget to import

也不要忘记导入

#import <CommonCrypto/CommonCryptor.h>

#4


0  

I use http://searchcode.com/codesearch/view/14846108 for MD5 encryption... and prove me wrong but it suppose MD5 is just one way encryption, it can't be decrypted just like that. It can be decrypted with brute force or with a large database of encrypted strings. That's why it's suppose to be safe.

我使用http://searchcode.com/codesearch/view/14846108进行MD5加密…证明我错了,假设MD5只是一种加密方式,不能像这样解密。它可以用蛮力解密,也可以用一个大的加密字符串数据库。这就是为什么它应该是安全的。

#5


0  

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.

好吧,这里有几点需要指出……首先,MD5不会给你足够的熵来考虑关键的安全性。虽然IV可以是公开的,但它应该是随机的,因此,md5也没有在那里工作。记住,有固定的IV或多或少是完全没有的。

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

如果您真的想要使用密码短语来生成加密密钥,最好的方法是使用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

上面的代码是从这个SO的答案中借来的

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.

编辑:请记住,对于包含加密的软件,您需要遵守美国的出口法律。