如何从NSData对象获取密钥到Crypto ++的密钥/ iv数组?

时间:2013-11-28 17:17:12

标签: ios encryption cryptography crypto++

我正在尝试为一些使用Crypto ++库的加密操作制作一个Objective-C包装类。我有几个问题,

这是我正在使用的代码

- (void)testSerpentEncryptonMechanism
{
     byte key[ CryptoPP::Serpent::MAX_KEYLENGTH ], iv[ CryptoPP::Serpent::BLOCKSIZE ];

    ::memset( key, 0x50 , CryptoPP::Serpent::MAX_KEYLENGTH );
    ::memset( iv, 0x10, CryptoPP::Serpent::BLOCKSIZE );

    NSString *andThisShalBeEncrypted = @"Serpentine and black...";

    NSLog(@"will encrypt %@",andThisShalBeEncrypted);

    NSString *encrypted = [self encryptWithSerpentString:andThisShalBeEncrypted withKey:key];

    NSLog(@"encrypted:%@",encrypted);

    NSString *decrypted = [self decryptWithSerpentString:encrypted withKey:key andIV:iv];

    NSLog(@"decrypted: %@",decrypted);


}

- (NSString *)encryptWithSerpentString:(NSString *)plaintext withKey:(byte[])keyArray
{
    std::string ptext = [plaintext UTF8String];
    std::string ciphertext;

    byte key[ CryptoPP::Serpent::MAX_KEYLENGTH ], iv[ CryptoPP::Serpent::BLOCKSIZE ];

    ::memset( key, 0x50 , CryptoPP::Serpent::MAX_KEYLENGTH );
    ::memset( iv, 0x10, CryptoPP::Serpent::BLOCKSIZE );

    CryptoPP::Serpent::Encryption serpentEncryptor (key, CryptoPP::Serpent::MAX_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcSerpentEncryptor (serpentEncryptor, iv);

    CryptoPP::StreamTransformationFilter stfSerpentEncryptor(cbcSerpentEncryptor, new CryptoPP::StringSink (ciphertext));
    stfSerpentEncryptor.Put( reinterpret_cast<const unsigned char*>( ptext.c_str() ), ptext.length() + 1);
    stfSerpentEncryptor.MessageEnd();

    std::string finalCT;
    CryptoPP::StringSource base64Encoder (ciphertext, true, new CryptoPP::Base64Encoder(new CryptoPP::StringSink(finalCT)));



    return @(finalCT.c_str());
}

- (NSString *)decryptWithSerpentString:(NSString *)ciphertext withKey:(byte[])keyArray andIV:(byte[])initializationVector
{
    std::string ctext;
    std::string plaintext;

    byte key[ CryptoPP::Serpent::MAX_KEYLENGTH ], iv[ CryptoPP::Serpent::BLOCKSIZE ];

//    ::memset( key, &keyArray , CryptoPP::Serpent::MAX_KEYLENGTH );
//    ::memset( iv, (byte[])initializationVector, CryptoPP::Serpent::BLOCKSIZE );

    ::memset( key, 0x50 , CryptoPP::Serpent::MAX_KEYLENGTH );
    ::memset( iv, 0x10, CryptoPP::Serpent::BLOCKSIZE );

    // decode from base64
    std::string encoded = [ciphertext UTF8String];
    CryptoPP::StringSource base64Encoder (encoded, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(ctext)));


    CryptoPP::Serpent::Decryption serpentDecryptor (key, CryptoPP::Serpent::MAX_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcSerpentDecryptor (serpentDecryptor, iv);

    CryptoPP::StreamTransformationFilter stfSerpentDecryptor(cbcSerpentDecryptor, new CryptoPP::StringSink (ctext));// crash
    stfSerpentDecryptor.Put( reinterpret_cast<const unsigned char*>( ctext.c_str() ), ctext.length() + 1);
    stfSerpentDecryptor.MessageEnd();


    return @(ctext.c_str());
}

1)如何将key / IV作为方法参数传递?请参阅注释后的代码,但不起作用......

2)尝试decrpyt时发生了崩溃

libc ++ abi.dylib:以CryptoPP类型的未捕获异常终止:: InvalidCiphertext:StreamTransformationFilter:密文长度不是块大小的倍数

为什么呢?我认为解密是自动的,加密将相应地填充明文... 我还想在方法中添加一个HMAC ...这将在加密后添加并在解密前检查,对吗?

1 个答案:

答案 0 :(得分:2)

要获得填充,您必须自己完成或拥有支持标准填充的API,例如PKCS7。基本加密,流加密除外,是基于块的,在较低级别必须有完整的块。一些更高级别的API提供填充。

我传递密钥,iv和数据as NSData *并以data.bytes的形式访问字节 对于密码输出数据:

NSMutableData  *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];
// ...
                   dataOut.mutableBytes,
                   dataOut.length,
                   &cryptBytes
// ...
dataOut.length = cryptBytes;

我会将我的API调用类似于:

- (NSString *)encryptWithSerpentText:(NSString *)text key:(NSData *)key iv:(NSData *)iv;

Mac很好,但你将如何验证它。最好研究身份验证的最佳实践。

对于HMAC,只需使用Apple提供的CommonCrypto库。 CommonCrypto还支持:AES128,DES,3DES,CAST,RC4和Blowfish,但不支持Serpent。

最后,为了让事情能够记录服务器和客户端中的每一步,这样就可以找到失败的错误步骤。在这种情况下,针对混合Objective-C / C ++版本的直接C ++版本。