Криптография во Flex.
Криптография - самое важное изобретение человечества в области интернета. Именно криптография позволяет сделать в интернете вокруг чего-то замкнутое пространство, защищенный домик - куда не могут войти посторонние. Это напоминает право собственности в реальном мире. Без криптографии все лазали бы в интернете везде - пишсали бы что угодно в любые базы, читали бы любые данные. Интернета в современном понимание просто не существовало бы - без возможности защитить хоть что-нибудь свое в интернете от посторонних.
Именно поэтому у меня чуть ли не в каждой моей заметке упоминается криптография:
- Remote SQL execute for PostgreSQL on GSM/GPRS channel with extreme compress and cryptography
- SqlClr_IndexCryptoProtector - криптографическая защита индексов SQL-сервера с помощью SQL CLR сборки.
- Шлюзы к платежным системам интернет-денег.
- WebActivator - клиент/сервер защиты от копирования для платных программ.
- Организация SSL транспортного уровня по программно загружаемому клиентскому сертификату
- Безопасность Web-приложений
- NetStringObfuscatorHelper - OpenSource моей библиотеки симметричного шифрования.
- Криптография по ГОСТ, Установка ГОСТ-сертификата на Web-сервер, Установка ГОСТ-сертификата на клиентский компьютер
- Защита параметров странички от подделки
- Устройство Смарт-карт и так далее - если вспоминать все более и более старые свои заметки.
Для Флекса нет ничего важнее криптографии. Для простых клиент-серверных 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-софтинку на эту же тему вы можете посмотреть здесь.
<SITEMAP> <MVC> <ASP> <NET> <DATA> <KIOSK> <FLEX> <SQL> <NOTES> <LINUX> <MONO> <FREEWARE> <DOCS> <ENG> <CHAT ME> <ABOUT ME> < THANKS ME> |