Objective c OpenSSL enc应用程序中可能存在双BIO_免费

Objective c OpenSSL enc应用程序中可能存在双BIO_免费,objective-c,cocoa,openssl,Objective C,Cocoa,Openssl,(抱歉,这太冗长了)我正在尝试向一个用Objective C for OS X 10.6编写的Cocoa应用程序(Snow Leopard)添加OpenSSL支持。为了简化问题,我有一个小的包装器类,它包含各种生物和密码上下文结构,AETOpenSSLWrapper。它看起来如下所示 h m 然后使用各种实用方法链接BIOs、写入输出BIO、刷新等,特别是一种-(void)PushEncrypting BIO链接加密过滤器BIO(已使用密钥、salt和初始向量初始化) 最后是我的dealloc程

(抱歉,这太冗长了)我正在尝试向一个用Objective C for OS X 10.6编写的Cocoa应用程序(Snow Leopard)添加OpenSSL支持。为了简化问题,我有一个小的包装器类,它包含各种生物和密码上下文结构,AETOpenSSLWrapper。它看起来如下所示

h

m

然后使用各种实用方法链接BIOs、写入输出BIO、刷新等,特别是一种-(void)PushEncrypting BIO链接加密过滤器BIO(已使用密钥、salt和初始向量初始化)

最后是我的dealloc程序。这是直接从openssl-1.0.1c发行版提供的enc程序中提取的

-(void)dealloc
{
   if(readWriteBuff!=NULL)
      OPENSSL_free(readWriteBuff);
   if(writeBIO!=NULL)
      BIO_free_all(writeBIO);
   if(encBIO!=NULL) <----------- this looks wrong
      BIO_free(encBIO); <---+

   [super dealloc];
}
和第682-688行

end:
   ERR_print_errors(bio_err);
   if (strbuf != NULL) OPENSSL_free(strbuf);
   if (buff != NULL) OPENSSL_free(buff);
   if (in != NULL) BIO_free(in);
   if (out != NULL) BIO_free_all(out);
   if (benc != NULL) BIO_free(benc); <--- are we sure about this?
结束:
错误打印错误(bio错误);
如果(strbuf!=NULL)OPENSSL_free(strbuf);
如果(buff!=NULL)OPENSSL_free(buff);
如果(in!=NULL)无生物素(in);
如果(out!=NULL)BIO_free_all(out);

如果(benc!=NULL)无生物(benc) 不久前我有机会使用BIOs,我认为你是对的。从OpenSSL手册页:

BIO_free_all()释放整个生物链,如果释放链中的单个生物时出错,它不会停止

此外,由于OpenSSL清理函数使用指向结构的指针,因此它们不能更改指针的值(即,这样做需要指针的地址)。即使OpenSSL将指针参数设置为NULL,也只有副本是NULL,这是一种无用的行为。因此,您可以将其设置为NULL

为您举一个具体的例子,下面的C++代码用于使用PKCSα5标准对明文进行加密。它接收一个密码作为参数,该参数将用于派生AES密钥。以下代码不泄漏(通过valgrind检查)

static int ENCRYPTION\u FAILED=1;
静态常量EVP_MD*MD=EVP_sha256();
静态常量EVP_CIPHER*CIPHER=EVP_aes_256_cbc();
静态int base64加密(常量字符串和toEncrypt、常量字符串和密码、字符串和base64加密)
{
静态常量char magic[]=“Salted_u;”;
int-ret=0;
EVP_CIPHER_CTX*CTX=NULL;
BUF_MEM*bptr=NULL;
无符号字符键[EVP_MAX_key_LENGTH],iv[EVP_MAX_iv_LENGTH];
未签名的半焦盐[PKCS5_salt_LEN];
char*encrypted=NULL;
/*在输出缓冲区中为附加块留出足够的空间*/
BIO*bMem=NULL;
BIO*b64=NULL;
BIO*benc=NULL;
//设置生物上下文
if((bMem=BIO_new(BIO_s_mem())==NULL){
ret=加密失败;转到错误0;
}
if((b64=BIO_new(BIO_f_base64())==NULL){
ret=加密失败;转到错误0;
}
生物推送(b64,bMem);
//产盐
if(RAND_伪字节(salt,sizeof(salt))<0){
ret=加密失败;转到错误0;
}
if((password.size()==0)和&EVP\u CIPHER\u iv\u length(CIPHER)!=0){
ret=加密失败;转到错误0;
}
//将salt写入bio,base 64编码
如果(BIO_write(b64,magic,sizeof magic-1)!=sizeof magic-1 | BIO_write(b64,(char*)salt,sizeof salt)!=sizeof salt){
ret=加密失败;转到错误0;
}   
//派生键
if(!EVP_BytesToKey(CIPHER,MD,salt,(unsigned char*)password.c_str(),password.size(),PKCS5_DEFAULT_ITER,key,iv)){
ret=加密失败;转到错误0;
}
if((benc=BIO_new(BIO_f_cipher())==NULL){
ret=加密失败;转到错误0;
}
BIO_-get_-cipher_-ctx(台式机和ctx);
if(!EVP_CipherInit_ex(ctx,CIPHER,NULL,NULL,1)){
ret=加密失败;转到错误0;
}
if(!EVP_cipheriit_ex(ctx,NULL,NULL,key,iv,1)){
ret=加密失败;转到错误0;
}
生物推送(台式,b64);
//写信给membio
if(BIO_write(benc,(char*)toEncrypt.c_str(),toEncrypt.size())!=(int)toEncrypt.size()){
ret=加密失败;转到错误0;
}   
如果(!BIO_冲洗(工作台)){
ret=加密失败;转到错误0;
}
BIO_get_mem_ptr(工作台和bptr);
如果(bptr->长度+1];
memcpy(加密,bptr->data,bptr->length);
加密的[bptr->length]='\0';
base64Encrypted=加密;
删除加密的[];
如果(benc!=NULL)BIO_free_all(benc);
返回0;
错误0:
如果(benc!=NULL)BIO_free_all(benc);
返回ret;
}
如您所见,我已经链接了三个BIOs,对BIO_free_all(benc)的一次调用将清除所有BIOs

问候

-(void)pushEncryptingBIO
{
   writeBIO=BIO_push(encBIO,writeBIO);
}
-(void)dealloc
{
   if(readWriteBuff!=NULL)
      OPENSSL_free(readWriteBuff);
   if(writeBIO!=NULL)
      BIO_free_all(writeBIO);
   if(encBIO!=NULL) <----------- this looks wrong
      BIO_free(encBIO); <---+

   [super dealloc];
}
if (benc != NULL)
   wbio=BIO_push(benc,wbio);
end:
   ERR_print_errors(bio_err);
   if (strbuf != NULL) OPENSSL_free(strbuf);
   if (buff != NULL) OPENSSL_free(buff);
   if (in != NULL) BIO_free(in);
   if (out != NULL) BIO_free_all(out);
   if (benc != NULL) BIO_free(benc); <--- are we sure about this?
static int ENCRYPTION_FAILED = 1;
static const EVP_MD *MD = EVP_sha256();
static const EVP_CIPHER *CIPHER = EVP_aes_256_cbc();

static int base64Encrypt(const string& toEncrypt, const string& password, string& base64Encrypted)
{
    static const char magic[]="Salted__";
    int ret = 0;
    EVP_CIPHER_CTX *ctx = NULL;
    BUF_MEM *bptr = NULL;
    unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
    unsigned char salt[PKCS5_SALT_LEN];
    char *encrypted = NULL;
    /* Allow enough space in output buffer for additional block */
    BIO *bMem = NULL;
    BIO *b64 = NULL;
    BIO *benc = NULL;

    // setting bio context
    if ( (bMem = BIO_new(BIO_s_mem())) == NULL ){
        ret = ENCRYPTION_FAILED; goto err0;
    }
    if ( (b64 = BIO_new(BIO_f_base64())) == NULL ){
        ret = ENCRYPTION_FAILED; goto err0;
    }
    BIO_push(b64,bMem);

    // Generating salt
    if (RAND_pseudo_bytes(salt, sizeof(salt) ) < 0){
        ret = ENCRYPTION_FAILED; goto err0;
    }

    if ((password.size() == 0) && EVP_CIPHER_iv_length(CIPHER) != 0) {
        ret = ENCRYPTION_FAILED; goto err0; 
    }

    // writing salt to bio, base 64 encoded
    if (BIO_write(b64, magic, sizeof magic-1) != sizeof magic-1 || BIO_write(b64, (char *)salt, sizeof salt) != sizeof salt) {
        ret = ENCRYPTION_FAILED; goto err0;
    }   

    // deriving key
    if (!EVP_BytesToKey(CIPHER, MD, salt, (unsigned char *)password.c_str(), password.size(), PKCS5_DEFAULT_ITER, key, iv)){
        ret = ENCRYPTION_FAILED; goto err0;
    }

    if ( (benc=BIO_new(BIO_f_cipher())) == NULL ){
        ret = ENCRYPTION_FAILED; goto err0;
    }
    BIO_get_cipher_ctx(benc, &ctx);

    if (!EVP_CipherInit_ex(ctx, CIPHER, NULL, NULL, NULL, 1)){
        ret = ENCRYPTION_FAILED; goto err0;
    }

    if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1)){
        ret = ENCRYPTION_FAILED; goto err0;
    }
    BIO_push(benc, b64);

        // writing to mem bio
    if (BIO_write(benc, (char *)toEncrypt.c_str(), toEncrypt.size()) != (int)toEncrypt.size()){
        ret = ENCRYPTION_FAILED; goto err0;
    }   

    if (!BIO_flush(benc)){

        ret = ENCRYPTION_FAILED; goto err0;
    }

    BIO_get_mem_ptr(benc, &bptr);
    if (bptr->length <= 0){
        ret = ENCRYPTION_FAILED; goto err0;
    }
    encrypted = new char[bptr->length + 1];
    memcpy(encrypted, bptr->data, bptr->length);
    encrypted[bptr->length] = '\0';
    base64Encrypted = encrypted;
    delete[] encrypted;

    if (benc != NULL) BIO_free_all(benc);
    return 0;

    err0:
    if (benc != NULL) BIO_free_all(benc);
    return ret;
}