(Flex) Flex (2012 год)

Криптография во Flex.

Криптография - самое важное изобретение человечества в области интернета. Именно криптография позволяет сделать в интернете вокруг чего-то замкнутое пространство, защищенный домик - куда не могут войти посторонние. Это напоминает право собственности в реальном мире. Без криптографии все лазали бы в интернете везде - пишсали бы что угодно в любые базы, читали бы любые данные. Интернета в современном понимание просто не существовало бы - без возможности защитить хоть что-нибудь свое в интернете от посторонних.

Именно поэтому у меня чуть ли не в каждой моей заметке упоминается криптография:


Для Флекса нет ничего важнее криптографии. Для простых клиент-серверных web-приложений типа ASP.NET, JAVA или PHP есть хоть какие-то иные механизмы защиты - например аутентификация по базе на сервере. Но для Flex и AIR ничего такого нет - это чисто клиентская технология - и если ей надо что-то передать на сервер - это сразу становится видно любому (в Firebug, WireShark и т.д.) И только криптография позволяет защитить хотя бы пароли, с которыми флешовый сайт или AIR ходят на сервер и в базу.

И поэтому любое сколько-нибудь реальное приложение на Flex основано в первую очередь на криптографии, вот сейчас я собираюсь написать серию флешовых сайтов на своих сервисах:


Для Флекса есть несколько библиотек криптографии. Я умею работать с двумя из них - as3crypto и flame - первая более старая, вторая Микрософтовская, полностью совместимая с NET-криптографией. Сейчас я решил во всех проектах применять FLAME (ибо пока на серверах я от NET не отказываюсь и полностью на JAVA я перейти пока не готов).

Самое главное - при работе клиента с сервером - добится полного взаимопонимания по всем основным алгоритмам Asymmetric (RSA, DiffieHellman), Hash (MD5, SHA1), Symmetric (Rijndael, AES, RC4). Для меня самые важные и любимые алгоритмы - RSA, MD5, Rijndael. Вся остальная криптография с легкостью надстраивается над этими алгоритмами.

Однако, мои предпочтения не являются лучшими решениями. Это все лишь дело привычки. Например мой сайт http://www.votpusk.ru/Default.asp весь сделан на Rjndael. Например зайдите в раздел FOTO и посмотрите ID любой фотографии.

Настоящий стандарт симметричного шифрования AES - и если вы хотите сначала идти правильным путем (а не копируете путь программиста со стажем работы 34 года, у которого есть странные и непонятные для вас предпочтения) - вы должны выбирать AES.

То же самое касается RSA. На смену ему пришла ECDH - которая тоже поддерживается FLAME. И если начинать идти сначала и правильным путем - то выбирайте ECDH.


Хеш-коды MD5.


Итак, ниже вы видите живое приложение для расчета хеша MD5, написанное мною на FLAME:



To view this page ensure that Adobe Flash Player version 11.1.0 or greater is installed.

Вот так выглядит исходный код этого приложения:


   1:  <?xml version="1.0" encoding="utf-8"?>
   2:  <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
   3:                 xmlns:s="library://ns.adobe.com/flex/spark" 
   4:                 xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="500" minHeight="700" height="700" width="500" xmlns:upload="services.upload.*" xmlns:upload_local="services.upload_local.*">
   5:      <fx:Script>
   6:          <![CDATA[
   7:              import flame.crypto.HashAlgorithm;
   8:              import flame.crypto.MD5;
   9:              import flame.utils.ByteArrayUtil;
  10:              
  11:              import mx.controls.Alert;
  12:              import mx.events.FlexEvent;
  13:              import mx.rpc.events.FaultEvent;
  14:              import mx.rpc.events.ResultEvent;
  15:              import valueObjects.OneUploadTicket;
  16:   
  17:              protected function button1_clickHandler(event:MouseEvent):void
  18:              {
  19:                  var OneTicket:OneUploadTicket = new OneUploadTicket;
  20:                  OneTicket.ReturnID = tx_ReturnID.text;
  21:                  OneTicket.FromCountry = tx_FromCountry.text;
  22:                  OneTicket.FromCity = tx_FromCity.text;
  23:                  OneTicket.FromAirport = tx_FromAirport.text;
  24:                  OneTicket.ToCountry = tx_ToCountry.text;
  25:                  OneTicket.ToCity = tx_ToCity.text;
  26:                  OneTicket.ToAirport = tx_ToAirport.text;
  27:                  OneTicket.FromDate = tx_FromDate.text;
  28:                  OneTicket.FromTime = tx_FromTime.text;
  29:                  OneTicket.FlyTime = tx_FlyTime.text;
  30:                  OneTicket.AviaCompanyCode = tx_AviaCompanyCode.text;
  31:                  OneTicket.FlyNumber = tx_FlyNumber.text;
  32:                  OneTicket.FlyClass = tx_FlyClass.text;
  33:                  OneTicket.Price = tx_Price.text as Number;
  34:                  OneTicket.HowMany = tx_HowMany.text;
  35:                  OneTicket.AirTransfer = tx_AirTransfer.text;
  36:                  OneTicket.AirTransferComment = tx_AirTransferComment.text;
  37:                  OneTicket.Suplier = tx_Suplier.text;
  38:                  GetTicketMD5Result.addEventListener(ResultEvent.RESULT,AsyncTicketMD5Result);
  39:                  GetTicketMD5Result.addEventListener(FaultEvent.FAULT, function(e:FaultEvent){
  40:                      Alert.show(e.fault.faultString + '\n' + e.fault.faultDetail);
  41:                  });
  42:                  getTicketMD5(OneTicket);
  43:                  GetFlameMD5();
  44:              }
  45:   
  46:              protected function GetFlameMD5(){
  47:                  var SumString:String = tx_ReturnID.text +
  48:                      tx_FromCountry.text +
  49:                      tx_FromCity.text +
  50:                      tx_FromAirport.text +
  51:                      tx_ToCountry.text +
  52:                      tx_ToCity.text +
  53:                      tx_ToAirport.text +
  54:                      tx_FromDate.text +
  55:                      tx_FromTime.text +
  56:                      tx_FlyTime.text +
  57:                      tx_AviaCompanyCode.text +
  58:                      tx_FlyNumber.text +
  59:                      tx_FlyClass.text +
  60:                      tx_Price.text +
  61:                      tx_HowMany.text +
  62:                      tx_AirTransfer.text +
  63:                      tx_AirTransferComment.text +
  64:                      tx_Suplier.text;
  65:                  var Arr1:ByteArray=new ByteArray();
  66:                  Arr1.writeUTFBytes(SumString);
  67:                  var Tst1:String = flame.utils.ByteArrayUtil.toHexString(Arr1);
  68:                      
  69:                  var md5:flame.crypto.HashAlgorithm = new flame.crypto.MD5();
  70:                  md5.computeHash(Arr1);
  71:                  tx_Flex_MD5.text = flame.utils.ByteArrayUtil.toHexString(md5.hash);
  72:              }
  73:              
  74:              protected function getTicketMD5(OneTicket:OneUploadTicket):void
  75:              {
  76:                  GetTicketMD5Result.token = upload.GetTicketMD5(OneTicket);
  77:              }
  78:              
  79:              protected function AsyncTicketMD5Result(e:ResultEvent):void
  80:              {
  81:                  if (e.result !== null){
  82:                      tx_NET_MD5.text = e.result as String;
  83:                  }
  84:              }
  85:              
  86:          ]]>
  87:      </fx:Script>
  88:      <fx:Declarations>
  89:          <s:CallResponder id="GetTicketMD5Result"/>
  90:          <upload:Upload id="upload"  result="AsyncTicketMD5Result" fault="Alert.show(event.fault.faultString + '\n' + event.fault.faultDetail)" showBusyCursor="true"/>
  91:      </fx:Declarations>
  92:      
  93:      <s:BorderContainer width="100%" height="100%" borderWeight="2"  cornerRadius="5" dropShadowVisible="true">
  94:          <s:backgroundFill>
  95:              <s:LinearGradient rotation="90">
  96:                  <s:GradientEntry color="0xF4F4F4" />
  97:                  <s:GradientEntry color="0xB9B9B9" />
  98:              </s:LinearGradient>
  99:          </s:backgroundFill>
 100:      </s:BorderContainer>
 101:      <mx:Form x="20" y="20">
 102:          <mx:FormItem label="ReturnID :">
 103:              <s:TextInput id="tx_ReturnID"  width="250" text="94a9c60f-2b5b-4d0e-b274-81495d42cb5f"/>
 104:          </mx:FormItem>
 105:          <mx:FormItem label="FromCountry :">
 106:              <s:TextInput id="tx_FromCountry"  width="250" text="Россия"/>
 107:          </mx:FormItem>
 108:          <mx:FormItem label="FromCity :">
 109:              <s:TextInput id="tx_FromCity"  width="250" text="Москва"/>
 110:          </mx:FormItem>
 111:          <mx:FormItem label="FromCity :">
 112:              <s:TextInput id="tx_FromAirport"  width="250" text="DME"/>
 113:          </mx:FormItem>
 114:          <mx:FormItem label="ToCountry :">
 115:              <s:TextInput id="tx_ToCountry"  width="250" text="Турция"/>
 116:          </mx:FormItem>
 117:          <mx:FormItem label="ToCity :">
 118:              <s:TextInput id="tx_ToCity"  width="250" text="Анталия"/>
 119:          </mx:FormItem>
 120:          <mx:FormItem label="ToAirport :">
 121:              <s:TextInput id="tx_ToAirport"  width="250" text="AYT-1"/>
 122:          </mx:FormItem>
 123:          <mx:FormItem label="FromDate :">
 124:              <s:TextInput id="tx_FromDate"  width="250" text="01.04.2012"/>
 125:          </mx:FormItem>
 126:          <mx:FormItem label="FromTime :">
 127:              <s:TextInput id="tx_FromTime"  width="250" text="14:00"/>
 128:          </mx:FormItem>
 129:          <mx:FormItem label="FlyTime :">
 130:              <s:TextInput id="tx_FlyTime"  width="250" text="15:00"/>
 131:          </mx:FormItem>
 132:          <mx:FormItem label="AviaCompanyCode :">
 133:              <s:TextInput id="tx_AviaCompanyCode"  width="250" text="LLM"/>
 134:          </mx:FormItem>
 135:          <mx:FormItem label="FlyNumber :">
 136:              <s:TextInput id="tx_FlyNumber"  width="250" text="9355"/>
 137:          </mx:FormItem>
 138:          <mx:FormItem label="FlyClass :">
 139:              <s:TextInput id="tx_FlyClass"  width="250" text="Economy"/>
 140:          </mx:FormItem>
 141:          <mx:FormItem label="Price :">
 142:              <s:TextInput id="tx_Price"  width="250" text="0"/>
 143:          </mx:FormItem>
 144:          <mx:FormItem label="HowMany :">
 145:              <s:TextInput id="tx_HowMany"  width="250" text="Есть"/>
 146:          </mx:FormItem>
 147:          <mx:FormItem label="AirTransfer :">
 148:              <s:TextInput id="tx_AirTransfer"  width="250" text="Нет"/>
 149:          </mx:FormItem>
 150:          <mx:FormItem label="AirTransferComment :">
 151:              <s:TextInput id="tx_AirTransferComment"  width="250" text="-"/>
 152:          </mx:FormItem>
 153:          <mx:FormItem label="Suplier :">
 154:              <s:TextInput id="tx_Suplier"  width="250" text="DDD"/>
 155:          </mx:FormItem>
 156:          <mx:FormItem>
 157:              <mx:VRule height="20" visible="false"/>
 158:              <s:Button label="Check MD5" click="button1_clickHandler(event)" width="250"/>
 159:              <mx:VRule height="20" visible="false"/>
 160:          </mx:FormItem>
 161:          <mx:FormItem label="Flex_MD5 :">
 162:              <s:TextArea id="tx_Flex_MD5"  width="250" height="20"  fontFamily="Courier New"/>
 163:          </mx:FormItem>
 164:          <mx:FormItem label="NET_MD5 :">
 165:              <s:TextArea id="tx_NET_MD5"  width="250" height="20"  fontFamily="Courier New"/>
 166:          </mx:FormItem>
 167:      </mx:Form>

Ссылку на сервис я поставил как описано в заметке - Создание асинхронного прокси для обращения к WCF средствами Adobe flex builder.

Теперь посмотрим согласованный NET-код:


   1:  Public Class Upload
   2:      Implements IUpload
   3:   
   4:      Public Function GetTicketMD5(ByVal OneTicket As OneUploadTicket) As String Implements IUpload.GetTicketMD5
   5:          Dim SB As New StringBuilder
   6:          SB.Append(OneTicket.ReturnID)
   7:          SB.Append(OneTicket.FromCountry)
   8:          SB.Append(OneTicket.FromCity)
   9:          SB.Append(OneTicket.FromAirport)
  10:          SB.Append(OneTicket.ToCountry)
  11:          SB.Append(OneTicket.ToCity)
  12:          SB.Append(OneTicket.ToAirport)
  13:          SB.Append(OneTicket.FromDate)
  14:          SB.Append(OneTicket.FromTime)
  15:          SB.Append(OneTicket.FlyTime)
  16:          SB.Append(OneTicket.AviaCompanyCode)
  17:          SB.Append(OneTicket.FlyNumber)
  18:          SB.Append(OneTicket.FlyClass)
  19:          SB.Append(OneTicket.Price)
  20:          SB.Append(OneTicket.HowMany)
  21:          SB.Append(OneTicket.AirTransfer)
  22:          SB.Append(OneTicket.AirTransferComment)
  23:          SB.Append(OneTicket.Suplier)
  24:          Dim Buf() As Byte = System.Text.Encoding.UTF8.GetBytes(SB.ToString)
  25:          Dim TST1 As String = RSA.ByteArrToString(Buf)
  26:          Dim MD5 As System.Security.Cryptography.MD5 = System.Security.Cryptography.MD5.Create
  27:          Return RSA.ByteArrToString(MD5.ComputeHash(Buf))
  28:      End Function
  29:   
  30:  ...
  31:  End Class


Как видите, хитрость в этом коде только одна - согласовать кодировки русских букв. У Флекса есть два стандартных метода сериализации строк в байтовый поток:

  • writeUTFBytes - Writes a UTF-8 string to the byte stream. Similar to the writeUTF() method, but writeUTFBytes() does not prefix the string with a 16-bit length word.
  • writeUTF - Writes a UTF-8 string to the byte stream. The length of the UTF-8 string in bytes is written first, as a 16-bit integer, followed by the bytes representing the characters of the string.

Исходя из этого и выбирается кодировка в NET.

Симметричная криптография Rijndael.

Ниже вы видите живое приложение для доступа в базу.


To view this page ensure that Adobe Flash Player version 11.1.0 or greater is installed.



Если вы зарегистрируетесь на сайте FlySeason.ru и получите логин/пароль и ключи - то сможете читать/писать в базу FlySeason. А этим тестовым приложением вы будете проверять доступ к базе.



Теперь посмотрим Флекс-код этого приложения:


   1:  <?xml version="1.0" encoding="utf-8"?>
   2:  <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
   3:                 xmlns:s="library://ns.adobe.com/flex/spark" 
   4:                 xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="700" minHeight="750" xmlns:ticketlist="services.ticketlist.*" height="750" width="700"  xmlns:ticketlist_remote="services.ticketlist_remote.*">
   5:      <fx:Script>
   6:          <![CDATA[
   7:              import flame.crypto.ICryptoTransform;
   8:              import flame.crypto.PaddingMode;
   9:              import flame.crypto.RSA;
  10:              import flame.crypto.RSAParameters;
  11:              import flame.crypto.Rijndael;
  12:              import flame.utils.ByteArrayUtil;
  13:              
  14:              import mx.collections.ArrayCollection;
  15:              import mx.controls.Alert;
  16:              import mx.events.FlexEvent;
  17:              import mx.rpc.events.FaultEvent;
  18:              import mx.rpc.events.ResultEvent;
  19:              import mx.utils.UIDUtil;
  20:              import valueObjects.AU;
  21:              import valueObjects.OneGUID;
  22:   
  23:              
  24:              
  25:              protected function button1_clickHandler(event:MouseEvent):void
  26:              {
  27:                  Data.removeAll();
  28:                  var OneGUID1:OneGUID = new OneGUID;
  29:                  OneGUID1.GUID=    TicketID.text;
  30:                  var AU1:AU = new AU;
  31:                  AU1.Username=Username.text;
  32:                  AU1.CryptoMode=IsCrypto.selected;
  33:                  if (IsCrypto.selected){
  34:                      try{
  35:                      
  36:                          var Arr1:ByteArray = new ByteArray();
  37:                          Arr1.writeUTFBytes(Password.text); 
  38:                          
  39:                          var RJ:flame.crypto.Rijndael = new flame.crypto.Rijndael();
  40:                          RJ.padding=flame.crypto.PaddingMode.PKCS7;
  41:                          RJ.keySize=128;
  42:                          RJ.blockSize=128;
  43:                          var RjKey:ByteArray = new ByteArray();
  44:                          var RjIV:ByteArray =  new ByteArray();
  45:                          var CryptoArr:ByteArray = new ByteArray();
  46:                          
  47:                          RjKey= flame.utils.ByteArrayUtil.fromHexString(RijndaelKey.text);
  48:                          RjIV=flame.utils.ByteArrayUtil.fromHexString(RijndaelIV.text);
  49:                          
  50:                          var CryptoTransform:flame.crypto.ICryptoTransform = RJ.createEncryptor(RjKey,RjIV);
  51:                          CryptoArr=CryptoTransform.transformFinalBlock(Arr1,0,Arr1.length);
  52:                          
  53:                          RawPass.text = flame.utils.ByteArrayUtil.toHexString(Arr1);
  54:                          CryptoPass.text = flame.utils.ByteArrayUtil.toHexString(CryptoArr);
  55:                          AU1.Password = CryptoPass.text;
  56:                      
  57:                      }
  58:                      catch (e:Error){
  59:                          Alert.show(e.message);
  60:                      }    
  61:                      
  62:                  }            
  63:                  else{
  64:                      
  65:                      RawPass.text=Password.text;
  66:                      CryptoPass.text="";
  67:                      AU1.Password=Password.text;
  68:                  }
  69:                  
  70:                  getOneTicketDilerInfo2(OneGUID1,AU1);    
  71:                  ticketList_remote.addEventListener(ResultEvent.RESULT,AsyncOneTicketDilerInfoResult)
  72:                  ticketList_remote.addEventListener(FaultEvent.FAULT,FaultOneTicketDilerInfoResult)    
  73:              }
  74:              
  75:              
  76:              [Bindable]
  77:              private var Data:ArrayCollection= new ArrayCollection;
  78:              
  79:              protected function AsyncOneTicketDilerInfoResult(e:ResultEvent):void
  80:              {
  81:                  if (e.result !== null){
  82:                      Data.addItem({Name:"i",Value:e.result.i.toString()});
  83:                      Data.addItem({Name:"ID",Value:e.result.ID.toString()});
  84:                      Data.addItem({Name:"ReturnID",Value:e.result.ReturnID});
  85:                      Data.addItem({Name:"CrDate",Value:e.result.CrDate});
  86:                      Data.addItem({Name:"Special",Value:e.result.Special});
  87:                      Data.addItem({Name:"FromCountry",Value:e.result.FromCountry});
  88:                      Data.addItem({Name:"FromCity",Value:e.result.FromCity});
  89:                      Data.addItem({Name:"FromAirport",Value:e.result.FromAirport});
  90:                      Data.addItem({Name:"ToCountry",Value:e.result.ToCountry});
  91:                      Data.addItem({Name:"ToCity",Value:e.result.ToCity});
  92:                      Data.addItem({Name:"ToAirport",Value:e.result.ToAirport});
  93:                      Data.addItem({Name:"FromDate",Value:e.result.FromDate});
  94:                      Data.addItem({Name:"FromTime",Value:e.result.FromTime});
  95:                      Data.addItem({Name:"FlyTime",Value:e.result.FlyTime});
  96:                      Data.addItem({Name:"AviaCompany",Value:e.result.AviaCompany});
  97:                      Data.addItem({Name:"AviaCompanyCode",Value:e.result.AviaCompanyCode});
  98:                      Data.addItem({Name:"FlyNumber",Value:e.result.FlyNumber});
  99:                      Data.addItem({Name:"FlyClass",Value:e.result.FlyClass});
 100:                      Data.addItem({Name:"Price",Value:e.result.Price});
 101:                      Data.addItem({Name:"HowMany",Value:e.result.HowMany});
 102:                      Data.addItem({Name:"AirTransfer",Value:e.result.AirTransfer});
 103:                      Data.addItem({Name:"AirTransferComment",Value:e.result.AirTransferComment});
 104:                  }
 105:              }
 106:              
 107:              
 108:              protected function getOneTicketDilerInfo2(TicketID:OneGUID, Login:AU):void
 109:              {
 110:                  try{
 111:                      GetOneTicketDilerInfoResult2.token = ticketList_remote.GetOneTicketDilerInfo(TicketID, Login);
 112:                  }
 113:                  catch(e:Error){
 114:                      Alert.show(e.message)
 115:                  }
 116:              }
 117:              
 118:              protected function FaultOneTicketDilerInfoResult(e:FaultEvent):void
 119:              {
 120:                  Alert.show(e.message.toString())
 121:              }
 122:          ]]>
 123:      </fx:Script>
 125:      <fx:Declarations>
 126:          <s:CallResponder id="GetOneTicketDilerInfoResult2"/>
 127:          <ticketlist_remote:TicketList_remote id="ticketList_remote" fault="Alert.show(event.fault.faultString + '\n' + event.fault.faultDetail)" showBusyCursor="true"/>
 128:      </fx:Declarations>
 129:      
 130:      <s:BorderContainer width="100%" height="100%" borderWeight="2"  cornerRadius="5" dropShadowVisible="true">
 131:          <s:backgroundFill>
 132:              <s:LinearGradient rotation="90">
 133:                  <s:GradientEntry color="0xF4F4F4" />
 134:                  <s:GradientEntry color="0xB9B9B9" />
 135:              </s:LinearGradient>
 136:          </s:backgroundFill>
 137:      </s:BorderContainer>
 138:      <mx:Form x="20" y="20">
 139:          <mx:FormItem label="Username :">
 140:              <s:TextInput id="Username"  width="250"/>
 141:          </mx:FormItem>
 142:          <mx:FormItem label="Password :">
 143:              <s:TextInput id="Password" width="250"/>
 144:          </mx:FormItem>
 145:          <mx:FormItem>
 146:              <mx:VRule height="10" visible="false"/>
 147:              <s:CheckBox id="IsCrypto" x="4" y="27" label="Send Crypto Request" selected="true"/>
 148:          </mx:FormItem>
 149:          <mx:FormItem label="Rijndael Key :">
 150:              <s:TextArea id="RijndaelKey" width="250"  height="20"/>
 151:          </mx:FormItem>
 152:          <mx:FormItem label="Rijndael IV :" >
 153:              <s:TextArea id="RijndaelIV" width="250" height="20"/>
 154:          </mx:FormItem>
 155:          <mx:FormItem>
 156:              <mx:VRule height="10" visible="false"/>
 157:          </mx:FormItem>
 158:          <mx:FormItem label="TicketID :">
 159:              <s:TextInput id="TicketID"  width="250"/>
 160:          </mx:FormItem>
 161:          <mx:FormItem>
 162:              <mx:VRule height="20" visible="false"/>
 163:              <s:Button label="Send" click="button1_clickHandler(event)" width="250"/>
 164:              <mx:VRule height="20" visible="false"/>
 165:          </mx:FormItem>
 166:          <mx:FormItem label="RawPassword :">
 167:              <s:Label id="RawPass" />
 168:          </mx:FormItem>
 169:          <mx:FormItem label="CryptoPassword :">
 170:              <s:TextArea id="CryptoPass"  width="500" height="70" />
 171:          </mx:FormItem>
 172:          <mx:FormItem label="Response :">
 173:              <mx:DataGrid id="Tab1" width="500" dataProvider="{Data}" height="280">
 174:                  <mx:columns>
 175:                      <mx:DataGridColumn headerText="Name" dataField="Name" />
 176:                      <mx:DataGridColumn headerText="Value" dataField="Value"/>
 177:                  </mx:columns>
 178:              </mx:DataGrid>
 179:          </mx:FormItem>
 180:      </mx:Form>
 181:  </s:Application>

Согласованный код NET-приложения выглядит так:


   1:  Public Class Cryptor
   2:   
   3:      Dim RJ As System.Security.Cryptography.Rijndael
   4:   
   5:      Public Sub New(ByVal UserName As String)
   6:          Try
   7:              Dim db1 As New DB.FlySeasonDataContext
   8:              Dim CurDiler = (From X In db1.Diler Select X Where X.Login = UserName).ToList
   9:              If CurDiler IsNot Nothing Then
  10:                  If CurDiler.Count > 0 Then
  11:                      PrivateKey = CurDiler(0).PrivateKey.ToString
  12:                      PublicKey = CurDiler(0).PublicKey.ToString
  13:                      '
  14:                      'Инициализация Rijndael
  15:                      RJ = System.Security.Cryptography.Rijndael.Create()
  16:                      RJ.KeySize = 128
  17:                      RJ.BlockSize = 128
  18:                      RJ.Padding = System.Security.Cryptography.PaddingMode.PKCS7
  19:                      RJ.Key = CurDiler(0).RijndaelKey.ToArray
  20:                      RJ.IV = CurDiler(0).RijndaelIV.ToArray
  21:                  End If
  22:              End If
  23:          Catch ex As Exception
  24:              Throw New Exception("No cryptographic key")
  25:          End Try
  26:      End Sub
  27:   
  28:      Public Function DeCryptBytesRJ(ByVal CryptoBytes As Byte()) As String
  29:          Try
  30:              Dim CryptoTransform As System.Security.Cryptography.ICryptoTransform = RJ.CreateDecryptor()
  31:              Dim TstKey As String = Common.ByteArrToString(RJ.Key)
  32:              Dim TstIV As String = Common.ByteArrToString(RJ.IV)
  33:              Dim TstCripto As String = Common.ByteArrToString(CryptoBytes)
  34:              Dim ClearBytes As Byte() = CryptoTransform.TransformFinalBlock(CryptoBytes, 0, CryptoBytes.Length)
  35:              Return System.Text.Encoding.UTF8.GetString(ClearBytes)
  36:          Catch ex As System.Security.Cryptography.CryptographicException
  37:              Return ""
  38:          End Try
  39:      End Function
  40:   
  41:  ...
  42:   
  43:  End Class

Вызывается класс Cryptor так:


   1:  Public Class Common
   2:   
   3:      Public Shared Function GetPassword(ByVal Login As AU) As String
   4:          If Not Login.CryptoMode Then
   5:              Return Login.Password
   6:          Else
   7:              Dim X As New Cryptor(Login.Username)
   8:              Dim Buf() As Byte = StringToByteArr(Login.Password)
   9:   
  10:              Dim RawPassword As String = X.DeCryptBytesRJ(Buf)
  11:              If RawPassword IsNot Nothing Then
  12:                  If RawPassword.Length > 0 Then
  13:                      Dim Pos1 As Integer = RawPassword.IndexOf("###")
  14:                      If Pos1 > 0 Then
  15:                          Return Left(RawPassword, Pos1)
  16:                      Else
  17:                          Return RawPassword
  18:                      End If
  19:                  End If
  20:              End If
  21:          End If
  22:      End Function
  23:   
  24:  ...
  25:   
  26:  End Class

Алгоритм Rijndael при некоторых параметрах ведет себя как стандартизированный AES, а при некоторых хитрее. Подробнее вы можете прочитать здесь - The Differences Between Rijndael and AES. Переделки кода (при переходе от Rijndael к AES и обратно не требуется) - просто замените Rijndael на AES.



В алгоритме RSA при кроссплатформенном подключении возникли неожиданные осложнения. В пределах платформы NET все нормально работает без форматеров и паддинга. Однако при кроссплатформенном подключении для сохранения устойчивости криптоалгоритма обязательно использовать классы RSAPKCSKeyExchangeDeformatter, RSAPKCSKeyExchangeFormatter, RSAOAEPKeyExchangeDeformatter, RSAOAEPKeyExchangeFormatter (http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsaoaepkeyexchangeformatter.aspx для паддингов OAEP или PKCS v1.5 (эту фишку мне любезно разъяснил Рубен Баньян из Микрософта, автор библиотеки FLAME - за что ему огромное спасибо).


Еще одну мою OpenSource-софтинку на эту же тему вы можете посмотреть здесь.

Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23
Link to this page: //www.vb-net.com/Flex_MD5_Rijndael_RSA/index.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <CHAT ME>  <ABOUT ME>  < THANKS ME>