2013-05-09 47 views
3

我目前正在研究一個iPhone應用程序,它是.NET C#功能子集的一個端口。我必須使用3DES加密密碼登錄服務器(是的,我知道這不是最佳標準,但請耐心等待)。將C#CryptoSys輔助3DES加密移植到Objective-C CommonCrypto問題

但是,到目前爲止,沒有快樂。我無法在此C#代碼中正確複製加密。在目標c股在C#代碼這些公共變量:

  1. strPassword是未加密的密碼,如「祕密」
  2. abPlain是一個字節數組與strPassword {73, 65, 63, 72, 65, 74, 02, 02}的十六進制值
  3. rpmPassword被一串隨機字符。
  4. rpmPasswordAsData是作爲NSData的使用UTF8編碼
  5. abPassword rpmPassword的目標-C僅表示被一個字節數組
  6. 我已經添加了代碼在下面的目標-C代碼來推導nLen rpmPassword的值

這裏的C#代碼第一:

static int ITERATIONCOUNT = 2048; 
static int KEYBYTES = 24; 
static int BLOCKBYTES = 8; 

byte[] abInitV = CryptoSysAPI.Rng.NonceBytes(BLOCKBYTES); 
byte[] abKey = CryptoSysAPI.Pbe.Kdf2(KEYBYTES, abPassword, abInitV, ITERATIONCOUNT); 

CryptoSysAPI.Tdea cipher = CryptoSysAPI.Tdea.Instance(); 
cipher.InitEncrypt(abKey, Mode.CBC, abInitV); 

byte[] abCipher = cipher.Update(abPlain); 

abOutput = new byte[abCipher.Length + BLOCKBYTES]; 
for (int i = 0; i < BLOCKBYTES; i++) abOutput[i] = abInitV[i]; 
for (int i = 0; i < nLen + nPad; i++) abOutput[BLOCKBYTES + i] = abCipher[i]; 

return CryptoSysAPI.Cnv.ToHex(abOutput) 

正如你所看到的,加密值這將返回實際上是AC十六進制值爲abInitVabCipher的中間值。

我一直在從羅布納皮爾試圖轉換成工作目標C代碼,但到目前爲止,它沒有發生。我生產長度合適的abInitVabCipher價值,而且我也連接起來將正常到abOutput,但我被服務器拒絕當我嘗試登錄。

這是我的目標c代碼(常量也宣告,我答應):

int nLen = [strPassword length]; 
int nPad = ((nLen/BLOCKBYTES) + 1) * BLOCKBYTES - nLen; 

NSData *abInitV = [self randomDataOfLength:BLOCKBYTES]; // This is the salthex for the encryption 
const unsigned char *abInitVAsBytes = [abInitV bytes]; 

NSData *abKey = [self TDEAKeyForPassword:strPassword salt:abInitV]; 

size_t movedBytes = 0;  
NSMutableData *abCipher = [NSMutableData dataWithLength:BLOCKBYTES]; 

CCCryptorStatus result = CCCrypt(kCCEncrypt, 
           kCCAlgorithm3DES, 
           ccNoPadding & kCCModeCBC, 
           [abKey bytes], 
           kCCKeySize3DES, 
           [abInitV bytes], 
           abPassword, 
           [rpmPasswordAsData length], 
           abCipher.mutableBytes, 
           KEYBYTES, 
           &movedBytes); 

if (result == kCCSuccess) 
{ 
    NSLog(@"abCipher == %@ \n", [abCipher description]); 
} 

NSMutableData *abOutput = [NSMutableData dataWithCapacity:[abCipher length] + BLOCKBYTES]; 
const unsigned char *abCipherAsBytes = [abCipher bytes]; 

for (int i = 0; i < BLOCKBYTES; i++) 
{ 
    [abOutput replaceBytesInRange:NSMakeRange(i, sizeof(abInitVAsBytes[i])) withBytes:&abInitVAsBytes[i]]; 
} 
for (int i = 0; i < nLen + nPad; i++) 
{ 
    [abOutput replaceBytesInRange:NSMakeRange(BLOCKBYTES + i, sizeof(abCipherAsBytes[i])) withBytes:&abCipherAsBytes[i]];   
} 

return [EncryptionUtil NSDataToHex:abOutput]; 

,這裏是支持方法調用上面的代碼:

+(NSString*) NSDataToHex:(NSData*)data 
{ 
    const unsigned char *dbytes = [data bytes]; 
    NSMutableString *hexStr = 
    [NSMutableString stringWithCapacity:[data length]*2]; 
    int i; 
    for (i = 0; i < [data length]; i++) { 
     [hexStr appendFormat:@"%02x ", dbytes[i]]; 
    } 
    return [NSString stringWithString: hexStr]; 
} 

+(NSData*)HexToNSData:(NSString*)hex 
{ 
    NSMutableData* data = [NSMutableData data]; 
    int idx; 
    for (idx = 0; idx+2 <= [hex length]; idx+=2) { 
     NSRange range = NSMakeRange(idx, 2); 
     NSString* hexStr = [hex substringWithRange:range]; 
     NSScanner* scanner = [NSScanner scannerWithString:hexStr]; 
     unsigned int intValue; 
     [scanner scanHexInt:&intValue]; 
     [data appendBytes:&intValue length:1]; 
    } 
    return data; 
} 

+(NSData *)randomDataOfLength:(size_t)length 
{ 
    NSMutableData *data = [NSMutableData dataWithLength:length]; 

    int result = SecRandomCopyBytes(kSecRandomDefault, 
           length, 
           data.mutableBytes); 

    NSAssert(result == 0, @"Unable to generate random bytes: %d", 
     errno); 

    return data; 
} 

+(NSData *)TDEAKeyForPassword:(NSString *)password 
        salt:(NSData *)salt 
{ 
    NSMutableData * 
    derivedKey = [NSMutableData dataWithLength:kCCKeySize3DES]; 

    int result = CCKeyDerivationPBKDF(kCCPBKDF2,   // algorithm 
            password.UTF8String, // password 
            password.length, // passwordLength 
            salt.bytes,   // salt 
            salt.length,   // saltLen 
            kCCPRFHmacAlgSHA1, // PRF 
            ITERATIONCOUNT,   // rounds 
            derivedKey.mutableBytes, // derivedKey 
            derivedKey.length); // derivedKeyLen 

    return derivedKey; 
} 

所以,如果有人能告訴我什麼我做錯了,我真誠地感謝你。如果讓我猜的話,我認爲這個問題是在兩個地方之一:

  1. 生成的關鍵,無論是在調用,或代碼的TDEAKeyForPassword
  2. 調用CCCrypt

這就是說,我試過每一個可用的PRF常量,以及填充和沒有填充。

我對加密非常不熟悉,所以我很感謝任何人都可以提供的幫助。

謝謝!

+0

什麼是'npad'?什麼是'strPassword'?什麼是'abPassword'?什麼是'rpmPasswordAsData'? – trudyscousin 2013-05-10 01:32:43

+0

對不起,trudyscousin。我的錯。我已經添加了上面的細節。 – Rob 2013-05-10 12:58:50

回答

0

首先,您的代碼示例看起來非常不同。 C#代碼正在加密abPlain。 ObjC代碼正在加密abPassword。您指出abPlain是靜態的,而abPassword是隨機的。你在ObjC中有一些填充,我沒有在C#中看到(也許這是0填充?這不是一種標準填充方式)。

如果刪除了隨機性,那麼每個實現應該對於相同的輸入返回完全相同的結果。首先,硬編碼一個隨機值(我通常喜歡使用0,這與其他編號一樣隨機),並且還選擇一個通用的abPassword。然後,在該過程的每個步驟中,確保兩個實現都生成相同的結果。最顯着的是abKey相同,然後是abCipher,最後是abOutput。在其中的一點上,你的實現明顯不同。 (從我的快速閱讀來看,他們似乎一直在做着非常不同的事情。)

有一件事很讓人困惑,那就是如何在abPasswordrpmPassword之間切換。在一種情況下,您通過abPassword,但長度爲rpmPasswordAsData。這感覺就像一個容易犯錯的地方。

abPassword的長度尚不清楚。我認爲它是8的倍數,否則你的ccNoPadding會爆炸。

NSMutableData有一個appendData方法。這比你更容易replaceBytesInRange:…

+0

謝謝,羅伯! abPlain/abPassword是問題的根源。我衷心感謝您閱讀本文。 – Rob 2013-05-16 18:17:46