微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在Cocoa中加密数据,用PHP解码

我试图解决的情况:在我的Cocoa应用程序中,我需要使用对称密码加密字符串,将其POST到PHP,并让该脚本解码数据.该过程需要反向工作以返回答案(PHP编码,Cocoa解码).

我错过了一些东西,因为尽管我可以在PHP和Cocoa中同时获得密钥和初始化向量(iv),但当一个应用程序将其编码数据发送到另一个应用程序时,解码永远不会起作用.两者都可以很好地编码/解码他们自己的数据(经过验证可以确保手头没有一些PEBKAC问题).我怀疑某个地方有填充问题,我只是没有看到它.

我的cocoa应用程序使用SSCrypto进行编码(这只是围绕OpenSSL函数一个方便的包装器).密码是Blowfish,模式是CBC. (原谅内存泄漏,代码已被剥离到最基本的要领)

NSData *secretText = [@"secretTextToEncode" dataUsingEncoding:NSUTF8StringEncoding];
NSData *symmetricKey = [@"ThisIsMyKey" dataUsingEncoding:NSUTF8StringEncoding];

unsigned char *input = (unsigned char *)[secretText bytes];
unsigned char *outbuf;
int outlen,templen,inlen;
inlen = [secretText length];

unsigned char evp_key[EVP_MAX_KEY_LENGTH] = {"\0"};
int cipherMaxIVLength = EVP_MAX_IV_LENGTH;
EVP_CIPHER_CTX cCtx;
const EVP_CIPHER *cipher = EVP_bf_cbc();

cipherMaxIVLength = EVP_CIPHER_iv_length( cipher );
unsigned char iv[cipherMaxIVLength];

EVP_BytesToKey(cipher,EVP_md5(),NULL,[symmetricKey bytes],[symmetricKey length],1,evp_key,iv);

NSData *initVector = [NSData dataWithBytes:iv length:cipherMaxIVLength];

EVP_CIPHER_CTX_init(&cCtx);

if (!EVP_Encryptinit_ex(&cCtx,cipher,iv)) {
    EVP_CIPHER_CTX_cleanup(&cCtx);
    return nil;
}
int ctx_CipherKeyLength = EVP_CIPHER_CTX_key_length( &cCtx );
EVP_CIPHER_CTX_set_key_length(&cCtx,ctx_CipherKeyLength);

outbuf = (unsigned char *)calloc(inlen + EVP_CIPHER_CTX_block_size(&cCtx),sizeof(unsigned char));

if (!EVP_EncryptUpdate(&cCtx,outbuf,&outlen,input,inlen)){
    EVP_CIPHER_CTX_cleanup(&cCtx);
    return nil;
}
if (!EVP_EncryptFinal(&cCtx,outbuf + outlen,&templen)){
    EVP_CIPHER_CTX_cleanup(&cCtx);
    return nil;
}
outlen += templen;
EVP_CIPHER_CTX_cleanup(&cCtx);

NSData *cipherText = [NSData dataWithBytes:outbuf length:outlen];

Nsstring *base64String = [cipherText encodeBase64WithNewlines:NO];
Nsstring *iv = [initVector encodeBase64WithNewlines:NO];

然后将base64String和iv发送给试图解码它的PHP

<?PHP

import_request_variables( "p","p_" );

if( $p_data != "" && $p_iv != "" )
{
    $encodedData = base64_decode( $p_data,true );
    $iv = base64_decode( $p_iv,true );

    $td = mcrypt_module_open( MCRYPT_BLOWFISH,'',MCRYPT_MODE_CBC,'' );
    $keySize = mcrypt_enc_get_key_size( $td );
    $key = substr( md5( "ThisIsMyKey" ),$keySize );

    $decodedData = mcrypt_decrypt(MCRYPT_BLOWFISH,$key,$encodedData,$iv );
    mcrypt_module_close( $td );

    echo "decoded: " . $decodedData;
}
?>

decodeData总是乱七八糟.

我试过逆转过程,将PHP的编码输出发送到Cocoa但EVP_DecryptFinal()失败,这使我相信某处存在NULL填充问题.我已经阅读并重新阅读了PHP和OpenSSL文档,但现在它们一起模糊了,我没有想法尝试.

解决方法

我认为你的问题是从密钥字符串中导出原始加密密钥的方法在双方是不同的. PHP md5()函数返回一个十六进制字符串,即’a476c3 …’,你正在砍掉密钥大小,而EVP_BytesToKey()是一个相当复杂的哈希例程,它返回一个原始字节字符串.它可能,提供的参数简化为原始MD5哈希,但我不能说.无论哪种方式,它都会与PHP哈希不同.

如果您将PHP更改为md5(“ThisIsMyKey”,TRUE),那将为您提供原始md5哈希.在可可方面,SSCrypto的getMD5ForData:方法应该为相同的字符串生成相同的字符串(文本编码问题除外).

编辑1:如果PHP字符串和Cocoa数据打印相同,它们在字节级别仍然不同. PHP字符串是十六进制编码的(即只包含字符0-9和a-f),而cocoa数据是原始字节(尽管NSData在NSLogged时有用地打印出其内容的十六进制编码字符串).您仍然需要将第二个TRUE参数添加PHP的md5()函数获取原始字节字符串.

编辑2:OpenSSL 1.1.0c changed the digest algorithm用于某些内部组件.以前使用MD5,1.1.0切换到SHA256.请注意,在EVP_BytesToKey和openssl enc等命令中,更改不会影响您.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐