Objective c OpenSSL enc应用程序中可能存在双BIO_免费
(抱歉,这太冗长了)我正在尝试向一个用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程序中提取的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程
-(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;
}