クラむアント/サヌバヌアヌキテクチャでのRSAアルゎリズムの実装

ニヌズの出珟







この蚘事は、自分のプロゞェクトを開発するずきに遭遇した問題の1぀に圓おられおいたす。 このプロゞェクトはクラむアント/サヌバヌアヌキテクチャを備えおおり、ビゞネスアプリケヌションです。 ネットワヌクを介したデヌタ送信の実装ずフレヌムの構築埌、ほが最初の質問に、送信デヌタの暗号化が必芁でした。 最初の可胜なアルゎリズム耇数をサポヌトする蚈画はRSA暗号化アルゎリズムを遞択したした。



この蚘事では、クラむアント/サヌバヌアヌキテクチャにRSAアルゎリズムを実装するためのオプションず、実際のプロゞェクトでのそのような実装の䟋を怜蚎したす。





RSAアルゎリズムの抂念



ここでは、このアルゎリズムの機胜に぀いおは説明したせんが、クラむアントサヌバヌアヌキテクチャでの䜿甚方法に぀いお具䜓的に説明したす。

ちょっずした玹介...実際、 RSA Rivest-Shamir-Adlemanの名前の文字の省略圢は公開鍵暗号アルゎリズムです。 これは、システムが公開鍵ず秘密鍵の2぀の異なるキヌを生成するこずを意味したす。

したがっお、公開キヌを誰にでも転送し、このキヌで暗号化されたメッセヌゞを受信できたす。このメッセヌゞは、私たちだけが秘密キヌを䜿甚しお解読できたす。



 №1.



この抂念を䞊図の図1に瀺したす。



ご芧のずおり、 青文字による生成埌のキヌは、平文の保護されおいないチャネルを介しお緑文字に送信されたす。 誰でも圌を傍受できたすが、圌の助けがなければメッセヌゞを暗号化するこずしかできたせん。



したがっお、 緑のキャラクタヌは公開鍵を簡単に受け取り、この鍵でメッセヌゞを暗号化したす。



その埌、圌は暗号化されたメッセヌゞを青文字に送信し、 青文字は秘密鍵を䜿甚しお解読したす。



2人の䞭で、このスキヌムは非垞に単玔です。 ただし、このようなシステムをクラむアント/サヌバヌアヌキテクチャ䞊で線成する必芁がある堎合は、以䞋で怜蚎するいく぀かの远加の問題が発生したす。





クラむアント-サヌバヌ





したがっお、最初にキヌを決定したす。 芚えおいるように、メッセヌゞを暗号化するには受信者の公開鍵が必芁です。 したがっお、サヌバヌにはクラむアントの公開鍵が必芁であり、クラむアントにはサヌバヌの公開鍵が必芁です。 したがっお、デヌタ転送を開始する前に、キヌを亀換する必芁がありたす。 これがどのように発生するかを、キヌを亀換するプロセスを瀺す図2で怜蚎したす。







1. クラむアントはサヌバヌぞの接続を開き、鍵の束を生成したすopen-secret。 次に、パケットをサヌバヌに送信し、 サヌバヌで公開キヌを転送したす。

2. サヌバヌはパケットを受信し、 クラむアントの公開キヌを読み取っお保存し、独自のキヌチェヌンを生成したす。 その埌、圌はパケットをクラむアントに送信し、 クラむアントで公開鍵を転送したす。

3. クラむアントはパケットを受信し、 サヌバヌの公開鍵を読み取っお保存したす 。





亀換は3段階で完了したす。 これで、サヌバヌずクラむアントの䞡方が、「行の反察偎に」察談者の公開鍵を持ちたす。 ただし、ここでは、サヌバヌがクラむアント甚のキヌを生成する方法に関する2぀の決定のうちの1぀を盎ちに遞択する必芁がありたす。





1. サヌバヌは、 すべおの クラむアントに察しお1぀のキヌを生成し たす 。

2. サヌバヌは、 個々の クラむアント ごずに新しいキヌを生成したす 。



皆さんは、キヌが倧きいほど、実甚性が高いこずを知っおいるず思いたす。 ただし、RSAアルゎリズムの堎合、鍵の生成は䞻芁な蚈算の耇雑さを衚すため、それほど単玔なタスクではありたせん。 さらに、アルゎリズムは、キヌが倧きいほど、より倚くのデヌタを送信する必芁があるように蚭蚈されおいたす。



たずえば、5バむトの長さのメッセヌゞを送信し、512ビットのキヌ長を䜿甚するず、暗号化されたメッセヌゞは64kバむトの「重さ」になりたす。 これは、このようなキヌで暗号化できるデヌタの最倧量が64〜11 = 53 kBビットシフトに11 kBが䜿甚されるであるためです。 さらに暗号化する必芁がある堎合は、53 KBのブロックに分割したす。 キヌ= 4096ビットを取埗するず、暗号化するのは5バむトのみであるにもかかわらず、最小ブロックは512 kバむトに等しくなりたす。





したがっお、以䞋を決定する必芁がありたす。



1.すべおのクラむアントに察しお1぀の倧きなキヌを生成したす 。これにより、過剰なトラフィックが発生し、より倚くのプロセッサリ゜ヌスが䜿甚されたす512よりも4096ビットのキヌでメッセヌゞを暗号化するのははるかに困難ですが、メモリを消費せず、開発に費やす時間も少なくなりたす;

2.たたは、 クラむアントごずに小さなキヌを生成し、その䜿甚期間が最倧蚱容倀を超えないこずを確認したす 512ビットキヌのクラックは長い間珟実でした。掚奚される長さは少なくずも1024ビットです。



誰もがそのアカりントに぀いお独自の芋解を持぀こずができたすが、どのオプションを奜むかは、開発䞭の補品に倧きく䟝存したす。 ただし、このプロゞェクトでは、 2番目のオプションを䜿甚するこずが決定されたした 。



キヌを生成しおサヌバヌに送信する





このプロゞェクトでは、クラむアントサヌバヌデヌタベヌスずいう3局アヌキテクチャを䜿甚しおいたす。 サヌバヌはJavaで蚘述され、クラむアントはCで蚘述されおいたす。 以䞋では、サヌバヌ偎ずクラむアント偎の䞡方での暗号化の実装に぀いお説明したす。 ナヌザヌ-クラむアントから始めたしょう。



したがっお、サヌバヌぞの接続は成功し、パケットを受信する準備が敎いたした。 これを行うには、.NETクラスRSACryptoServiceProvider Cを䜿甚しおキヌを䜜成したす。



  1. プラむベヌト RSACryptoServiceProvider m_Rsa ;
  2. プラむベヌト RSAParameters m_ExternKey ;
  3. プラむベヌト RSAParameters m_InternKey ;
  4. パブリック CryptoRsa  
  5. {
  6. m_Rsa = 新しい RSACryptoServiceProvider  512  ;
  7. m_InternKey = m_Rsa。 ExportParameters  true  ;
  8. }




このリストには、 CryptoRsaクラスのコンストラクタヌがありたす。これは、512ビットキヌを自動的に生成し、キヌパラメヌタヌパブリックだけでなく秘密キヌも゚クスポヌトする必芁があるこずを瀺すをm_InternKey倉数に゚クスポヌトしたす。



次に、公開鍵をバむト圢匏で保存し、サヌバヌに送信する必芁がありたす。 これを行うには、RSAキヌの構成芁玠を少し理解する必芁がありたす。 芁するに、それらはいわゆるパブリック指数ずシヌクレット指数、および䞡方のキヌの単䞀モゞュヌルで構成されおいたす。 したがっお、公開鍵は公開指数ずモゞュヌルであり、秘密鍵は秘密指数ずモゞュヌルです。 詳现に぀いおは、「公開キヌず秘密キヌを䜜成するためのアルゎリズム」の章を参照しおください。



出力バッファにオヌプン指数を曞き蟌みたすC



  1. //指数の長さを曞き蟌む->指数->モゞュヌル
  2. バフ。 Write   Byte  m_InternKey。Exponent。Length  ;
  3. バフ。 曞き蟌み  m_InternKey。Exponent  ;
  4. バフ。 Write  m_InternKey。Modulus  ;




この堎合、指数の終了䜍眮ずモゞュヌルの開始䜍眮サヌバヌ䞊のデヌタを読み取るずきを正確に知るために、指数の長さが必芁です。 蚘録埌、デヌタをサヌバヌに送信したす。



サヌバヌがキヌ付きのパケットを受信したら、パケットからキヌを取埗しお保存する必芁がありたす。 私たちは芋たすJava



  1. //指数の長さ
  2. int expLength =パケット。 readByte   ;
  3. //指数バむトを取埗したす
  4. バむト [ ]指数= 新しい バむト [ expLength ] ;
  5. システム arraycopy  packet。Bytes 、packet。Offset、exponent、 0 、expLength  ;
  6. //モゞュヌルのバむトを取埗したす
  7. バむト [ ]モゞュラス= 新しい バむト [ 1 +パケット。 バむト 長さ - パケット。 オフセット + expLength  ] ;
  8. システム arraycopy  packet。Bytes、packet。Offset + expLength、modulus、 1 、modulus。length - 1  ;
  9. //ブヌドゥヌマゞック
  10. モゞュラス[ 0 ] = 0 ;
  11. //キヌを保存したす
  12. RSAPublicKeySpec rsaPubKeySpec = 新しい RSAPublicKeySpec  新しい BigInteger モゞュラス 、 新しい BigInteger 指数  ;
  13. m_ExternPublicKey =  RSAPublicKey  KeyFactory 。 getInstance  "RSA"  。 generatePublic  rsaPubKeySpec  ;




モゞュヌルの最初のバむトをれロに蚭定する「ブヌドゥヌマゞック」ず呌ばれる奇劙な行を陀いお、ここでコヌドに぀いお特にコメントする必芁はないず思いたす。 そしお、ここにありたす私にはわからない理由で、JavaでのRSAの実装では、キヌモゞュヌルは垞にれロから開始する必芁がありたす。 おそらく、これはモゞュヌルが0より倧きいためです。 倧きな数BigIntegerを䜿甚しお自分でJavaにRSAを実装しようずしたずきに、最初のバむトがれロに等しくない堎合、負の数が取埗されたす。 Khabravchanyの玳士、この質問をあなたに任せたす。誰かがこの機胜を説明しおくれたらずおもうれしいです。



次は、サヌバヌによるキヌ生成です。 次のコヌドを怜蚎しおくださいJava



  1. //キヌゞェネレヌタヌを取埗しお初期化したす
  2. KeyPairGenerator keyGen = KeyPairGenerator 。 getInstance  "RSA"  ;
  3. keyGen。 初期化  Config。CRYPTO_KEY_NUM_BITS  ;
  4. //束を生成したす
  5. m_KeyPair = keyGen。 genKeyPair   ;
  6. //公開鍵ず秘密鍵を取埗したす
  7. m_InternPublicKey =  RSAPublicKey  KeyFactory 。 getInstance  "RSA"  。 generatePublic 
  8. new X509EncodedKeySpec  m_KeyPair。getPublic   。 getEncoded     ;
  9. m_InternPrivateKey =  RSAPrivateKey  KeyFactory 。 getInstance  "RSA"  。 generatePrivate 
  10. new PKCS8EncodedKeySpec  m_KeyPair。getPrivate   。 getEncoded     ;




ここではすべおが明確だず思いたす。 もちろん、もっず深く掘り䞋げる堎合は、 X509やPKCS8 X509EncodedKeySpecおよびPKCS8EncodedKeySpecなどのクリヌチャヌの䞻題をグヌグルで怜玢する必芁がありたす。



次のステップは、キヌをサヌバヌに送信するこずです。 これは、クラむアントJavaの堎合ずほが同じ方法で行われたす。



  1. //指数の長さを曞き蟌む->指数->モゞュヌル
  2. バオ。 write  exponent。length  0xff  ; //バむトずしお曞き蟌む
  3. バオ。 曞きたす 指数 ;
  4. バオ。 曞き蟌み モゞュラス ;




そしお最埌に、クラむアント偎でキヌを取埗し、読み取り、保存したすC



  1. バむト expLength =パケット。 ReadByte   ;
  2. バむト [ ]指数= 新しい バむト [ expLength ] ;
  3. 緩衝液 BlockCopy  packet。Bytes 、packet。Offset、exponent、 0 、expLength  ;
  4. バむト [ ]モゞュラス= 新しい バむト [パケット。 バむト 長さ - パケット。 オフセット + expLength  -1 ] ;
  5. 緩衝液 BlockCopy パケット。 バむト 、パケット。 オフセット + expLength + 1 、モゞュラス、 0 、モゞュラス。 長さ  ;
  6. m_ExternKey = new RSAParameters   ;
  7. m_ExternKey。 指数 =指数;
  8. m_ExternKey。 モゞュラス =モゞュラス;




実際、それがすべおです。 これで、クラむアントは倉数m_ExternKeyにサヌバヌの公開鍵を持ち、サヌバヌは倉数m_ExternPublicKeyにクラむアントの公開鍵を持ちたす。 デヌタ転送自䜓を敎理するためだけに残りたす。 これはさらに簡単になりたすC



  1. //キヌをむンポヌトしたす
  2. m_Rsa。 ImportParameters  m_ExternKey  ;
  3. //暗号化されたデヌタを暗号化し、バッファに曞き蟌みたす
  4. バッファ。 曞き蟌み  m_Rsa。Encrypt  bytesToEncrypt、 false   ;




サヌバヌの堎合、もう少し耇雑ですJava



  1. byte [ ] cipherText = null ;
  2. 暗号cipher =暗号。 getInstance  "RSA / ECB / PKCS1Padding"  ;
  3. 暗号。 init 暗号。ENCRYPT_MODE、m_ExternPublicKey  ;
  4. cipherText =暗号。 doFinal  tempBytes  ;
  5. バオ。 曞き蟌み  cipherText  ;




暗号化されたメッセヌゞは、受信者が秘密鍵を䜿甚しお送信および埩号化する準備ができおいたす。 忘れおはならない唯䞀のこずは、暗号化できる最倧メッセヌゞサむズがキヌサむズから11バむトを匕いたものに等しいこずです。 したがっお、暗号化するずきは、デヌタをブロックに分割しお順番に暗号化する必芁がありたす。 Cの䟋を次に瀺したす。



  1. m_Rsa。 ImportParameters  m_ExternKey  ;
  2. ByteBuffer buffer = new ByteBuffer   ;
  3. int dataLength = bytesToEncrypt。 長さ ;
  4. int maxLength =  m_Rsa。KeySize / 8  -12 ;
  5. int iterations =  int 数孊。 倩井   フロヌト  bytesToEncrypt。 長さ / maxLength  ;
  6. for  Int32 i = 0 ; i <繰り返し; i ++ 
  7. {
  8. バむト [ ] tempBytes = 新しい バむト [
  9.  dataLength - maxLength * i > maxLength   maxLength 
  10. dataLength - maxLength * i ] ;
  11. 緩衝液 BlockCopy  bytesToEncrypt、maxLength * i、tempBytes、 0 、
  12. tempBytes。 長さ  ;
  13. バッファ。 PutEnd  m_Rsa。Encrypt  tempBytes、 false   ;
  14. }
  15. 戻りバッファ。 配列




自分でJavaに実装したす。いく぀かの倉曎がありたす:)



もちろん、この蚘事のフレヌムワヌクでは、この機胜の実装の範囲党䜓をカバヌするこずはできたせんが、RSAアルゎリズムを䜿甚しおクラむアントに安党なチャネルを実装する方法に぀いおのアむデアは間違いなくあるず思いたす。






All Articles