如何在使用Objective-C的iOS上执行相同的加密/解密PHP函数?

如何在使用Objective-C的iOS上执行相同的加密/解密PHP函数?,php,ios,objective-c,encryption,Php,Ios,Objective C,Encryption,我在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, MCRYP

我在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;
}
我这样称呼它:

echo encrypt_decrypt('decrypt', '2Fa9cICuUFa/UnmAAa5FjXZK4ht9q3cN2qgk1pCvDSs=');
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];

对于
NSString
,如何使用Objective-C在iOS上执行完全相同的操作?它需要与此PHP函数兼容。

因此您希望在CBC模式下使用AES256进行加密。 您正在查找的库是CommonCrypto,您可以在此处找到一篇关于它的好文章:

您还需要一个MD5函数,可以在此处找到:

您的代码应该如下所示:

echo encrypt_decrypt('decrypt', '2Fa9cICuUFa/UnmAAa5FjXZK4ht9q3cN2qgk1pCvDSs=');
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];
并确保在这两种情况下使用相同的UTF8编码,然后使用此导入:

#import <CommonCrypto/CommonCryptor.h>
#导入
我很确定这应该行得通


编辑:密钥长度应为32,因为您使用的是AES256 256bit=32字节。默认情况下,MD5输出与此长度不匹配。

我认为此类别可能会对您有所帮助

也别忘了导入

#import <CommonCrypto/CommonCryptor.h>
#导入

我用于MD5加密。。。证明我错了,但假设MD5只是单向加密,它不能像那样被解密。它可以用蛮力或加密字符串的大型数据库进行解密。这就是为什么它被认为是安全的。

为什么不使用PHP使用的同一个mcrypt

问题是Rijndael并不完全是AES,所以我不确定其他解决方案是否真的能在这里工作。Rijndael允许不同的块大小和键对,AES是Rijndael的一种特殊情况,键大小为128、192和256,但块大小始终为128。因此,使用PHP使用的相同的
mcrypt
将保证相同的结果

<>这个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à¢äè"˜‚)
示例的输出与PHP代码完全相同(只需测试它!:-)。下面的代码是自己编译的

  • 它要求您编译libmcrypt(我在本示例中使用了2.5.8版)
  • md5和Base64函数也需要OpenSSL(但您可以跳过…)
。。。请注意,我只为md5()和我的Base64类使用了OpenSSL,这与我在许多方面使用的是相同的,但是您可以替换为其他md5/Base64解决方案,然后您就可以摆脱OpenSSL。很简单。苹果现在正转向通用加密

/////////////////////////
// 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;
}
/////////////////////////
//Base64.h
#ifndef BASE64_H
#定义BASE64_H
#包括
#包括
基类64
{
公众:
静态std::字符串编码(常量无符号字符*p_缓冲区,大小p_大小);
静态标准::字符串编码(常量标准::字符串和p_字符串);
静态std::字符串编码(const std::vector&p_buffer);
静态标准::字符串解码(常量标准::字符串和p_输入);
静态无效解码(常量std::string&p_输入,std::vector&p_输出);
};
#endif//BASE64_H
/////////////////////////
//Base64.cpp
//#包括“Base64.h”
#包括
使用名称空间std;
字符串Base64::encode(常量无符号字符*p_缓冲区,大小p_大小)
{
无符号字符*输出(新的无符号字符[p_大小*4/3+4]);
大小\u t输出长度(EVP\u编码块(输出、p\u缓冲区、静态\u转换(p\u大小));
字符串ret(重新解释转换(输出),输出长度);
删除[]输出;
返回ret;
}
字符串Base64::encode(常量字符串和p_字符串)
{
返回Base64::encode(reinterpret_cast(p_string.c_str()),p_string.size());
}
字符串Base64::encode(常量向量&p\u缓冲区)
{
返回Base64::encode(&p_buffer[0],p_buffer.size());
}
void Base64::解码(常量字符串和p_输入,向量和p_输出)
{
p_output.resize(p_input.length()*3/4);
size\u t outputLength(EVP\u DecodeBlock(&p\u output[0],重新解释\u cast(p\u input.c\u str()),静态\u cast(p\u input.size());
长度(p_input.length());
如果(p_输入[长度-2]='='=')
{
输出长度-=2;
}
else if(p_输入[长度-1]='='=')
{
输出长度--;
}
p_output.resize(输出长度);
}
字符串Base64::解码(常量字符串和p_输入)
{
向量<无符号字符>输出;
Base64::解码(p_输入、输出);
返回reinterpret_cast(&output[0]);
}
/////////////////////////
//main.cpp
#包括
#包括
#包括
#包括
#包括
#定义MCRYPT_模式_CBC“CBC”
使用名称空间std;
字符串md5(常量字符串和p_字符串)
{
执行副总裁MD CTX mdContext;
工程执行副总裁(总经理)总经理(总经理);;
无符号整数输出长度;
无符号字符输出[16];
OpenSSL_添加_所有_摘要();
如果(!(md=EVP\u get\u digestbyname(“MD5”))
{
抛出std::runtime_错误(“无法初始化MD5摘要”);
}
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_清理(&mdContext);
字符输出字符串[sizeof(输出)*2+1];
for(int i(0);i和p_输出,常量char*p_加密引擎,常量字符串和p_密钥,常量向量和p_输入,常量char*p_模式,常量字符串和p_iv)
{
MCRYPT td=MCRYPT_模块打开((char*)p_加密引擎,0,(char*)p_模式,0);
如果(td==MCRYPT_失败)
{
抛出std::runtime_错误(“不能初始化mcrypt”);
}
if(mcrypt_generic_init(td,(c