web-dev-qa-db-ja.com

RC4を使用したCryptoAPIからCommonCryptoへ

Crypto API関数を使用するWindowsプラットフォームで使用される暗号化コードがあり、これをOS XのCommon Cryptoを使用するように変換する必要があります。

基本的に、元のコードはこれです。簡潔にするためにエラーチェックは削除されています。-

CryptAcquireContext(&m_hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT));
CryptCreateHash(m_hProv, CALG_MD5 ,0, 0, &hHash);
CryptHashData(hHash,(LPBYTE)pszInputData, lstrlen(pszInputData)*sizeof(TCHAR), 0);

CryptDeriveKey(m_hProv, CALG_RC4, hHash, CRYPT_EXPORTABLE | 0x00280000, &m_hKey);
CryptDecrypt(m_hKey, 0, bFinal, 0, pData, pdwDataSize);

私が理解している限り、これは起こっていることです:-

CryptAcquireContext-暗号化を処理するオブジェクトを取得します

CryptCreateHash-MD5ハッシュオブジェクトを作成する

CryptHashData-MD5で入力データをハッシュする

CryptDeriveKey、CryptDecrypt-キーm_hKeyを使用して、RC4でpDataをデコードする

PszInputDataのサイズは12バイトで、MD5ハッシュオブジェクトの出力配列は両方のプラットフォームで同じです。

RC4でデコードするには、Common Cryptoで次のようにします:-

CCCryptorRef cryptor = NULL;
CCCryptorCreate(kCCDecrypt, kCCAlgorithmRC4, 0,
                      (void*)m_hKey.data(), m_hKey.length(), NULL, &cryptor);

char outBuffer[12];
size_t outBytes;
CCCryptorUpdate(cryptor, (void*)pData, *pdwDataSize, outBuffer, 12, &outBytes);

オンラインのRC4デコーダーでCommon Cryptoからの出力(outBuffer配列)をテストすると、これは正しくデコードされます。

ただし、pDataのWindowsコードからの最終出力は、Common CryptoでデコードされたRC4と一致しません。

ここに、Windows Crypto API呼び出しで欠けている、または理解していない手順がありますか?なぜ出力が異なるのですか?

(RC4を使用する際のセキュリティや欠陥についてのコメントは探していません)

3
TheDarkKnight

CryptDeriveKey()documentation によると、dwFlagsパラメータの上位ワードは、希望するキーサイズをビット単位で指定します。あなたのケースでは、40ビット(0x28)のキーを生成し、MD5出力の最初の5バイトを除くすべてを効果的に破棄する必要があります。

CommonCryptoで同様の動作を実現するには、これを試すことができます。

_CCCryptorCreate(kCCDecrypt, kCCAlgorithmRC4, 0,
                      (void*)m_hKey.data(), 5, NULL, &cryptor);
_

編集:

実際、上記のコードはCryptDeriveKey()と互換性がありません。 (コメントで公開されたテストベクタから)Windowsは依然として16バイトのキーを使用しているが、最後の11バイトはゼロに設定されていることがわかります(したがって、有効なキーの長さは5バイトまたは40ビットです)。 Pythonコード:

_from Crypto.Cipher import ARC4
import binascii

KEY = "cfba3dd2ed"
DATA = "eb b9 bd 6f 5d 46 8d 17 c1 88 db 78"

key = binascii.unhexlify(KEY) + "\x00" * 11
rc4 = ARC4.new(key)
print binascii.hexlify(rc4.encrypt(binascii.unhexlify(DATA.replace(" ", "").strip())))
_

私のための出力:

_04021f02730101000000ff9b
_

このCommonCryptoコードは機能するはずです。

_if (m_hKey.length() > 5) {    
    memset(m_hKey.data() + 5, 0, m_hKey.length() - 5);
}

CCCryptorCreate(kCCDecrypt, kCCAlgorithmRC4, 0,
                          (void*)m_hKey.data(), m_hKey.length(), NULL, &cryptor);
_
2
Andrey