暗号化について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
たろう

暗号化について

#1

投稿記事 by たろう » 15年前

文字列を暗号化するにはどうしたらよろしいでしょうか?
たとえば、list1.txtという文字列を暗号化キー0x58747382で暗号化するにはどうしたらよいでしょうか?
暗号化の方式は何でもいいのですが、できたら、DESの方を教えていただくとうれしいです。
後、初心者なので暗号化について基礎的なことを教えてもらえるとありがたいです。
なにか勘違いしてるかもしれないですが、わかりやすく説明よろしくお願いします。

めるぽん

Re:暗号化について

#2

投稿記事 by めるぽん » 15年前

Windows で暗号化を行うなら CryptoAPI を使います。
CryptAcquireContext でプロバイダを取得して、CryptCreateHash でハッシュを作って、CryptHashData でハッシュにデータ(キーの値となる 0x58747382)を入れて、CryptDeriveKey でハッシュからキーを取得して、そのキーを使って CryptEncrypt を呼び出すことで list.txt のデータの暗号化ができます。
はい、面倒です。

http://eternalwindows.jp/#crypto
http://eternalwindows.jp/crypto/csp/csp00.html

あたりが、暗号化の基礎的な知識から CryptoAPI の仕組みや実際のコードが載ってたりしてすごく分かりやすかったですね。

ookami

Re:暗号化について

#3

投稿記事 by ookami » 15年前

DESの場合は、キーは56ビット(パリティを入れると64ビット)のようです。
http://ja.wikipedia.org/wiki/DES_(%E6%9A%97%E5%8F%B7)

0x58747382ですとビット数が合いませんね^^;

どのような経緯で暗号化に取り組まれているのか分からないので、
ちょっと回答が難しいですが...
とりあえず「公開鍵」「秘密鍵」「ハッシュ」「パリティ」あたりの用語はどの程度理解されていますか?

たろう

Re:暗号化について

#4

投稿記事 by たろう » 15年前

ぬるぽんさん回答ありがとうございます。
CryptoAPIと言うのがあるのですか。
このサイト参考にありがたく使わせていただきます。
複合化のことについても載っているのでしょうか?

ookamiさん回答ありがとうございます。

>どのような経緯で暗号化に取り組まれているのか分からないので、
ちょっと回答が難しいですが...
友達に自分で作る予定のゲームを画像や音楽を隠したいので画像と音楽の入ったファイルを1つにして暗号化したいと思っています。
DESについては56ビットと言うのは知ってたのですが、どのように使えばいいのかわかりません。
暗号技術入門っという本で一度二度読んだ程度です。公開鍵は暗号キーで暗号化してを相手には別の復号化キーで複合化する。秘密鍵は、相手に暗号キーで暗号化してその暗号化キーを復号化キーにして複合化するだったような気がします。「ハッシュ」「パリティ」は聞いたことがあるくらいです。

ookami

Re:暗号化について

#5

投稿記事 by ookami » 15年前

でしたら俄然オススメなのがこちら。
http://homepage2.nifty.com/natupaji/DxL ... c.html#T11

リソースの暗号化は時々話題にのぼるようですねw
http://www.play21.jp/board/formz.cgi?ac ... &rln=51927

-- 追記

あ、すいません。「DXライブラリを使っているなら」ですが。 画像

めるぽん

Re:暗号化について

#6

投稿記事 by めるぽん » 15年前

>複合化のことについても載っているのでしょうか?
もちろんです。
ただまあ、ローカルで使われる画像や音楽の暗号化程度なら CryptoAPI を使う必要は無いでしょうね。

たろう

Re:暗号化について

#7

投稿記事 by たろう » 15年前

回答ありがとうございます。
早速やってみたのですが、
#include "stdafx.h"
#include <Windows.h>
#include <Wincrypt.h>

#pragma comment(lib, "Crypt32.lib")
#define    PASSWORD    "password"

int _tmain(int argc, _TCHAR* argv[/url])
{
    // キーコンテナの取得
    HCRYPTPROV    hProv;

    if(!CryptAcquireContext(&hProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0)) {
        if(!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_AES, CRYPT_NEWKEYSET)) {
            wprintf(_T("CryptAcquireContext error\n"));
            return 1;
        }
    }

    // ハッシュのインスタンス
    HCRYPTHASH    hHash;

    if(!CryptCreateHash(hProv, CALG_SHA1, 0,0,&hHash)) {
        wprintf(_T("CryptCreateHash error\n"));
        return 2;
    }

    if(!CryptHashData(hHash, (BYTE*)PASSWORD, (DWORD)strlen(PASSWORD), 0)) {
        wprintf(_T("CryptHashData error"));
        return 3;
    }

    // 鍵の生成
#define    KEYLENGTH_256    256 * 0x10000
    HCRYPTKEY    hKey;

    if(!CryptDeriveKey(hProv, CALG_AES_256, hHash, KEYLENGTH_256, &hKey)) {
        wprintf(_T("CryptDeriveKey error\n"));
        return 4;
    }

    // ブロック暗号化のパディングを設定
    DWORD        padding_mode=PKCS5_PADDING;

    if(!CryptSetKeyParam(hKey, KP_PADDING, (BYTE*)&padding_mode, 0)) {
        wprintf(_T("CryptSetKeyParam error\n"));
        return 5;
    }

    /*
    // ブロックサイズを取得
    {
        DWORD    blkLen;
        DWORD    dwDataLen=(DWORD)sizeof(DWORD);
        if(!CryptGetKeyParam(hKey, KP_BLOCKLEN, (BYTE*)&blkLen, &dwDataLen, 0)) {
            wprintf(_T("CryptGetKeyParam error"));
            return 97;
        } else {
            wprintf(_T("Bolock length is %d bytes.\n"), blkLen / 8);
        }
    }
    /**/

    // 初期化ベクタ
    BYTE    iv[/url]={0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};

    if(!CryptSetKeyParam(hKey, KP_IV, iv, 0)) {
        wprintf(_T("CryptSetKeyParam error\n"));
        return 98;
    }

    // Cipherモードを設定
    DWORD    mode = CRYPT_MODE_CFB;
    if(!CryptSetKeyParam(hKey, KP_MODE, (BYTE*)&mode, 0)) {
        wprintf(_T("CryptSetKeyParam error\n"));
        return 99;
    }

    // 復号用にキーを複製
    HCRYPTKEY    hdKey;

    if(!CryptDuplicateKey(hKey, NULL, 0, &hdKey)) {
        wprintf(_T("CryptDuplicateKey error\n"));
        return 6;
    }

    // 暗号化
#define    BUF_LEN    100

    BYTE    pbData[BUF_LEN]="This is a palin text data.";
    DWORD    dwDataLen=(DWORD)(strlen((char*)pbData)+1);

    if(!CryptEncrypt(hKey, 0, TRUE, 0, pbData, &dwDataLen, (DWORD)BUF_LEN)) {
        wprintf(_T("CryptEncrypt error\n"));
        return 7;
    } else {
        WCHAR    str[1000];
        DWORD    strLen=1000;

        CryptBinaryToString(pbData, dwDataLen, CRYPT_STRING_HEXASCIIADDR, str, &strLen);
        wprintf(str);
        wprintf(_T("Encrypted data length is %d bytes\n"), dwDataLen);
    }

    // 復号
    if(!CryptDecrypt(hdKey, 0, TRUE, 0, pbData, &dwDataLen)) {
        wprintf(_T("CryptDecrypt error\n"));
        return 8;
    } else {
        WCHAR    str[1000];
        DWORD    strLen=1000;

        CryptBinaryToString(pbData, dwDataLen, CRYPT_STRING_HEXASCIIADDR, str, &strLen);
        wprintf(str);
        wprintf(_T("Decrypted data length is %d bytes\n"), dwDataLen);
    }

    // 後始末
    CryptDestroyKey(hKey);
    CryptDestroyKey(hdKey);
    CryptDestroyHash(hHash);
    CryptReleaseContext(hProv, 0);

    return 0;
}
でどうしても、wprintf(_T("CryptAcquireContext error\n"));で止まってしまいます。
どうしたらよいでしょうか?

めるぽん

Re:暗号化について

#8

投稿記事 by めるぽん » 15年前

うーん、直接の原因は分かりましたが、スマートな解決方法が分かりませんね・・・。
多分 Windows XP ですよね?


MS_ENH_RSA_AES_PROV を定義している部分を見てみると、
#if (NTDDI_VERSION >= NTDDI_WS03)
#define MS_ENH_RSA_AES_PROV_A   "Microsoft Enhanced RSA and AES Cryptographic Provider"
#define MS_ENH_RSA_AES_PROV_W   L"Microsoft Enhanced RSA and AES Cryptographic Provider"
#elif (NTDDI_VERSION == NTDDI_WINXP)
#define MS_ENH_RSA_AES_PROV_A   "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
#define MS_ENH_RSA_AES_PROV_W   L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
#endif //(NTDDI_VERSION >= NTDDI_WS03)
#if (NTDDI_VERSION >= NTDDI_WINXP)
#ifdef UNICODE
#define MS_ENH_RSA_AES_PROV     MS_ENH_RSA_AES_PROV_W
#else
#define MS_ENH_RSA_AES_PROV     MS_ENH_RSA_AES_PROV_A
#endif
#endif //(NTDDI_VERSION >= NTDDI_WINXP)
となっています。自分の環境(Windows XP SP3)では NTDDI_VERSION >= NTDDI_WS03 に引っかかって、 "(Prototype)" の付いていない方が選択されていました。


MS_ENH_RSA_AES_PROV のドキュメント(http://msdn.microsoft.com/en-us/library ... 85%29.aspx)を見てみると
<blockquote>
Windows XP: The Microsoft AES Cryptographic Provider was named Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype).
</blockquote>
とあります。なので XP では "(Prototype)" のある方の文字列を渡さないといけないのですが、なぜかそちらが選択されないようなのです。


なので MS_ENH_RSA_AES_PROV と書かずに _T("Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)") とすればうまくいったのですが、もっとスマートな方法があるような気がしますね。 画像

めるぽん

Re:暗号化について

#9

投稿記事 by めるぽん » 15年前

あ、あと全然関係ない話ですけど、TCHAR の文字列を出力する場合は wprintf ではなくて _tprintf を使用した方がいいですね。

たろう

Re:暗号化について

#10

投稿記事 by たろう » 15年前

返信遅れてしまってすみません。
回答ありがとうございます。
原因がわかっただけでもよかったです。
おかげでできました。
ありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る