私は現在、.NET C# 機能のサブセットのポートである iPhone アプリに取り組んでいます。3DES で暗号化されたパスワードを使用してサーバーにログインする必要があります (はい、これが最適な標準ではないことは承知していますが、ご容赦ください)。
しかし、これまでのところ、喜びはありません。この C# コードでは、暗号化を適切に複製できません。Objective-C の両方の C# のコードは、次の共通の変数を共有しています。
strPassword
「secret」などの暗号化されていないパスワードです。abPlain
strPassword の 16 進値を持つバイト配列です{73, 65, 63, 72, 65, 74, 02, 02}
rpmPassword
ランダムな文字列です。rpmPasswordAsData
UTF8 エンコーディングを使用した NSData としての rpmPassword の Objective-C のみの表現です。abPassword
rpmPassword の値を持つバイト配列です。nLen
以下の目的の C コードで派生するコードを追加しました
最初の 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)
abInitV
ご覧のとおり、これが返す暗号化された値は、実際にはとの 16 進値を連結したものabCipher
です。
私は Rob Napier から、これを実用的な Objective-C コードに変換しようとしていますが、これまでのところ、それは起こっていません。私は適切な長さの値を生成しており、それらを適切に連結していますがabInitV
、ログインしようとするとサーバーによって拒否されています.abCipher
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;
}
だから、誰かが私が間違っていることを教えてくれたら、心から感謝します。推測を危険にさらす必要がある場合、問題は次の2つの場所のいずれかにあると思います。
- の呼び出しまたはコードでのキーの生成
TDEAKeyForPassword
- 呼び出し
CCCrypt
ます。
そうは言っても、利用可能なすべての PRF 定数と、パディングとパディングなしを試しました。
私は暗号化に非常に慣れていないので、誰かが提供できる助けをいただければ幸いです。
ありがとう!