我正在目标C下试验OpenSSL . 我正在尝试编写SMIME非对称密钥加密数据 . 打开文件,加密文件并将其写入磁盘我没有问题 . 我可以加密单个内存缓冲区 . 我想要做的是实现一种分散 - 聚集方法,将多个内存缓冲区输入同一个加密BIO并串行写入磁盘 .

我的代码很简单 . 我设置了一个密码并使用 PEM_read_bio_X509_AUX() 获取公钥/证书 . 我用 sk_X509_push(certs,...) 将它推到 STACK_OF X509s, certs 上 . 我用 writeBIO=BIO_new_file() 打开输出文件 . 我用 readBIO=BIO_new_mem_buf(buf,len); 创建一个内存BIO,并用 p7=PKCS_encrypt(certs,readBIO,...); 加密它 . 最后我使用 i2d_PKCS7_bio(writeBIO,p7); 将其写入输出 . 这适用于一个内存缓冲区 . 如果我尝试在循环中传递多个缓冲区,则只输出最后一个缓冲区 . 我已经尝试释放并重新分配 readBIO abd p7 结构在 BIO_new_mem_buf 之间的调用,但这不起作用 .

有任何想法吗?


更新 - 我有一个解决方案,但没有一个我喜出望外:

我有一个名为AETPublicKeyWrapper的OpenSSL包装器

@interface AETPublicKeyWrapper : NSObject
    {
    @private
       BIO *readBIO;
       BIO *writeBIO;
       STACK_OF(X509) *certs;
       const char *rmode,*wmode;
       PKCS7 *p7;
       EVP_PKEY *privateKey;
       const EVP_CIPHER *cipher;
       int informat,outformat,flags;
    }

    ...
    -(BOOL)openInputFile:(const char*)fname;
    -(BOOL)openOutputFile:(const char*)fname;
    -(BOOL)openInputBuffer;
    -(int)writeToInputBuffer:(const void*)buf length:(unsigned long long)len;
    -(BOOL)loadPublicKeyCert:(const char*)certFileName;
    ...
    -(BOOL)encryptInput;
    -(BOOL)writeEncryptedOutput;
    -(BOOL)writeDecryptedOutput;
    ...

这封装了各种OpenSSL API调用 . -(BOOL)openOutputFile: 例如就是

-(BOOL)openOutputFile:(const char*)fname
    {
       if(!(writeBIO=BIO_new_file((char*)fname,"wb")))
          return NO;
       return YES;
    }

我将多个缓冲区的加密例程转换为相同的输出,如下所示:

AETPublicKeyWrapper *owrapper=[[AETPublicKeyWrapper alloc] init];
    [owrapper loadPublicKeyCert:[keyPath cStringUsingEncoding:NSASCIIStringEncoding]]
    [owrapper openOutputFile:[saveAsPath cStringUsingEncoding:NSASCIIStringEncoding]]
    [owrapper openInputBuffer]
    /* fileData is a header */
    [owrapper writeToInputBuffer:[fileData bytes] length:[fileData length]]
    /* dirArray is an array of buffers */
    for(NSData *itemData in dirArray)
       [owrapper writeToInputBuffer:[itemData bytes] length:[itemData length]];
    [owrapper encryptInput]
    [owrapper writeEncryptedOutput]
    [owrapper flush]
    [owrapper release]

各种方法是(大多数错误处理省略;转换是关闭编译器)

-(BOOL)loadPublicKeyCert:(const char*)certFileName
    {
       X509 *x=NULL;
       BIO *newCert;
       certs=sk_X509_new_null();
       newCert=BIO_new(BIO_s_file());
       BIO_read_filename(newCert,certFileName);
       x=PEM_read_bio_X509_AUX(newCert,NULL,NULL,NULL);
       sk_X509_push(certs,x);
       return YES;
    }

    -(BOOL)openInputBuffer
    {
       if(!(readBIO=BIO_new(BIO_s_mem())))
          return NO;
       return YES;
    }

    -(int)writeToInputBuffer:(const void*)buf length:(unsigned long long)len
    {
       return BIO_write(readBIO,(void*)buf,(int)len);
    }

    -(BOOL)encryptInput
    {
       if(!(p7=PKCS7_encrypt(certs,readBIO,cipher,flags)))
          return NO;
       return YES;
    }

    -(BOOL)writeEncryptedOutput
    {
       if(i2d_PKCS7_bio(writeBIO,p7)<=0)
          return NO;
       return YES;
    }

这是有效的,但我担心的是输入缓冲区可能会变得任意大,所以我宁愿能够写入输出并让它在每次写入时刷新而不是累积并在最后执行整个加密/写入操作 .