【问题标题】:Duplicating Java Encryption in Objective C在 Objective C 中复制 Java 加密
【发布时间】:2011-11-06 01:02:45
【问题描述】:

这是PBEWithMD5AndDES Encryption in iOS这个问题的延续,因为有人建议我用不同的方法开始一个新问题。

我基本上需要在这里做的是复制一些在 android 应用程序中发生的加密,在 iOS 应用程序中。我有一些加密工作,但正如在上一个问题中所说,加密值不一致。我需要 iOS 端的加密值与 android 端的加密值相同,因为它们将共享该数据。我包括 java 函数以及目标 c 类。这两个方面都很灵活,我只是对加密算法了解有限。

这里是java函数。

public DesEncrypter(String passPhrase) {
try {
    // Create the key
    KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount);
    SecretKey key = SecretKeyFactory.getInstance(
        "PBEWithMD5AndDES").generateSecret(keySpec);
    ecipher = Cipher.getInstance(key.getAlgorithm());
    dcipher = Cipher.getInstance(key.getAlgorithm());

    // Prepare the parameter to the ciphers
    AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);

    // Create the ciphers
    ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
    dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
} catch (java.security.InvalidAlgorithmParameterException e) {
} catch (java.security.spec.InvalidKeySpecException e) {
} catch (javax.crypto.NoSuchPaddingException e) {
} catch (java.security.NoSuchAlgorithmException e) {
} catch (java.security.InvalidKeyException e) {
}

}

这是目标 c 类。

@implementation CryptoHelper

#pragma mark -
#pragma mark Init Methods
- (id)init
{
    if(self = [super init])
    {

    }
    return self;
}

#pragma mark -
#pragma mark String Specific Methods

/** 
 *  Encrypts a string for social blast service. 
 *  
 *  @param  plainString The string to encrypt;
 *
 *  @return NSString    The encrypted string. 
 */
- (NSString *)encryptString: (NSString *) plainString{

    // Convert string to data and encrypt
    NSData *data = [self encryptPBEWithMD5AndDESData:[plainString dataUsingEncoding:NSUTF8StringEncoding] password:@"1111"];



    // Get encrypted string from data
    return [data base64EncodingWithLineLength:1024];

}


/** 
 *  Descrypts a string from social blast service. 
 *  
 *  @param  plainString The string to decrypt;
 *
 *  @return NSString    The decrypted string. 
 */
- (NSString *)decryptString: (NSString *) encryptedString{

    // decrypt the data
    NSData * data = [self decryptPBEWithMD5AndDESData:[NSData dataWithBase64EncodedString:encryptedString] password:@"1111"];

    // extract and return string
    return [NSString stringWithUTF8String:[data bytes]];

}


#pragma mark -
#pragma mark Crypto Methods

- (NSData *)encryptPBEWithMD5AndDESData:(NSData *)inData password:(NSString *)password {
    return [self encodePBEWithMD5AndDESData:inData password:password direction:1];
}

- (NSData *)decryptPBEWithMD5AndDESData:(NSData *)inData password:(NSString *)password {
    return [self encodePBEWithMD5AndDESData:inData password:password direction:0];
}

- (NSData *)encodePBEWithMD5AndDESData:(NSData *)inData password:(NSString *)password direction:(int)direction
{
    NSLog(@"helper data = %@", inData);

    static const char gSalt[] =
    {
        (unsigned char)0xAA, (unsigned char)0xAA, (unsigned char)0xAA, (unsigned char)0xAA,
        (unsigned char)0xAA, (unsigned char)0xAA, (unsigned char)0xAA, (unsigned char)0xAA,
        (unsigned char)0x00
    };

    unsigned char *salt = (unsigned char *)gSalt;
    int saltLen = strlen(gSalt);
    int iterations = 15;

    EVP_CIPHER_CTX cipherCtx;


    unsigned char *mResults; // allocated storage of results
    int mResultsLen = 0;

    const char *cPassword = [password UTF8String];

    unsigned char *mData = (unsigned char *)[inData bytes];
    int mDataLen = [inData length];


    SSLeay_add_all_algorithms();
    X509_ALGOR *algorithm = PKCS5_pbe_set(NID_pbeWithMD5AndDES_CBC,
                                          iterations, salt, saltLen);



    memset(&cipherCtx, 0, sizeof(cipherCtx));

    if (algorithm != NULL)
    {
        EVP_CIPHER_CTX_init(&(cipherCtx));



        if (EVP_PBE_CipherInit(algorithm->algorithm, cPassword, strlen(cPassword),
                               algorithm->parameter, &(cipherCtx), direction))
        {

            EVP_CIPHER_CTX_set_padding(&cipherCtx, 1);

            int blockSize = EVP_CIPHER_CTX_block_size(&cipherCtx);
            int allocLen = mDataLen + blockSize + 1; // plus 1 for null terminator on decrypt
            mResults = (unsigned char *)OPENSSL_malloc(allocLen);


            unsigned char *in_bytes = mData;
            int inLen = mDataLen;
            unsigned char *out_bytes = mResults;
            int outLen = 0;



            int outLenPart1 = 0;
            if (EVP_CipherUpdate(&(cipherCtx), out_bytes, &outLenPart1, in_bytes, inLen))
            {
                out_bytes += outLenPart1;
                int outLenPart2 = 0;
                if (EVP_CipherFinal(&(cipherCtx), out_bytes, &outLenPart2))
                {
                    outLen += outLenPart1 + outLenPart2;
                    mResults[outLen] = 0;
                    mResultsLen = outLen;
                }
            } else {
                unsigned long err = ERR_get_error();

                ERR_load_crypto_strings();
                ERR_load_ERR_strings();
                char errbuff[256];
                errbuff[0] = 0;
                ERR_error_string_n(err, errbuff, sizeof(errbuff));
                NSLog(@"OpenSLL ERROR:\n\tlib:%s\n\tfunction:%s\n\treason:%s\n",
                      ERR_lib_error_string(err),
                      ERR_func_error_string(err),
                      ERR_reason_error_string(err));
                ERR_free_strings();
            }


            NSData *encryptedData = [NSData dataWithBytes:mResults length:mResultsLen]; //(NSData *)encr_buf;


            //NSLog(@"encryption result: %@\n", [encryptedData base64EncodingWithLineLength:1024]);

            EVP_cleanup();

            return encryptedData;
        }
    }
    EVP_cleanup();
    return nil;

}

@end

我正在为 ios 使用 openssl 静态库。

谢谢, 布兰登

【问题讨论】:

  • 不太确定。只是我看到的例子。这似乎行得通。只是我在不同类的上下文中加密时加密的值不同。我对加密的完成方式非常灵活,它只需要在两个平台上都一样。

标签: iphone objective-c ios encryption openssl


【解决方案1】:

为了使加密正常工作,两端的一切都必须完全相同。相同的模式,相同的键,相同的 IV 和相同的填充。您需要检查每一项。不要依赖默认模式,而是在两端显式指定 CBC(或 CTR)。生成密钥后,在两端以十六进制打印,以便检查它是否相同。在两端以十六进制打印 IV 进行检查。不要依赖默认值,而是明确指定两端的填充(PKCS5 或 PKCS7)。

我还看到了 cyphertext 的问题,其中 is 以一种字符编码转换为字符串,但又转换回字节,就好像它以另一种字符编码一样。确保您在两端使用相同的字符编码。

一旦您确定了不匹配发生的位置,您就可以修复它们。

在旁注中,我注意到您正在使用 DES。这现在已经过时了,只能用于向后兼容。将 AES 用于所有新应用程序。

【讨论】:

  • 我已经尝试在两个不同的类中使用上面的目标 c 函数。他们根据自己所在的班级产生不同的加密字符串。尽管如此,他们始终在这些班级中产生相同的加密字符串。我从该加密设置中具体遗漏了什么?我相信他们设置为对上面列出的所有内容使用相同的东西。我是否滥用了 openssl 函数?
  • 查看C代码我对salt的设置方式感到不满。它被定义为一个 0xAA 字节的数组,然后转换为 char* 字符串。 0x00 字节将在哪里标记字符串的结尾?如果代码位于具有不同内存内容的不同类中,那么这可能会导致输出不同,那么生成的字符串将具有不同的长度和不同的内容。尝试在盐的末尾添加一个显式的 0x00 字节。
  • 添加了终止字节,一切顺利。这几天我一直在试图弄清楚这有什么问题。为了匹配 java 代码,我回到了没有 IV 的原始算法。该问题已更新以反映新代码。
猜你喜欢
  • 2016-08-18
  • 2013-03-19
  • 2015-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-15
  • 2011-12-05
  • 1970-01-01
相关资源
最近更新 更多