【问题标题】:3DES encryption with CBC mode in objective c在目标 c 中使用 CBC 模式进行 3DES 加密
【发布时间】:2012-09-28 20:00:58
【问题描述】:

我正在尝试在 iOS 上使用 3DES 和 CBC 模式加密来加密 NSString。

在 ASP.NET 上也使用了相同的加密方法,并且他们获得的加密字符串可与 Web 服务一起使用。从.NET代码中得到woodcraft554的加密字符串为:9SWzd+rlvu/tK5UZoCXt8Q==

.NET 使用零填充进行加密。我使用的代码是:

+(NSString*)new3DESwithoperand:(NSString*)plaintext encryptOrDecrypt:(CCOperation)encryptorDecrypt key:(NSString*)key initVec:(NSString*)initVec
{     

NSData* data = [plaintext dataUsingEncoding:NSUTF8StringEncoding];
const void *vplainText = [data bytes];;
size_t plainTextBufferSize = [data length];
NSLog(@"%@, Length: %u",[data description],[data length]);

size_t bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
NSLog(@"%zu, sizof of uint8_t: %zu",bufferPtrSize, sizeof(uint8_t));
size_t movedBytes = 0;
uint8_t *bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
NSLog(@"%zu",sizeof(bufferPtr));
memset((void*)bufferPtr, 0x0, bufferPtrSize);
NSLog(@"%zu",sizeof(bufferPtr));
//    memset((void *)initVec, 0x0, (size_t) sizeof(initVec));
const void * vkey = [[NSString base64DataFromString:key] bytes];
const void *vinitVec = [[NSString base64DataFromString:initVec] bytes];
NSLog(@"vinitvec: %@",[[NSString base64DataFromString:initVec] description]);

CCCryptorStatus ccStatus;
ccStatus = CCCrypt(encryptorDecrypt,
                   kCCAlgorithm3DES,
                   kCCOptionPKCS7Padding & kCCModeCBC,
                   vkey,
                   kCCKeySize3DES,
                   vinitVec,
                   vplainText,
                   plainTextBufferSize,
                   (void*)bufferPtr,
                   bufferPtrSize,
                   &movedBytes);

NSData* result = [NSData dataWithBytes:(const void*)bufferPtr length:(NSUInteger)movedBytes];
NSString* str = [NSString base64StringFromData:result length:result.length];
NSLog(@"%@",str);

return str;
}

我将 Objective-c 代码中的 vplainTextvkeyvinitVec 与 .NET 中的代码进行了比较。他们是一样的。我得到的加密字符串是9SWzd+rlvu8=。我相信这与填充有关。

这是他们正在使用的等效 .NET 代码:

protected string EncryptCreditCard(string creditCard)
{
    try
    {
        string ENCRYPTION_KEY = ConfigurationManager.AppSettings["ENCRYPTION_KEY"].ToString();
        string ENCRYPTION_IV = ConfigurationManager.AppSettings["ENCRYPTION_IV"].ToString();

        SymmetricAlgorithm sa = SymmetricAlgorithm.Create("TripleDES");
        sa.Key =   System.Convert.FromBase64String(ENCRYPTION_KEY);
        sa.IV =  System.Convert.FromBase64String(ENCRYPTION_IV);
        sa.Padding = PaddingMode.Zeros;

        byte[] inputByteArray = Encoding.ASCII.GetBytes(creditCard);
        MemoryStream mS = new MemoryStream();

        ICryptoTransform trans = sa.CreateEncryptor();
        byte[] buf = new byte[2048];
        CryptoStream cs = new CryptoStream(mS, trans, CryptoStreamMode.Write);
        cs.Write(inputByteArray, 0, inputByteArray.Length);
        cs.FlushFinalBlock();

        return Convert.ToBase64String(mS.ToArray());
    }
    catch
    {
        return "";
    }
}

如何在 iOS 中获得正确的加密字符串?

【问题讨论】:

    标签: objective-c ios xcode encryption


    【解决方案1】:

    通过使用零填充。您的代码清楚地说明了kCCOptionPKCS7Padding,这不是零填充。否则密文似乎相同。

    请注意,最好在 .NET 代码中使用 PaddingMode.PKCS7。它会在奇怪的情况下添加一些数据,即纯文本的大小已经是块大小的数倍,但它是标准化的,并且取消填充不再取决于纯文本值。

    【讨论】:

    • 感谢 owlstead 的回复。您将如何在 iOS 代码上应用零填充。我尝试在 CCCrypt 方法中传递 '0' 作为参数来代替 kCCOptionPKCS7Padding。它似乎也不起作用。
    • 您可能必须自己编程 - 零填充不是标准化的。零填充只是将零字节添加到明文,直到明文是块大小的倍数。在您的情况下,它不会填充,因为情况已经如此。请注意,零填充不应用于无法确定长度的二进制数据(因为二进制数据可能以设置为 0 的字节结尾)
    • 显然最好在 .NET 兼容代码中切换到 PaddingMode.PKCS7,以防万一。您要求做相反的事情,但建议使用 PKCS#7 填充。
    • 现在无法在 .NET 中更改代码。我必须在 iOS 中实现零填充。我在网上找不到任何在 iOS 中实现零填充的资源。
    • 只需将纯文本复制到一个新的或密文缓冲区(应该足够大)。然后添加值 00 的字节,直到到达末尾。将标准纯文本缓冲区替换为您将纯文本复制到 + 填充中的缓冲区并对其进行加密,而不使用 kCCOptionPKCS7Padding。不需要图书馆。
    【解决方案2】:

    问题在于用于加密的“密钥”。 iOS 使用 24Byte 密钥,而 Adnroid 和 .NET 使用 16Byte 密钥。

    已针对同一问题发布了详细的解决方案,其中描述了密钥生成。 Solution for different encryption value generated in iOS

    【讨论】:

    • 这不是 iOS 与 Adnroid 的问题,它是 3DES 密钥的两种不同方案。 3DES 使用三个 8 字节的密钥串行加密(这 3 个字节中只有 56 位用作密钥材料)。 “完整”3DES 是 24 字节,通常采用 ede 方案(用第一个密钥加密,用第二个密钥解密输出,用第三个密钥加密输出),但偶尔也会使用其他序列。对于某些向后兼容系统(银行是主要系统),有一个版本使用两个 8 字节密钥,一个使用两次。这就是 Android 在这里所做的。
    • @Zaph 我提到问题出在所使用的密钥上。 Android或iOS没有问题。也谢谢你提到银行业,我不知道。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-14
    • 1970-01-01
    • 1970-01-01
    • 2015-11-02
    • 1970-01-01
    • 2011-12-16
    • 1970-01-01
    相关资源
    最近更新 更多