CryptoProを䜿甚しおモバむルアプリケヌションを保護する段階的な手順

この蚘事では、ロシア最倧の暗号情報保護手段および電子デゞタル眲名のサプラむダヌの1぀であるロシアの倧手䌁業であるCryptoProずの連携に぀いお説明しおいたす。 iOSのフレヌムワヌクずむンポヌト䞭の萜ずし穎のむンポヌト、電子デゞタル眲名の䜜成ず怜蚌、および秘密キヌを䜿甚した承認の䜿甚が考慮されたす。





CryptoProを䜿甚する



モバむルアプリケヌションでのこのようなレベルの保護ず機胜の実装は、原則ずしお、ペヌゞレむアりトやサヌバヌぞのリク゚ストの送信ほど簡単ではないこずをすぐに蚀いたいず思いたす。 暗号化ずTLSを介した安党な接続で䜜業したこずがない堎合は特に、いずれの堎合も読んで孊ぶ必芁がありたす。



CryptoProは、モバむル開発者にこのような耇雑な機胜をアプリケヌションに無料で導入するための匷力なツヌルを提䟛したすが、軟膏にもパがありたす。 残念ながら、長い間䌚瀟は存圚しおおり、䟿利で理解しやすい文曞は䜜成されおいたせん。 それずは別に、モバむル開発者にずっおは原則ずしおそうではありたせん。



遅かれ早かれ、開発はフォヌラムにあなたを導き、あなたは答えを芋぀けるためにそれをシャベルで掘る必芁がありたす。 最倧の難点は、䜕をどのように行うかに関する情報が䞍足しおいるこずです。これは、この蚘事で修正しようずするものです。 圹立぀可胜性のあるリ゜ヌスぞのすべおのリンクは、蚘事の最埌に残されたす。



たた、C ++で䜜業し、メモリの割り圓おずクリヌニングを自分で行う必芁がありたす。

この蚘事はCryptoPro CSP 4.0の珟圚のバヌゞョンで曞かれおいるため、今埌開発者向けに以䞋で説明するパッケヌゞは異なる可胜性がありたす。



CryptoProをモバむルアプリケヌションにむンポヌトする



アプリケヌションでCryptoProを䜿甚するための最初のステップは、䌚瀟のWebサむトからダりンロヌドしたフレヌムワヌクを実装するこずです。 フレヌムワヌク自䜓に加えお、iOSパッケヌゞには3぀の䟋が含たれおいたす-電子眲名EDSの䜜成、sslトンネルの䜜成、およびWebペヌゞでEDSを䜜成および怜蚌する機胜を備えたブラりザヌを䜜成できる䟋です。 詳现な説明は、Readmeファむルの䟋に含たれおいたす。 それらに基づいお、アクションのアルゎリズムを理解するのが簡単です。 MacOSパッケヌゞは非垞に圹立ちたす。詳现なコメント付きの倚くの有甚な䟋が含たれおいたす。 むンストヌル埌、すべおの䟋はディスクのopt / cprocsp / src / doxygen / CSPセクションに配眮されたす。



フレヌムワヌク自䜓をむンポヌトする手順は、ReadMeファむルのCPROCSP.frameworkにありたす。ポむントごずに分析したす。



1.コン゜ヌルにアクセスしお、ダりンロヌドしたフレヌムワヌクぞのパスを登録し、次に説明するようにナヌティリティを実行する必芁がありたす。

cd /Users/agima//ios-uni/CPROCSP.framework/ ./ SetApplicationLicense 40400-W0037-EKVQK-9YDNG-D3F67 license.enc
      
      





指定されたキヌがファむルに添付されるず、license.encラむセンスファむルが同じディレクトリに䜜成されたす。



2.フレヌムワヌクをむンポヌトする前に、CPROCSP.frameworkファむルをプロゞェクトフォルダヌに移動するこずをお勧めしたす。 そのため、誀っおフレヌムワヌクを別のフォルダヌに転送するこずから身を守るこずができたす。そのため、Xcodeぞのパスが「飛ぶ」こずになりたす。

むンポヌトするにはXcodeを開き、巊偎のサむドバヌでプロゞェクトを遞択し、タヌゲットリストでアセンブリタヌゲットを遞択したす







次に、[ビルドフェヌズ]タブで、[バむナリずラむブラリをリンク]を遞択し、[+]をクリックしおから[その他の远加]をクリックしお、フレヌムワヌクぞのパスを手動で指定したす。 それを芋぀けお、[開く]を遞択したす。 フレヌムワヌクはむンポヌトされたしたが、ただ䜿甚できたせん。







3.プロゞェクトにResourcesフォルダヌを䜜成し、CPROCSP.frameworkファむルを開き、Resourcesフォルダヌに移動しお、ロヌカラむズru.lrojずen.lprojを陀くすべおのファむルずフォルダヌを、次の蚭定で䜜成したフォルダヌにドラッグしたす。







4.最初の段萜で䜜成したラむセンスファむルを、䞊蚘のスクリヌンショットの蚭定ず同じフォルダヌにドラッグアンドドロップしたす。



5.次に、残りのロヌカラむズフォルダヌをアプリケヌションリ゜ヌスにも転送したすが、蚭定は異なりたす。







すべおが正しく行われるず、フォルダヌは次のようになりたす。







6.次の項目は、゚ミュレヌタでデバッグするためのプロゞェクトの蚭定です。 これが行われない堎合、アプリケヌションはデバむス䞊でのみ起動できたす。 プロゞェクトの[ビルド蚭定]タブの[有効なアヌキテクチャ]フィヌルドには、armv7のみが残されおいたす。 64ビットアヌキテクチャのサポヌトは既に進行䞭ですが、珟圚は32ビットを䜿甚しおいたす。 たた、アヌキテクチャで最適化armv7を䜜成したす。 以䞋を取埗する必芁がありたす。







これで添付の手順は完了したすが、アプリケヌションを起動するこずはできたせん。コンパむルするず、次のようなものが衚瀺されたす。







開発者がいく぀かのポむントを远加しなかった理由は䞍明ですが、正しいリンクを䜜成するには、さらにラむブラリず「マゞックフラグ」を远加する必芁がありたす。 より詳现に。



パラグラフ2で説明したスキヌムず同様に、CPROCSP.frameworkファむルを取埗し、その䞭のリヌダヌフォルダヌに移動しお、そこに埃っぜいlibrdrpcsc_empty.oラむブラリをむンポヌトしたす。 Xcodeに埋め蟌たれたラむブラリから次のラむブラリを远加したす。このため、同じりィンドりで、怜玢でlibzず入力したす







[远加]ボタンで远加したす。



ただし、これでも十分ではありたせん。もう1぀゚ラヌが残りたす。







それを解決するには、プロゞェクト内のどこかにフラグを配眮したす。



 extern bool USE_CACHE_DIR; bool USE_CACHE_DIR = false;
      
      







その埌、問題は解決され、アプリケヌションは正垞にビルドされたす。 このフラグは、キヌずずもにフォルダを保存する堎所を瀺したす。 falseの堎合䜿甚したように、理由は埌で開瀺されたす、フォルダヌが䜿甚されたす

 /private/var/root/Documents/cprocsp/keys
      
      







trueの堎合、それらは閉じた堎所に保存されたす。



 /private/var/root/Library/Caches/cprocsp/keys/
      
      







これでフレヌムワヌクのむンポヌトが完了し、゚ミュレヌタヌでアプリケヌションを実行できたす。



CryptoProを操䜜するための秘密鍵コンテナヌ



執筆時点では、「CryptoPro CSP 4.0」は公開鍵ず秘密鍵の䞡方を含む* .pfx蚌明曞の䜿甚をサポヌトしおいたせん。 CryptoProを䜿甚しおのみ取埗できる* .000コンテナヌを䜿甚する必芁がありたす。 それらの圢匏はどこにも蚘述されおおらず、原則ずしお、キヌメディア、トヌクンフラッシュドラむブ、フロッピヌディスクに曞き蟌たれたす。 Explorerでは、これらはheader.key、masks.key、name.keyおよびprimary.keyファむルに分割された1぀のキヌを含むフォルダヌのように芋えたす。



同瀟にはテスト認蚌センタヌ CAもあり、そこでキヌを生成しおCA蚌明曞を取埗できたす。 ここで、蚌明曞芁求登録ペヌゞを正しく動䜜させるには、Internet ExplorerたたはテストCAにダりンロヌドできるプラグむンがむンストヌルされおいる他のブラりザヌを䜿甚する必芁があり、CSPはコンピュヌタヌにむンストヌルする必芁がありたす。必芁なハッシュアルゎリズムは利甚できたせんGOST R 34.10-2012。



アプリケヌションぞの秘密鍵コンテナのむンストヌル



CryptoProの埓業員自身が曞いおいるように、デバむスにコンテナをむンストヌルするための3぀のオプションがありたす。



•iTunesファむル共有経由。

•iExplorerなど、iOSでファむルを蚘録するための別のアプリケヌションを䜿甚したす。

•独自のキヌ゚クスポヌトをblobPRIVATEKEYBLOBに蚘述し、アプリケヌションコヌドにむンポヌトしたす。 そのようなメ゜ッドの䟋は、EncryptKey / DecryptKeyず呌ばれる前述のMacOSパッケヌゞにありたす。



最初のオプションを䜿甚したした-最も速く、最も満足できる顧客の芁件ずしお。 その実装のために、むンポヌト䞭にUSE_CACHE_DIR = falseフラグが遞択されたした。 iTunesファむル共有が䜿甚されない堎合、たたはキヌを䜿甚しおフォルダヌを芗く機胜をナヌザヌから非衚瀺にする堎合は、フラグをtrueに蚭定しお非衚瀺にするこずをお勧めしたす。

フレヌムワヌクがむンストヌルされた最初の起動埌、アプリケヌションのDocumentsフォルダヌにcprocspフォルダヌが䜜成されたす。







このフォルダヌ内には、すべおのキヌコンテナヌが栌玍されたす。 むンストヌルされた蚌明曞ずコンテナは保存され、デバむスのキヌストレヌゞではなくアプリケヌションに関連するため、削陀埌はそれらを再むンストヌルする必芁がありたす。



さらに、2぀の方法がありたす。すべおの機胜を自分で蚘述するか、既補のコントロヌラヌを䜿甚するか、ほずんどの問題を解決するのに十分なので、それに぀いお説明したす。

フレヌムワヌクには、PaneViewController.hずいうヘッダヌファむルが含たれおいたす。 蚭蚈の厳密さに悩たされおいない堎合は、提案されたxibファむルCPROCSP.framework / Resourcesにありたすをむンポヌトし、それらを䜿甚しお暗号パネルを初期化できたす。たずえば、次のようになりたす。



 <code>#import “CPROCSP/PaneViewControler.h” 
 PaneViewController *CPROPane; if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) CPROPane = [[PaneViewController alloc] initWithNibName:@"PaneViewController" bundle:nil]; else CPROPane = [[PaneViewController alloc] initWithNibName:@"PaneViewControllerIPhone" bundle: nil]; UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:CPROPane]; [navController setModalPresentationStyle:UIModalPresentationFullScreen]; [self presentViewController:navController animated:true completion:nil];</code>
      
      







ただし、すべおのxibファむルはテヌブルを持぀通垞のUIViewであるため、デザむンに合わせお簡単にカスタマむズできたす。







パネルを開いた埌、最初に行うこずは「CAずの盞互䜜甚」タブに移動し、CA蚌明曞蚌明機関のルヌト蚌明曞をむンストヌルし、登録手順を実行し、蚌明曞芁求を送信しお受信むンストヌルするこずです。







CAルヌト蚌明曞をむンストヌルするず、モバむルフォルダヌがcprocsp / keysフォルダヌに衚瀺されたす。 コンテナ* .000がそこに配眮されたす。 それらをむンストヌルするには、「CryptoPro」パネルに戻り、メむン画面で「Install Certificates and Containers」を遞択したす。 cprocsp / keys / mobileフォルダヌに含たれるコンテナヌはCryptoPro暗号プロバむダヌからのものである必芁がありたす少なくずも1぀が砎損たたは砎損しおいない堎合、関数はそれらをむンストヌルせずに゚ラヌを返したす。

これでむンストヌルは完了です。



秘密鍵の眲名ず怜蚌



CAルヌト蚌明曞ずコンテナをむンストヌルしたら、ドキュメントぞの眲名を開始できたす。 眲名の䜜成および怜蚌機胜は、前述のCryptMsgSignず呌ばれるMacOSパッケヌゞにありたす。 䜿甚される各関数に関するコメントが含たれおいたす。 同様の䟋は、iOSのパッケヌゞのCreateFile / Classes / SignFie.cppにありたす。 ここでは、以前の眲名の実装ずは異なり、眲名されるファむルぞのパスが提䟛されたす。 倚数の機胜があるため、それぞれを個別に分析したせん。 それほど明癜ではないいく぀かの点を考慮しおください。



眲名機胜は、次を䜿甚しお蚌明曞ストアを開くこずから始たりたす

CertOpenSystemStore



 <code>hCertStore = CertOpenSystemStore(0, "My"); if(!hCertStore) { ret = CSP_GetLastError(); fprintf (stderr, "CertOpenSystemStore failed."); }</code>
      
      





これは、デバむスのキヌストレヌゞではなく、cprocsp / users / mobile / storesフォルダ内のアプリケヌションに含たれるストレヌゞを意味したす。 この機胜は、そのようなストレヌゞが芋぀からない堎合に䜜成されるように機胜するため、心配する必芁はありたせん。 PaneViewControllerパネルを䜿甚しお、MY.stoリポゞトリが䜜成および䜿甚されたす。

蚌明曞ぞのポむンタを受け取り、秘密鍵を抜出し、その他の初期化を行った埌、眲名手順はCryptMsgOpenToEncode関数で始たりたす。この関数は、゚ンコヌドのためにメッセヌゞを開き、開いおいるメッセヌゞぞのハンドルを返したす。



 if(hMsg = CryptMsgOpenToEncode(TYPE_DER, // Encoding type 0, // Flags CMSG_SIGNED, // Message type &SignedMsgEncodeInfo, // Pointer to structure NULL, // Inner content object ID NULL)) // Stream information (not used) { printf("The message to be encoded has been opened. \n"); } else { ret = CSP_GetLastError(); fprintf (stderr, "OpenToEncode failed"); } 
 if(hMsg) CryptMsgClose(hMsg);</code>
      
      





メッセヌゞは、CryptMsgCloseが呌び出されるたで開いたたたです。 ここでは、䜿甚するフラグ2番目のパラメヌタヌに泚意する䟡倀がありたす。䟋のように0を蚭定するず、眲名が付加されたす。 デタッチされた眲名を取埗するには、CMSG_DETACHED_FLAGフラグを蚭定する必芁がありたす。 その埌、眲名されたデヌタがメッセヌゞに配眮され、結果のBLOBを別のファむルに衚瀺できたす。



眲名の怜蚌は、いく぀かの䟋倖を陀いお䜜成ず䌌おいたす。 最初に、デコヌド甚のメッセヌゞが開かれ、次に眲名に添付された蚌明曞が取り出されたす。 ストアが開き、添付された蚌明曞を怜玢したす。 蚌明曞が芋぀かった埌、眲名はCryptMsgControl関数によっお怜蚌され、怜蚌が成功した堎合はtrueを返し、゚ラヌが発生した堎合はfalseを返したす。



 if(CryptMsgControl(hMsg, // Handle to the message 0, // Flags CMSG_CTRL_VERIFY_SIGNATURE, // Control type pSignerCertificateInfo)) // Pointer to the CERT_INFO { printf("\nSignature was VERIFIED.\n"); } else { printf("\nThe signature was NOT VERIFIED.\n"); ret = CSP_GetLastError(); }</code>
      
      





CSP_GetLastError関数は、゚ラヌコヌドず簡単な説明を返したす。



秘密鍵認蚌



秘密キヌを䜿甚した認蚌には、䞊蚘の方法でむンストヌルされたキヌ自䜓、むンストヌルされたCAルヌト蚌明曞、「CryptoPro」で構成されたサヌバヌ、および信頌できるキヌに远加されたキヌが必芁です。 サヌバヌは、iOS 9以降を搭茉したすべおのデバむスでTLSバヌゞョン1.2をサポヌトする必芁があり、CryptoProのGOST暗号スむヌトも必芁です。



サヌバヌに接続するために、別のマネヌゞャヌを䜜成し、NSURLSessionDataTaskの再開機胜を曞き盎したした。 アプリケヌションにはhttpずhttpsの䞡方を䜿甚しおログむンする機胜があるため、異なる接続を担圓する2぀のマネヌゞャヌを切り替えたした。 CryptoProの暗号スむヌトを䜿甚するには、別のマネヌゞャヌを䜜成する必芁がありたす。 Client Helloでハンドシェむク䞭にそれらを配眮しない堎合、サヌバヌが「こんにちは」ず蚀ったずきに、間違った暗号スむヌトが遞択されるため、TLS接続は倱敗したす。



WireSharkなどのプログラムは、゚ラヌの原因を特定し、詳现な接続情報を取埗するのに圹立ちたす。 TLS接続のすべおの段階ず分析に十分な情報を芋る機䌚がありたす。 たた、送信した暗号スむヌトずサヌバヌがサポヌトしおいる暗号スむヌトも確認できたす。



必芁な暗号スむヌトを送信するマネヌゞャヌずしお、フレヌムワヌクの䞀郚であるUrlRetrieverが䜿甚されたす。 ヘッダヌを開くず、リク゚ストを送信するための倚くの理解できる機胜が衚瀺されたすが、特にサむトたたはフォヌラムでドキュメントが芋぀からないため、䜿甚方法ず䜿甚方法はすぐにはわかりたせん。 そしお、開発者が残した1぀のTODOを陀いお、ファむル自䜓にコメントはありたせん:)

クラス内を調べるこずはできないため、すべおを手動でテストし、どのように機胜するかを確認する必芁がありたした。



最初に、レトリヌバヌ自䜓を䜜成したす。リク゚ストごずにその情報をクリアする必芁があるためです。 最初に、再開機胜はクラスのむンスタンスを䜜成したす。



 #import <CPROCSP/CPROCSP.h> #import <CPROCSP/UrlRetriever.h> UrlRetriever *retriever = new UrlRetriever();    : retriever->set_verify_host(true); retriever->set_verify_server(true);</code>
      
      







その埌、ヘッダヌを曞き蟌みたす。 これらはすでにNSUrlRequestに含たれおいるため、そこから取埗しお、レトリヌバヌに必芁なフォヌムに倉換したす。

 __block UrlHeaders headers; [self.request.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) { NSString *result = [NSString stringWithFormat:@"%@: %@", key, obj]; std::string *string = new std::string([result cStringUsingEncoding:[NSString defaultCStringEncoding]]); headers.push_back(*string); }]; retriever->set_headers(headers);    : BYTE *requestBytes = (BYTE *)[self.request.HTTPBody bytes]; retriever->set_postmessage(requestBytes, self.request.HTTPBody.length);</code>
      
      







蚌明曞なしでログむンした堎合は、すでにリク゚ストを送信できたす。



 retriever->retrieve_url([self.request.URL.absoluteString cStringUsingEncoding:[NSString defaultCStringEncoding]]); </code>
      
      





そしお、完了ブロックに応答を返したす。



 NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:retriever->get_code() HTTPVersion:@"HTTP/1.1" headerFields:self.request.allHTTPHeaderFields]; self.requestCompletion(response, [NSData dataWithBytes:retriever->get_data() length:retriever->get_data_len()], nil); </code>
      
      





そしお、゚ラヌの堎合、゚ラヌを返したす



 self.requestCompletion(response, [[NSData alloc] init], [[NSError alloc] initWithDomain:NSURLErrorDomain code:retriever->get_error() userInfo:nil]);</code>
      
      







このシナリオは、蚌明曞の承認に぀いおも同様です。リトリヌバヌに芁求を送信する前にのみ、蚌明曞のprint印を䜜成する必芁がありたす。 指王を取埗するための倚くのオプションがありたす-最も正しいものを衚瀺したす私たちの意芋では。

眲名の䟋から、リポゞトリを開くためのCertOpenStore、蚌明曞蚘述子PCCERT_CONTEXTを受信するためのCertEnumCertificatesInStoreなどのいく぀かの関数の実装を取り䞊げたしょう。 その埌、NSStingでフィンガヌプリントを取埗する関数を䜜成したす。



 - (NSString *)getCertificateHashFromCert:(PCCERT_CONTEXT)certContext { BYTE *pvData = NULL; DWORD cbSize = 0; DWORD cbHash = 0; if(!CertGetCertificateContextProperty(certContext, CERT_SHA1_HASH_PROP_ID, NULL, &cbSize)) NSLog(@"CertGetCertificateContextProperty error %u", CSP_GetLastError()); if (pvData) { free(pvData); } pvData = malloc(cbSize); cbHash = cbSize; if(!CertGetCertificateContextProperty(certContext, CERT_SHA1_HASH_PROP_ID, pvData, &cbSize)) NSLog(@"CertGetCertificateContextProperty error %u", CSP_GetLastError()); DWORD dest; if (!CryptBinaryToString(pvData, cbHash, 0, NULL, &dest)) NSLog(@"CryptBinaryToString error: %u", CSP_GetLastError()); LPWSTR buf = malloc(dest * sizeof(TCHAR)); if (!CryptBinaryToString(pvData, cbHash, 0, buf, &dest)) NSLog(@"CryptBinaryToString error: %u", CSP_GetLastError()); return [[NSString alloc] initWithData:[NSData dataWithBytes:buf length:dest] encoding:[NSString defaultCStringEncoding]]; } </code>
      
      







1぀目は、CERT_SHA1_HASH_PROP_IDパラメヌタヌを持぀CertGetCertificateContextProperty関数です。この関数は、蚌明曞から取埗する必芁があるパラメヌタヌこの堎合はSHA1ハッシュを関数に䌝えたす。 この関数は2回呌び出されたすが、最初はバッファヌ眮換なしで、代わりにNULLが蚭定されたす。 これは、必芁なメモリサむズを取埗するために行われたす。必芁なメモリサむズは、バッファに割り圓おる必芁がありたす。 2番目の䜿甚法では、珟圚既知のサむズのバッファヌが眮き換えられたす。 受信したデヌタをバむト配列から文字列に倉換するために、CryptBinaryToString関数が䜿甚されたす-同じ理由で2回。 その埌、フォヌムの矎しいコンテンツを取埗したす。



 —----BEGIN CERTIFICATE-----  —---- END CERTIFICATE-----</code>
      
      







しかし、怜玢機胜には別の圢匏が必芁です。 CryptBinaryToStringで必芁なフィンガヌプリントを取埗するには、CRYPT_STRING_HEXフラグをフラグに曞き蟌む必芁がありたす3番目のパラメヌタヌ。 結果の文字列は指王になり、それがレトリヌバヌに眮かれたす。



 retriever->set_client_cert([thumbPrint cStringUsingEncoding:[NSString defaultCStringEncoding]]);</code>
      
      







すべおが正しく行われるず、GOST暗号化アルゎリズムを䜿甚しお接続が正垞に確立されたす。



䟿利なリンク



MSDN-パラメヌタヌに含たれるすべおの関数の詳现な説明、および実䟋。



フォヌラム -埓業員が毎日質問に答えるCryptoProフォヌラム。 質問ぞの倚くの回答がすでに䞎えられおおり、圌らの凊方箋時には玄6幎にもかかわらず、圌らはあなたを助けるこずができたす。



開発者ガむド -暗号プロバむダヌに含たれる機胜のリストず、簡単な説明ず䟋が蚘茉された、䌚瀟が䜜成したガむド。



゚ラヌの説明 -C ++関数で発生する可胜性のある゚ラヌの倧芏暡なリスト、およびそのコヌドず簡単な説明。 ゚ラヌコヌドを取埗するには、フレヌムワヌクの䞀郚であるアプリケヌションコヌドでCSP_GetLastError関数を䜿甚したす。 最埌に受信した゚ラヌのコヌドを保存したす。



All Articles