それで、新しい「暗号ゲーム」が私の好みになりました。 したがって、今日は、C ++とOpenMPを使用した簡単なマルチスレッドブラウザーの実装、およびプロジェクトでのCryptoPP暗号ライブラリとサードパーティのfastpbkdf2モジュール(CおよびPlus用)の使用について簡単に説明します。
クッキーの下に行く、そこにクッキー!
免責事項。 他人のパスワードを整理することは不可能です。 自分宛てでないテキストを読むことはできません 。コンピューター情報への不正アクセスを目的としたマルウェアを作成および配布することはできません 。 刑法により処罰可能。 ディクシ
解析条件
タスクの実際のラッパーは、次のテキストが記載された小さなカードです。
SGFzaGVkU2FsdCg4Ynl0ZXNJblVURjE2TEUpQ291bnRlckNpcGhlcnRleHRB
RVMyNTZFQ0J8MWE0MDhhYTVhZjkzMDkxOGRkYjkyNzQ3NDBhMDJjMmJkM2Vl
N2NkNjU3MDQwMDAwMDQxN2E2Nzc4Yzc3YzYwZjcxMGJlNTNiNmViODQ0ZDg0
MmUwZWEwZGYwNDA2NTU4NWEzMzIzYTUwZjc2OGY1N3xQb3NzaWJsZVBhc3N3
b3JkUGF0dGVybnN8RERMTExMTEx8RExMTExMTER8TExMRERMTEx8TExMTExM
REQ=
Base64ではなぜですか? 先生はこれに答えました:「条件のための選択の選択がないように」。 本当に欲しくない。 また、言い換えれば、パスワードをキーに変換するために使用されるアルゴリズム(PBKDF2_HMAC_SHA1)についての情報が送信され、簡単なゲーム条件が定式化されました:「ブロック暗号で暗号化されたメッセージを回復するパスワードを選択します。 パスワードは辞書ではなく、数字とラテンアルファベットの小文字、塩で構成できます-小文字のみ。 エンコーディングが隠しているものを見てみましょう:
HashedSalt(8bytesInUTF16LE)CounterCiphertextAES256ECB|1a408a
a5af930918ddb9274740a02c2bd3ee7cd6570400000417a6778c77c60f71
0be53b6eb844d842e0ea0df04065585a3323a50f768f57|PossiblePassw
ordPatterns|DDLLLLLL|DLLLLLLD|LLLDDLLL|LLLLLLDD
何が見えますか? メッセージの最初の部分(最初の垂直スラッシュの前)は、おそらく2番目の部分に直接示されているデータの順序です:ソルトハッシュ(括弧内のエンコード情報付き)、PBKDF2の反復カウンター、使用されるブロック暗号、および暗号化モード AESもここに来ました。誰が考えたでしょう... 3番目と最後は、必要なパスワードの潜在的なマスクです。Lは文字(文字)、Dは数字(数字)です。 また、パスワードは8文字で構成されていると判断されます。 論理的に聞こえるかもしれませんが、受信した情報を構造化するのが良いでしょう。
メッセージの2番目のブロックを分析しましょう。 タスクに使用されるソルトハッシュ関数に関する情報はありません。したがって、SHA1であると想定します。これは、20バイトの出力長を持つ唯一の広く使用されている暗号化ハッシュ関数であるためです(このサイズのみがパーティションの残りに完全に適合します)。 カウンターがリトルエンディアンで表示されることも明らかです。少なくとも、PBKDF2の0x57040000 = 1459879936の反復は列挙の最良の見込みではないので、少なくともそう思うと思います。そして最後に、それぞれ16バイトの2つのAESブロックがあります。 したがって、次の図があります。
1A408AA5AF930918DDB9274740A02C2BD3EE7CD6
ソルトハッシュ(20バイト);
0x00000457 = 1111
反復カウンターPBKDF2;
0417a6778c77c60f710be53b6eb844d8
暗号文の最初のブロック(16バイト);
42e0ea0df04065585a3323a50f768f57
暗号文の2番目のブロック(16バイト)。
塩回収
さて、初心者向けに、塩分回収のための
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Usage: python3 crack_salt_hash.py from hashlib import sha1 from itertools import product ALPH = 'abcdefghijklmnopqrstuvwxyz' SIZE = 4 TOTAL = len(ALPH)**SIZE def crack_hash(func, output, enc): progress = 0 for salt in product( *([ALPH]*SIZE) ): if func(''.join(salt).encode(encoding=enc)).hexdigest() == output: print(progress+1, 'of', TOTAL) return ''.join(salt) progress += 1 if progress % 10000 == 0: print(progress, 'of', TOTAL) return None if __name__ == '__main__': print(crack_hash(sha1, '1a408aa5af930918ddb9274740a02c2bd3ee7cd6', 'UTF-16LE'))
3秒後に、結果は " dukg "になります。 2バイトのエンコーディングが与えられた場合、最終的なソルト形式(PBKDF2に入力するのに適した)は " d \ x00 u \ x00 k \ x00 g \ x00 "になります。
暗号化のニーズ
次に、暗号化を操作するためのツールを選択する必要があります。 順序:最初に、パスワードからキーを取得することについて考え、次にメッセージを復号化することについて考えましょう。 両方の問題を解決するために、OpenSSLまたはCrypto ++(別名CryptoPP)という2つの選択肢がすぐに思い浮かびます。 どちらのパッケージも広く知られており、C ++で作業することは難しくありません(言語の選択は、高速な検索速度の必要性に基づいて行われました)。
キー生成
少し先を見ると、1111回の繰り返しで特定のカウンターのOpenSSLからの標準関数PKCS5_PBKDF2_HMAC_SHA1が4コアIntel Core i5 2.60GHzで実行中に1000キー/秒の平均速度を示したと言う価値があります。 最良の結果ではないため、キーを生成するための代替の「ポンプ」ソリューションを探すことにしました。 このソリューションは、サードパーティ開発者のfastpbkdf2ライブラリでした。 ライブラリは同じOpenSSL(そこからのハッシュ関数自体の実装)に基づいていますが、説明によると、PBKDF2を計算するときに「内部forループのさまざまな最適化」を使用します。 この説明は私に非常によく合います。さらに、パフォーマンスは約3.45倍に向上しました。現在、3450パスワード/秒の速度で破壊されています。
モジュールはCで記述されており、C99をサポートするコンパイラが必要です。したがって、Plusプロジェクトにモジュール(モジュール)を埋め込むには、ソースからコンパイルし、次のように動的ライブラリを作成します。
$ gcc fastpbkdf2.c -fPIC -std=c99 -O3 -c -g -Wall -Werror -o fastpbkdf2.o $ gcc -shared -lcrypto -o libfastpbkdf2.so fastpbkdf2.o
そして今、最終的なブルーター(まだ書いていませんが、元の名前-" bruter.cxx "を思いついています)を起動するには、次のようにこのライブラリーにフィードを送る必要があります。
$ g++ bruter.cxx -o bruter -L"/path/to/libfastpbkdf2.so" -Wl,-rpath="/path/to/libfastpbkdf2.so" -lfastpbkdf2
最後に、自動化のためにMakefileを追加します。 次に、パスワードの有効性チェックがどのように行われるかを見てみましょう。
bool checkPassword( uint8_t* password, const uint8_t* ciphertext, uint8_t* decrypted, int& decryptedLength ) { uint8_t key[KEY_LENGTH]; fastpbkdf2_hmac_sha1( password, PASSWORD_LENGTH, salt, SALT_LENGTH, iterations, key, KEY_LENGTH ); decryptedLength = CryptoPP_Decrypt_AES_256_ECB( ciphertext, (uint8_t*) key, decrypted ); if (isPrintable(decrypted, decryptedLength)) return true; return false; }
CryptoPP_Decrypt_AES_256_ECB
は、まだ記述されていない復号化関数です。 戻り値は、基準チェックの結果に応じてtrue / falseです。 正しい復号化の基準は、すべてのプレーンテキスト文字の印刷可能性であり、基準の評価は
isPrintable
関数にあります(結論の完全なリストを参照)。
メッセージの復号化
メッセージを解読するために、 Crypto ++ライブラリに助けを求めます。
このパッケージのフレームワーク内でブロック暗号を操作する手順に従って、次の手順を実行します。ECB(復号化)モードでAESを復号化するための機能オブジェクトを作成し、キーで初期化し(キーのサイズによってAESのバージョンが決まります-この場合はAES-256)、出力バッファーを割り当てますデクリプターを含むアルゴリズムに従って、暗号文をプレーンテキストに変換する操作を実行します。 また、ブロックの仕上げ( PADDING )はまったく使用されていないと仮定します。これは、仕上げの形式について条件が沈黙しているためです。 したがって、元のメッセージの長さは、1つのAESブロックの長さの倍数でなければなりません。
int CryptoPP_Decrypt_AES_256_ECB( const uint8_t* ciphertext, uint8_t* key, uint8_t* plaintext ) { ECB_Mode<AES>::Decryption decryptor; decryptor.SetKey(key, AES::MAX_KEYLENGTH); ArraySink ps(&plaintext[0], PLAINTEXT_LENGTH); ArraySource( ciphertext, CIPHERTEXT_LENGTH, true, new StreamTransformationFilter( decryptor, new Redirector(ps), StreamTransformationFilter::NO_PADDING ) ); return ps.TotalPutLength(); }
この関数は、復号化されたメッセージの長さを返します。
新しい情報
日中、上記の準備作業で忙しかったが、著者からメールで「パスワード構造に関する新しい情報が表面化した」という手紙が届いた。 一般的に、パスフレーズを作成するときに、ユーザーがユニットと文字「 q 」を入力するときに誤ってShiftを押したままになっていることが報告されました。 メッセージを言い換えると、パスワードの保証されたコンポーネントとして、記号「 ! 」(数字の代わり)と文字「 Q 」(文字の代わり)が得られます。 ユーザーにとってニュースは最高ではありませんが、私たちにとっては素晴らしいことです。これは、検索エリアの大幅な絞り込みを意味します。 完全に検索するために必要な時間を評価するとき、少し後に、非常にうまく得られた利点の数値評価を行います。
並列ブルーター
事は小さいです:制御関数を書き、マルチスレッドの要素を導入することは残っています。 計算を並列化するには、OpenMPプラグマを使用します。 列挙するパスワードの総数は既知の量です。 たとえば、4つのパスワードモデルのいずれかを考えます(数字の1つが実際に「!」であり、文字の1つが「Q」である場合)。
最初の2つのブラケットは、それぞれ26〜5および10〜1(5文字と1桁)の繰り返しがある配置の数です。3番目のブラケットの要素は、置換「!」です。 ( 2つの位置に立つことができます)および順列「Q」( 6つの位置に立つことができます)。 結果に4を掛けて、完全な列挙領域を定義します。 または57億
リージョンの境界が定義されているため、パスワードを生成するために、ネストされたforループとomp parallel forプラグマをcollapse()パラメーターとともに使用して 、複数のループを1つの大きなループに「折りたたみ」ます。 collapse()を使用するには、ループの「完全なネスト」を維持する必要があることを覚えておく必要があります。 つまり、後続の各サイクル(もちろん最後のサイクルを除く)には次のforステートメントのみが含まれ、すべての操作は最後のネストサイクルで実行されます。
また、コードの記述を開始する前に、興味深い機能に注目しましょう。次の各パスワードモデルは、別のモデルの1つまたは3つの位置による循環シフトです。 これを考慮すると、ループの1回の繰り返しで各モデルからのパスワードの列挙をより簡単に整理できます。
void Parallel_TotalBruteForce( uint8_t* goodPassword, uint8_t* goodDecrypted, int& goodDecryptedLength ) { uint8_t alp[27] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\0' }; uint8_t num[11] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '\0' }; #ifdef WITH_OPENMP omp_set_num_threads(myOMP_THREADS); #endif uint64_t progress = 0; bool notFinished = true; #pragma omp parallel for shared(progress, notFinished) collapse(8) for (int a = 0; a < 2; a++) for (int b = 2; b < 8; b++) for (int c = 0; c < 26; c++) for (int d = 0; d < 26; d++) for (int e = 0; e < 26; e++) for (int f = 0; f < 26; f++) for (int g = 0; g < 26; g++) for (int h = 0; h < 10; h++) { if (notFinished) { uint8_t password[9]; password[PASSWORD_LENGTH] = '\0'; uint8_t indeces[6] = { 2,3,4,5,6,7 }; memmove(indeces+b, indeces+b+1, 5-b); uint8_t decrypted[100]; int decryptedLength; password[ a] = '!'; // 0-1 password[ !a] = num[h]; // 0-1 password[ b] = 'Q'; // 2-7 password[indeces[0]] = alp[c]; // 2-7 password[indeces[1]] = alp[d]; // 2-7 password[indeces[2]] = alp[e]; // 2-7 password[indeces[3]] = alp[f]; // 2-7 password[indeces[4]] = alp[g]; // 2-7 if ( // DDLLLLLL checkPassword( password, ciphertext, decrypted, decryptedLength ) || // DLLLLLLD checkPassword( rotateLeft(password, 1), ciphertext, decrypted, decryptedLength ) || // LLLLLLDD checkPassword( rotateLeft(password, 1), ciphertext, decrypted, decryptedLength ) || // LLLDDLLL checkPassword( rotateLeft(password, 3), ciphertext, decrypted, decryptedLength ) ) { #pragma omp critical { memcpy( goodPassword, password, 9 ); memcpy( goodDecrypted, decrypted, decryptedLength ); goodDecryptedLength = decryptedLength; notFinished = false; } } if (progress % PROGRESS_SEP == 0) cout << progress << " of " << TOTAL << endl; progress += STEP; } } }
の
notFinished
フラグ
notFinished
使用されます。 この方法は、 pthreadを直接操作するためのより一般的な方法です。OpenMPには
#pragma omp cancel
があり
#pragma omp cancel
が、コンパイラーは警告を私に打ちつけました。その性質は私には明らかではないため、フラグを使用することにしました。
次に、結果のシステムのパフォーマンスを調べて、完全な検索に必要な時間を評価します。
パフォーマンスの評価とさらなるパワーの発見
上記のように、4コアIntel Core i5 2.60GHzでの並列操作中、約3450パスワード/秒の速度が達成されました。 必要なパスワードがセット全体の最後になると仮定すると、たった57億のパスワードしかありません。したがって、単純な計算では19日間のマシン操作が推定されます。 見込みがない。
ちょっとした不正行為の時間です。 悪名高いAmazon EC2クラウドコンピューティングサービスを使用します。 CPUの優位性を備えたコンピューティング用のインスタンスを選択し(特性を下のスクリーンショットに示します)、パフォーマンスを確認します。
スレッド数を4から36(+より高速なサーバープロセス)に増やすと、最近のアンチメルトダウンパッチのロールアップによるサービスのスローダウンにもかかわらず、スピードが10倍になりました。 このような仮想マシンの2つのインスタンスをスポット価格$ 0.37 / hで調達したため、24時間以内にセット全体を整理し、同時に$ 17.76(または現在のコース状態で約1,000ルーブル)でレイアウトする機会が得られます。 学習課題としてはそれほど高価ではありませんが、スポーツへの関心はまだ勝っているので、結果を共有する準備ができています。
しかし、最初に、入力中のユーザーエラーに関する追加情報を「予期せずに」表面化した場合に、どれだけの時間が必要かを見てみましょう。 この場合、パスワードセット全体のパワーは次のように記述されます。
したがって、3450 p / sの速度で完全な検索を行うには、マルチスレッドモードでセクションの冒頭に示されたプロセッサでコンピューターを使用する場合は1 年以上かかり、1つのスレッドで作業する場合は4年以上かかります[シリーズ「Horrors of Our Town」から)。
結果
回復されたパスワード:「
ldQ9!nwd
」。
クリアテキスト:
2E2B2A602A2B2C20594F552044495341524D4544204D4521202C2B2A602A2B2E
メッセージ:「。+ * `* +、YOU DISARMED ME !, + *` * +。」。
法令は、わずか半日で届きました。 あるパスワードモデルを他のパスワードモデルと比較してシフトするアプローチを使用すると、次の図が得られました:組み合わせ「 9!NwdldQ 」が最初に(モデルから )、および左に3回循環シフトした後、必要なパスワードが確認されました。
結論、ソースコード
バランスの取れたゲームを作ってくれた著者のおかげで、新年は私にとってかなり珍しい経験でした。
ネタバレの下の完全なブルートコード:
bruter.cxx
/** * @file bruter.cxx * @author Sam Freeside <snovvcrash@protonmail[.]ch> * @date 2018-01 * * @brief Brute forcing 4 password patterns: "DDLLLLLL", "DLLLLLLD", "LLLLLLDD", "LLLDDLLL" */ /** * LEGAL DISCLAIMER * * bruter.cxx was written for use in educational purposes only. * Using this tool without prior mutual consistency can be considered * as an illegal activity. It is the final user's responsibility * to obey all applicable local, state and federal laws. * * The author assume no liability and is not responsible for any misuse or * damage caused by this tool. */ #include <iostream> #include <algorithm> #include <cstring> #include <cstdlib> #include <ctime> #include <ctype.h> #include <omp.h> #include "cryptopp/filters.h" #include "cryptopp/files.h" #include "cryptopp/modes.h" #include "cryptopp/hex.h" #include "cryptopp/aes.h" #include "lib/fastpbkdf2.h" #define myOMP_THREADS 4 // == CPU(s) = [Thread(s) per core] * [Core(s) per socket] * [Socket(s)] #define myOMP_SCHEDULE_CHUNKS 4 #define TOTAL 5703060480 // == 26*26*26*26*26*10 * 2*6 * 4 #define STEP 4 #define PROGRESS_SEP 1000000 using namespace std; using namespace CryptoPP; const uint8_t ciphertext[100] = { 0x04, 0x17, 0xA6, 0x77, 0x8C, 0x77, 0xC6, 0x0F, 0x71, 0x0B, 0xE5, 0x3B, 0x6E, 0xB8, 0x44, 0xD8, 0x42, 0xE0, 0xEA, 0x0D, 0xF0, 0x40, 0x65, 0x58, 0x5A, 0x33, 0x23, 0xA5, 0x0F, 0x76, 0x8F, 0x57 }; const int PLAINTEXT_LENGTH = 32; const int CIPHERTEXT_LENGTH = 32; const int SALT_LENGTH = 8; const int PASSWORD_LENGTH = 8; const int KEY_LENGTH = 32; const uint8_t salt[SALT_LENGTH] = { 'd', 0x00, 'u', 0x00, 'k', 0x00, 'g' }; const uint32_t iterations = 0x00000457; // == 1111 void Parallel_TotalBruteForce( uint8_t* goodPassword, uint8_t* goodDecrypted, int& goodDecryptedLength ); int CryptoPP_Decrypt_AES_256_ECB( const uint8_t* ciphertext, uint8_t* key, uint8_t* plaintext ); bool checkPassword( uint8_t* password, const uint8_t* ciphertext, uint8_t* decrypted, int& decryptedLength ); uint8_t* rotateLeft( uint8_t* password, int n ); bool isPrintable( uint8_t* text, int textLength ); int main() { uint8_t goodPassword[9] = { '*','*','*','*','*','*','*','*', '\0' }; uint8_t goodDecrypted[100]; int goodDecryptedLength = 0; HexEncoder encoder(new FileSink(cout)); cout << "[*] Ciphertext:" << endl; encoder.Put(ciphertext, CIPHERTEXT_LENGTH); encoder.MessageEnd(); cout << endl << endl; Parallel_TotalBruteForce(goodPassword, goodDecrypted, goodDecryptedLength); cout << endl << "[+] Decrypted block:" << endl; encoder.Put(goodDecrypted, goodDecryptedLength); encoder.MessageEnd(); cout << endl; goodDecrypted[goodDecryptedLength++] = '\0'; cout << "[+] Decrypted string:" << endl; cout << '\"' << goodDecrypted << '\"' << endl; cout << "[+] Password:" << endl; cout << '\"' << goodPassword << '\"' << endl << endl; return 0; } void Parallel_TotalBruteForce( uint8_t* goodPassword, uint8_t* goodDecrypted, int& goodDecryptedLength ) { uint8_t alp[27] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\0' }; uint8_t num[11] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '\0' }; #ifdef WITH_OPENMP omp_set_num_threads(myOMP_THREADS); #endif uint64_t progress = 0; bool notFinished = true; #pragma omp parallel for shared(progress, notFinished) collapse(8) for (int a = 0; a < 2; a++) for (int b = 2; b < 8; b++) for (int c = 0; c < 26; c++) for (int d = 0; d < 26; d++) for (int e = 0; e < 26; e++) for (int f = 0; f < 26; f++) for (int g = 0; g < 26; g++) for (int h = 0; h < 10; h++) { if (notFinished) { uint8_t password[9]; password[PASSWORD_LENGTH] = '\0'; uint8_t indeces[6] = { 2,3,4,5,6,7 }; memmove(indeces+b, indeces+b+1, 5-b); uint8_t decrypted[100]; int decryptedLength; password[ a] = '!'; // 0-1 password[ !a] = num[h]; // 0-1 password[ b] = 'Q'; // 2-7 password[indeces[0]] = alp[c]; // 2-7 password[indeces[1]] = alp[d]; // 2-7 password[indeces[2]] = alp[e]; // 2-7 password[indeces[3]] = alp[f]; // 2-7 password[indeces[4]] = alp[g]; // 2-7 if ( // DDLLLLLL checkPassword( password, ciphertext, decrypted, decryptedLength ) || // DLLLLLLD checkPassword( rotateLeft(password, 1), ciphertext, decrypted, decryptedLength ) || // LLLLLLDD checkPassword( rotateLeft(password, 1), ciphertext, decrypted, decryptedLength ) || // LLLDDLLL checkPassword( rotateLeft(password, 3), ciphertext, decrypted, decryptedLength ) ) { #pragma omp critical { memcpy( goodPassword, password, 9 ); memcpy( goodDecrypted, decrypted, decryptedLength ); goodDecryptedLength = decryptedLength; notFinished = false; } } if (progress % PROGRESS_SEP == 0) cout << progress << " of " << TOTAL << endl; progress += STEP; } } } uint8_t* rotateLeft( uint8_t* password, int n ) { rotate(&password[0], &password[n], &password[PASSWORD_LENGTH]); return password; } bool checkPassword( uint8_t* password, const uint8_t* ciphertext, uint8_t* decrypted, int& decryptedLength ) { uint8_t key[KEY_LENGTH]; fastpbkdf2_hmac_sha1( password, PASSWORD_LENGTH, salt, SALT_LENGTH, iterations, key, KEY_LENGTH ); decryptedLength = CryptoPP_Decrypt_AES_256_ECB( ciphertext, (uint8_t*) key, decrypted ); if (isPrintable(decrypted, decryptedLength)) return true; return false; } int CryptoPP_Decrypt_AES_256_ECB( const uint8_t* ciphertext, uint8_t* key, uint8_t* plaintext ) { ECB_Mode<AES>::Decryption decryptor; decryptor.SetKey(key, AES::MAX_KEYLENGTH); ArraySink ps(&plaintext[0], PLAINTEXT_LENGTH); ArraySource( ciphertext, CIPHERTEXT_LENGTH, true, new StreamTransformationFilter( decryptor, new Redirector(ps), StreamTransformationFilter::NO_PADDING ) ); return ps.TotalPutLength(); } bool isPrintable( uint8_t* text, int textLength ) { // OuKSJJRlqS7Tqzn+r9GZ4g== for (int i = 0; i < textLength; i++) if (!isprint(text[i])) return false; return true; }
約束どおり、2番目のスポイラーの下のメイクファイルコード:
メイクファイル
CXXTARGET = bruter CXXSOURCES = $(wildcard *.cxx) CXXOBJECTS = $(patsubst %.cxx, %.o, $(CXXSOURCES)) CSOURCES = $(wildcard */*.c) CHEADERS = $(wildcard */*.h) COBJECTS = $(patsubst %.c, %.o, $(CSOURCES)) SHARED_LIB = lib/libfastpbkdf2.so CXX = g++ CC = gcc CXXFLAGS += -std=c++11 -O3 -c -g -Wall CXXLIBS += -L"./lib" -Wl,-rpath="./lib" -lfastpbkdf2 -L"/usr/lib" -lssl -lcrypto -lcryptopp CFLAGS += -fPIC -std=c99 -O3 -c -g -Wall -Werror -Wextra -pedantic CLIBS += -lcrypto .PHONY: all default openmp clean .PRECIOUS: $(CXXSOURCES) $(CSOURCES) ($CHEADERS) $(SHARED_LIB) default: $(CXXTARGET) @echo "=> Project builded" all: clean openmp $(CXXTARGET): $(SHARED_LIB) $(CXXOBJECTS) @echo "=> Linking project files" @echo "(CXX) $?" @$(CXX) $(CXXOBJECTS) $(CXXLIBS) -o $@ $(CXXOBJECTS): $(CXXSOURCES) @echo "=> Compiling project files" @echo "(CXX) $?" @$(CXX) $(CXXFLAGS) $< -o $@ $(SHARED_LIB): $(COBJECTS) @echo "=> Creating shared library" @echo "(CC) $?" @$(CC) -shared $< -o $@ $(COBJECTS): $(CSOURCES) $(CHEADERS) @echo "=> Compiling fastpbkdf2 sources" @echo "(CC) $?" @$(CC) $(CFLAGS) $(CLIBS) $< -o $@ openmp: CXXFLAGS += -fopenmp -DWITH_OPENMP openmp: CXXLIBS += -fopenmp openmp: CFLAGS += -fopenmp -DWITH_OPENMP openmp: default @echo "WITH OPENMP" clean: @rm -rfv *.o */*.o $(SHARED_LIB) $(CXXTARGET) @echo "=> Cleaning done"
ご静聴ありがとうございました!